middleware_test.go 18 KB

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