From 4626f083bb36636cc38b85aa0115106348bf53c2 Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 23 Jan 2019 17:01:09 +0100 Subject: [PATCH] store oauth login error messages in an encrypted cookie --- pkg/api/login.go | 47 +++++++++++++++++++++++++++++++++++++++--- pkg/api/login_oauth.go | 16 +++++++------- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/pkg/api/login.go b/pkg/api/login.go index 0348a956bbf..db75b12a202 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -1,6 +1,8 @@ package api import ( + "encoding/hex" + "net/http" "net/url" "github.com/grafana/grafana/pkg/api/dtos" @@ -10,10 +12,12 @@ import ( "github.com/grafana/grafana/pkg/metrics" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/util" ) const ( - ViewIndex = "index" + ViewIndex = "index" + LoginErrorCookieName = "login_error" ) func (hs *HTTPServer) LoginView(c *m.ReqContext) { @@ -33,8 +37,8 @@ func (hs *HTTPServer) LoginView(c *m.ReqContext) { viewData.Settings["loginHint"] = setting.LoginHint viewData.Settings["disableLoginForm"] = setting.DisableLoginForm - if loginError, ok := c.Session.Get("loginError").(string); ok { - c.Session.Delete("loginError") + if loginError, ok := tryGetEncryptedCookie(c, LoginErrorCookieName); ok { + deleteCookie(c, LoginErrorCookieName) viewData.Settings["loginError"] = loginError } @@ -141,3 +145,40 @@ func (hs *HTTPServer) Logout(c *m.ReqContext) { c.Redirect(setting.AppSubUrl + "/login") } } + +func tryGetEncryptedCookie(ctx *m.ReqContext, cookieName string) (string, bool) { + cookie := ctx.GetCookie(cookieName) + if cookie == "" { + return "", false + } + + decoded, err := hex.DecodeString(cookie) + if err != nil { + return "", false + } + + decryptedError, err := util.Decrypt([]byte(decoded), setting.SecretKey) + return string(decryptedError), err == nil +} + +func deleteCookie(ctx *m.ReqContext, cookieName string) { + ctx.SetCookie(cookieName, "", -1, setting.AppSubUrl+"/") +} + +func (hs *HTTPServer) trySetEncryptedCookie(ctx *m.ReqContext, cookieName string, value string, maxAge int) error { + encryptedError, err := util.Encrypt([]byte(value), setting.SecretKey) + if err != nil { + return err + } + + http.SetCookie(ctx.Resp, &http.Cookie{ + Name: cookieName, + MaxAge: 60, + Value: hex.EncodeToString(encryptedError), + HttpOnly: true, + Path: setting.AppSubUrl + "/", + Secure: hs.Cfg.LoginCookieSecure, + }) + + return nil +} diff --git a/pkg/api/login_oauth.go b/pkg/api/login_oauth.go index 36c9c12905f..91f0dde9e64 100644 --- a/pkg/api/login_oauth.go +++ b/pkg/api/login_oauth.go @@ -52,7 +52,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *m.ReqContext) { if errorParam != "" { errorDesc := ctx.Query("error_description") oauthLogger.Error("failed to login ", "error", errorParam, "errorDesc", errorDesc) - redirectWithError(ctx, login.ErrProviderDeniedRequest, "error", errorParam, "errorDesc", errorDesc) + hs.redirectWithError(ctx, login.ErrProviderDeniedRequest, "error", errorParam, "errorDesc", errorDesc) return } @@ -142,7 +142,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *m.ReqContext) { userInfo, err := connect.UserInfo(client, token) if err != nil { if sErr, ok := err.(*social.Error); ok { - redirectWithError(ctx, sErr) + hs.redirectWithError(ctx, sErr) } else { ctx.Handle(500, fmt.Sprintf("login.OAuthLogin(get info from %s)", name), err) } @@ -153,13 +153,13 @@ func (hs *HTTPServer) OAuthLogin(ctx *m.ReqContext) { // validate that we got at least an email address if userInfo.Email == "" { - redirectWithError(ctx, login.ErrNoEmail) + hs.redirectWithError(ctx, login.ErrNoEmail) return } // validate that the email is allowed to login to grafana if !connect.IsEmailAllowed(userInfo.Email) { - redirectWithError(ctx, login.ErrEmailNotAllowed) + hs.redirectWithError(ctx, login.ErrEmailNotAllowed) return } @@ -182,9 +182,10 @@ func (hs *HTTPServer) OAuthLogin(ctx *m.ReqContext) { ExternalUser: extUser, SignupAllowed: connect.IsSignupAllowed(), } + err = bus.Dispatch(cmd) if err != nil { - redirectWithError(ctx, err) + hs.redirectWithError(ctx, err) return } @@ -218,8 +219,9 @@ func hashStatecode(code, seed string) string { return hex.EncodeToString(hashBytes[:]) } -func redirectWithError(ctx *m.ReqContext, err error, v ...interface{}) { +func (hs *HTTPServer) redirectWithError(ctx *m.ReqContext, err error, v ...interface{}) { ctx.Logger.Error(err.Error(), v...) - ctx.Session.Set("loginError", err.Error()) + hs.trySetEncryptedCookie(ctx, LoginErrorCookieName, err.Error(), 60) + ctx.Redirect(setting.AppSubUrl + "/login") }