middleware_test.go 19 KB

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