middleware_test.go 22 KB

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