user_token_test.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. package api
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. "github.com/grafana/grafana/pkg/bus"
  7. m "github.com/grafana/grafana/pkg/models"
  8. "github.com/grafana/grafana/pkg/services/auth"
  9. . "github.com/smartystreets/goconvey/convey"
  10. )
  11. func TestUserTokenApiEndpoint(t *testing.T) {
  12. Convey("When current user attempts to revoke an auth token for a non-existing user", t, func() {
  13. userId := int64(0)
  14. bus.AddHandler("test", func(cmd *m.GetUserByIdQuery) error {
  15. userId = cmd.Id
  16. return m.ErrUserNotFound
  17. })
  18. cmd := m.RevokeAuthTokenCmd{AuthTokenId: 2}
  19. revokeUserAuthTokenScenario("Should return not found when calling POST on", "/api/user/revoke-auth-token", "/api/user/revoke-auth-token", cmd, 200, func(sc *scenarioContext) {
  20. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  21. So(sc.resp.Code, ShouldEqual, 404)
  22. So(userId, ShouldEqual, 200)
  23. })
  24. })
  25. Convey("When current user gets auth tokens for a non-existing user", t, func() {
  26. userId := int64(0)
  27. bus.AddHandler("test", func(cmd *m.GetUserByIdQuery) error {
  28. userId = cmd.Id
  29. return m.ErrUserNotFound
  30. })
  31. getUserAuthTokensScenario("Should return not found when calling GET on", "/api/user/auth-tokens", "/api/user/auth-tokens", 200, func(sc *scenarioContext) {
  32. sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
  33. So(sc.resp.Code, ShouldEqual, 404)
  34. So(userId, ShouldEqual, 200)
  35. })
  36. })
  37. Convey("When logout an existing user from all devices", t, func() {
  38. bus.AddHandler("test", func(cmd *m.GetUserByIdQuery) error {
  39. cmd.Result = &m.User{Id: 200}
  40. return nil
  41. })
  42. logoutUserFromAllDevicesInternalScenario("Should be successful", 1, func(sc *scenarioContext) {
  43. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  44. So(sc.resp.Code, ShouldEqual, 200)
  45. })
  46. })
  47. Convey("When logout a non-existing user from all devices", t, func() {
  48. bus.AddHandler("test", func(cmd *m.GetUserByIdQuery) error {
  49. return m.ErrUserNotFound
  50. })
  51. logoutUserFromAllDevicesInternalScenario("Should return not found", TestUserID, func(sc *scenarioContext) {
  52. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  53. So(sc.resp.Code, ShouldEqual, 404)
  54. })
  55. })
  56. Convey("When revoke an auth token for a user", t, func() {
  57. bus.AddHandler("test", func(cmd *m.GetUserByIdQuery) error {
  58. cmd.Result = &m.User{Id: 200}
  59. return nil
  60. })
  61. cmd := m.RevokeAuthTokenCmd{AuthTokenId: 2}
  62. token := &m.UserToken{Id: 1}
  63. revokeUserAuthTokenInternalScenario("Should be successful", cmd, 200, token, func(sc *scenarioContext) {
  64. sc.userAuthTokenService.GetUserTokenProvider = func(ctx context.Context, userId, userTokenId int64) (*m.UserToken, error) {
  65. return &m.UserToken{Id: 2}, nil
  66. }
  67. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  68. So(sc.resp.Code, ShouldEqual, 200)
  69. })
  70. })
  71. Convey("When revoke the active auth token used by himself", t, func() {
  72. bus.AddHandler("test", func(cmd *m.GetUserByIdQuery) error {
  73. cmd.Result = &m.User{Id: TestUserID}
  74. return nil
  75. })
  76. cmd := m.RevokeAuthTokenCmd{AuthTokenId: 2}
  77. token := &m.UserToken{Id: 2}
  78. revokeUserAuthTokenInternalScenario("Should not be successful", cmd, TestUserID, token, func(sc *scenarioContext) {
  79. sc.userAuthTokenService.GetUserTokenProvider = func(ctx context.Context, userId, userTokenId int64) (*m.UserToken, error) {
  80. return token, nil
  81. }
  82. sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
  83. So(sc.resp.Code, ShouldEqual, 400)
  84. })
  85. })
  86. Convey("When gets auth tokens for a user", t, func() {
  87. bus.AddHandler("test", func(cmd *m.GetUserByIdQuery) error {
  88. cmd.Result = &m.User{Id: TestUserID}
  89. return nil
  90. })
  91. currentToken := &m.UserToken{Id: 1}
  92. getUserAuthTokensInternalScenario("Should be successful", currentToken, func(sc *scenarioContext) {
  93. tokens := []*m.UserToken{
  94. {
  95. Id: 1,
  96. ClientIp: "127.0.0.1",
  97. UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36",
  98. CreatedAt: time.Now().Unix(),
  99. SeenAt: time.Now().Unix(),
  100. },
  101. {
  102. Id: 2,
  103. ClientIp: "127.0.0.2",
  104. UserAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1",
  105. CreatedAt: time.Now().Unix(),
  106. SeenAt: time.Now().Unix(),
  107. },
  108. }
  109. sc.userAuthTokenService.GetUserTokensProvider = func(ctx context.Context, userId int64) ([]*m.UserToken, error) {
  110. return tokens, nil
  111. }
  112. sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
  113. So(sc.resp.Code, ShouldEqual, 200)
  114. result := sc.ToJSON()
  115. So(result.MustArray(), ShouldHaveLength, 2)
  116. resultOne := result.GetIndex(0)
  117. So(resultOne.Get("id").MustInt64(), ShouldEqual, tokens[0].Id)
  118. So(resultOne.Get("isActive").MustBool(), ShouldBeTrue)
  119. So(resultOne.Get("clientIp").MustString(), ShouldEqual, "127.0.0.1")
  120. So(resultOne.Get("createdAt").MustString(), ShouldEqual, time.Unix(tokens[0].CreatedAt, 0).Format(time.RFC3339))
  121. So(resultOne.Get("seenAt").MustString(), ShouldEqual, time.Unix(tokens[0].SeenAt, 0).Format(time.RFC3339))
  122. So(resultOne.Get("device").MustString(), ShouldEqual, "Other")
  123. So(resultOne.Get("browser").MustString(), ShouldEqual, "Chrome")
  124. So(resultOne.Get("browserVersion").MustString(), ShouldEqual, "72.0")
  125. So(resultOne.Get("os").MustString(), ShouldEqual, "Linux")
  126. So(resultOne.Get("osVersion").MustString(), ShouldEqual, "")
  127. resultTwo := result.GetIndex(1)
  128. So(resultTwo.Get("id").MustInt64(), ShouldEqual, tokens[1].Id)
  129. So(resultTwo.Get("isActive").MustBool(), ShouldBeFalse)
  130. So(resultTwo.Get("clientIp").MustString(), ShouldEqual, "127.0.0.2")
  131. So(resultTwo.Get("createdAt").MustString(), ShouldEqual, time.Unix(tokens[1].CreatedAt, 0).Format(time.RFC3339))
  132. So(resultTwo.Get("seenAt").MustString(), ShouldEqual, time.Unix(tokens[1].SeenAt, 0).Format(time.RFC3339))
  133. So(resultTwo.Get("device").MustString(), ShouldEqual, "iPhone")
  134. So(resultTwo.Get("browser").MustString(), ShouldEqual, "Mobile Safari")
  135. So(resultTwo.Get("browserVersion").MustString(), ShouldEqual, "11.0")
  136. So(resultTwo.Get("os").MustString(), ShouldEqual, "iOS")
  137. So(resultTwo.Get("osVersion").MustString(), ShouldEqual, "11.0")
  138. })
  139. })
  140. }
  141. func revokeUserAuthTokenScenario(desc string, url string, routePattern string, cmd m.RevokeAuthTokenCmd, userId int64, fn scenarioFunc) {
  142. Convey(desc+" "+url, func() {
  143. defer bus.ClearBusHandlers()
  144. fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
  145. hs := HTTPServer{
  146. Bus: bus.GetBus(),
  147. AuthTokenService: fakeAuthTokenService,
  148. }
  149. sc := setupScenarioContext(url)
  150. sc.userAuthTokenService = fakeAuthTokenService
  151. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  152. sc.context = c
  153. sc.context.UserId = userId
  154. sc.context.OrgId = TestOrgID
  155. sc.context.OrgRole = m.ROLE_ADMIN
  156. return hs.RevokeUserAuthToken(c, cmd)
  157. })
  158. sc.m.Post(routePattern, sc.defaultHandler)
  159. fn(sc)
  160. })
  161. }
  162. func getUserAuthTokensScenario(desc string, url string, routePattern string, userId int64, fn scenarioFunc) {
  163. Convey(desc+" "+url, func() {
  164. defer bus.ClearBusHandlers()
  165. fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
  166. hs := HTTPServer{
  167. Bus: bus.GetBus(),
  168. AuthTokenService: fakeAuthTokenService,
  169. }
  170. sc := setupScenarioContext(url)
  171. sc.userAuthTokenService = fakeAuthTokenService
  172. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  173. sc.context = c
  174. sc.context.UserId = userId
  175. sc.context.OrgId = TestOrgID
  176. sc.context.OrgRole = m.ROLE_ADMIN
  177. return hs.GetUserAuthTokens(c)
  178. })
  179. sc.m.Get(routePattern, sc.defaultHandler)
  180. fn(sc)
  181. })
  182. }
  183. func logoutUserFromAllDevicesInternalScenario(desc string, userId int64, fn scenarioFunc) {
  184. Convey(desc, func() {
  185. defer bus.ClearBusHandlers()
  186. hs := HTTPServer{
  187. Bus: bus.GetBus(),
  188. AuthTokenService: auth.NewFakeUserAuthTokenService(),
  189. }
  190. sc := setupScenarioContext("/")
  191. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  192. sc.context = c
  193. sc.context.UserId = TestUserID
  194. sc.context.OrgId = TestOrgID
  195. sc.context.OrgRole = m.ROLE_ADMIN
  196. return hs.logoutUserFromAllDevicesInternal(context.Background(), userId)
  197. })
  198. sc.m.Post("/", sc.defaultHandler)
  199. fn(sc)
  200. })
  201. }
  202. func revokeUserAuthTokenInternalScenario(desc string, cmd m.RevokeAuthTokenCmd, userId int64, token *m.UserToken, fn scenarioFunc) {
  203. Convey(desc, func() {
  204. defer bus.ClearBusHandlers()
  205. fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
  206. hs := HTTPServer{
  207. Bus: bus.GetBus(),
  208. AuthTokenService: fakeAuthTokenService,
  209. }
  210. sc := setupScenarioContext("/")
  211. sc.userAuthTokenService = fakeAuthTokenService
  212. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  213. sc.context = c
  214. sc.context.UserId = TestUserID
  215. sc.context.OrgId = TestOrgID
  216. sc.context.OrgRole = m.ROLE_ADMIN
  217. sc.context.UserToken = token
  218. return hs.revokeUserAuthTokenInternal(c, userId, cmd)
  219. })
  220. sc.m.Post("/", sc.defaultHandler)
  221. fn(sc)
  222. })
  223. }
  224. func getUserAuthTokensInternalScenario(desc string, token *m.UserToken, fn scenarioFunc) {
  225. Convey(desc, func() {
  226. defer bus.ClearBusHandlers()
  227. fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
  228. hs := HTTPServer{
  229. Bus: bus.GetBus(),
  230. AuthTokenService: fakeAuthTokenService,
  231. }
  232. sc := setupScenarioContext("/")
  233. sc.userAuthTokenService = fakeAuthTokenService
  234. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  235. sc.context = c
  236. sc.context.UserId = TestUserID
  237. sc.context.OrgId = TestOrgID
  238. sc.context.OrgRole = m.ROLE_ADMIN
  239. sc.context.UserToken = token
  240. return hs.getUserAuthTokensInternal(c, TestUserID)
  241. })
  242. sc.m.Get("/", sc.defaultHandler)
  243. fn(sc)
  244. })
  245. }