diff --git a/pkg/middleware/middleware.go b/pkg/middleware/middleware.go index 6cec2b9ad05..6c4ce1c20ae 100644 --- a/pkg/middleware/middleware.go +++ b/pkg/middleware/middleware.go @@ -1,8 +1,6 @@ package middleware import ( - "net/http" - "net/url" "strconv" "github.com/grafana/grafana/pkg/bus" @@ -51,8 +49,7 @@ func GetContextHandler(ats *auth.UserAuthTokenService) macaron.Handler { case initContextWithApiKey(ctx): case initContextWithBasicAuth(ctx, orgId): case initContextWithAuthProxy(ctx, orgId): - //case initContextWithUserSessionCookie(ctx, orgId): - case initContextWithToken(ctx, orgId, ats): + case ats.InitContextWithToken(ctx, orgId): case initContextWithAnonymousUser(ctx): } @@ -91,53 +88,6 @@ func initContextWithAnonymousUser(ctx *m.ReqContext) bool { return true } -func initContextWithToken(ctx *m.ReqContext, orgID int64, ts *auth.UserAuthTokenService) bool { - //auth User - unhashedToken := ctx.GetCookie("grafana_session") - if unhashedToken == "" { - return false - } - - user, err := ts.LookupToken(unhashedToken) - if err != nil { - ctx.Logger.Info("failed to look up user based on cookie") - return false - } - - query := m.GetSignedInUserQuery{UserId: user.UserId, OrgId: orgID} - if err := bus.Dispatch(&query); err != nil { - ctx.Logger.Error("Failed to get user with id", "userId", user.UserId, "error", err) - return false - } - - ctx.SignedInUser = query.Result - ctx.IsSignedIn = true - ctx.UserToken = user - - //rotate session token if needed. - rotated, err := ts.RefreshToken(ctx.UserToken, ctx.RemoteAddr(), ctx.Req.UserAgent()) - if err != nil { - ctx.Logger.Error("failed to rotate token", "error", err, "user.id", user.UserId, "user_token.id", user.Id) - return true - } - - if rotated { - ctx.Logger.Info("new token", "unhashed token", ctx.UserToken.UnhashedToken) - ctx.Resp.Header().Del("Set-Cookie") - cookie := http.Cookie{ - Name: setting.SessionOptions.CookieName, - Value: url.QueryEscape(ctx.UserToken.UnhashedToken), - HttpOnly: true, - Domain: setting.Domain, - Path: setting.AppSubUrl + "/", - } - - http.SetCookie(ctx.Resp, &cookie) - } - - return true -} - // func initContextWithUserSessionCookie(ctx *m.ReqContext, orgId int64) bool { // // initialize session // if err := ctx.Session.Start(ctx.Context); err != nil { diff --git a/pkg/services/auth/auth_token.go b/pkg/services/auth/auth_token.go index 5929043573e..49d40400205 100644 --- a/pkg/services/auth/auth_token.go +++ b/pkg/services/auth/auth_token.go @@ -7,6 +7,7 @@ import ( "net/url" "time" + "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/registry" @@ -23,6 +24,7 @@ var ( now = time.Now RotateTime = 1 * time.Minute UrgentRotateTime = 30 * time.Second + oneYearInSeconds = 31557600 //used as default maxage for session cookies. We validate/rotate them more often. ) // UserAuthTokenService are used for generating and validating user auth tokens @@ -37,38 +39,70 @@ func (s *UserAuthTokenService) Init() error { return nil } +func (s *UserAuthTokenService) InitContextWithToken(ctx *models.ReqContext, orgID int64) bool { + //auth User + unhashedToken := ctx.GetCookie(setting.SessionOptions.CookieName) + if unhashedToken == "" { + return false + } + + user, err := s.LookupToken(unhashedToken) + if err != nil { + ctx.Logger.Info("failed to look up user based on cookie", "error", err) + return false + } + + query := models.GetSignedInUserQuery{UserId: user.UserId, OrgId: orgID} + if err := bus.Dispatch(&query); err != nil { + ctx.Logger.Error("Failed to get user with id", "userId", user.UserId, "error", err) + return false + } + + ctx.SignedInUser = query.Result + ctx.IsSignedIn = true + ctx.UserToken = user + + //rotate session token if needed. + rotated, err := s.RefreshToken(ctx.UserToken, ctx.RemoteAddr(), ctx.Req.UserAgent()) + if err != nil { + ctx.Logger.Error("failed to rotate token", "error", err, "user.id", user.UserId, "user_token.id", user.Id) + return true + } + + if rotated { + s.writeSessionCookie(ctx, ctx.UserToken.UnhashedToken, oneYearInSeconds) + } + + return true +} + +func (s *UserAuthTokenService) writeSessionCookie(ctx *models.ReqContext, value string, maxAge int) { + ctx.Logger.Info("new token", "unhashed token", ctx.UserToken.UnhashedToken) + ctx.Resp.Header().Del("Set-Cookie") + cookie := http.Cookie{ + Name: setting.SessionOptions.CookieName, + Value: url.QueryEscape(value), + HttpOnly: true, + Domain: setting.Domain, + Path: setting.AppSubUrl + "/", + Secure: setting.SessionOptions.Secure, + } + + http.SetCookie(ctx.Resp, &cookie) +} + func (s *UserAuthTokenService) UserAuthenticatedHook(user *models.User, c *models.ReqContext) error { userToken, err := s.CreateToken(user.Id, c.RemoteAddr(), c.Req.UserAgent()) if err != nil { return err } - c.Resp.Header().Del("Set-Cookie") - cookie := http.Cookie{ - Name: setting.SessionOptions.CookieName, - Value: url.QueryEscape(userToken.UnhashedToken), - HttpOnly: true, - Domain: setting.Domain, - Path: setting.AppSubUrl + "/", - Secure: setting.SessionOptions.Secure, - } - - http.SetCookie(c.Resp, &cookie) - + s.writeSessionCookie(c, userToken.UnhashedToken, oneYearInSeconds) return nil } func (s *UserAuthTokenService) UserSignedOutHook(c *models.ReqContext) { - c.Resp.Header().Del("Set-Cookie") - cookie := http.Cookie{ - Name: setting.SessionOptions.CookieName, - Value: "", - HttpOnly: true, - Domain: setting.Domain, - Path: setting.AppSubUrl + "/", - Secure: setting.SessionOptions.Secure, - } - http.SetCookie(c.Resp, &cookie) + s.writeSessionCookie(c, "", -1) } func (s *UserAuthTokenService) CreateToken(userId int64, clientIP, userAgent string) (*models.UserAuthToken, error) {