From 257519490a1578471f1182131dbd6a7de85fcd12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 27 Jan 2015 12:05:23 +0100 Subject: [PATCH] Worked on login remember cookie, and redirect after login --- grafana | 2 +- pkg/api/login.go | 79 +++++++++++++++++++++++++++-- pkg/api/signup.go | 1 + pkg/middleware/auth.go | 5 ++ pkg/models/user.go | 2 + pkg/services/sqlstore/migrations.go | 3 ++ pkg/services/sqlstore/sqlstore.go | 1 + pkg/services/sqlstore/user.go | 1 + pkg/util/encoding.go | 9 ++++ 9 files changed, 98 insertions(+), 5 deletions(-) diff --git a/grafana b/grafana index 11b74baf792..4572747bd60 160000 --- a/grafana +++ b/grafana @@ -1 +1 @@ -Subproject commit 11b74baf7920bcd4e39b5e77bfb49e6b08752dc2 +Subproject commit 4572747bd60c688f7cc2cbf8a2303b9c95ad7b9d diff --git a/pkg/api/login.go b/pkg/api/login.go index 6f337283363..79f92b0d13b 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -1,21 +1,72 @@ package api import ( + "net/url" + "github.com/torkelo/grafana-pro/pkg/api/dtos" "github.com/torkelo/grafana-pro/pkg/bus" "github.com/torkelo/grafana-pro/pkg/log" "github.com/torkelo/grafana-pro/pkg/middleware" m "github.com/torkelo/grafana-pro/pkg/models" + "github.com/torkelo/grafana-pro/pkg/setting" "github.com/torkelo/grafana-pro/pkg/util" ) +const ( + VIEW_INDEX = "index" +) + func LoginView(c *middleware.Context) { if err := setIndexViewData(c); err != nil { c.Handle(500, "Failed to get settings", err) return } - c.HTML(200, "index") + // Check auto-login. + uname := c.GetCookie(setting.CookieUserName) + if len(uname) == 0 { + c.HTML(200, VIEW_INDEX) + return + } + + isSucceed := false + defer func() { + if !isSucceed { + log.Trace("auto-login cookie cleared: %s", uname) + c.SetCookie(setting.CookieUserName, "", -1, setting.AppSubUrl+"/") + c.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubUrl+"/") + return + } + }() + + userQuery := m.GetUserByLoginQuery{LoginOrEmail: uname} + if err := bus.Dispatch(&userQuery); err != nil { + if err != m.ErrUserNotFound { + c.Handle(500, "GetUserByLoginQuery", err) + } else { + c.HTML(200, VIEW_INDEX) + } + return + } + + user := userQuery.Result + + if val, _ := c.GetSuperSecureCookie( + util.EncodeMd5(user.Rands+user.Password), setting.CookieRememberName); val != user.Login { + c.HTML(200, VIEW_INDEX) + return + } + + isSucceed = true + loginUserWithUser(user, c) + + if redirectTo, _ := url.QueryUnescape(c.GetCookie("redirect_to")); len(redirectTo) > 0 { + c.SetCookie("redirect_to", "", -1, setting.AppSubUrl+"/") + c.Redirect(redirectTo) + return + } + + c.Redirect(setting.AppSubUrl + "/") } func LoginPost(c *middleware.Context, cmd dtos.LoginCommand) { @@ -36,9 +87,27 @@ func LoginPost(c *middleware.Context, cmd dtos.LoginCommand) { return } + // default to true here for now + cmd.Remember = true + + if cmd.Remember { + days := 86400 * setting.LogInRememberDays + c.SetCookie(setting.CookieUserName, user.Login, days, setting.AppSubUrl+"/") + c.SetSuperSecureCookie(util.EncodeMd5(user.Rands+user.Password), setting.CookieRememberName, user.Login, days, setting.AppSubUrl+"/") + } + loginUserWithUser(user, c) - c.JsonOK("User logged in") + result := map[string]interface{}{ + "message": "Logged in", + } + + if redirectTo, _ := url.QueryUnescape(c.GetCookie("redirect_to")); len(redirectTo) > 0 { + result["redirectUrl"] = redirectTo + c.SetCookie("redirect_to", "", -1, setting.AppSubUrl+"/") + } + + c.JSON(200, result) } func loginUserWithUser(user *m.User, c *middleware.Context) { @@ -50,6 +119,8 @@ func loginUserWithUser(user *m.User, c *middleware.Context) { } func LogoutPost(c *middleware.Context) { - c.Session.Delete("userId") - c.JSON(200, util.DynMap{"status": "logged out"}) + c.SetCookie(setting.CookieUserName, "", -1, setting.AppSubUrl+"/") + c.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubUrl+"/") + c.Session.Destory(c.Context) + c.JsonOK("logged out") } diff --git a/pkg/api/signup.go b/pkg/api/signup.go index d7ab99dc422..786a43d8b7a 100644 --- a/pkg/api/signup.go +++ b/pkg/api/signup.go @@ -12,6 +12,7 @@ func SignUp(c *middleware.Context, cmd m.CreateUserCommand) { cmd.Login = cmd.Email cmd.Salt = util.GetRandomString(10) + cmd.Rands = util.GetRandomString(10) cmd.Password = util.EncodePassword(cmd.Password, cmd.Salt) if err := bus.Dispatch(&cmd); err != nil { diff --git a/pkg/middleware/auth.go b/pkg/middleware/auth.go index b7ff7459aa6..e4216341443 100644 --- a/pkg/middleware/auth.go +++ b/pkg/middleware/auth.go @@ -1,10 +1,12 @@ package middleware import ( + "net/url" "strings" "github.com/Unknwon/macaron" + "github.com/torkelo/grafana-pro/pkg/log" m "github.com/torkelo/grafana-pro/pkg/models" "github.com/torkelo/grafana-pro/pkg/setting" ) @@ -45,6 +47,7 @@ func getApiKey(c *Context) string { func authDenied(c *Context) { if c.IsApiRequest() { c.JsonApiErr(401, "Access denied", nil) + return } c.Redirect(setting.AppSubUrl + "/login") @@ -69,6 +72,8 @@ func Auth(options *AuthOptions) macaron.Handler { return func(c *Context) { if !c.IsSignedIn && options.ReqSignedIn { + log.Info("AppSubUrl: %v", setting.AppSubUrl) + c.SetCookie("redirect_to", url.QueryEscape(setting.AppSubUrl+c.Req.RequestURI), 0, setting.AppSubUrl+"/") authDenied(c) return } diff --git a/pkg/models/user.go b/pkg/models/user.go index fe031f00de2..6efc5dd7b07 100644 --- a/pkg/models/user.go +++ b/pkg/models/user.go @@ -17,6 +17,7 @@ type User struct { Login string Password string Salt string + Rands string Company string IsAdmin bool @@ -36,6 +37,7 @@ type CreateUserCommand struct { Company string `json:"compay"` Password string `json:"password" binding:"Required"` Salt string `json:"-"` + Rands string `json:"-"` IsAdmin bool `json:"-"` Result User `json:"-"` diff --git a/pkg/services/sqlstore/migrations.go b/pkg/services/sqlstore/migrations.go index 8f87992e73f..0fddf7397d0 100644 --- a/pkg/services/sqlstore/migrations.go +++ b/pkg/services/sqlstore/migrations.go @@ -50,6 +50,9 @@ func addUserMigrations(mg *Migrator) { Table("user").Columns("login").Unique()) mg.AddMigration("add unique index user.email", new(AddIndexMigration). Table("user").Columns("email").Unique()) + + mg.AddMigration("add column user.rands", new(AddColumnMigration). + Table("user").Column(&Column{Name: "rands", Type: DB_NVarchar, Length: 255, Nullable: true})) } func addAccountMigrations(mg *Migrator) { diff --git a/pkg/services/sqlstore/sqlstore.go b/pkg/services/sqlstore/sqlstore.go index c47c2a4e90c..9e47776f66c 100644 --- a/pkg/services/sqlstore/sqlstore.go +++ b/pkg/services/sqlstore/sqlstore.go @@ -41,6 +41,7 @@ func EnsureAdminUser() { cmd.Login = setting.AdminUser cmd.Email = setting.AdminUser + "@localhost" cmd.Salt = util.GetRandomString(10) + cmd.Rands = util.GetRandomString(10) cmd.Password = util.EncodePassword(setting.AdminPassword, cmd.Salt) cmd.IsAdmin = true diff --git a/pkg/services/sqlstore/user.go b/pkg/services/sqlstore/user.go index 57bb2863085..78a42bf6e5d 100644 --- a/pkg/services/sqlstore/user.go +++ b/pkg/services/sqlstore/user.go @@ -43,6 +43,7 @@ func CreateUser(cmd *m.CreateUserCommand) error { Login: cmd.Login, Company: cmd.Company, Salt: cmd.Salt, + Rands: cmd.Rands, IsAdmin: cmd.IsAdmin, AccountId: account.Id, Created: time.Now(), diff --git a/pkg/util/encoding.go b/pkg/util/encoding.go index e69d688492b..417ee14f69f 100644 --- a/pkg/util/encoding.go +++ b/pkg/util/encoding.go @@ -2,8 +2,10 @@ package util import ( "crypto/hmac" + "crypto/md5" "crypto/rand" "crypto/sha256" + "encoding/hex" "fmt" "hash" ) @@ -28,6 +30,13 @@ func EncodePassword(password string, salt string) string { return fmt.Sprintf("%x", newPasswd) } +// Encode string to md5 hex value. +func EncodeMd5(str string) string { + m := md5.New() + m.Write([]byte(str)) + return hex.EncodeToString(m.Sum(nil)) +} + // http://code.google.com/p/go/source/browse/pbkdf2/pbkdf2.go?repo=crypto func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte { prf := hmac.New(h, password)