middleware_test.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. package middleware
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "net/http/httptest"
  6. "path/filepath"
  7. "testing"
  8. msession "github.com/go-macaron/session"
  9. "github.com/grafana/grafana/pkg/bus"
  10. m "github.com/grafana/grafana/pkg/models"
  11. "github.com/grafana/grafana/pkg/services/auth"
  12. "github.com/grafana/grafana/pkg/services/auth/authtoken"
  13. "github.com/grafana/grafana/pkg/services/session"
  14. "github.com/grafana/grafana/pkg/setting"
  15. "github.com/grafana/grafana/pkg/util"
  16. . "github.com/smartystreets/goconvey/convey"
  17. "gopkg.in/macaron.v1"
  18. )
  19. func TestMiddlewareContext(t *testing.T) {
  20. setting.ERR_TEMPLATE_NAME = "error-template"
  21. Convey("Given the grafana middleware", t, func() {
  22. middlewareScenario("middleware should add context to injector", func(sc *scenarioContext) {
  23. sc.fakeReq("GET", "/").exec()
  24. So(sc.context, ShouldNotBeNil)
  25. })
  26. middlewareScenario("Default middleware should allow get request", func(sc *scenarioContext) {
  27. sc.fakeReq("GET", "/").exec()
  28. So(sc.resp.Code, ShouldEqual, 200)
  29. })
  30. middlewareScenario("middleware should add Cache-Control header for GET requests to API", func(sc *scenarioContext) {
  31. sc.fakeReq("GET", "/api/search").exec()
  32. So(sc.resp.Header().Get("Cache-Control"), ShouldEqual, "no-cache")
  33. So(sc.resp.Header().Get("Pragma"), ShouldEqual, "no-cache")
  34. So(sc.resp.Header().Get("Expires"), ShouldEqual, "-1")
  35. })
  36. middlewareScenario("middleware should not add Cache-Control header to for non-API GET requests", func(sc *scenarioContext) {
  37. sc.fakeReq("GET", "/").exec()
  38. So(sc.resp.Header().Get("Cache-Control"), ShouldBeEmpty)
  39. })
  40. middlewareScenario("Invalid api key", func(sc *scenarioContext) {
  41. sc.apiKey = "invalid_key_test"
  42. sc.fakeReq("GET", "/").exec()
  43. Convey("Should not init session", func() {
  44. So(sc.resp.Header().Get("Set-Cookie"), ShouldBeEmpty)
  45. })
  46. Convey("Should return 401", func() {
  47. So(sc.resp.Code, ShouldEqual, 401)
  48. So(sc.respJson["message"], ShouldEqual, "Invalid API key")
  49. })
  50. })
  51. middlewareScenario("Using basic auth", func(sc *scenarioContext) {
  52. bus.AddHandler("test", func(query *m.GetUserByLoginQuery) error {
  53. query.Result = &m.User{
  54. Password: util.EncodePassword("myPass", "salt"),
  55. Salt: "salt",
  56. }
  57. return nil
  58. })
  59. bus.AddHandler("test", func(loginUserQuery *m.LoginUserQuery) error {
  60. return nil
  61. })
  62. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  63. query.Result = &m.SignedInUser{OrgId: 2, UserId: 12}
  64. return nil
  65. })
  66. setting.BasicAuthEnabled = true
  67. authHeader := util.GetBasicAuthHeader("myUser", "myPass")
  68. sc.fakeReq("GET", "/").withAuthorizationHeader(authHeader).exec()
  69. Convey("Should init middleware context with user", func() {
  70. So(sc.context.IsSignedIn, ShouldEqual, true)
  71. So(sc.context.OrgId, ShouldEqual, 2)
  72. So(sc.context.UserId, ShouldEqual, 12)
  73. })
  74. })
  75. middlewareScenario("Valid api key", func(sc *scenarioContext) {
  76. keyhash := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd")
  77. bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error {
  78. query.Result = &m.ApiKey{OrgId: 12, Role: m.ROLE_EDITOR, Key: keyhash}
  79. return nil
  80. })
  81. sc.fakeReq("GET", "/").withValidApiKey().exec()
  82. Convey("Should return 200", func() {
  83. So(sc.resp.Code, ShouldEqual, 200)
  84. })
  85. Convey("Should init middleware context", func() {
  86. So(sc.context.IsSignedIn, ShouldEqual, true)
  87. So(sc.context.OrgId, ShouldEqual, 12)
  88. So(sc.context.OrgRole, ShouldEqual, m.ROLE_EDITOR)
  89. })
  90. })
  91. middlewareScenario("Valid api key, but does not match db hash", func(sc *scenarioContext) {
  92. keyhash := "something_not_matching"
  93. bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error {
  94. query.Result = &m.ApiKey{OrgId: 12, Role: m.ROLE_EDITOR, Key: keyhash}
  95. return nil
  96. })
  97. sc.fakeReq("GET", "/").withValidApiKey().exec()
  98. Convey("Should return api key invalid", func() {
  99. So(sc.resp.Code, ShouldEqual, 401)
  100. So(sc.respJson["message"], ShouldEqual, "Invalid API key")
  101. })
  102. })
  103. middlewareScenario("Valid api key via Basic auth", func(sc *scenarioContext) {
  104. keyhash := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd")
  105. bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error {
  106. query.Result = &m.ApiKey{OrgId: 12, Role: m.ROLE_EDITOR, Key: keyhash}
  107. return nil
  108. })
  109. authHeader := util.GetBasicAuthHeader("api_key", "eyJrIjoidjVuQXdwTWFmRlA2em5hUzR1cmhkV0RMUzU1MTFNNDIiLCJuIjoiYXNkIiwiaWQiOjF9")
  110. sc.fakeReq("GET", "/").withAuthorizationHeader(authHeader).exec()
  111. Convey("Should return 200", func() {
  112. So(sc.resp.Code, ShouldEqual, 200)
  113. })
  114. Convey("Should init middleware context", func() {
  115. So(sc.context.IsSignedIn, ShouldEqual, true)
  116. So(sc.context.OrgId, ShouldEqual, 12)
  117. So(sc.context.OrgRole, ShouldEqual, m.ROLE_EDITOR)
  118. })
  119. })
  120. middlewareScenario("Non-expired auth token in cookie which not are being rotated", func(sc *scenarioContext) {
  121. sc.withTokenSessionCookie("token")
  122. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  123. query.Result = &m.SignedInUser{OrgId: 2, UserId: 12}
  124. return nil
  125. })
  126. sc.userAuthTokenService.lookupTokenProvider = func(unhashedToken string) (auth.UserToken, error) {
  127. return &userTokenImpl{
  128. userId: 12,
  129. token: unhashedToken,
  130. }, nil
  131. }
  132. sc.fakeReq("GET", "/").exec()
  133. Convey("should init context with user info", func() {
  134. So(sc.context.IsSignedIn, ShouldBeTrue)
  135. So(sc.context.UserId, ShouldEqual, 12)
  136. So(sc.context.UserToken.GetUserId(), ShouldEqual, 12)
  137. So(sc.context.UserToken.GetToken(), ShouldEqual, "token")
  138. })
  139. Convey("should not set cookie", func() {
  140. So(sc.resp.Header().Get("Set-Cookie"), ShouldEqual, "")
  141. })
  142. })
  143. middlewareScenario("Non-expired auth token in cookie which are being rotated", func(sc *scenarioContext) {
  144. sc.withTokenSessionCookie("token")
  145. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  146. query.Result = &m.SignedInUser{OrgId: 2, UserId: 12}
  147. return nil
  148. })
  149. sc.userAuthTokenService.lookupTokenProvider = func(unhashedToken string) (auth.UserToken, error) {
  150. return &userTokenImpl{
  151. userId: 12,
  152. token: unhashedToken,
  153. }, nil
  154. }
  155. sc.userAuthTokenService.tryRotateTokenProvider = func(userToken auth.UserToken, clientIP, userAgent string) (bool, error) {
  156. userToken.(fakeUserToken).SetToken("rotated")
  157. return true, nil
  158. }
  159. expectedCookie := &http.Cookie{
  160. Name: cookieName,
  161. Value: "rotated",
  162. Path: setting.AppSubUrl + "/",
  163. HttpOnly: true,
  164. MaxAge: OneYearInSeconds,
  165. SameSite: http.SameSiteLaxMode,
  166. }
  167. sc.fakeReq("GET", "/").exec()
  168. Convey("should init context with user info", func() {
  169. So(sc.context.IsSignedIn, ShouldBeTrue)
  170. So(sc.context.UserId, ShouldEqual, 12)
  171. So(sc.context.UserToken.GetUserId(), ShouldEqual, 12)
  172. So(sc.context.UserToken.GetToken(), ShouldEqual, "rotated")
  173. })
  174. Convey("should set cookie", func() {
  175. So(sc.resp.Header().Get("Set-Cookie"), ShouldEqual, expectedCookie.String())
  176. })
  177. })
  178. middlewareScenario("Invalid/expired auth token in cookie", func(sc *scenarioContext) {
  179. sc.withTokenSessionCookie("token")
  180. sc.userAuthTokenService.lookupTokenProvider = func(unhashedToken string) (auth.UserToken, error) {
  181. return nil, authtoken.ErrAuthTokenNotFound
  182. }
  183. sc.fakeReq("GET", "/").exec()
  184. Convey("should not init context with user info", func() {
  185. So(sc.context.IsSignedIn, ShouldBeFalse)
  186. So(sc.context.UserId, ShouldEqual, 0)
  187. So(sc.context.UserToken, ShouldBeNil)
  188. })
  189. })
  190. middlewareScenario("When anonymous access is enabled", func(sc *scenarioContext) {
  191. setting.AnonymousEnabled = true
  192. setting.AnonymousOrgName = "test"
  193. setting.AnonymousOrgRole = string(m.ROLE_EDITOR)
  194. bus.AddHandler("test", func(query *m.GetOrgByNameQuery) error {
  195. So(query.Name, ShouldEqual, "test")
  196. query.Result = &m.Org{Id: 2, Name: "test"}
  197. return nil
  198. })
  199. sc.fakeReq("GET", "/").exec()
  200. Convey("should init context with org info", func() {
  201. So(sc.context.UserId, ShouldEqual, 0)
  202. So(sc.context.OrgId, ShouldEqual, 2)
  203. So(sc.context.OrgRole, ShouldEqual, m.ROLE_EDITOR)
  204. })
  205. Convey("context signed in should be false", func() {
  206. So(sc.context.IsSignedIn, ShouldBeFalse)
  207. })
  208. })
  209. middlewareScenario("When auth_proxy is enabled enabled and user exists", func(sc *scenarioContext) {
  210. setting.AuthProxyEnabled = true
  211. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  212. setting.AuthProxyHeaderProperty = "username"
  213. setting.LdapEnabled = false
  214. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  215. query.Result = &m.SignedInUser{OrgId: 2, UserId: 12}
  216. return nil
  217. })
  218. bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
  219. cmd.Result = &m.User{Id: 12}
  220. return nil
  221. })
  222. setting.SessionOptions = msession.Options{}
  223. sc.fakeReq("GET", "/")
  224. sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
  225. sc.exec()
  226. Convey("should init context with user info", func() {
  227. So(sc.context.IsSignedIn, ShouldBeTrue)
  228. So(sc.context.UserId, ShouldEqual, 12)
  229. So(sc.context.OrgId, ShouldEqual, 2)
  230. })
  231. })
  232. middlewareScenario("When auth_proxy is enabled enabled and user does not exists", func(sc *scenarioContext) {
  233. setting.AuthProxyEnabled = true
  234. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  235. setting.AuthProxyHeaderProperty = "username"
  236. setting.AuthProxyAutoSignUp = true
  237. setting.LdapEnabled = false
  238. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  239. if query.UserId > 0 {
  240. query.Result = &m.SignedInUser{OrgId: 4, UserId: 33}
  241. return nil
  242. }
  243. return m.ErrUserNotFound
  244. })
  245. bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
  246. cmd.Result = &m.User{Id: 33}
  247. return nil
  248. })
  249. sc.fakeReq("GET", "/")
  250. sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
  251. sc.exec()
  252. Convey("Should create user if auto sign up is enabled", func() {
  253. So(sc.context.IsSignedIn, ShouldBeTrue)
  254. So(sc.context.UserId, ShouldEqual, 33)
  255. So(sc.context.OrgId, ShouldEqual, 4)
  256. })
  257. })
  258. middlewareScenario("When auth_proxy is enabled and IPv4 request RemoteAddr is not trusted", func(sc *scenarioContext) {
  259. setting.AuthProxyEnabled = true
  260. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  261. setting.AuthProxyHeaderProperty = "username"
  262. setting.AuthProxyWhitelist = "192.168.1.1, 2001::23"
  263. sc.fakeReq("GET", "/")
  264. sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
  265. sc.req.RemoteAddr = "192.168.3.1:12345"
  266. sc.exec()
  267. Convey("should return 407 status code", func() {
  268. So(sc.resp.Code, ShouldEqual, 407)
  269. So(sc.resp.Body.String(), ShouldContainSubstring, "Request for user (torkelo) from 192.168.3.1 is not from the authentication proxy")
  270. })
  271. })
  272. middlewareScenario("When auth_proxy is enabled and IPv4 request RemoteAddr is not within trusted CIDR block", func(sc *scenarioContext) {
  273. setting.AuthProxyEnabled = true
  274. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  275. setting.AuthProxyHeaderProperty = "username"
  276. setting.AuthProxyWhitelist = "192.168.1.0/24, 2001::0/120"
  277. sc.fakeReq("GET", "/")
  278. sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
  279. sc.req.RemoteAddr = "192.168.3.1:12345"
  280. sc.exec()
  281. Convey("should return 407 status code", func() {
  282. So(sc.resp.Code, ShouldEqual, 407)
  283. So(sc.resp.Body.String(), ShouldContainSubstring, "Request for user (torkelo) from 192.168.3.1 is not from the authentication proxy")
  284. })
  285. })
  286. middlewareScenario("When auth_proxy is enabled and IPv6 request RemoteAddr is not trusted", func(sc *scenarioContext) {
  287. setting.AuthProxyEnabled = true
  288. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  289. setting.AuthProxyHeaderProperty = "username"
  290. setting.AuthProxyWhitelist = "192.168.1.1, 2001::23"
  291. sc.fakeReq("GET", "/")
  292. sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
  293. sc.req.RemoteAddr = "[2001:23]:12345"
  294. sc.exec()
  295. Convey("should return 407 status code", func() {
  296. So(sc.resp.Code, ShouldEqual, 407)
  297. So(sc.resp.Body.String(), ShouldContainSubstring, "Request for user (torkelo) from 2001:23 is not from the authentication proxy")
  298. })
  299. })
  300. middlewareScenario("When auth_proxy is enabled and IPv6 request RemoteAddr is not within trusted CIDR block", func(sc *scenarioContext) {
  301. setting.AuthProxyEnabled = true
  302. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  303. setting.AuthProxyHeaderProperty = "username"
  304. setting.AuthProxyWhitelist = "192.168.1.0/24, 2001::0/120"
  305. sc.fakeReq("GET", "/")
  306. sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
  307. sc.req.RemoteAddr = "[2001:23]:12345"
  308. sc.exec()
  309. Convey("should return 407 status code", func() {
  310. So(sc.resp.Code, ShouldEqual, 407)
  311. So(sc.resp.Body.String(), ShouldContainSubstring, "Request for user (torkelo) from 2001:23 is not from the authentication proxy")
  312. })
  313. })
  314. middlewareScenario("When auth_proxy is enabled and request RemoteAddr is trusted", func(sc *scenarioContext) {
  315. setting.AuthProxyEnabled = true
  316. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  317. setting.AuthProxyHeaderProperty = "username"
  318. setting.AuthProxyWhitelist = "192.168.1.1, 2001::23"
  319. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  320. query.Result = &m.SignedInUser{OrgId: 4, UserId: 33}
  321. return nil
  322. })
  323. bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
  324. cmd.Result = &m.User{Id: 33}
  325. return nil
  326. })
  327. sc.fakeReq("GET", "/")
  328. sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
  329. sc.req.RemoteAddr = "[2001::23]:12345"
  330. sc.exec()
  331. Convey("Should init context with user info", func() {
  332. So(sc.context.IsSignedIn, ShouldBeTrue)
  333. So(sc.context.UserId, ShouldEqual, 33)
  334. So(sc.context.OrgId, ShouldEqual, 4)
  335. })
  336. })
  337. middlewareScenario("When auth_proxy is enabled and IPv4 request RemoteAddr is within trusted CIDR block", func(sc *scenarioContext) {
  338. setting.AuthProxyEnabled = true
  339. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  340. setting.AuthProxyHeaderProperty = "username"
  341. setting.AuthProxyWhitelist = "192.168.1.0/24, 2001::0/120"
  342. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  343. query.Result = &m.SignedInUser{OrgId: 4, UserId: 33}
  344. return nil
  345. })
  346. bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
  347. cmd.Result = &m.User{Id: 33}
  348. return nil
  349. })
  350. sc.fakeReq("GET", "/")
  351. sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
  352. sc.req.RemoteAddr = "192.168.1.10:12345"
  353. sc.exec()
  354. Convey("Should init context with user info", func() {
  355. So(sc.context.IsSignedIn, ShouldBeTrue)
  356. So(sc.context.UserId, ShouldEqual, 33)
  357. So(sc.context.OrgId, ShouldEqual, 4)
  358. })
  359. })
  360. middlewareScenario("When auth_proxy is enabled and IPv6 request RemoteAddr is within trusted CIDR block", func(sc *scenarioContext) {
  361. setting.AuthProxyEnabled = true
  362. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  363. setting.AuthProxyHeaderProperty = "username"
  364. setting.AuthProxyWhitelist = "192.168.1.0/24, 2001::0/120"
  365. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  366. query.Result = &m.SignedInUser{OrgId: 4, UserId: 33}
  367. return nil
  368. })
  369. bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
  370. cmd.Result = &m.User{Id: 33}
  371. return nil
  372. })
  373. sc.fakeReq("GET", "/")
  374. sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
  375. sc.req.RemoteAddr = "[2001::23]:12345"
  376. sc.exec()
  377. Convey("Should init context with user info", func() {
  378. So(sc.context.IsSignedIn, ShouldBeTrue)
  379. So(sc.context.UserId, ShouldEqual, 33)
  380. So(sc.context.OrgId, ShouldEqual, 4)
  381. })
  382. })
  383. middlewareScenario("When session exists for previous user, create a new session", func(sc *scenarioContext) {
  384. setting.AuthProxyEnabled = true
  385. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  386. setting.AuthProxyHeaderProperty = "username"
  387. setting.AuthProxyWhitelist = ""
  388. bus.AddHandler("test", func(query *m.UpsertUserCommand) error {
  389. query.Result = &m.User{Id: 32}
  390. return nil
  391. })
  392. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  393. query.Result = &m.SignedInUser{OrgId: 4, UserId: 32}
  394. return nil
  395. })
  396. // create session
  397. sc.fakeReq("GET", "/").handler(func(c *m.ReqContext) {
  398. c.Session.Set(session.SESS_KEY_USERID, int64(33))
  399. }).exec()
  400. oldSessionID := sc.context.Session.ID()
  401. sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
  402. sc.exec()
  403. newSessionID := sc.context.Session.ID()
  404. Convey("Should not share session with other user", func() {
  405. So(oldSessionID, ShouldNotEqual, newSessionID)
  406. })
  407. })
  408. middlewareScenario("When auth_proxy and ldap enabled call sync with ldap user", func(sc *scenarioContext) {
  409. setting.AuthProxyEnabled = true
  410. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  411. setting.AuthProxyHeaderProperty = "username"
  412. setting.AuthProxyWhitelist = ""
  413. setting.LdapEnabled = true
  414. called := false
  415. syncGrafanaUserWithLdapUser = func(query *m.LoginUserQuery) error {
  416. called = true
  417. query.User = &m.User{Id: 32}
  418. return nil
  419. }
  420. bus.AddHandler("test", func(query *m.UpsertUserCommand) error {
  421. query.Result = &m.User{Id: 32}
  422. return nil
  423. })
  424. bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
  425. query.Result = &m.SignedInUser{OrgId: 4, UserId: 32}
  426. return nil
  427. })
  428. sc.fakeReq("GET", "/")
  429. sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
  430. sc.exec()
  431. Convey("Should call syncGrafanaUserWithLdapUser", func() {
  432. So(called, ShouldBeTrue)
  433. })
  434. })
  435. })
  436. }
  437. func middlewareScenario(desc string, fn scenarioFunc) {
  438. Convey(desc, func() {
  439. defer bus.ClearBusHandlers()
  440. sc := &scenarioContext{}
  441. viewsPath, _ := filepath.Abs("../../public/views")
  442. sc.m = macaron.New()
  443. sc.m.Use(macaron.Renderer(macaron.RenderOptions{
  444. Directory: viewsPath,
  445. Delims: macaron.Delims{Left: "[[", Right: "]]"},
  446. }))
  447. session.Init(&msession.Options{}, 0)
  448. sc.userAuthTokenService = newFakeUserAuthTokenService()
  449. sc.m.Use(GetContextHandler(sc.userAuthTokenService))
  450. // mock out gc goroutine
  451. session.StartSessionGC = func() {}
  452. setting.SessionOptions = msession.Options{}
  453. sc.m.Use(OrgRedirect())
  454. sc.m.Use(AddDefaultResponseHeaders())
  455. sc.defaultHandler = func(c *m.ReqContext) {
  456. sc.context = c
  457. if sc.handlerFunc != nil {
  458. sc.handlerFunc(sc.context)
  459. }
  460. }
  461. sc.m.Get("/", sc.defaultHandler)
  462. fn(sc)
  463. })
  464. }
  465. type scenarioContext struct {
  466. m *macaron.Macaron
  467. context *m.ReqContext
  468. resp *httptest.ResponseRecorder
  469. apiKey string
  470. authHeader string
  471. tokenSessionCookie string
  472. respJson map[string]interface{}
  473. handlerFunc handlerFunc
  474. defaultHandler macaron.Handler
  475. url string
  476. userAuthTokenService *fakeUserAuthTokenService
  477. req *http.Request
  478. }
  479. func (sc *scenarioContext) withValidApiKey() *scenarioContext {
  480. sc.apiKey = "eyJrIjoidjVuQXdwTWFmRlA2em5hUzR1cmhkV0RMUzU1MTFNNDIiLCJuIjoiYXNkIiwiaWQiOjF9"
  481. return sc
  482. }
  483. func (sc *scenarioContext) withTokenSessionCookie(unhashedToken string) *scenarioContext {
  484. sc.tokenSessionCookie = unhashedToken
  485. return sc
  486. }
  487. func (sc *scenarioContext) withAuthorizationHeader(authHeader string) *scenarioContext {
  488. sc.authHeader = authHeader
  489. return sc
  490. }
  491. func (sc *scenarioContext) fakeReq(method, url string) *scenarioContext {
  492. sc.resp = httptest.NewRecorder()
  493. req, err := http.NewRequest(method, url, nil)
  494. So(err, ShouldBeNil)
  495. sc.req = req
  496. // add session cookie from last request
  497. if sc.context != nil {
  498. if sc.context.Session.ID() != "" {
  499. req.Header.Add("Cookie", "grafana_sess="+sc.context.Session.ID()+";")
  500. }
  501. }
  502. return sc
  503. }
  504. func (sc *scenarioContext) fakeReqWithParams(method, url string, queryParams map[string]string) *scenarioContext {
  505. sc.resp = httptest.NewRecorder()
  506. req, err := http.NewRequest(method, url, nil)
  507. q := req.URL.Query()
  508. for k, v := range queryParams {
  509. q.Add(k, v)
  510. }
  511. req.URL.RawQuery = q.Encode()
  512. So(err, ShouldBeNil)
  513. sc.req = req
  514. return sc
  515. }
  516. func (sc *scenarioContext) handler(fn handlerFunc) *scenarioContext {
  517. sc.handlerFunc = fn
  518. return sc
  519. }
  520. func (sc *scenarioContext) exec() {
  521. if sc.apiKey != "" {
  522. sc.req.Header.Add("Authorization", "Bearer "+sc.apiKey)
  523. }
  524. if sc.authHeader != "" {
  525. sc.req.Header.Add("Authorization", sc.authHeader)
  526. }
  527. if sc.tokenSessionCookie != "" {
  528. sc.req.AddCookie(&http.Cookie{
  529. Name: cookieName,
  530. Value: sc.tokenSessionCookie,
  531. })
  532. }
  533. sc.m.ServeHTTP(sc.resp, sc.req)
  534. if sc.resp.Header().Get("Content-Type") == "application/json; charset=UTF-8" {
  535. err := json.NewDecoder(sc.resp.Body).Decode(&sc.respJson)
  536. So(err, ShouldBeNil)
  537. }
  538. }
  539. type scenarioFunc func(c *scenarioContext)
  540. type handlerFunc func(c *m.ReqContext)
  541. type fakeUserToken interface {
  542. auth.UserToken
  543. SetToken(token string)
  544. }
  545. type userTokenImpl struct {
  546. userId int64
  547. token string
  548. }
  549. func (ut *userTokenImpl) GetUserId() int64 {
  550. return ut.userId
  551. }
  552. func (ut *userTokenImpl) GetToken() string {
  553. return ut.token
  554. }
  555. func (ut *userTokenImpl) SetToken(token string) {
  556. ut.token = token
  557. }
  558. type fakeUserAuthTokenService struct {
  559. createTokenProvider func(userId int64, clientIP, userAgent string) (auth.UserToken, error)
  560. tryRotateTokenProvider func(token auth.UserToken, clientIP, userAgent string) (bool, error)
  561. lookupTokenProvider func(unhashedToken string) (auth.UserToken, error)
  562. revokeTokenProvider func(token auth.UserToken) error
  563. }
  564. func newFakeUserAuthTokenService() *fakeUserAuthTokenService {
  565. return &fakeUserAuthTokenService{
  566. createTokenProvider: func(userId int64, clientIP, userAgent string) (auth.UserToken, error) {
  567. return &userTokenImpl{
  568. userId: 0,
  569. token: "",
  570. }, nil
  571. },
  572. tryRotateTokenProvider: func(token auth.UserToken, clientIP, userAgent string) (bool, error) {
  573. return false, nil
  574. },
  575. lookupTokenProvider: func(unhashedToken string) (auth.UserToken, error) {
  576. return &userTokenImpl{
  577. userId: 0,
  578. token: "",
  579. }, nil
  580. },
  581. revokeTokenProvider: func(token auth.UserToken) error {
  582. return nil
  583. },
  584. }
  585. }
  586. func (s *fakeUserAuthTokenService) CreateToken(userId int64, clientIP, userAgent string) (auth.UserToken, error) {
  587. return s.createTokenProvider(userId, clientIP, userAgent)
  588. }
  589. func (s *fakeUserAuthTokenService) LookupToken(unhashedToken string) (auth.UserToken, error) {
  590. return s.lookupTokenProvider(unhashedToken)
  591. }
  592. func (s *fakeUserAuthTokenService) TryRotateToken(token auth.UserToken, clientIP, userAgent string) (bool, error) {
  593. return s.tryRotateTokenProvider(token, clientIP, userAgent)
  594. }
  595. func (s *fakeUserAuthTokenService) RevokeToken(token auth.UserToken) error {
  596. return s.revokeTokenProvider(token)
  597. }