diff --git a/pkg/bus/bus.go b/pkg/bus/bus.go index 2865c740fd1..80b80698a1c 100644 --- a/pkg/bus/bus.go +++ b/pkg/bus/bus.go @@ -121,3 +121,7 @@ func Dispatch(msg Msg) error { func Publish(msg Msg) error { return globalBus.Publish(msg) } + +func ClearBusHandlers() { + globalBus = New() +} diff --git a/pkg/middleware/middleware.go b/pkg/middleware/middleware.go index b93cd517364..efeee0ac3e7 100644 --- a/pkg/middleware/middleware.go +++ b/pkg/middleware/middleware.go @@ -1,6 +1,7 @@ package middleware import ( + "fmt" "strconv" "strings" @@ -78,11 +79,13 @@ func initContextWithUserSessionCookie(ctx *Context) bool { var userId int64 if userId = getRequestUserId(ctx); userId == 0 { + fmt.Printf("Not userId") return false } query := m.GetSignedInUserQuery{UserId: userId} if err := bus.Dispatch(&query); err != nil { + log.Error(3, "Failed to get user with id %v", userId) return false } else { ctx.SignedInUser = query.Result diff --git a/pkg/middleware/middleware_test.go b/pkg/middleware/middleware_test.go index e8e75465c82..ebbf0a1f038 100644 --- a/pkg/middleware/middleware_test.go +++ b/pkg/middleware/middleware_test.go @@ -10,38 +10,131 @@ import ( "github.com/Unknwon/macaron" "github.com/grafana/grafana/pkg/bus" m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" "github.com/macaron-contrib/session" . "github.com/smartystreets/goconvey/convey" ) -type scenarioContext struct { - m *macaron.Macaron - context *Context - resp *httptest.ResponseRecorder - apiKey string - respJson map[string]interface{} +func TestMiddlewareContext(t *testing.T) { + + Convey("Given the grafana middleware", t, func() { + middlewareScenario("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) { + sc.fakeReq("GET", "/").exec() + So(sc.resp.Code, ShouldEqual, 200) + }) + + middlewareScenario("Non api request should init session", func(sc *scenarioContext) { + sc.fakeReq("GET", "/").exec() + So(sc.resp.Header().Get("Set-Cookie"), ShouldContainSubstring, "grafana_sess") + }) + + middlewareScenario("Invalid api key", func(sc *scenarioContext) { + sc.apiKey = "invalid_key_test" + sc.fakeReq("GET", "/").exec() + + Convey("Should not init session", func() { + So(sc.resp.Header().Get("Set-Cookie"), ShouldBeEmpty) + }) + + Convey("Should return 401", func() { + So(sc.resp.Code, ShouldEqual, 401) + So(sc.respJson["message"], ShouldEqual, "Invalid API key") + }) + }) + + middlewareScenario("Valid api key", func(sc *scenarioContext) { + keyhash := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd") + + bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error { + query.Result = &m.ApiKey{OrgId: 12, Role: m.ROLE_EDITOR, Key: keyhash} + return nil + }) + + sc.fakeReq("GET", "/").withValidApiKey().exec() + + Convey("Should return 200", func() { + So(sc.resp.Code, ShouldEqual, 200) + }) + + Convey("Should init middleware context", func() { + So(sc.context.IsSignedIn, ShouldEqual, true) + So(sc.context.OrgId, ShouldEqual, 12) + So(sc.context.OrgRole, ShouldEqual, m.ROLE_EDITOR) + }) + }) + + middlewareScenario("Valid api key, but does not match db hash", func(sc *scenarioContext) { + keyhash := "something_not_matching" + + bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error { + query.Result = &m.ApiKey{OrgId: 12, Role: m.ROLE_EDITOR, Key: keyhash} + return nil + }) + + sc.fakeReq("GET", "/").withValidApiKey().exec() + + Convey("Should return api key invalid", func() { + So(sc.resp.Code, ShouldEqual, 401) + So(sc.respJson["message"], ShouldEqual, "Invalid API key") + }) + }) + + middlewareScenario("UserId in session", func(sc *scenarioContext) { + + sc.fakeReq("GET", "/").handler(func(c *Context) { + c.Session.Set(SESS_KEY_USERID, int64(12)) + }).exec() + + bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error { + query.Result = &m.SignedInUser{OrgId: 2, UserId: 12} + return nil + }) + + sc.fakeReq("GET", "/").exec() + + Convey("should init context with user info", func() { + So(sc.context.IsSignedIn, ShouldBeTrue) + So(sc.context.UserId, ShouldEqual, 12) + }) + }) + + middlewareScenario("When anonymous access is enabled", func(sc *scenarioContext) { + setting.AnonymousEnabled = true + setting.AnonymousOrgName = "test" + setting.AnonymousOrgRole = string(m.ROLE_EDITOR) + + bus.AddHandler("test", func(query *m.GetOrgByNameQuery) error { + So(query.Name, ShouldEqual, "test") + + query.Result = &m.Org{Id: 2, Name: "test"} + return nil + }) + + sc.fakeReq("GET", "/").exec() + + Convey("should init context with org info", func() { + So(sc.context.UserId, ShouldEqual, 0) + So(sc.context.OrgId, ShouldEqual, 2) + So(sc.context.OrgRole, ShouldEqual, m.ROLE_EDITOR) + }) + + Convey("context signed in should be false", func() { + So(sc.context.IsSignedIn, ShouldBeFalse) + }) + }) + }) } -func (sc *scenarioContext) PerformGet(url string) { - req, err := http.NewRequest("GET", "/", nil) - So(err, ShouldBeNil) - if sc.apiKey != "" { - req.Header.Add("Authorization", "Bearer "+sc.apiKey) - } - sc.m.ServeHTTP(sc.resp, req) - - if sc.resp.Header().Get("Content-Type") == "application/json; charset=UTF-8" { - err := json.NewDecoder(sc.resp.Body).Decode(&sc.respJson) - So(err, ShouldBeNil) - } -} - -type scenarioFunc func(c *scenarioContext) -type reqModifier func(c *http.Request) - func middlewareScenario(desc string, fn scenarioFunc) { Convey(desc, func() { + defer bus.ClearBusHandlers() + sc := &scenarioContext{} viewsPath, _ := filepath.Abs("../../public/views") @@ -58,65 +151,69 @@ func middlewareScenario(desc string, fn scenarioFunc) { sc.m.Get("/", func(c *Context) { sc.context = c + if sc.handlerFunc != nil { + sc.handlerFunc(sc.context) + } }) - sc.resp = httptest.NewRecorder() fn(sc) }) } -func TestMiddlewareContext(t *testing.T) { +type scenarioContext struct { + m *macaron.Macaron + context *Context + resp *httptest.ResponseRecorder + apiKey string + respJson map[string]interface{} + handlerFunc handlerFunc - Convey("Given grafana context", t, func() { - middlewareScenario("middleware should add context to injector", func(sc *scenarioContext) { - sc.PerformGet("/") - So(sc.context, ShouldNotBeNil) - }) - - middlewareScenario("Default middleware should allow get request", func(sc *scenarioContext) { - sc.PerformGet("/") - So(sc.resp.Code, ShouldEqual, 200) - }) - - middlewareScenario("Non api request should init session", func(sc *scenarioContext) { - sc.PerformGet("/") - So(sc.resp.Header().Get("Set-Cookie"), ShouldContainSubstring, "grafana_sess") - }) - - middlewareScenario("Invalid api key", func(sc *scenarioContext) { - sc.apiKey = "invalid_key_test" - sc.PerformGet("/") - - Convey("Should not init session", func() { - So(sc.resp.Header().Get("Set-Cookie"), ShouldBeEmpty) - }) - - Convey("Should return 401", func() { - So(sc.resp.Code, ShouldEqual, 401) - So(sc.respJson["message"], ShouldEqual, "Invalid API key") - }) - }) - - middlewareScenario("Valid api key", func(sc *scenarioContext) { - sc.apiKey = "eyJrIjoidjVuQXdwTWFmRlA2em5hUzR1cmhkV0RMUzU1MTFNNDIiLCJuIjoiYXNkIiwiaWQiOjF9" - keyhash := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd") - - bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error { - query.Result = &m.ApiKey{OrgId: 12, Role: m.ROLE_EDITOR, Key: keyhash} - return nil - }) - - sc.PerformGet("/") - - Convey("Should return 200", func() { - So(sc.resp.Code, ShouldEqual, 200) - }) - - Convey("Should init middleware context", func() { - So(sc.context.OrgId, ShouldEqual, 12) - So(sc.context.OrgRole, ShouldEqual, m.ROLE_EDITOR) - }) - }) - - }) + req *http.Request } + +func (sc *scenarioContext) withValidApiKey() *scenarioContext { + sc.apiKey = "eyJrIjoidjVuQXdwTWFmRlA2em5hUzR1cmhkV0RMUzU1MTFNNDIiLCJuIjoiYXNkIiwiaWQiOjF9" + return sc +} + +func (sc *scenarioContext) withInvalidApiKey() *scenarioContext { + sc.apiKey = "nvalidhhhhds" + return sc +} + +func (sc *scenarioContext) fakeReq(method, url string) *scenarioContext { + sc.resp = httptest.NewRecorder() + req, err := http.NewRequest(method, url, nil) + 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 +} + +func (sc *scenarioContext) handler(fn handlerFunc) *scenarioContext { + sc.handlerFunc = fn + return sc +} + +func (sc *scenarioContext) exec() { + if sc.apiKey != "" { + sc.req.Header.Add("Authorization", "Bearer "+sc.apiKey) + } + + sc.m.ServeHTTP(sc.resp, sc.req) + + if sc.resp.Header().Get("Content-Type") == "application/json; charset=UTF-8" { + err := json.NewDecoder(sc.resp.Body).Decode(&sc.respJson) + So(err, ShouldBeNil) + } +} + +type scenarioFunc func(c *scenarioContext) +type handlerFunc func(c *Context)