From aba6148c4322ca914dd564f5a1d64d5d9ce39804 Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 16 Jan 2019 14:53:59 +0100 Subject: [PATCH] login users based on token cookie --- pkg/api/http_server.go | 16 +++---- pkg/api/login.go | 8 ++-- pkg/middleware/middleware.go | 33 +++++++++++++-- pkg/middleware/org_redirect.go | 1 - pkg/services/auth/auth_token.go | 62 +++++++++++++++++----------- pkg/services/auth/auth_token_test.go | 36 ++++++++-------- 6 files changed, 95 insertions(+), 61 deletions(-) diff --git a/pkg/api/http_server.go b/pkg/api/http_server.go index 600157878fe..54f0601e577 100644 --- a/pkg/api/http_server.go +++ b/pkg/api/http_server.go @@ -11,16 +11,8 @@ import ( "path" "time" - "github.com/grafana/grafana/pkg/services/auth" - - "github.com/grafana/grafana/pkg/api/routing" - "github.com/prometheus/client_golang/prometheus" - - "github.com/prometheus/client_golang/prometheus/promhttp" - - macaron "gopkg.in/macaron.v1" - "github.com/grafana/grafana/pkg/api/live" + "github.com/grafana/grafana/pkg/api/routing" httpstatic "github.com/grafana/grafana/pkg/api/static" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" @@ -29,11 +21,15 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/registry" + "github.com/grafana/grafana/pkg/services/auth" "github.com/grafana/grafana/pkg/services/cache" "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/hooks" "github.com/grafana/grafana/pkg/services/rendering" "github.com/grafana/grafana/pkg/setting" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + macaron "gopkg.in/macaron.v1" ) func init() { @@ -226,7 +222,7 @@ func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() { m.Use(hs.healthHandler) m.Use(hs.metricsEndpoint) - m.Use(middleware.GetContextHandler()) + m.Use(middleware.GetContextHandler(hs.AuthTokenService)) m.Use(middleware.Sessioner(&setting.SessionOptions, setting.SessionConnMaxLifetime)) m.Use(middleware.OrgRedirect()) diff --git a/pkg/api/login.go b/pkg/api/login.go index f0902a60f58..37b12d03299 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -42,10 +42,10 @@ func (hs *HTTPServer) LoginView(c *m.ReqContext) { return } - if !hs.tryLoginUsingRememberCookie(c) { - c.HTML(200, ViewIndex, viewData) - return - } + //if !hs.tryLoginUsingRememberCookie(c) { + c.HTML(200, ViewIndex, viewData) + return + //} if redirectTo, _ := url.QueryUnescape(c.GetCookie("redirect_to")); len(redirectTo) > 0 { c.SetCookie("redirect_to", "", -1, setting.AppSubUrl+"/") diff --git a/pkg/middleware/middleware.go b/pkg/middleware/middleware.go index ace72d998eb..28f08869425 100644 --- a/pkg/middleware/middleware.go +++ b/pkg/middleware/middleware.go @@ -3,15 +3,15 @@ package middleware import ( "strconv" - "gopkg.in/macaron.v1" - "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/apikeygen" "github.com/grafana/grafana/pkg/log" m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/auth" "github.com/grafana/grafana/pkg/services/session" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" + "gopkg.in/macaron.v1" ) var ( @@ -21,7 +21,7 @@ var ( ReqOrgAdmin = RoleAuth(m.ROLE_ADMIN) ) -func GetContextHandler() macaron.Handler { +func GetContextHandler(ats *auth.UserAuthTokenService) macaron.Handler { return func(c *macaron.Context) { ctx := &m.ReqContext{ Context: c, @@ -49,7 +49,8 @@ func GetContextHandler() macaron.Handler { case initContextWithApiKey(ctx): case initContextWithBasicAuth(ctx, orgId): case initContextWithAuthProxy(ctx, orgId): - case initContextWithUserSessionCookie(ctx, orgId): + //case initContextWithUserSessionCookie(ctx, orgId): + case initContextWithToken(ctx, orgId, ats): case initContextWithAnonymousUser(ctx): } @@ -58,6 +59,11 @@ func GetContextHandler() macaron.Handler { c.Map(ctx) + c.Next() + + //if signed in with token + //ats.RefreshToken() + // update last seen every 5min if ctx.ShouldUpdateLastSeenAt() { ctx.Logger.Debug("Updating last user_seen_at", "user_id", ctx.UserId) @@ -88,6 +94,25 @@ func initContextWithAnonymousUser(ctx *m.ReqContext) bool { return true } +func initContextWithToken(ctx *m.ReqContext, orgID int64, ts *auth.UserAuthTokenService) bool { + user, err := ts.LookupToken(ctx) + 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 + + 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/middleware/org_redirect.go b/pkg/middleware/org_redirect.go index db263c2a17a..ca63733946c 100644 --- a/pkg/middleware/org_redirect.go +++ b/pkg/middleware/org_redirect.go @@ -9,7 +9,6 @@ import ( "github.com/grafana/grafana/pkg/bus" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" - "gopkg.in/macaron.v1" ) diff --git a/pkg/services/auth/auth_token.go b/pkg/services/auth/auth_token.go index aefcccadbd6..d812124f1c1 100644 --- a/pkg/services/auth/auth_token.go +++ b/pkg/services/auth/auth_token.go @@ -3,16 +3,17 @@ package auth import ( "crypto/sha256" "encoding/hex" + "fmt" + "net/http" + "net/url" "time" - "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/util" - macaron "gopkg.in/macaron.v1" - "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/registry" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/util" ) func init() { @@ -42,7 +43,15 @@ func (s *UserAuthTokenService) UserAuthenticatedHook(user *models.User, c *model } c.Resp.Header().Del("Set-Cookie") - c.SetCookie(sessionCookieKey, userToken.unhashedToken, setting.AppSubUrl+"/", setting.Domain, false, true) + cookie := http.Cookie{ + Name: sessionCookieKey, + Value: url.QueryEscape(userToken.unhashedToken), + HttpOnly: true, + Expires: time.Now().Add(time.Minute * 10), + Domain: setting.Domain, + } + + c.Resp.Header().Add("Set-Cookie", cookie.String()) return nil } @@ -51,27 +60,27 @@ func (s *UserAuthTokenService) UserSignedOutHook(c *models.ReqContext) { c.SetCookie(sessionCookieKey, "", -1, setting.AppSubUrl+"/", setting.Domain, false, true) } -func (s *UserAuthTokenService) RequestMiddleware() macaron.Handler { - return func(ctx *models.ReqContext) { - authToken := ctx.GetCookie(sessionCookieKey) - userToken, err := s.lookupToken(authToken) - if err != nil { +// func (s *UserAuthTokenService) RequestMiddleware() macaron.Handler { +// return func(ctx *models.ReqContext) { +// authToken := ctx.GetCookie(sessionCookieKey) +// userToken, err := s.LookupToken(authToken) +// if err != nil { - } +// } - ctx.Next() +// ctx.Next() - refreshed, err := s.refreshToken(userToken, ctx.RemoteAddr(), ctx.Req.UserAgent()) - if err != nil { +// refreshed, err := s.RefreshToken(userToken, ctx.RemoteAddr(), ctx.Req.UserAgent()) +// if err != nil { - } +// } - if refreshed { - ctx.Resp.Header().Del("Set-Cookie") - ctx.SetCookie(sessionCookieKey, userToken.unhashedToken, setting.AppSubUrl+"/", setting.Domain, false, true) - } - } -} +// if refreshed { +// ctx.Resp.Header().Del("Set-Cookie") +// ctx.SetCookie(sessionCookieKey, userToken.unhashedToken, setting.AppSubUrl+"/", setting.Domain, false, true) +// } +// } +// } func (s *UserAuthTokenService) CreateToken(userId int64, clientIP, userAgent string) (*userAuthToken, error) { clientIP = util.ParseIPAddress(clientIP) @@ -104,7 +113,12 @@ func (s *UserAuthTokenService) CreateToken(userId int64, clientIP, userAgent str return &userToken, nil } -func (s *UserAuthTokenService) lookupToken(unhashedToken string) (*userAuthToken, error) { +func (s *UserAuthTokenService) LookupToken(ctx *models.ReqContext) (*userAuthToken, error) { + unhashedToken := ctx.GetCookie(sessionCookieKey) + if unhashedToken == "" { + return nil, fmt.Errorf("session token cookie is empty") + } + hashedToken := hashToken(unhashedToken) var userToken userAuthToken @@ -157,7 +171,7 @@ func (s *UserAuthTokenService) lookupToken(unhashedToken string) (*userAuthToken return &userToken, nil } -func (s *UserAuthTokenService) refreshToken(token *userAuthToken, clientIP, userAgent string) (bool, error) { +func (s *UserAuthTokenService) RefreshToken(token *userAuthToken, clientIP, userAgent string) (bool, error) { // lookup token in db // refresh token if needed diff --git a/pkg/services/auth/auth_token_test.go b/pkg/services/auth/auth_token_test.go index 2e4618c10ed..4a0ca952bd1 100644 --- a/pkg/services/auth/auth_token_test.go +++ b/pkg/services/auth/auth_token_test.go @@ -27,22 +27,22 @@ func TestUserAuthToken(t *testing.T) { So(token.AuthTokenSeen, ShouldBeFalse) Convey("When lookup unhashed token should return user auth token", func() { - lookupToken, err := userAuthTokenService.lookupToken(token.unhashedToken) + LookupToken, err := userAuthTokenService.LookupToken(token.unhashedToken) So(err, ShouldBeNil) - So(lookupToken, ShouldNotBeNil) - So(lookupToken.UserId, ShouldEqual, userID) - So(lookupToken.AuthTokenSeen, ShouldBeTrue) + So(LookupToken, ShouldNotBeNil) + So(LookupToken.UserId, ShouldEqual, userID) + So(LookupToken.AuthTokenSeen, ShouldBeTrue) - storedAuthToken, err := ctx.getAuthTokenByID(lookupToken.Id) + storedAuthToken, err := ctx.getAuthTokenByID(LookupToken.Id) So(err, ShouldBeNil) So(storedAuthToken, ShouldNotBeNil) So(storedAuthToken.AuthTokenSeen, ShouldBeTrue) }) Convey("When lookup hashed token should return user auth token not found error", func() { - lookupToken, err := userAuthTokenService.lookupToken(token.AuthToken) + LookupToken, err := userAuthTokenService.LookupToken(token.AuthToken) So(err, ShouldEqual, ErrAuthTokenNotFound) - So(lookupToken, ShouldBeNil) + So(LookupToken, ShouldBeNil) }) }) @@ -51,25 +51,25 @@ func TestUserAuthToken(t *testing.T) { So(err, ShouldBeNil) So(token, ShouldNotBeNil) - _, err = userAuthTokenService.lookupToken(token.unhashedToken) + _, err = userAuthTokenService.LookupToken(token.unhashedToken) So(err, ShouldBeNil) token, err = ctx.getAuthTokenByID(token.Id) So(err, ShouldBeNil) // set now (now - 23 hours) - _, err = userAuthTokenService.refreshToken(token, "192.168.10.11:1234", "some user agent") + _, err = userAuthTokenService.RefreshToken(token, "192.168.10.11:1234", "some user agent") So(err, ShouldBeNil) - _, err = userAuthTokenService.lookupToken(token.unhashedToken) + _, err = userAuthTokenService.LookupToken(token.unhashedToken) So(err, ShouldBeNil) - stillGood, err := userAuthTokenService.lookupToken(token.unhashedToken) + stillGood, err := userAuthTokenService.LookupToken(token.unhashedToken) So(err, ShouldBeNil) So(stillGood, ShouldNotBeNil) // set now (new - 2 hours) - notGood, err := userAuthTokenService.lookupToken(token.unhashedToken) + notGood, err := userAuthTokenService.LookupToken(token.unhashedToken) So(err, ShouldEqual, ErrAuthTokenNotFound) So(notGood, ShouldBeNil) }) @@ -82,7 +82,7 @@ func TestUserAuthToken(t *testing.T) { prevToken := token.AuthToken unhashedPrev := token.unhashedToken - refreshed, err := userAuthTokenService.refreshToken(token, "192.168.10.12:1234", "a new user agent") + refreshed, err := userAuthTokenService.RefreshToken(token, "192.168.10.12:1234", "a new user agent") So(err, ShouldBeNil) So(refreshed, ShouldBeFalse) @@ -95,7 +95,7 @@ func TestUserAuthToken(t *testing.T) { return t } - refreshed, err = userAuthTokenService.refreshToken(token, "192.168.10.12:1234", "a new user agent") + refreshed, err = userAuthTokenService.RefreshToken(token, "192.168.10.12:1234", "a new user agent") So(err, ShouldBeNil) So(refreshed, ShouldBeTrue) @@ -112,13 +112,13 @@ func TestUserAuthToken(t *testing.T) { So(token.SeenAt, ShouldEqual, 0) So(token.PrevAuthToken, ShouldEqual, prevToken) - lookedUp, err := userAuthTokenService.lookupToken(token.unhashedToken) + lookedUp, err := userAuthTokenService.LookupToken(token.unhashedToken) So(err, ShouldBeNil) So(lookedUp, ShouldNotBeNil) So(lookedUp.AuthTokenSeen, ShouldBeTrue) So(lookedUp.SeenAt, ShouldEqual, t.Unix()) - lookedUp, err = userAuthTokenService.lookupToken(unhashedPrev) + lookedUp, err = userAuthTokenService.LookupToken(unhashedPrev) So(err, ShouldBeNil) So(lookedUp, ShouldNotBeNil) So(lookedUp.Id, ShouldEqual, token.Id) @@ -127,7 +127,7 @@ func TestUserAuthToken(t *testing.T) { return t.Add(2 * time.Minute) } - lookedUp, err = userAuthTokenService.lookupToken(unhashedPrev) + lookedUp, err = userAuthTokenService.LookupToken(unhashedPrev) So(err, ShouldBeNil) So(lookedUp, ShouldNotBeNil) @@ -136,7 +136,7 @@ func TestUserAuthToken(t *testing.T) { So(lookedUp, ShouldNotBeNil) So(lookedUp.AuthTokenSeen, ShouldBeFalse) - refreshed, err = userAuthTokenService.refreshToken(token, "192.168.10.12:1234", "a new user agent") + refreshed, err = userAuthTokenService.RefreshToken(token, "192.168.10.12:1234", "a new user agent") So(err, ShouldBeNil) So(refreshed, ShouldBeTrue)