diff --git a/pkg/api/login.go b/pkg/api/login.go index d25e83d34e8..def24f983c1 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -137,7 +137,7 @@ func (hs *HTTPServer) loginUserWithUser(user *m.User, c *m.ReqContext) { hs.log.Error("failed to create auth token", "error", err) } - middleware.WriteSessionCookie(c, userToken.GetToken(), middleware.OneYearInSeconds) + middleware.WriteSessionCookie(c, userToken.GetToken(), hs.Cfg.LoginMaxLifetimeDays) } func (hs *HTTPServer) Logout(c *m.ReqContext) { @@ -185,7 +185,8 @@ func (hs *HTTPServer) trySetEncryptedCookie(ctx *m.ReqContext, cookieName string Value: hex.EncodeToString(encryptedError), HttpOnly: true, Path: setting.AppSubUrl + "/", - Secure: hs.Cfg.SecurityHTTPSCookies, + Secure: hs.Cfg.CookieSecure, + SameSite: hs.Cfg.CookieSameSite, }) return nil diff --git a/pkg/api/login_oauth.go b/pkg/api/login_oauth.go index 4160d48733e..87a8ecc876f 100644 --- a/pkg/api/login_oauth.go +++ b/pkg/api/login_oauth.go @@ -214,7 +214,8 @@ func (hs *HTTPServer) writeCookie(w http.ResponseWriter, name string, value stri Value: value, HttpOnly: true, Path: setting.AppSubUrl + "/", - Secure: hs.Cfg.SecurityHTTPSCookies, + Secure: hs.Cfg.CookieSecure, + SameSite: hs.Cfg.CookieSameSite, }) } diff --git a/pkg/middleware/middleware.go b/pkg/middleware/middleware.go index 6cf29340b82..9a3e5e1e01c 100644 --- a/pkg/middleware/middleware.go +++ b/pkg/middleware/middleware.go @@ -4,6 +4,7 @@ import ( "net/http" "net/url" "strconv" + "time" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/apikeygen" @@ -168,11 +169,8 @@ func initContextWithBasicAuth(ctx *m.ReqContext, orgId int64) bool { return true } -const cookieName = "grafana_session" -const OneYearInSeconds = 31557600 //used as default maxage for session cookies. We validate/rotate them more often. - func initContextWithToken(authTokenService authtoken.UserAuthTokenService, ctx *m.ReqContext, orgID int64) bool { - rawToken := ctx.GetCookie(cookieName) + rawToken := ctx.GetCookie(setting.LoginCookieName) if rawToken == "" { return false } @@ -200,26 +198,34 @@ func initContextWithToken(authTokenService authtoken.UserAuthTokenService, ctx * } if rotated { - WriteSessionCookie(ctx, token.GetToken(), OneYearInSeconds) + WriteSessionCookie(ctx, token.GetToken(), setting.LoginMaxLifetimeDays) } return true } -func WriteSessionCookie(ctx *m.ReqContext, value string, maxAge int) { +func WriteSessionCookie(ctx *m.ReqContext, value string, maxLifetimeDays int) { if setting.Env == setting.DEV { ctx.Logger.Info("new token", "unhashed token", value) } + var maxAge int + if maxLifetimeDays <= 0 { + maxAge = -1 + } else { + maxAgeHours := (time.Duration(setting.LoginMaxLifetimeDays) * 24 * time.Hour) + time.Hour + maxAge = int(maxAgeHours.Seconds()) + } + ctx.Resp.Header().Del("Set-Cookie") cookie := http.Cookie{ - Name: cookieName, + Name: setting.LoginCookieName, Value: url.QueryEscape(value), HttpOnly: true, Path: setting.AppSubUrl + "/", - Secure: false, // TODO: use setting SecurityHTTPSCookies + Secure: setting.CookieSecure, MaxAge: maxAge, - SameSite: http.SameSiteLaxMode, // TODO: use setting LoginCookieSameSite + SameSite: setting.CookieSameSite, } http.SetCookie(ctx.Resp, &cookie) diff --git a/pkg/middleware/middleware_test.go b/pkg/middleware/middleware_test.go index 4e10ee39201..fdcc56da3bf 100644 --- a/pkg/middleware/middleware_test.go +++ b/pkg/middleware/middleware_test.go @@ -6,6 +6,7 @@ import ( "net/http/httptest" "path/filepath" "testing" + "time" msession "github.com/go-macaron/session" "github.com/grafana/grafana/pkg/bus" @@ -197,13 +198,17 @@ func TestMiddlewareContext(t *testing.T) { return true, nil } + maxAgeHours := (time.Duration(setting.LoginMaxLifetimeDays) * 24 * time.Hour) + maxAge := (maxAgeHours + time.Hour).Seconds() + expectedCookie := &http.Cookie{ - Name: cookieName, + Name: setting.LoginCookieName, Value: "rotated", Path: setting.AppSubUrl + "/", HttpOnly: true, - MaxAge: OneYearInSeconds, - SameSite: http.SameSiteLaxMode, + MaxAge: int(maxAge), + Secure: setting.CookieSecure, + SameSite: setting.CookieSameSite, } sc.fakeReq("GET", "/").exec() @@ -545,6 +550,9 @@ func middlewareScenario(desc string, fn scenarioFunc) { Convey(desc, func() { defer bus.ClearBusHandlers() + setting.LoginCookieName = "grafana_session" + setting.LoginMaxLifetimeDays = 30 + sc := &scenarioContext{} viewsPath, _ := filepath.Abs("../../public/views") @@ -655,7 +663,7 @@ func (sc *scenarioContext) exec() { if sc.tokenSessionCookie != "" { sc.req.AddCookie(&http.Cookie{ - Name: cookieName, + Name: setting.LoginCookieName, Value: sc.tokenSessionCookie, }) }