middleware_test.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. package middleware
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "net/http/httptest"
  6. "path/filepath"
  7. "testing"
  8. "github.com/Unknwon/macaron"
  9. "github.com/grafana/grafana/pkg/bus"
  10. m "github.com/grafana/grafana/pkg/models"
  11. "github.com/grafana/grafana/pkg/setting"
  12. "github.com/grafana/grafana/pkg/util"
  13. "github.com/macaron-contrib/session"
  14. . "github.com/smartystreets/goconvey/convey"
  15. )
  16. func TestMiddlewareContext(t *testing.T) {
  17. Convey("Given the grafana middleware", t, func() {
  18. middlewareScenario("middleware should add context to injector", func(sc *scenarioContext) {
  19. sc.fakeReq("GET", "/").exec()
  20. So(sc.context, ShouldNotBeNil)
  21. })
  22. middlewareScenario("Default middleware should allow get request", func(sc *scenarioContext) {
  23. sc.fakeReq("GET", "/").exec()
  24. So(sc.resp.Code, ShouldEqual, 200)
  25. })
  26. middlewareScenario("Non api request should init session", func(sc *scenarioContext) {
  27. sc.fakeReq("GET", "/").exec()
  28. So(sc.resp.Header().Get("Set-Cookie"), ShouldContainSubstring, "grafana_sess")
  29. })
  30. middlewareScenario("Invalid api key", func(sc *scenarioContext) {
  31. sc.apiKey = "invalid_key_test"
  32. sc.fakeReq("GET", "/").exec()
  33. Convey("Should not init session", func() {
  34. So(sc.resp.Header().Get("Set-Cookie"), ShouldBeEmpty)
  35. })
  36. Convey("Should return 401", func() {
  37. So(sc.resp.Code, ShouldEqual, 401)
  38. So(sc.respJson["message"], ShouldEqual, "Invalid API key")
  39. })
  40. })
  41. middlewareScenario("Valid api key", func(sc *scenarioContext) {
  42. keyhash := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd")
  43. bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error {
  44. query.Result = &m.ApiKey{OrgId: 12, Role: m.ROLE_EDITOR, Key: keyhash}
  45. return nil
  46. })
  47. sc.fakeReq("GET", "/").withValidApiKey().exec()
  48. Convey("Should return 200", func() {
  49. So(sc.resp.Code, ShouldEqual, 200)
  50. })
  51. Convey("Should init middleware context", func() {
  52. So(sc.context.IsSignedIn, ShouldEqual, true)
  53. So(sc.context.OrgId, ShouldEqual, 12)
  54. So(sc.context.OrgRole, ShouldEqual, m.ROLE_EDITOR)
  55. })
  56. })
  57. middlewareScenario("Valid api key, but does not match db hash", func(sc *scenarioContext) {
  58. keyhash := "something_not_matching"
  59. bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error {
  60. query.Result = &m.ApiKey{OrgId: 12, Role: m.ROLE_EDITOR, Key: keyhash}
  61. return nil
  62. })
  63. sc.fakeReq("GET", "/").withValidApiKey().exec()
  64. Convey("Should return api key invalid", func() {
  65. So(sc.resp.Code, ShouldEqual, 401)
  66. So(sc.respJson["message"], ShouldEqual, "Invalid API key")
  67. })
  68. })
  69. middlewareScenario("UserId in session", func(sc *scenarioContext) {
  70. sc.fakeReq("GET", "/").handler(func(c *Context) {
  71. c.Session.Set(SESS_KEY_USERID, int64(12))
  72. }).exec()
  73. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  74. query.Result = &m.SignedInUser{OrgId: 2, UserId: 12}
  75. return nil
  76. })
  77. sc.fakeReq("GET", "/").exec()
  78. Convey("should init context with user info", func() {
  79. So(sc.context.IsSignedIn, ShouldBeTrue)
  80. So(sc.context.UserId, ShouldEqual, 12)
  81. })
  82. })
  83. middlewareScenario("When anonymous access is enabled", func(sc *scenarioContext) {
  84. setting.AnonymousEnabled = true
  85. setting.AnonymousOrgName = "test"
  86. setting.AnonymousOrgRole = string(m.ROLE_EDITOR)
  87. bus.AddHandler("test", func(query *m.GetOrgByNameQuery) error {
  88. So(query.Name, ShouldEqual, "test")
  89. query.Result = &m.Org{Id: 2, Name: "test"}
  90. return nil
  91. })
  92. sc.fakeReq("GET", "/").exec()
  93. Convey("should init context with org info", func() {
  94. So(sc.context.UserId, ShouldEqual, 0)
  95. So(sc.context.OrgId, ShouldEqual, 2)
  96. So(sc.context.OrgRole, ShouldEqual, m.ROLE_EDITOR)
  97. })
  98. Convey("context signed in should be false", func() {
  99. So(sc.context.IsSignedIn, ShouldBeFalse)
  100. })
  101. })
  102. middlewareScenario("When auth_proxy is enabled enabled and user exists", func(sc *scenarioContext) {
  103. setting.AuthProxyEnabled = true
  104. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  105. setting.AuthProxyHeaderProperty = "username"
  106. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  107. query.Result = &m.SignedInUser{OrgId: 2, UserId: 12}
  108. return nil
  109. })
  110. sc.fakeReq("GET", "/")
  111. sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
  112. sc.exec()
  113. Convey("should init context with user info", func() {
  114. So(sc.context.IsSignedIn, ShouldBeTrue)
  115. So(sc.context.UserId, ShouldEqual, 12)
  116. So(sc.context.OrgId, ShouldEqual, 2)
  117. })
  118. })
  119. middlewareScenario("When auth_proxy is enabled enabled and user does not exists", func(sc *scenarioContext) {
  120. setting.AuthProxyEnabled = true
  121. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  122. setting.AuthProxyHeaderProperty = "username"
  123. setting.AuthProxyAutoSignUp = true
  124. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  125. if query.UserId > 0 {
  126. query.Result = &m.SignedInUser{OrgId: 4, UserId: 33}
  127. return nil
  128. } else {
  129. return m.ErrUserNotFound
  130. }
  131. })
  132. var createUserCmd *m.CreateUserCommand
  133. bus.AddHandler("test", func(cmd *m.CreateUserCommand) error {
  134. createUserCmd = cmd
  135. cmd.Result = m.User{Id: 33}
  136. return nil
  137. })
  138. sc.fakeReq("GET", "/")
  139. sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
  140. sc.exec()
  141. Convey("Should create user if auto sign up is enabled", func() {
  142. So(sc.context.IsSignedIn, ShouldBeTrue)
  143. So(sc.context.UserId, ShouldEqual, 33)
  144. So(sc.context.OrgId, ShouldEqual, 4)
  145. })
  146. })
  147. })
  148. }
  149. func middlewareScenario(desc string, fn scenarioFunc) {
  150. Convey(desc, func() {
  151. defer bus.ClearBusHandlers()
  152. sc := &scenarioContext{}
  153. viewsPath, _ := filepath.Abs("../../public/views")
  154. sc.m = macaron.New()
  155. sc.m.Use(macaron.Renderer(macaron.RenderOptions{
  156. Directory: viewsPath,
  157. Delims: macaron.Delims{Left: "[[", Right: "]]"},
  158. }))
  159. sc.m.Use(GetContextHandler())
  160. // mock out gc goroutine
  161. startSessionGC = func() {}
  162. sc.m.Use(Sessioner(&session.Options{}))
  163. sc.defaultHandler = func(c *Context) {
  164. sc.context = c
  165. if sc.handlerFunc != nil {
  166. sc.handlerFunc(sc.context)
  167. }
  168. }
  169. sc.m.Get("/", sc.defaultHandler)
  170. fn(sc)
  171. })
  172. }
  173. type scenarioContext struct {
  174. m *macaron.Macaron
  175. context *Context
  176. resp *httptest.ResponseRecorder
  177. apiKey string
  178. respJson map[string]interface{}
  179. handlerFunc handlerFunc
  180. defaultHandler macaron.Handler
  181. req *http.Request
  182. }
  183. func (sc *scenarioContext) withValidApiKey() *scenarioContext {
  184. sc.apiKey = "eyJrIjoidjVuQXdwTWFmRlA2em5hUzR1cmhkV0RMUzU1MTFNNDIiLCJuIjoiYXNkIiwiaWQiOjF9"
  185. return sc
  186. }
  187. func (sc *scenarioContext) withInvalidApiKey() *scenarioContext {
  188. sc.apiKey = "nvalidhhhhds"
  189. return sc
  190. }
  191. func (sc *scenarioContext) fakeReq(method, url string) *scenarioContext {
  192. sc.resp = httptest.NewRecorder()
  193. req, err := http.NewRequest(method, url, nil)
  194. So(err, ShouldBeNil)
  195. sc.req = req
  196. // add session cookie from last request
  197. if sc.context != nil {
  198. if sc.context.Session.ID() != "" {
  199. req.Header.Add("Cookie", "grafana_sess="+sc.context.Session.ID()+";")
  200. }
  201. }
  202. return sc
  203. }
  204. func (sc *scenarioContext) handler(fn handlerFunc) *scenarioContext {
  205. sc.handlerFunc = fn
  206. return sc
  207. }
  208. func (sc *scenarioContext) exec() {
  209. if sc.apiKey != "" {
  210. sc.req.Header.Add("Authorization", "Bearer "+sc.apiKey)
  211. }
  212. sc.m.ServeHTTP(sc.resp, sc.req)
  213. if sc.resp.Header().Get("Content-Type") == "application/json; charset=UTF-8" {
  214. err := json.NewDecoder(sc.resp.Body).Decode(&sc.respJson)
  215. So(err, ShouldBeNil)
  216. }
  217. }
  218. type scenarioFunc func(c *scenarioContext)
  219. type handlerFunc func(c *Context)