diff --git a/devenv/docker/blocks/openldap/notes.md b/devenv/docker/blocks/openldap/notes.md index 65155423616..d52e6bc6b6d 100644 --- a/devenv/docker/blocks/openldap/notes.md +++ b/devenv/docker/blocks/openldap/notes.md @@ -2,7 +2,7 @@ Any ldif files added to the prepopulate subdirectory will be automatically imported into the OpenLdap database. -The ldif files add three users, `ldapviewer`, `ldapeditor` and `ldapadmin`. Two groups, `admins` and `users`, are added that correspond with the group mappings in the default conf/ldap.toml. `ldapadmin` is a member of `admins` and `ldapeditor` is a member of `users`. +The ldif files add eight users, `ldap-admin`, `ldap-editor`, `ldap-viewer`, `ldap-carl`, `ldap-daniel`, `ldap-leo`, `ldap-tobias` and `ldap-torkel`. Two groups, `admins` and `users`, are added that correspond with the group mappings in the default conf/ldap.toml. `ldap-admin` is a member of `admins` and `ldap-editor` is a member of `users`. Note that users that are added here need to specify a `memberOf` attribute manually as well as the `member` attribute for the group. The `memberOf` module usually does this automatically (if you add a group in Apache Directory Studio for example) but this does not work in the entrypoint script as it uses the `slapadd` command to add entries before the server has started and before the `memberOf` module is loaded. diff --git a/pkg/api/common_test.go b/pkg/api/common_test.go index 4e0b0dcd998..0764fb0bfd6 100644 --- a/pkg/api/common_test.go +++ b/pkg/api/common_test.go @@ -9,9 +9,8 @@ import ( "github.com/grafana/grafana/pkg/middleware" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/auth" - "gopkg.in/macaron.v1" - . "github.com/smartystreets/goconvey/convey" + "gopkg.in/macaron.v1" ) func loggedInUserScenario(desc string, url string, fn scenarioFunc) { @@ -124,7 +123,7 @@ func setupScenarioContext(url string) *scenarioContext { Delims: macaron.Delims{Left: "[[", Right: "]]"}, })) - sc.m.Use(middleware.GetContextHandler(nil)) + sc.m.Use(middleware.GetContextHandler(nil, nil)) return sc } diff --git a/pkg/api/http_server.go b/pkg/api/http_server.go index 2a430147b55..2efa22c34fb 100644 --- a/pkg/api/http_server.go +++ b/pkg/api/http_server.go @@ -16,6 +16,7 @@ import ( httpstatic "github.com/grafana/grafana/pkg/api/static" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/infra/remotecache" "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/models" @@ -26,7 +27,6 @@ import ( "github.com/grafana/grafana/pkg/services/hooks" "github.com/grafana/grafana/pkg/services/quota" "github.com/grafana/grafana/pkg/services/rendering" - "github.com/grafana/grafana/pkg/services/session" "github.com/grafana/grafana/pkg/setting" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -48,15 +48,16 @@ type HTTPServer struct { streamManager *live.StreamManager httpSrv *http.Server - RouteRegister routing.RouteRegister `inject:""` - Bus bus.Bus `inject:""` - RenderService rendering.Service `inject:""` - Cfg *setting.Cfg `inject:""` - HooksService *hooks.HooksService `inject:""` - CacheService *cache.CacheService `inject:""` - DatasourceCache datasources.CacheService `inject:""` - AuthTokenService models.UserTokenService `inject:""` - QuotaService *quota.QuotaService `inject:""` + RouteRegister routing.RouteRegister `inject:""` + Bus bus.Bus `inject:""` + RenderService rendering.Service `inject:""` + Cfg *setting.Cfg `inject:""` + HooksService *hooks.HooksService `inject:""` + CacheService *cache.CacheService `inject:""` + DatasourceCache datasources.CacheService `inject:""` + AuthTokenService models.UserTokenService `inject:""` + QuotaService *quota.QuotaService `inject:""` + RemoteCacheService *remotecache.RemoteCache `inject:""` } func (hs *HTTPServer) Init() error { @@ -66,8 +67,6 @@ func (hs *HTTPServer) Init() error { hs.macaron = hs.newMacaron() hs.registerRoutes() - session.Init(&setting.SessionOptions, setting.SessionConnMaxLifetime) - return nil } @@ -226,7 +225,10 @@ func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() { m.Use(hs.healthHandler) m.Use(hs.metricsEndpoint) - m.Use(middleware.GetContextHandler(hs.AuthTokenService)) + m.Use(middleware.GetContextHandler( + hs.AuthTokenService, + hs.RemoteCacheService, + )) m.Use(middleware.OrgRedirect()) // needs to be after context handler diff --git a/pkg/infra/remotecache/remotecache.go b/pkg/infra/remotecache/remotecache.go index 9219fa33a08..c5049f8b27f 100644 --- a/pkg/infra/remotecache/remotecache.go +++ b/pkg/infra/remotecache/remotecache.go @@ -7,12 +7,10 @@ import ( "errors" "time" - "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/log" - "github.com/grafana/grafana/pkg/services/sqlstore" - "github.com/grafana/grafana/pkg/registry" + "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/setting" ) var ( diff --git a/pkg/infra/remotecache/remotecache_test.go b/pkg/infra/remotecache/remotecache_test.go index bf1675ec87c..b3ff41375ec 100644 --- a/pkg/infra/remotecache/remotecache_test.go +++ b/pkg/infra/remotecache/remotecache_test.go @@ -5,7 +5,6 @@ import ( "time" "github.com/bmizerany/assert" - "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/setting" ) diff --git a/pkg/infra/remotecache/testing.go b/pkg/infra/remotecache/testing.go new file mode 100644 index 00000000000..43cd449cb68 --- /dev/null +++ b/pkg/infra/remotecache/testing.go @@ -0,0 +1,34 @@ +package remotecache + +import ( + "testing" + + "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/setting" +) + +// NewFakeStore creates store for testing +func NewFakeStore(t *testing.T) *RemoteCache { + t.Helper() + + opts := &setting.RemoteCacheOptions{ + Name: "database", + ConnStr: "", + } + + SQLStore := sqlstore.InitTestDB(t) + + dc := &RemoteCache{ + SQLStore: SQLStore, + Cfg: &setting.Cfg{ + RemoteCacheOptions: opts, + }, + } + + err := dc.Init() + if err != nil { + t.Fatalf("failed to init remote cache for test. error: %v", err) + } + + return dc +} diff --git a/pkg/middleware/auth_proxy.go b/pkg/middleware/auth_proxy.go index 93ee577e3c6..b1e32819677 100644 --- a/pkg/middleware/auth_proxy.go +++ b/pkg/middleware/auth_proxy.go @@ -9,18 +9,19 @@ import ( "time" "github.com/grafana/grafana/pkg/bus" - "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/infra/remotecache" "github.com/grafana/grafana/pkg/login" m "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/session" "github.com/grafana/grafana/pkg/setting" ) -var ( - AUTH_PROXY_SESSION_VAR = "authProxyHeaderValue" +const ( + + // cachePrefix is a prefix for the cache key + cachePrefix = "auth-proxy-sync-ttl:%s" ) -func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool { +func initContextWithAuthProxy(store *remotecache.RemoteCache, ctx *m.ReqContext, orgID int64) bool { if !setting.AuthProxyEnabled { return false } @@ -36,46 +37,17 @@ func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool { return true } - // initialize session - if err := ctx.Session.Start(ctx.Context); err != nil { - log.Error(3, "Failed to start session. error %v", err) - return false - } - - defer func() { - if err := ctx.Session.Release(); err != nil { - ctx.Logger.Error("failed to save session data", "error", err) - } - }() - query := &m.GetSignedInUserQuery{OrgId: orgID} + cacheKey := fmt.Sprintf(cachePrefix, proxyHeaderValue) + userID, err := store.Get(cacheKey) + inCache := err == nil - // if this session has already been authenticated by authProxy just load the user - sessProxyValue := ctx.Session.Get(AUTH_PROXY_SESSION_VAR) - if sessProxyValue != nil && sessProxyValue.(string) == proxyHeaderValue && getRequestUserId(ctx) > 0 { - // if we're using ldap, sync user periodically - if setting.LdapEnabled { - syncQuery := &m.LoginUserQuery{ - ReqContext: ctx, - Username: proxyHeaderValue, - } - - if err := syncGrafanaUserWithLdapUser(syncQuery); err != nil { - if err == login.ErrInvalidCredentials { - ctx.Handle(500, "Unable to authenticate user", err) - return false - } + // load the user if we have them + if inCache { + query.UserId = userID.(int64) - ctx.Handle(500, "Failed to sync user", err) - return false - } - } - - query.UserId = getRequestUserId(ctx) // if we're using ldap, pass authproxy login name to ldap user sync } else if setting.LdapEnabled { - ctx.Session.Delete(session.SESS_KEY_LASTLDAPSYNC) - syncQuery := &m.LoginUserQuery{ ReqContext: ctx, Username: proxyHeaderValue, @@ -86,9 +58,6 @@ func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool { ctx.Handle(500, "Unable to authenticate user", err) return false } - - ctx.Handle(500, "Failed to sync user", err) - return false } if syncQuery.User == nil { @@ -149,67 +118,40 @@ func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool { ctx.Handle(500, "Failed to find user", err) return true } + ctx.SignedInUser = query.Result + ctx.IsSignedIn = true - // Make sure that we cannot share a session between different users! - if getRequestUserId(ctx) > 0 && getRequestUserId(ctx) != query.Result.UserId { - // remove session - if err := ctx.Session.Destory(ctx.Context); err != nil { - log.Error(3, "Failed to destroy session. error: %v", err) - } + expiration := time.Duration(-setting.AuthProxyLdapSyncTtl) * time.Minute + value := query.UserId - // initialize a new session - if err := ctx.Session.Start(ctx.Context); err != nil { - log.Error(3, "Failed to start session. error: %v", err) + // This is here to make sure we do not + // rewrite the expiration all the time + if inCache == false { + if err = store.Set(cacheKey, value, expiration); err != nil { + ctx.Handle(500, "Couldn't write a user in cache key", err) + return true } } - ctx.Session.Set(AUTH_PROXY_SESSION_VAR, proxyHeaderValue) - - ctx.SignedInUser = query.Result - ctx.IsSignedIn = true - ctx.Session.Set(session.SESS_KEY_USERID, ctx.UserId) - return true } var syncGrafanaUserWithLdapUser = func(query *m.LoginUserQuery) error { - expireEpoch := time.Now().Add(time.Duration(-setting.AuthProxyLdapSyncTtl) * time.Minute).Unix() - - var lastLdapSync int64 - if lastLdapSyncInSession := query.ReqContext.Session.Get(session.SESS_KEY_LASTLDAPSYNC); lastLdapSyncInSession != nil { - lastLdapSync = lastLdapSyncInSession.(int64) + ldapCfg := login.LdapCfg + if len(ldapCfg.Servers) < 1 { + return fmt.Errorf("No LDAP servers available") } - if lastLdapSync < expireEpoch { - ldapCfg := login.LdapCfg - - if len(ldapCfg.Servers) < 1 { - return fmt.Errorf("No LDAP servers available") + for _, server := range ldapCfg.Servers { + author := login.NewLdapAuthenticator(server) + if err := author.SyncUser(query); err != nil { + return err } - - for _, server := range ldapCfg.Servers { - author := login.NewLdapAuthenticator(server) - if err := author.SyncUser(query); err != nil { - return err - } - } - - query.ReqContext.Session.Set(session.SESS_KEY_LASTLDAPSYNC, time.Now().Unix()) } return nil } -func getRequestUserId(c *m.ReqContext) int64 { - userID := c.Session.Get(session.SESS_KEY_USERID) - - if userID != nil { - return userID.(int64) - } - - return 0 -} - func checkAuthenticationProxy(remoteAddr string, proxyHeaderValue string) error { if len(strings.TrimSpace(setting.AuthProxyWhitelist)) == 0 { return nil diff --git a/pkg/middleware/auth_proxy_test.go b/pkg/middleware/auth_proxy_test.go deleted file mode 100644 index 47ed2f71a79..00000000000 --- a/pkg/middleware/auth_proxy_test.go +++ /dev/null @@ -1,145 +0,0 @@ -package middleware - -import ( - "testing" - "time" - - "github.com/grafana/grafana/pkg/login" - m "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/session" - "github.com/grafana/grafana/pkg/setting" - . "github.com/smartystreets/goconvey/convey" - "gopkg.in/macaron.v1" -) - -func TestAuthProxyWithLdapEnabled(t *testing.T) { - Convey("When calling sync grafana user with ldap user", t, func() { - - setting.LdapEnabled = true - setting.AuthProxyLdapSyncTtl = 60 - - servers := []*login.LdapServerConf{{Host: "127.0.0.1"}} - login.LdapCfg = login.LdapConfig{Servers: servers} - mockLdapAuther := mockLdapAuthenticator{} - - login.NewLdapAuthenticator = func(server *login.LdapServerConf) login.ILdapAuther { - return &mockLdapAuther - } - - Convey("When user logs in, call SyncUser", func() { - // arrange - sess := newMockSession() - ctx := m.ReqContext{Session: &sess} - So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldBeNil) - - // act - syncGrafanaUserWithLdapUser(&m.LoginUserQuery{ - ReqContext: &ctx, - Username: "test", - }) - - // assert - So(mockLdapAuther.syncUserCalled, ShouldBeTrue) - So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldBeGreaterThan, 0) - }) - - Convey("When session variable not expired, don't sync and don't change session var", func() { - // arrange - sess := newMockSession() - ctx := m.ReqContext{Session: &sess} - now := time.Now().Unix() - sess.Set(session.SESS_KEY_LASTLDAPSYNC, now) - sess.Set(AUTH_PROXY_SESSION_VAR, "test") - - // act - syncGrafanaUserWithLdapUser(&m.LoginUserQuery{ - ReqContext: &ctx, - Username: "test", - }) - - // assert - So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldEqual, now) - So(mockLdapAuther.syncUserCalled, ShouldBeFalse) - }) - - Convey("When lastldapsync is expired, session variable should be updated", func() { - // arrange - sess := newMockSession() - ctx := m.ReqContext{Session: &sess} - expiredTime := time.Now().Add(time.Duration(-120) * time.Minute).Unix() - sess.Set(session.SESS_KEY_LASTLDAPSYNC, expiredTime) - sess.Set(AUTH_PROXY_SESSION_VAR, "test") - - // act - syncGrafanaUserWithLdapUser(&m.LoginUserQuery{ - ReqContext: &ctx, - Username: "test", - }) - - // assert - So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldBeGreaterThan, expiredTime) - So(mockLdapAuther.syncUserCalled, ShouldBeTrue) - }) - }) -} - -type mockSession struct { - value map[interface{}]interface{} -} - -func newMockSession() mockSession { - session := mockSession{} - session.value = make(map[interface{}]interface{}) - return session -} - -func (s *mockSession) Start(c *macaron.Context) error { - return nil -} - -func (s *mockSession) Set(k interface{}, v interface{}) error { - s.value[k] = v - return nil -} - -func (s *mockSession) Get(k interface{}) interface{} { - return s.value[k] -} - -func (s *mockSession) Delete(k interface{}) interface{} { - delete(s.value, k) - return nil -} - -func (s *mockSession) ID() string { - return "" -} - -func (s *mockSession) Release() error { - return nil -} - -func (s *mockSession) Destory(c *macaron.Context) error { - return nil -} - -func (s *mockSession) RegenerateId(c *macaron.Context) error { - return nil -} - -type mockLdapAuthenticator struct { - syncUserCalled bool -} - -func (a *mockLdapAuthenticator) Login(query *m.LoginUserQuery) error { - return nil -} - -func (a *mockLdapAuthenticator) SyncUser(query *m.LoginUserQuery) error { - a.syncUserCalled = true - return nil -} - -func (a *mockLdapAuthenticator) GetGrafanaUserFor(ctx *m.ReqContext, ldapUser *login.LdapUserInfo) (*m.User, error) { - return nil, nil -} diff --git a/pkg/middleware/auth_test.go b/pkg/middleware/auth_test.go index 81b0f525e98..50d959270ad 100644 --- a/pkg/middleware/auth_test.go +++ b/pkg/middleware/auth_test.go @@ -11,7 +11,7 @@ func TestMiddlewareAuth(t *testing.T) { Convey("Given the grafana middleware", t, func() { reqSignIn := Auth(&AuthOptions{ReqSignedIn: true}) - middlewareScenario("ReqSignIn true and unauthenticated request", func(sc *scenarioContext) { + middlewareScenario(t, "ReqSignIn true and unauthenticated request", func(sc *scenarioContext) { sc.m.Get("/secure", reqSignIn, sc.defaultHandler) sc.fakeReq("GET", "/secure").exec() @@ -21,7 +21,7 @@ func TestMiddlewareAuth(t *testing.T) { }) }) - middlewareScenario("ReqSignIn true and unauthenticated API request", func(sc *scenarioContext) { + middlewareScenario(t, "ReqSignIn true and unauthenticated API request", func(sc *scenarioContext) { sc.m.Get("/api/secure", reqSignIn, sc.defaultHandler) sc.fakeReq("GET", "/api/secure").exec() diff --git a/pkg/middleware/dashboard_redirect_test.go b/pkg/middleware/dashboard_redirect_test.go index ebef4c92730..ca4ea9c84b2 100644 --- a/pkg/middleware/dashboard_redirect_test.go +++ b/pkg/middleware/dashboard_redirect_test.go @@ -27,7 +27,7 @@ func TestMiddlewareDashboardRedirect(t *testing.T) { return nil }) - middlewareScenario("GET dashboard by legacy url", func(sc *scenarioContext) { + middlewareScenario(t, "GET dashboard by legacy url", func(sc *scenarioContext) { sc.m.Get("/dashboard/db/:slug", redirectFromLegacyDashboardUrl, sc.defaultHandler) sc.fakeReqWithParams("GET", "/dashboard/db/dash?orgId=1&panelId=2", map[string]string{}).exec() @@ -40,7 +40,7 @@ func TestMiddlewareDashboardRedirect(t *testing.T) { }) }) - middlewareScenario("GET dashboard solo by legacy url", func(sc *scenarioContext) { + middlewareScenario(t, "GET dashboard solo by legacy url", func(sc *scenarioContext) { sc.m.Get("/dashboard-solo/db/:slug", redirectFromLegacyDashboardSoloUrl, sc.defaultHandler) sc.fakeReqWithParams("GET", "/dashboard-solo/db/dash?orgId=1&panelId=2", map[string]string{}).exec() diff --git a/pkg/middleware/middleware.go b/pkg/middleware/middleware.go index fa335eb10d9..61f86824118 100644 --- a/pkg/middleware/middleware.go +++ b/pkg/middleware/middleware.go @@ -8,9 +8,9 @@ import ( "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/apikeygen" + "github.com/grafana/grafana/pkg/infra/remotecache" "github.com/grafana/grafana/pkg/log" m "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/session" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" macaron "gopkg.in/macaron.v1" @@ -23,12 +23,11 @@ var ( ReqOrgAdmin = RoleAuth(m.ROLE_ADMIN) ) -func GetContextHandler(ats m.UserTokenService) macaron.Handler { +func GetContextHandler(ats m.UserTokenService, remoteCache *remotecache.RemoteCache) macaron.Handler { return func(c *macaron.Context) { ctx := &m.ReqContext{ Context: c, SignedInUser: &m.SignedInUser{}, - Session: session.GetSession(), // should only be used by auth_proxy IsSignedIn: false, AllowAnonymous: false, SkipCache: false, @@ -50,7 +49,7 @@ func GetContextHandler(ats m.UserTokenService) macaron.Handler { case initContextWithRenderAuth(ctx): case initContextWithApiKey(ctx): case initContextWithBasicAuth(ctx, orgId): - case initContextWithAuthProxy(ctx, orgId): + case initContextWithAuthProxy(remoteCache, ctx, orgId): case initContextWithToken(ats, ctx, orgId): case initContextWithAnonymousUser(ctx): } diff --git a/pkg/middleware/middleware_test.go b/pkg/middleware/middleware_test.go index 2fc8e0c456f..7f52e9892bf 100644 --- a/pkg/middleware/middleware_test.go +++ b/pkg/middleware/middleware_test.go @@ -2,6 +2,7 @@ package middleware import ( "encoding/json" + "fmt" "net/http" "net/http/httptest" "path/filepath" @@ -10,6 +11,7 @@ import ( msession "github.com/go-macaron/session" "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/infra/remotecache" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/auth" "github.com/grafana/grafana/pkg/services/session" @@ -23,29 +25,29 @@ func TestMiddlewareContext(t *testing.T) { setting.ERR_TEMPLATE_NAME = "error-template" Convey("Given the grafana middleware", t, func() { - middlewareScenario("middleware should add context to injector", func(sc *scenarioContext) { + middlewareScenario(t, "middleware should add context to injector", func(sc *scenarioContext) { sc.fakeReq("GET", "/").exec() So(sc.context, ShouldNotBeNil) }) - middlewareScenario("Default middleware should allow get request", func(sc *scenarioContext) { + middlewareScenario(t, "Default middleware should allow get request", func(sc *scenarioContext) { sc.fakeReq("GET", "/").exec() So(sc.resp.Code, ShouldEqual, 200) }) - middlewareScenario("middleware should add Cache-Control header for GET requests to API", func(sc *scenarioContext) { + middlewareScenario(t, "middleware should add Cache-Control header for GET requests to API", func(sc *scenarioContext) { sc.fakeReq("GET", "/api/search").exec() So(sc.resp.Header().Get("Cache-Control"), ShouldEqual, "no-cache") So(sc.resp.Header().Get("Pragma"), ShouldEqual, "no-cache") So(sc.resp.Header().Get("Expires"), ShouldEqual, "-1") }) - middlewareScenario("middleware should not add Cache-Control header to for non-API GET requests", func(sc *scenarioContext) { + middlewareScenario(t, "middleware should not add Cache-Control header to for non-API GET requests", func(sc *scenarioContext) { sc.fakeReq("GET", "/").exec() So(sc.resp.Header().Get("Cache-Control"), ShouldBeEmpty) }) - middlewareScenario("Invalid api key", func(sc *scenarioContext) { + middlewareScenario(t, "Invalid api key", func(sc *scenarioContext) { sc.apiKey = "invalid_key_test" sc.fakeReq("GET", "/").exec() @@ -59,7 +61,7 @@ func TestMiddlewareContext(t *testing.T) { }) }) - middlewareScenario("Using basic auth", func(sc *scenarioContext) { + middlewareScenario(t, "Using basic auth", func(sc *scenarioContext) { bus.AddHandler("test", func(query *m.GetUserByLoginQuery) error { query.Result = &m.User{ @@ -89,7 +91,7 @@ func TestMiddlewareContext(t *testing.T) { }) }) - middlewareScenario("Valid api key", func(sc *scenarioContext) { + middlewareScenario(t, "Valid api key", func(sc *scenarioContext) { keyhash := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd") bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error { @@ -110,7 +112,7 @@ func TestMiddlewareContext(t *testing.T) { }) }) - middlewareScenario("Valid api key, but does not match db hash", func(sc *scenarioContext) { + middlewareScenario(t, "Valid api key, but does not match db hash", func(sc *scenarioContext) { keyhash := "something_not_matching" bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error { @@ -126,7 +128,7 @@ func TestMiddlewareContext(t *testing.T) { }) }) - middlewareScenario("Valid api key via Basic auth", func(sc *scenarioContext) { + middlewareScenario(t, "Valid api key via Basic auth", func(sc *scenarioContext) { keyhash := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd") bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error { @@ -148,7 +150,7 @@ func TestMiddlewareContext(t *testing.T) { }) }) - middlewareScenario("Non-expired auth token in cookie which not are being rotated", func(sc *scenarioContext) { + middlewareScenario(t, "Non-expired auth token in cookie which not are being rotated", func(sc *scenarioContext) { sc.withTokenSessionCookie("token") bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { @@ -177,7 +179,7 @@ func TestMiddlewareContext(t *testing.T) { }) }) - middlewareScenario("Non-expired auth token in cookie which are being rotated", func(sc *scenarioContext) { + middlewareScenario(t, "Non-expired auth token in cookie which are being rotated", func(sc *scenarioContext) { sc.withTokenSessionCookie("token") bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { @@ -224,7 +226,7 @@ func TestMiddlewareContext(t *testing.T) { }) }) - middlewareScenario("Invalid/expired auth token in cookie", func(sc *scenarioContext) { + middlewareScenario(t, "Invalid/expired auth token in cookie", func(sc *scenarioContext) { sc.withTokenSessionCookie("token") sc.userAuthTokenService.LookupTokenProvider = func(unhashedToken string) (*m.UserToken, error) { @@ -240,7 +242,7 @@ func TestMiddlewareContext(t *testing.T) { }) }) - middlewareScenario("When anonymous access is enabled", func(sc *scenarioContext) { + middlewareScenario(t, "When anonymous access is enabled", func(sc *scenarioContext) { setting.AnonymousEnabled = true setting.AnonymousOrgName = "test" setting.AnonymousOrgRole = string(m.ROLE_EDITOR) @@ -265,287 +267,192 @@ func TestMiddlewareContext(t *testing.T) { }) }) - middlewareScenario("When auth_proxy is enabled enabled and user exists", func(sc *scenarioContext) { - setting.AuthProxyEnabled = true - setting.AuthProxyHeaderName = "X-WEBAUTH-USER" - setting.AuthProxyHeaderProperty = "username" - setting.LdapEnabled = false - - bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { - query.Result = &m.SignedInUser{OrgId: 2, UserId: 12} - return nil - }) - - bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error { - cmd.Result = &m.User{Id: 12} - return nil - }) - - setting.SessionOptions = msession.Options{} - sc.fakeReq("GET", "/") - sc.req.Header.Add("X-WEBAUTH-USER", "torkelo") - sc.exec() - - Convey("should init context with user info", func() { - So(sc.context.IsSignedIn, ShouldBeTrue) - So(sc.context.UserId, ShouldEqual, 12) - So(sc.context.OrgId, ShouldEqual, 2) - }) - }) - - middlewareScenario("When auth_proxy is enabled enabled and user does not exists", func(sc *scenarioContext) { + Convey("auth_proxy", func() { setting.AuthProxyEnabled = true + setting.AuthProxyWhitelist = "" + setting.AuthProxyAutoSignUp = true + setting.LdapEnabled = true setting.AuthProxyHeaderName = "X-WEBAUTH-USER" setting.AuthProxyHeaderProperty = "username" - setting.AuthProxyAutoSignUp = true - setting.LdapEnabled = false + name := "markelog" - bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { - if query.UserId > 0 { - query.Result = &m.SignedInUser{OrgId: 4, UserId: 33} + middlewareScenario(t, "should sync the user if it's not in the cache", func(sc *scenarioContext) { + called := false + syncGrafanaUserWithLdapUser = func(query *m.LoginUserQuery) error { + called = true + query.User = &m.User{Id: 32} return nil } - return m.ErrUserNotFound - }) - - bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error { - cmd.Result = &m.User{Id: 33} - return nil - }) - sc.fakeReq("GET", "/") - sc.req.Header.Add("X-WEBAUTH-USER", "torkelo") - sc.exec() - - Convey("Should create user if auto sign up is enabled", func() { - So(sc.context.IsSignedIn, ShouldBeTrue) - So(sc.context.UserId, ShouldEqual, 33) - So(sc.context.OrgId, ShouldEqual, 4) - - }) - }) - - middlewareScenario("When auth_proxy is enabled and IPv4 request RemoteAddr is not trusted", func(sc *scenarioContext) { - setting.AuthProxyEnabled = true - setting.AuthProxyHeaderName = "X-WEBAUTH-USER" - setting.AuthProxyHeaderProperty = "username" - setting.AuthProxyWhitelist = "192.168.1.1, 2001::23" - - sc.fakeReq("GET", "/") - sc.req.Header.Add("X-WEBAUTH-USER", "torkelo") - sc.req.RemoteAddr = "192.168.3.1:12345" - sc.exec() - - Convey("should return 407 status code", func() { - So(sc.resp.Code, ShouldEqual, 407) - So(sc.resp.Body.String(), ShouldContainSubstring, "Request for user (torkelo) from 192.168.3.1 is not from the authentication proxy") - }) - }) - - middlewareScenario("When auth_proxy is enabled and IPv4 request RemoteAddr is not within trusted CIDR block", func(sc *scenarioContext) { - setting.AuthProxyEnabled = true - setting.AuthProxyHeaderName = "X-WEBAUTH-USER" - setting.AuthProxyHeaderProperty = "username" - setting.AuthProxyWhitelist = "192.168.1.0/24, 2001::0/120" - - sc.fakeReq("GET", "/") - sc.req.Header.Add("X-WEBAUTH-USER", "torkelo") - sc.req.RemoteAddr = "192.168.3.1:12345" - sc.exec() + bus.AddHandler("test", func(query *m.UpsertUserCommand) error { + query.Result = &m.User{Id: 32} + return nil + }) - Convey("should return 407 status code", func() { - So(sc.resp.Code, ShouldEqual, 407) - So(sc.resp.Body.String(), ShouldContainSubstring, "Request for user (torkelo) from 192.168.3.1 is not from the authentication proxy") - }) - }) + bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { + query.Result = &m.SignedInUser{OrgId: 4, UserId: 32} + return nil + }) - middlewareScenario("When auth_proxy is enabled and IPv6 request RemoteAddr is not trusted", func(sc *scenarioContext) { - setting.AuthProxyEnabled = true - setting.AuthProxyHeaderName = "X-WEBAUTH-USER" - setting.AuthProxyHeaderProperty = "username" - setting.AuthProxyWhitelist = "192.168.1.1, 2001::23" + sc.fakeReq("GET", "/") - sc.fakeReq("GET", "/") - sc.req.Header.Add("X-WEBAUTH-USER", "torkelo") - sc.req.RemoteAddr = "[2001:23]:12345" - sc.exec() + sc.req.Header.Add(setting.AuthProxyHeaderName, name) + sc.exec() - Convey("should return 407 status code", func() { - So(sc.resp.Code, ShouldEqual, 407) - So(sc.resp.Body.String(), ShouldContainSubstring, "Request for user (torkelo) from 2001:23 is not from the authentication proxy") + Convey("Should init user via ldap", func() { + So(called, ShouldBeTrue) + So(sc.context.IsSignedIn, ShouldBeTrue) + So(sc.context.UserId, ShouldEqual, 32) + So(sc.context.OrgId, ShouldEqual, 4) + }) }) - }) - - middlewareScenario("When auth_proxy is enabled and IPv6 request RemoteAddr is not within trusted CIDR block", func(sc *scenarioContext) { - setting.AuthProxyEnabled = true - setting.AuthProxyHeaderName = "X-WEBAUTH-USER" - setting.AuthProxyHeaderProperty = "username" - setting.AuthProxyWhitelist = "192.168.1.0/24, 2001::0/120" - - sc.fakeReq("GET", "/") - sc.req.Header.Add("X-WEBAUTH-USER", "torkelo") - sc.req.RemoteAddr = "[2001:23]:12345" - sc.exec() - Convey("should return 407 status code", func() { - So(sc.resp.Code, ShouldEqual, 407) - So(sc.resp.Body.String(), ShouldContainSubstring, "Request for user (torkelo) from 2001:23 is not from the authentication proxy") - }) - }) + middlewareScenario(t, "should not sync the user if it's in the cache", func(sc *scenarioContext) { + called := false + syncGrafanaUserWithLdapUser = func(query *m.LoginUserQuery) error { + called = true + query.User = &m.User{Id: 32} + return nil + } - middlewareScenario("When auth_proxy is enabled and request RemoteAddr is trusted", func(sc *scenarioContext) { - setting.AuthProxyEnabled = true - setting.AuthProxyHeaderName = "X-WEBAUTH-USER" - setting.AuthProxyHeaderProperty = "username" - setting.AuthProxyWhitelist = "192.168.1.1, 2001::23" + bus.AddHandler("test", func(query *m.UpsertUserCommand) error { + query.Result = &m.User{Id: 32} + return nil + }) - bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { - query.Result = &m.SignedInUser{OrgId: 4, UserId: 33} - return nil - }) + bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { + query.Result = &m.SignedInUser{OrgId: 4, UserId: 32} + return nil + }) - bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error { - cmd.Result = &m.User{Id: 33} - return nil - }) + key := fmt.Sprintf(cachePrefix, name) + sc.remoteCacheService.Set(key, int64(33), 0) + sc.fakeReq("GET", "/") - sc.fakeReq("GET", "/") - sc.req.Header.Add("X-WEBAUTH-USER", "torkelo") - sc.req.RemoteAddr = "[2001::23]:12345" - sc.exec() + sc.req.Header.Add(setting.AuthProxyHeaderName, name) + sc.exec() - Convey("Should init context with user info", func() { - So(sc.context.IsSignedIn, ShouldBeTrue) - So(sc.context.UserId, ShouldEqual, 33) - So(sc.context.OrgId, ShouldEqual, 4) - }) - }) + cacheValue, cacheErr := sc.remoteCacheService.Get(key) - middlewareScenario("When auth_proxy is enabled and IPv4 request RemoteAddr is within trusted CIDR block", func(sc *scenarioContext) { - setting.AuthProxyEnabled = true - setting.AuthProxyHeaderName = "X-WEBAUTH-USER" - setting.AuthProxyHeaderProperty = "username" - setting.AuthProxyWhitelist = "192.168.1.0/24, 2001::0/120" + Convey("Should init user via cache", func() { + So(called, ShouldBeFalse) - bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { - query.Result = &m.SignedInUser{OrgId: 4, UserId: 33} - return nil - }) + So(sc.context.IsSignedIn, ShouldBeTrue) + So(sc.context.UserId, ShouldEqual, 32) + So(sc.context.OrgId, ShouldEqual, 4) - bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error { - cmd.Result = &m.User{Id: 33} - return nil + So(cacheValue, ShouldEqual, 33) + So(cacheErr, ShouldBeNil) + }) }) - sc.fakeReq("GET", "/") - sc.req.Header.Add("X-WEBAUTH-USER", "torkelo") - sc.req.RemoteAddr = "192.168.1.10:12345" - sc.exec() + middlewareScenario(t, "should create an user from a header", func(sc *scenarioContext) { + setting.LdapEnabled = false + setting.AuthProxyAutoSignUp = true - Convey("Should init context with user info", func() { - So(sc.context.IsSignedIn, ShouldBeTrue) - So(sc.context.UserId, ShouldEqual, 33) - So(sc.context.OrgId, ShouldEqual, 4) - }) - }) + bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { + if query.UserId > 0 { + query.Result = &m.SignedInUser{OrgId: 4, UserId: 33} + return nil + } + return m.ErrUserNotFound + }) - middlewareScenario("When auth_proxy is enabled and IPv6 request RemoteAddr is within trusted CIDR block", func(sc *scenarioContext) { - setting.AuthProxyEnabled = true - setting.AuthProxyHeaderName = "X-WEBAUTH-USER" - setting.AuthProxyHeaderProperty = "username" - setting.AuthProxyWhitelist = "192.168.1.0/24, 2001::0/120" + bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error { + cmd.Result = &m.User{Id: 33} + return nil + }) - bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { - query.Result = &m.SignedInUser{OrgId: 4, UserId: 33} - return nil - }) + sc.fakeReq("GET", "/") + sc.req.Header.Add(setting.AuthProxyHeaderName, name) + sc.exec() - bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error { - cmd.Result = &m.User{Id: 33} - return nil + Convey("Should create user from header info", func() { + So(sc.context.IsSignedIn, ShouldBeTrue) + So(sc.context.UserId, ShouldEqual, 33) + So(sc.context.OrgId, ShouldEqual, 4) + }) }) - sc.fakeReq("GET", "/") - sc.req.Header.Add("X-WEBAUTH-USER", "torkelo") - sc.req.RemoteAddr = "[2001::23]:12345" - sc.exec() + middlewareScenario(t, "should get an existing user from header", func(sc *scenarioContext) { + setting.LdapEnabled = false - Convey("Should init context with user info", func() { - So(sc.context.IsSignedIn, ShouldBeTrue) - So(sc.context.UserId, ShouldEqual, 33) - So(sc.context.OrgId, ShouldEqual, 4) - }) - }) + bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { + query.Result = &m.SignedInUser{OrgId: 2, UserId: 12} + return nil + }) - middlewareScenario("When session exists for previous user, create a new session", func(sc *scenarioContext) { - setting.AuthProxyEnabled = true - setting.AuthProxyHeaderName = "X-WEBAUTH-USER" - setting.AuthProxyHeaderProperty = "username" - setting.AuthProxyWhitelist = "" + bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error { + cmd.Result = &m.User{Id: 12} + return nil + }) - bus.AddHandler("test", func(query *m.UpsertUserCommand) error { - query.Result = &m.User{Id: 32} - return nil - }) + sc.fakeReq("GET", "/") + sc.req.Header.Add(setting.AuthProxyHeaderName, name) + sc.exec() - bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { - query.Result = &m.SignedInUser{OrgId: 4, UserId: 32} - return nil + Convey("should init context with user info", func() { + So(sc.context.IsSignedIn, ShouldBeTrue) + So(sc.context.UserId, ShouldEqual, 12) + So(sc.context.OrgId, ShouldEqual, 2) + }) }) - // create session - sc.fakeReq("GET", "/").handler(func(c *m.ReqContext) { - c.Session.Set(session.SESS_KEY_USERID, int64(33)) - }).exec() + middlewareScenario(t, "should allow the request from whitelist IP", func(sc *scenarioContext) { + setting.AuthProxyWhitelist = "192.168.1.0/24, 2001::0/120" + setting.LdapEnabled = false - oldSessionID := sc.context.Session.ID() + bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { + query.Result = &m.SignedInUser{OrgId: 4, UserId: 33} + return nil + }) - sc.req.Header.Add("X-WEBAUTH-USER", "torkelo") - sc.exec() + bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error { + cmd.Result = &m.User{Id: 33} + return nil + }) - newSessionID := sc.context.Session.ID() + sc.fakeReq("GET", "/") + sc.req.Header.Add(setting.AuthProxyHeaderName, name) + sc.req.RemoteAddr = "[2001::23]:12345" + sc.exec() - Convey("Should not share session with other user", func() { - So(oldSessionID, ShouldNotEqual, newSessionID) + Convey("Should init context with user info", func() { + So(sc.context.IsSignedIn, ShouldBeTrue) + So(sc.context.UserId, ShouldEqual, 33) + So(sc.context.OrgId, ShouldEqual, 4) + }) }) - }) - middlewareScenario("When auth_proxy and ldap enabled call sync with ldap user", func(sc *scenarioContext) { - setting.AuthProxyEnabled = true - setting.AuthProxyHeaderName = "X-WEBAUTH-USER" - setting.AuthProxyHeaderProperty = "username" - setting.AuthProxyWhitelist = "" - setting.LdapEnabled = true - - called := false - syncGrafanaUserWithLdapUser = func(query *m.LoginUserQuery) error { - called = true - query.User = &m.User{Id: 32} - return nil - } + middlewareScenario(t, "should not allow the request from whitelist IP", func(sc *scenarioContext) { + setting.AuthProxyWhitelist = "8.8.8.8" + setting.LdapEnabled = false - bus.AddHandler("test", func(query *m.UpsertUserCommand) error { - query.Result = &m.User{Id: 32} - return nil - }) + bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { + query.Result = &m.SignedInUser{OrgId: 4, UserId: 33} + return nil + }) - bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { - query.Result = &m.SignedInUser{OrgId: 4, UserId: 32} - return nil - }) + bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error { + cmd.Result = &m.User{Id: 33} + return nil + }) - sc.fakeReq("GET", "/") - sc.req.Header.Add("X-WEBAUTH-USER", "torkelo") - sc.exec() + sc.fakeReq("GET", "/") + sc.req.Header.Add(setting.AuthProxyHeaderName, name) + sc.req.RemoteAddr = "[2001::23]:12345" + sc.exec() - Convey("Should call syncGrafanaUserWithLdapUser", func() { - So(called, ShouldBeTrue) + Convey("should return 407 status code", func() { + So(sc.resp.Code, ShouldEqual, 407) + So(sc.context, ShouldBeNil) + }) }) }) }) } -func middlewareScenario(desc string, fn scenarioFunc) { +func middlewareScenario(t *testing.T, desc string, fn scenarioFunc) { Convey(desc, func() { defer bus.ClearBusHandlers() @@ -562,9 +469,10 @@ func middlewareScenario(desc string, fn scenarioFunc) { Delims: macaron.Delims{Left: "[[", Right: "]]"}, })) - session.Init(&msession.Options{}, 0) sc.userAuthTokenService = auth.NewFakeUserAuthTokenService() - sc.m.Use(GetContextHandler(sc.userAuthTokenService)) + sc.remoteCacheService = remotecache.NewFakeStore(t) + + sc.m.Use(GetContextHandler(sc.userAuthTokenService, sc.remoteCacheService)) // mock out gc goroutine session.StartSessionGC = func() {} setting.SessionOptions = msession.Options{} @@ -597,6 +505,7 @@ type scenarioContext struct { defaultHandler macaron.Handler url string userAuthTokenService *auth.FakeUserAuthTokenService + remoteCacheService *remotecache.RemoteCache req *http.Request } @@ -622,13 +531,6 @@ func (sc *scenarioContext) fakeReq(method, url string) *scenarioContext { So(err, ShouldBeNil) sc.req = req - // add session cookie from last request - if sc.context != nil { - if sc.context.Session.ID() != "" { - req.Header.Add("Cookie", "grafana_sess="+sc.context.Session.ID()+";") - } - } - return sc } diff --git a/pkg/middleware/org_redirect_test.go b/pkg/middleware/org_redirect_test.go index fe5b2736035..f307376331e 100644 --- a/pkg/middleware/org_redirect_test.go +++ b/pkg/middleware/org_redirect_test.go @@ -1,9 +1,8 @@ package middleware import ( - "testing" - "fmt" + "testing" "github.com/grafana/grafana/pkg/bus" m "github.com/grafana/grafana/pkg/models" @@ -13,7 +12,7 @@ import ( func TestOrgRedirectMiddleware(t *testing.T) { Convey("Can redirect to correct org", t, func() { - middlewareScenario("when setting a correct org for the user", func(sc *scenarioContext) { + middlewareScenario(t, "when setting a correct org for the user", func(sc *scenarioContext) { sc.withTokenSessionCookie("token") bus.AddHandler("test", func(query *m.SetUsingOrgCommand) error { return nil @@ -39,7 +38,7 @@ func TestOrgRedirectMiddleware(t *testing.T) { }) }) - middlewareScenario("when setting an invalid org for user", func(sc *scenarioContext) { + middlewareScenario(t, "when setting an invalid org for user", func(sc *scenarioContext) { sc.withTokenSessionCookie("token") bus.AddHandler("test", func(query *m.SetUsingOrgCommand) error { return fmt.Errorf("") diff --git a/pkg/middleware/quota_test.go b/pkg/middleware/quota_test.go index 0ba42e708bc..c3b448c9f6a 100644 --- a/pkg/middleware/quota_test.go +++ b/pkg/middleware/quota_test.go @@ -3,11 +3,10 @@ package middleware import ( "testing" - "github.com/grafana/grafana/pkg/services/auth" - "github.com/grafana/grafana/pkg/services/quota" - "github.com/grafana/grafana/pkg/bus" m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/auth" + "github.com/grafana/grafana/pkg/services/quota" "github.com/grafana/grafana/pkg/setting" . "github.com/smartystreets/goconvey/convey" ) @@ -43,7 +42,7 @@ func TestMiddlewareQuota(t *testing.T) { } QuotaFn := Quota(qs) - middlewareScenario("with user not logged in", func(sc *scenarioContext) { + middlewareScenario(t, "with user not logged in", func(sc *scenarioContext) { bus.AddHandler("globalQuota", func(query *m.GetGlobalQuotaByTargetQuery) error { query.Result = &m.GlobalQuotaDTO{ Target: query.Target, @@ -81,7 +80,7 @@ func TestMiddlewareQuota(t *testing.T) { }) }) - middlewareScenario("with user logged in", func(sc *scenarioContext) { + middlewareScenario(t, "with user logged in", func(sc *scenarioContext) { sc.withTokenSessionCookie("token") bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { query.Result = &m.SignedInUser{OrgId: 2, UserId: 12} diff --git a/pkg/middleware/recovery_test.go b/pkg/middleware/recovery_test.go index 00f3b7a3032..f1a3dd31cb4 100644 --- a/pkg/middleware/recovery_test.go +++ b/pkg/middleware/recovery_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/infra/remotecache" m "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/auth" "github.com/grafana/grafana/pkg/setting" @@ -17,7 +18,7 @@ func TestRecoveryMiddleware(t *testing.T) { Convey("Given an api route that panics", t, func() { apiURL := "/api/whatever" - recoveryScenario("recovery middleware should return json", apiURL, func(sc *scenarioContext) { + recoveryScenario(t, "recovery middleware should return json", apiURL, func(sc *scenarioContext) { sc.handlerFunc = PanicHandler sc.fakeReq("GET", apiURL).exec() sc.req.Header.Add("content-type", "application/json") @@ -30,7 +31,7 @@ func TestRecoveryMiddleware(t *testing.T) { Convey("Given a non-api route that panics", t, func() { apiURL := "/whatever" - recoveryScenario("recovery middleware should return html", apiURL, func(sc *scenarioContext) { + recoveryScenario(t, "recovery middleware should return html", apiURL, func(sc *scenarioContext) { sc.handlerFunc = PanicHandler sc.fakeReq("GET", apiURL).exec() @@ -45,7 +46,7 @@ func PanicHandler(c *m.ReqContext) { panic("Handler has panicked") } -func recoveryScenario(desc string, url string, fn scenarioFunc) { +func recoveryScenario(t *testing.T, desc string, url string, fn scenarioFunc) { Convey(desc, func() { defer bus.ClearBusHandlers() @@ -64,7 +65,9 @@ func recoveryScenario(desc string, url string, fn scenarioFunc) { })) sc.userAuthTokenService = auth.NewFakeUserAuthTokenService() - sc.m.Use(GetContextHandler(sc.userAuthTokenService)) + sc.remoteCacheService = remotecache.NewFakeStore(t) + + sc.m.Use(GetContextHandler(sc.userAuthTokenService, sc.remoteCacheService)) // mock out gc goroutine sc.m.Use(OrgRedirect()) sc.m.Use(AddDefaultResponseHeaders()) diff --git a/pkg/services/sqlstore/sqlstore.go b/pkg/services/sqlstore/sqlstore.go index 6debaca89a1..116c246cbe3 100644 --- a/pkg/services/sqlstore/sqlstore.go +++ b/pkg/services/sqlstore/sqlstore.go @@ -11,6 +11,8 @@ import ( "testing" "time" + "github.com/go-sql-driver/mysql" + "github.com/go-xorm/xorm" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/log" m "github.com/grafana/grafana/pkg/models" @@ -21,12 +23,8 @@ import ( "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/services/sqlstore/sqlutil" "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/util" - - "github.com/go-sql-driver/mysql" - "github.com/go-xorm/xorm" - _ "github.com/grafana/grafana/pkg/tsdb/mssql" + "github.com/grafana/grafana/pkg/util" _ "github.com/lib/pq" sqlite3 "github.com/mattn/go-sqlite3" )