middleware_test.go 8.5 KB

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