middleware_test.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  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("Using basic auth", func(sc *scenarioContext) {
  42. bus.AddHandler("test", func(query *m.GetUserByLoginQuery) error {
  43. query.Result = &m.User{
  44. Password: util.EncodePassword("myPass", "salt"),
  45. Salt: "salt",
  46. }
  47. return nil
  48. })
  49. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  50. query.Result = &m.SignedInUser{OrgId: 2, UserId: 12}
  51. return nil
  52. })
  53. setting.BasicAuthEnabled = true
  54. authHeader := util.GetBasicAuthHeader("myUser", "myPass")
  55. sc.fakeReq("GET", "/").withAuthoriziationHeader(authHeader).exec()
  56. Convey("Should init middleware context with user", func() {
  57. So(sc.context.IsSignedIn, ShouldEqual, true)
  58. So(sc.context.OrgId, ShouldEqual, 2)
  59. So(sc.context.UserId, ShouldEqual, 12)
  60. })
  61. })
  62. middlewareScenario("Valid api key", func(sc *scenarioContext) {
  63. keyhash := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd")
  64. bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error {
  65. query.Result = &m.ApiKey{OrgId: 12, Role: m.ROLE_EDITOR, Key: keyhash}
  66. return nil
  67. })
  68. sc.fakeReq("GET", "/").withValidApiKey().exec()
  69. Convey("Should return 200", func() {
  70. So(sc.resp.Code, ShouldEqual, 200)
  71. })
  72. Convey("Should init middleware context", func() {
  73. So(sc.context.IsSignedIn, ShouldEqual, true)
  74. So(sc.context.OrgId, ShouldEqual, 12)
  75. So(sc.context.OrgRole, ShouldEqual, m.ROLE_EDITOR)
  76. })
  77. })
  78. middlewareScenario("Valid api key, but does not match db hash", func(sc *scenarioContext) {
  79. keyhash := "something_not_matching"
  80. bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error {
  81. query.Result = &m.ApiKey{OrgId: 12, Role: m.ROLE_EDITOR, Key: keyhash}
  82. return nil
  83. })
  84. sc.fakeReq("GET", "/").withValidApiKey().exec()
  85. Convey("Should return api key invalid", func() {
  86. So(sc.resp.Code, ShouldEqual, 401)
  87. So(sc.respJson["message"], ShouldEqual, "Invalid API key")
  88. })
  89. })
  90. middlewareScenario("UserId in session", func(sc *scenarioContext) {
  91. sc.fakeReq("GET", "/").handler(func(c *Context) {
  92. c.Session.Set(SESS_KEY_USERID, int64(12))
  93. }).exec()
  94. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  95. query.Result = &m.SignedInUser{OrgId: 2, UserId: 12}
  96. return nil
  97. })
  98. sc.fakeReq("GET", "/").exec()
  99. Convey("should init context with user info", func() {
  100. So(sc.context.IsSignedIn, ShouldBeTrue)
  101. So(sc.context.UserId, ShouldEqual, 12)
  102. })
  103. })
  104. middlewareScenario("When anonymous access is enabled", func(sc *scenarioContext) {
  105. setting.AnonymousEnabled = true
  106. setting.AnonymousOrgName = "test"
  107. setting.AnonymousOrgRole = string(m.ROLE_EDITOR)
  108. bus.AddHandler("test", func(query *m.GetOrgByNameQuery) error {
  109. So(query.Name, ShouldEqual, "test")
  110. query.Result = &m.Org{Id: 2, Name: "test"}
  111. return nil
  112. })
  113. sc.fakeReq("GET", "/").exec()
  114. Convey("should init context with org info", func() {
  115. So(sc.context.UserId, ShouldEqual, 0)
  116. So(sc.context.OrgId, ShouldEqual, 2)
  117. So(sc.context.OrgRole, ShouldEqual, m.ROLE_EDITOR)
  118. })
  119. Convey("context signed in should be false", func() {
  120. So(sc.context.IsSignedIn, ShouldBeFalse)
  121. })
  122. })
  123. middlewareScenario("When auth_proxy is enabled enabled and user exists", func(sc *scenarioContext) {
  124. setting.AuthProxyEnabled = true
  125. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  126. setting.AuthProxyHeaderProperty = "username"
  127. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  128. query.Result = &m.SignedInUser{OrgId: 2, UserId: 12}
  129. return nil
  130. })
  131. sc.fakeReq("GET", "/")
  132. sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
  133. sc.exec()
  134. Convey("should init context with user info", func() {
  135. So(sc.context.IsSignedIn, ShouldBeTrue)
  136. So(sc.context.UserId, ShouldEqual, 12)
  137. So(sc.context.OrgId, ShouldEqual, 2)
  138. })
  139. })
  140. middlewareScenario("When auth_proxy is enabled enabled and user does not exists", func(sc *scenarioContext) {
  141. setting.AuthProxyEnabled = true
  142. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  143. setting.AuthProxyHeaderProperty = "username"
  144. setting.AuthProxyAutoSignUp = true
  145. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  146. if query.UserId > 0 {
  147. query.Result = &m.SignedInUser{OrgId: 4, UserId: 33}
  148. return nil
  149. } else {
  150. return m.ErrUserNotFound
  151. }
  152. })
  153. var createUserCmd *m.CreateUserCommand
  154. bus.AddHandler("test", func(cmd *m.CreateUserCommand) error {
  155. createUserCmd = cmd
  156. cmd.Result = m.User{Id: 33}
  157. return nil
  158. })
  159. sc.fakeReq("GET", "/")
  160. sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
  161. sc.exec()
  162. Convey("Should create user if auto sign up is enabled", func() {
  163. So(sc.context.IsSignedIn, ShouldBeTrue)
  164. So(sc.context.UserId, ShouldEqual, 33)
  165. So(sc.context.OrgId, ShouldEqual, 4)
  166. })
  167. })
  168. })
  169. }
  170. func middlewareScenario(desc string, fn scenarioFunc) {
  171. Convey(desc, func() {
  172. defer bus.ClearBusHandlers()
  173. sc := &scenarioContext{}
  174. viewsPath, _ := filepath.Abs("../../public/views")
  175. sc.m = macaron.New()
  176. sc.m.Use(macaron.Renderer(macaron.RenderOptions{
  177. Directory: viewsPath,
  178. Delims: macaron.Delims{Left: "[[", Right: "]]"},
  179. }))
  180. sc.m.Use(GetContextHandler())
  181. // mock out gc goroutine
  182. startSessionGC = func() {}
  183. sc.m.Use(Sessioner(&session.Options{}))
  184. sc.defaultHandler = func(c *Context) {
  185. sc.context = c
  186. if sc.handlerFunc != nil {
  187. sc.handlerFunc(sc.context)
  188. }
  189. }
  190. sc.m.Get("/", sc.defaultHandler)
  191. fn(sc)
  192. })
  193. }
  194. type scenarioContext struct {
  195. m *macaron.Macaron
  196. context *Context
  197. resp *httptest.ResponseRecorder
  198. apiKey string
  199. authHeader string
  200. respJson map[string]interface{}
  201. handlerFunc handlerFunc
  202. defaultHandler macaron.Handler
  203. req *http.Request
  204. }
  205. func (sc *scenarioContext) withValidApiKey() *scenarioContext {
  206. sc.apiKey = "eyJrIjoidjVuQXdwTWFmRlA2em5hUzR1cmhkV0RMUzU1MTFNNDIiLCJuIjoiYXNkIiwiaWQiOjF9"
  207. return sc
  208. }
  209. func (sc *scenarioContext) withInvalidApiKey() *scenarioContext {
  210. sc.apiKey = "nvalidhhhhds"
  211. return sc
  212. }
  213. func (sc *scenarioContext) withAuthoriziationHeader(authHeader string) *scenarioContext {
  214. sc.authHeader = authHeader
  215. return sc
  216. }
  217. func (sc *scenarioContext) fakeReq(method, url string) *scenarioContext {
  218. sc.resp = httptest.NewRecorder()
  219. req, err := http.NewRequest(method, url, nil)
  220. So(err, ShouldBeNil)
  221. sc.req = req
  222. // add session cookie from last request
  223. if sc.context != nil {
  224. if sc.context.Session.ID() != "" {
  225. req.Header.Add("Cookie", "grafana_sess="+sc.context.Session.ID()+";")
  226. }
  227. }
  228. return sc
  229. }
  230. func (sc *scenarioContext) handler(fn handlerFunc) *scenarioContext {
  231. sc.handlerFunc = fn
  232. return sc
  233. }
  234. func (sc *scenarioContext) exec() {
  235. if sc.apiKey != "" {
  236. sc.req.Header.Add("Authorization", "Bearer "+sc.apiKey)
  237. }
  238. if sc.authHeader != "" {
  239. sc.req.Header.Add("Authorization", sc.authHeader)
  240. }
  241. sc.m.ServeHTTP(sc.resp, sc.req)
  242. if sc.resp.Header().Get("Content-Type") == "application/json; charset=UTF-8" {
  243. err := json.NewDecoder(sc.resp.Body).Decode(&sc.respJson)
  244. So(err, ShouldBeNil)
  245. }
  246. }
  247. type scenarioFunc func(c *scenarioContext)
  248. type handlerFunc func(c *Context)