middleware_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. package middleware
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "net/http"
  7. "net/http/httptest"
  8. "path/filepath"
  9. "testing"
  10. "time"
  11. . "github.com/smartystreets/goconvey/convey"
  12. "gopkg.in/macaron.v1"
  13. "github.com/grafana/grafana/pkg/api/dtos"
  14. "github.com/grafana/grafana/pkg/bus"
  15. "github.com/grafana/grafana/pkg/infra/remotecache"
  16. "github.com/grafana/grafana/pkg/models"
  17. "github.com/grafana/grafana/pkg/services/auth"
  18. "github.com/grafana/grafana/pkg/services/login"
  19. "github.com/grafana/grafana/pkg/setting"
  20. "github.com/grafana/grafana/pkg/util"
  21. "github.com/stretchr/testify/assert"
  22. )
  23. const errorTemplate = "error-template"
  24. func mockGetTime() {
  25. var timeSeed int64
  26. getTime = func() time.Time {
  27. fakeNow := time.Unix(timeSeed, 0)
  28. timeSeed++
  29. return fakeNow
  30. }
  31. }
  32. func resetGetTime() {
  33. getTime = time.Now
  34. }
  35. func TestMiddleWareSecurityHeaders(t *testing.T) {
  36. setting.ERR_TEMPLATE_NAME = errorTemplate
  37. Convey("Given the grafana middleware", t, func() {
  38. middlewareScenario(t, "middleware should get correct x-xss-protection header", func(sc *scenarioContext) {
  39. setting.XSSProtectionHeader = true
  40. sc.fakeReq("GET", "/api/").exec()
  41. So(sc.resp.Header().Get("X-XSS-Protection"), ShouldEqual, "1; mode=block")
  42. })
  43. middlewareScenario(t, "middleware should not get x-xss-protection when disabled", func(sc *scenarioContext) {
  44. setting.XSSProtectionHeader = false
  45. sc.fakeReq("GET", "/api/").exec()
  46. So(sc.resp.Header().Get("X-XSS-Protection"), ShouldBeEmpty)
  47. })
  48. middlewareScenario(t, "middleware should add correct Strict-Transport-Security header", func(sc *scenarioContext) {
  49. setting.StrictTransportSecurity = true
  50. setting.Protocol = setting.HTTPS
  51. setting.StrictTransportSecurityMaxAge = 64000
  52. sc.fakeReq("GET", "/api/").exec()
  53. So(sc.resp.Header().Get("Strict-Transport-Security"), ShouldEqual, "max-age=64000")
  54. setting.StrictTransportSecurityPreload = true
  55. sc.fakeReq("GET", "/api/").exec()
  56. So(sc.resp.Header().Get("Strict-Transport-Security"), ShouldEqual, "max-age=64000; preload")
  57. setting.StrictTransportSecuritySubDomains = true
  58. sc.fakeReq("GET", "/api/").exec()
  59. So(sc.resp.Header().Get("Strict-Transport-Security"), ShouldEqual, "max-age=64000; preload; includeSubDomains")
  60. })
  61. })
  62. }
  63. func TestMiddlewareContext(t *testing.T) {
  64. setting.ERR_TEMPLATE_NAME = errorTemplate
  65. Convey("Given the grafana middleware", t, func() {
  66. middlewareScenario(t, "middleware should add context to injector", func(sc *scenarioContext) {
  67. sc.fakeReq("GET", "/").exec()
  68. So(sc.context, ShouldNotBeNil)
  69. })
  70. middlewareScenario(t, "Default middleware should allow get request", func(sc *scenarioContext) {
  71. sc.fakeReq("GET", "/").exec()
  72. So(sc.resp.Code, ShouldEqual, 200)
  73. })
  74. middlewareScenario(t, "middleware should add Cache-Control header for requests to API", func(sc *scenarioContext) {
  75. sc.fakeReq("GET", "/api/search").exec()
  76. So(sc.resp.Header().Get("Cache-Control"), ShouldEqual, "no-cache")
  77. So(sc.resp.Header().Get("Pragma"), ShouldEqual, "no-cache")
  78. So(sc.resp.Header().Get("Expires"), ShouldEqual, "-1")
  79. })
  80. middlewareScenario(t, "middleware should not add Cache-Control header for requests to datasource proxy API", func(sc *scenarioContext) {
  81. sc.fakeReq("GET", "/api/datasources/proxy/1/test").exec()
  82. So(sc.resp.Header().Get("Cache-Control"), ShouldBeEmpty)
  83. So(sc.resp.Header().Get("Pragma"), ShouldBeEmpty)
  84. So(sc.resp.Header().Get("Expires"), ShouldBeEmpty)
  85. })
  86. middlewareScenario(t, "middleware should add Cache-Control header for requests with html response", func(sc *scenarioContext) {
  87. sc.handler(func(c *models.ReqContext) {
  88. data := &dtos.IndexViewData{
  89. User: &dtos.CurrentUser{},
  90. Settings: map[string]interface{}{},
  91. NavTree: []*dtos.NavLink{},
  92. }
  93. c.HTML(200, "index-template", data)
  94. })
  95. sc.fakeReq("GET", "/").exec()
  96. So(sc.resp.Code, ShouldEqual, 200)
  97. So(sc.resp.Header().Get("Cache-Control"), ShouldEqual, "no-cache")
  98. So(sc.resp.Header().Get("Pragma"), ShouldEqual, "no-cache")
  99. So(sc.resp.Header().Get("Expires"), ShouldEqual, "-1")
  100. })
  101. middlewareScenario(t, "middleware should add X-Frame-Options header with deny for request when not allowing embedding", func(sc *scenarioContext) {
  102. sc.fakeReq("GET", "/api/search").exec()
  103. So(sc.resp.Header().Get("X-Frame-Options"), ShouldEqual, "deny")
  104. })
  105. middlewareScenario(t, "middleware should not add X-Frame-Options header for request when allowing embedding", func(sc *scenarioContext) {
  106. setting.AllowEmbedding = true
  107. sc.fakeReq("GET", "/api/search").exec()
  108. So(sc.resp.Header().Get("X-Frame-Options"), ShouldBeEmpty)
  109. })
  110. middlewareScenario(t, "Invalid api key", func(sc *scenarioContext) {
  111. sc.apiKey = "invalid_key_test"
  112. sc.fakeReq("GET", "/").exec()
  113. Convey("Should not init session", func() {
  114. So(sc.resp.Header().Get("Set-Cookie"), ShouldBeEmpty)
  115. })
  116. Convey("Should return 401", func() {
  117. So(sc.resp.Code, ShouldEqual, 401)
  118. So(sc.respJson["message"], ShouldEqual, "Invalid API key")
  119. })
  120. })
  121. middlewareScenario(t, "Using basic auth", func(sc *scenarioContext) {
  122. bus.AddHandler("test", func(query *models.GetUserByLoginQuery) error {
  123. query.Result = &models.User{
  124. Password: util.EncodePassword("myPass", "salt"),
  125. Salt: "salt",
  126. }
  127. return nil
  128. })
  129. bus.AddHandler("test", func(loginUserQuery *models.LoginUserQuery) error {
  130. return nil
  131. })
  132. bus.AddHandler("test", func(query *models.GetSignedInUserQuery) error {
  133. query.Result = &models.SignedInUser{OrgId: 2, UserId: 12}
  134. return nil
  135. })
  136. setting.BasicAuthEnabled = true
  137. authHeader := util.GetBasicAuthHeader("myUser", "myPass")
  138. sc.fakeReq("GET", "/").withAuthorizationHeader(authHeader).exec()
  139. Convey("Should init middleware context with user", func() {
  140. So(sc.context.IsSignedIn, ShouldEqual, true)
  141. So(sc.context.OrgId, ShouldEqual, 2)
  142. So(sc.context.UserId, ShouldEqual, 12)
  143. })
  144. })
  145. middlewareScenario(t, "Valid api key", func(sc *scenarioContext) {
  146. keyhash := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd")
  147. bus.AddHandler("test", func(query *models.GetApiKeyByNameQuery) error {
  148. query.Result = &models.ApiKey{OrgId: 12, Role: models.ROLE_EDITOR, Key: keyhash}
  149. return nil
  150. })
  151. sc.fakeReq("GET", "/").withValidApiKey().exec()
  152. Convey("Should return 200", func() {
  153. So(sc.resp.Code, ShouldEqual, 200)
  154. })
  155. Convey("Should init middleware context", func() {
  156. So(sc.context.IsSignedIn, ShouldEqual, true)
  157. So(sc.context.OrgId, ShouldEqual, 12)
  158. So(sc.context.OrgRole, ShouldEqual, models.ROLE_EDITOR)
  159. })
  160. })
  161. middlewareScenario(t, "Valid api key, but does not match db hash", func(sc *scenarioContext) {
  162. keyhash := "something_not_matching"
  163. bus.AddHandler("test", func(query *models.GetApiKeyByNameQuery) error {
  164. query.Result = &models.ApiKey{OrgId: 12, Role: models.ROLE_EDITOR, Key: keyhash}
  165. return nil
  166. })
  167. sc.fakeReq("GET", "/").withValidApiKey().exec()
  168. Convey("Should return api key invalid", func() {
  169. So(sc.resp.Code, ShouldEqual, 401)
  170. So(sc.respJson["message"], ShouldEqual, "Invalid API key")
  171. })
  172. })
  173. middlewareScenario(t, "Valid api key, but expired", func(sc *scenarioContext) {
  174. mockGetTime()
  175. defer resetGetTime()
  176. keyhash := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd")
  177. bus.AddHandler("test", func(query *models.GetApiKeyByNameQuery) error {
  178. // api key expired one second before
  179. expires := getTime().Add(-1 * time.Second).Unix()
  180. query.Result = &models.ApiKey{OrgId: 12, Role: models.ROLE_EDITOR, Key: keyhash,
  181. Expires: &expires}
  182. return nil
  183. })
  184. sc.fakeReq("GET", "/").withValidApiKey().exec()
  185. Convey("Should return 401", func() {
  186. So(sc.resp.Code, ShouldEqual, 401)
  187. So(sc.respJson["message"], ShouldEqual, "Expired API key")
  188. })
  189. })
  190. middlewareScenario(t, "Valid api key via Basic auth", func(sc *scenarioContext) {
  191. keyhash := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd")
  192. bus.AddHandler("test", func(query *models.GetApiKeyByNameQuery) error {
  193. query.Result = &models.ApiKey{OrgId: 12, Role: models.ROLE_EDITOR, Key: keyhash}
  194. return nil
  195. })
  196. authHeader := util.GetBasicAuthHeader("api_key", "eyJrIjoidjVuQXdwTWFmRlA2em5hUzR1cmhkV0RMUzU1MTFNNDIiLCJuIjoiYXNkIiwiaWQiOjF9")
  197. sc.fakeReq("GET", "/").withAuthorizationHeader(authHeader).exec()
  198. Convey("Should return 200", func() {
  199. So(sc.resp.Code, ShouldEqual, 200)
  200. })
  201. Convey("Should init middleware context", func() {
  202. So(sc.context.IsSignedIn, ShouldEqual, true)
  203. So(sc.context.OrgId, ShouldEqual, 12)
  204. So(sc.context.OrgRole, ShouldEqual, models.ROLE_EDITOR)
  205. })
  206. })
  207. middlewareScenario(t, "Non-expired auth token in cookie which not are being rotated", func(sc *scenarioContext) {
  208. sc.withTokenSessionCookie("token")
  209. bus.AddHandler("test", func(query *models.GetSignedInUserQuery) error {
  210. query.Result = &models.SignedInUser{OrgId: 2, UserId: 12}
  211. return nil
  212. })
  213. sc.userAuthTokenService.LookupTokenProvider = func(ctx context.Context, unhashedToken string) (*models.UserToken, error) {
  214. return &models.UserToken{
  215. UserId: 12,
  216. UnhashedToken: unhashedToken,
  217. }, nil
  218. }
  219. sc.fakeReq("GET", "/").exec()
  220. Convey("should init context with user info", func() {
  221. So(sc.context.IsSignedIn, ShouldBeTrue)
  222. So(sc.context.UserId, ShouldEqual, 12)
  223. So(sc.context.UserToken.UserId, ShouldEqual, 12)
  224. So(sc.context.UserToken.UnhashedToken, ShouldEqual, "token")
  225. })
  226. Convey("should not set cookie", func() {
  227. So(sc.resp.Header().Get("Set-Cookie"), ShouldEqual, "")
  228. })
  229. })
  230. middlewareScenario(t, "Non-expired auth token in cookie which are being rotated", func(sc *scenarioContext) {
  231. sc.withTokenSessionCookie("token")
  232. bus.AddHandler("test", func(query *models.GetSignedInUserQuery) error {
  233. query.Result = &models.SignedInUser{OrgId: 2, UserId: 12}
  234. return nil
  235. })
  236. sc.userAuthTokenService.LookupTokenProvider = func(ctx context.Context, unhashedToken string) (*models.UserToken, error) {
  237. return &models.UserToken{
  238. UserId: 12,
  239. UnhashedToken: "",
  240. }, nil
  241. }
  242. sc.userAuthTokenService.TryRotateTokenProvider = func(ctx context.Context, userToken *models.UserToken, clientIP, userAgent string) (bool, error) {
  243. userToken.UnhashedToken = "rotated"
  244. return true, nil
  245. }
  246. maxAgeHours := (time.Duration(setting.LoginMaxLifetimeDays) * 24 * time.Hour)
  247. maxAge := (maxAgeHours + time.Hour).Seconds()
  248. expectedCookie := &http.Cookie{
  249. Name: setting.LoginCookieName,
  250. Value: "rotated",
  251. Path: setting.AppSubUrl + "/",
  252. HttpOnly: true,
  253. MaxAge: int(maxAge),
  254. Secure: setting.CookieSecure,
  255. SameSite: setting.CookieSameSite,
  256. }
  257. sc.fakeReq("GET", "/").exec()
  258. Convey("should init context with user info", func() {
  259. So(sc.context.IsSignedIn, ShouldBeTrue)
  260. So(sc.context.UserId, ShouldEqual, 12)
  261. So(sc.context.UserToken.UserId, ShouldEqual, 12)
  262. So(sc.context.UserToken.UnhashedToken, ShouldEqual, "rotated")
  263. })
  264. Convey("should set cookie", func() {
  265. So(sc.resp.Header().Get("Set-Cookie"), ShouldEqual, expectedCookie.String())
  266. })
  267. })
  268. middlewareScenario(t, "Invalid/expired auth token in cookie", func(sc *scenarioContext) {
  269. sc.withTokenSessionCookie("token")
  270. sc.userAuthTokenService.LookupTokenProvider = func(ctx context.Context, unhashedToken string) (*models.UserToken, error) {
  271. return nil, models.ErrUserTokenNotFound
  272. }
  273. sc.fakeReq("GET", "/").exec()
  274. Convey("should not init context with user info", func() {
  275. So(sc.context.IsSignedIn, ShouldBeFalse)
  276. So(sc.context.UserId, ShouldEqual, 0)
  277. So(sc.context.UserToken, ShouldBeNil)
  278. })
  279. })
  280. middlewareScenario(t, "When anonymous access is enabled", func(sc *scenarioContext) {
  281. setting.AnonymousEnabled = true
  282. setting.AnonymousOrgName = "test"
  283. setting.AnonymousOrgRole = string(models.ROLE_EDITOR)
  284. bus.AddHandler("test", func(query *models.GetOrgByNameQuery) error {
  285. So(query.Name, ShouldEqual, "test")
  286. query.Result = &models.Org{Id: 2, Name: "test"}
  287. return nil
  288. })
  289. sc.fakeReq("GET", "/").exec()
  290. Convey("should init context with org info", func() {
  291. So(sc.context.UserId, ShouldEqual, 0)
  292. So(sc.context.OrgId, ShouldEqual, 2)
  293. So(sc.context.OrgRole, ShouldEqual, models.ROLE_EDITOR)
  294. })
  295. Convey("context signed in should be false", func() {
  296. So(sc.context.IsSignedIn, ShouldBeFalse)
  297. })
  298. })
  299. Convey("auth_proxy", func() {
  300. setting.AuthProxyEnabled = true
  301. setting.AuthProxyWhitelist = ""
  302. setting.AuthProxyAutoSignUp = true
  303. setting.LDAPEnabled = true
  304. setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
  305. setting.AuthProxyHeaderProperty = "username"
  306. name := "markelog"
  307. middlewareScenario(t, "should not sync the user if it's in the cache", func(sc *scenarioContext) {
  308. bus.AddHandler("test", func(query *models.GetSignedInUserQuery) error {
  309. query.Result = &models.SignedInUser{OrgId: 4, UserId: query.UserId}
  310. return nil
  311. })
  312. key := fmt.Sprintf(cachePrefix, name)
  313. sc.remoteCacheService.Set(key, int64(33), 0)
  314. sc.fakeReq("GET", "/")
  315. sc.req.Header.Add(setting.AuthProxyHeaderName, name)
  316. sc.exec()
  317. Convey("Should init user via cache", func() {
  318. So(sc.context.IsSignedIn, ShouldBeTrue)
  319. So(sc.context.UserId, ShouldEqual, 33)
  320. So(sc.context.OrgId, ShouldEqual, 4)
  321. })
  322. })
  323. middlewareScenario(t, "should respect auto signup option", func(sc *scenarioContext) {
  324. setting.LDAPEnabled = false
  325. setting.AuthProxyAutoSignUp = false
  326. var actualAuthProxyAutoSignUp *bool = nil
  327. bus.AddHandler("test", func(cmd *models.UpsertUserCommand) error {
  328. actualAuthProxyAutoSignUp = &cmd.SignupAllowed
  329. return login.ErrInvalidCredentials
  330. })
  331. sc.fakeReq("GET", "/")
  332. sc.req.Header.Add(setting.AuthProxyHeaderName, name)
  333. sc.exec()
  334. assert.False(t, *actualAuthProxyAutoSignUp)
  335. assert.Equal(t, sc.resp.Code, 500)
  336. assert.Nil(t, sc.context)
  337. })
  338. middlewareScenario(t, "should create an user from a header", func(sc *scenarioContext) {
  339. setting.LDAPEnabled = false
  340. setting.AuthProxyAutoSignUp = true
  341. bus.AddHandler("test", func(query *models.GetSignedInUserQuery) error {
  342. if query.UserId > 0 {
  343. query.Result = &models.SignedInUser{OrgId: 4, UserId: 33}
  344. return nil
  345. }
  346. return models.ErrUserNotFound
  347. })
  348. bus.AddHandler("test", func(cmd *models.UpsertUserCommand) error {
  349. cmd.Result = &models.User{Id: 33}
  350. return nil
  351. })
  352. sc.fakeReq("GET", "/")
  353. sc.req.Header.Add(setting.AuthProxyHeaderName, name)
  354. sc.exec()
  355. Convey("Should create user from header info", func() {
  356. So(sc.context.IsSignedIn, ShouldBeTrue)
  357. So(sc.context.UserId, ShouldEqual, 33)
  358. So(sc.context.OrgId, ShouldEqual, 4)
  359. })
  360. })
  361. middlewareScenario(t, "should get an existing user from header", func(sc *scenarioContext) {
  362. setting.LDAPEnabled = false
  363. bus.AddHandler("test", func(query *models.GetSignedInUserQuery) error {
  364. query.Result = &models.SignedInUser{OrgId: 2, UserId: 12}
  365. return nil
  366. })
  367. bus.AddHandler("test", func(cmd *models.UpsertUserCommand) error {
  368. cmd.Result = &models.User{Id: 12}
  369. return nil
  370. })
  371. sc.fakeReq("GET", "/")
  372. sc.req.Header.Add(setting.AuthProxyHeaderName, name)
  373. sc.exec()
  374. Convey("should init context with user info", func() {
  375. So(sc.context.IsSignedIn, ShouldBeTrue)
  376. So(sc.context.UserId, ShouldEqual, 12)
  377. So(sc.context.OrgId, ShouldEqual, 2)
  378. })
  379. })
  380. middlewareScenario(t, "should allow the request from whitelist IP", func(sc *scenarioContext) {
  381. setting.AuthProxyWhitelist = "192.168.1.0/24, 2001::0/120"
  382. setting.LDAPEnabled = false
  383. bus.AddHandler("test", func(query *models.GetSignedInUserQuery) error {
  384. query.Result = &models.SignedInUser{OrgId: 4, UserId: 33}
  385. return nil
  386. })
  387. bus.AddHandler("test", func(cmd *models.UpsertUserCommand) error {
  388. cmd.Result = &models.User{Id: 33}
  389. return nil
  390. })
  391. sc.fakeReq("GET", "/")
  392. sc.req.Header.Add(setting.AuthProxyHeaderName, name)
  393. sc.req.RemoteAddr = "[2001::23]:12345"
  394. sc.exec()
  395. Convey("Should init context with user info", func() {
  396. So(sc.context.IsSignedIn, ShouldBeTrue)
  397. So(sc.context.UserId, ShouldEqual, 33)
  398. So(sc.context.OrgId, ShouldEqual, 4)
  399. })
  400. })
  401. middlewareScenario(t, "should not allow the request from whitelist IP", func(sc *scenarioContext) {
  402. setting.AuthProxyWhitelist = "8.8.8.8"
  403. setting.LDAPEnabled = false
  404. bus.AddHandler("test", func(query *models.GetSignedInUserQuery) error {
  405. query.Result = &models.SignedInUser{OrgId: 4, UserId: 33}
  406. return nil
  407. })
  408. bus.AddHandler("test", func(cmd *models.UpsertUserCommand) error {
  409. cmd.Result = &models.User{Id: 33}
  410. return nil
  411. })
  412. sc.fakeReq("GET", "/")
  413. sc.req.Header.Add(setting.AuthProxyHeaderName, name)
  414. sc.req.RemoteAddr = "[2001::23]:12345"
  415. sc.exec()
  416. Convey("should return 407 status code", func() {
  417. So(sc.resp.Code, ShouldEqual, 407)
  418. So(sc.context, ShouldBeNil)
  419. })
  420. })
  421. })
  422. })
  423. }
  424. func middlewareScenario(t *testing.T, desc string, fn scenarioFunc) {
  425. Convey(desc, func() {
  426. defer bus.ClearBusHandlers()
  427. setting.LoginCookieName = "grafana_session"
  428. setting.LoginMaxLifetimeDays = 30
  429. sc := &scenarioContext{}
  430. viewsPath, _ := filepath.Abs("../../public/views")
  431. sc.m = macaron.New()
  432. sc.m.Use(AddDefaultResponseHeaders())
  433. sc.m.Use(macaron.Renderer(macaron.RenderOptions{
  434. Directory: viewsPath,
  435. Delims: macaron.Delims{Left: "[[", Right: "]]"},
  436. }))
  437. sc.userAuthTokenService = auth.NewFakeUserAuthTokenService()
  438. sc.remoteCacheService = remotecache.NewFakeStore(t)
  439. sc.m.Use(GetContextHandler(sc.userAuthTokenService, sc.remoteCacheService))
  440. sc.m.Use(OrgRedirect())
  441. sc.defaultHandler = func(c *models.ReqContext) {
  442. sc.context = c
  443. if sc.handlerFunc != nil {
  444. sc.handlerFunc(sc.context)
  445. }
  446. }
  447. sc.m.Get("/", sc.defaultHandler)
  448. fn(sc)
  449. })
  450. }
  451. type scenarioContext struct {
  452. m *macaron.Macaron
  453. context *models.ReqContext
  454. resp *httptest.ResponseRecorder
  455. apiKey string
  456. authHeader string
  457. tokenSessionCookie string
  458. respJson map[string]interface{}
  459. handlerFunc handlerFunc
  460. defaultHandler macaron.Handler
  461. url string
  462. userAuthTokenService *auth.FakeUserAuthTokenService
  463. remoteCacheService *remotecache.RemoteCache
  464. req *http.Request
  465. }
  466. func (sc *scenarioContext) withValidApiKey() *scenarioContext {
  467. sc.apiKey = "eyJrIjoidjVuQXdwTWFmRlA2em5hUzR1cmhkV0RMUzU1MTFNNDIiLCJuIjoiYXNkIiwiaWQiOjF9"
  468. return sc
  469. }
  470. func (sc *scenarioContext) withTokenSessionCookie(unhashedToken string) *scenarioContext {
  471. sc.tokenSessionCookie = unhashedToken
  472. return sc
  473. }
  474. func (sc *scenarioContext) withAuthorizationHeader(authHeader string) *scenarioContext {
  475. sc.authHeader = authHeader
  476. return sc
  477. }
  478. func (sc *scenarioContext) fakeReq(method, url string) *scenarioContext {
  479. sc.resp = httptest.NewRecorder()
  480. req, err := http.NewRequest(method, url, nil)
  481. So(err, ShouldBeNil)
  482. sc.req = req
  483. return sc
  484. }
  485. func (sc *scenarioContext) fakeReqWithParams(method, url string, queryParams map[string]string) *scenarioContext {
  486. sc.resp = httptest.NewRecorder()
  487. req, err := http.NewRequest(method, url, nil)
  488. q := req.URL.Query()
  489. for k, v := range queryParams {
  490. q.Add(k, v)
  491. }
  492. req.URL.RawQuery = q.Encode()
  493. So(err, ShouldBeNil)
  494. sc.req = req
  495. return sc
  496. }
  497. func (sc *scenarioContext) handler(fn handlerFunc) *scenarioContext {
  498. sc.handlerFunc = fn
  499. return sc
  500. }
  501. func (sc *scenarioContext) exec() {
  502. if sc.apiKey != "" {
  503. sc.req.Header.Add("Authorization", "Bearer "+sc.apiKey)
  504. }
  505. if sc.authHeader != "" {
  506. sc.req.Header.Add("Authorization", sc.authHeader)
  507. }
  508. if sc.tokenSessionCookie != "" {
  509. sc.req.AddCookie(&http.Cookie{
  510. Name: setting.LoginCookieName,
  511. Value: sc.tokenSessionCookie,
  512. })
  513. }
  514. sc.m.ServeHTTP(sc.resp, sc.req)
  515. if sc.resp.Header().Get("Content-Type") == "application/json; charset=UTF-8" {
  516. err := json.NewDecoder(sc.resp.Body).Decode(&sc.respJson)
  517. So(err, ShouldBeNil)
  518. }
  519. }
  520. type scenarioFunc func(c *scenarioContext)
  521. type handlerFunc func(c *models.ReqContext)