user_token_test.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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("userAgent").MustString(), ShouldEqual, "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36")
  121. So(resultOne.Get("createdAt").MustString(), ShouldEqual, time.Unix(tokens[0].CreatedAt, 0).Format(time.RFC3339))
  122. So(resultOne.Get("seenAt").MustString(), ShouldEqual, time.Unix(tokens[0].SeenAt, 0).Format(time.RFC3339))
  123. resultTwo := result.GetIndex(1)
  124. So(resultTwo.Get("id").MustInt64(), ShouldEqual, tokens[1].Id)
  125. So(resultTwo.Get("isActive").MustBool(), ShouldBeFalse)
  126. So(resultTwo.Get("clientIp").MustString(), ShouldEqual, "127.0.0.2")
  127. So(resultTwo.Get("userAgent").MustString(), ShouldEqual, "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")
  128. So(resultTwo.Get("createdAt").MustString(), ShouldEqual, time.Unix(tokens[1].CreatedAt, 0).Format(time.RFC3339))
  129. So(resultTwo.Get("seenAt").MustString(), ShouldEqual, time.Unix(tokens[1].SeenAt, 0).Format(time.RFC3339))
  130. })
  131. })
  132. }
  133. func revokeUserAuthTokenScenario(desc string, url string, routePattern string, cmd m.RevokeAuthTokenCmd, userId int64, fn scenarioFunc) {
  134. Convey(desc+" "+url, func() {
  135. defer bus.ClearBusHandlers()
  136. fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
  137. hs := HTTPServer{
  138. Bus: bus.GetBus(),
  139. AuthTokenService: fakeAuthTokenService,
  140. }
  141. sc := setupScenarioContext(url)
  142. sc.userAuthTokenService = fakeAuthTokenService
  143. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  144. sc.context = c
  145. sc.context.UserId = userId
  146. sc.context.OrgId = TestOrgID
  147. sc.context.OrgRole = m.ROLE_ADMIN
  148. return hs.RevokeUserAuthToken(c, cmd)
  149. })
  150. sc.m.Post(routePattern, sc.defaultHandler)
  151. fn(sc)
  152. })
  153. }
  154. func getUserAuthTokensScenario(desc string, url string, routePattern string, userId int64, fn scenarioFunc) {
  155. Convey(desc+" "+url, func() {
  156. defer bus.ClearBusHandlers()
  157. fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
  158. hs := HTTPServer{
  159. Bus: bus.GetBus(),
  160. AuthTokenService: fakeAuthTokenService,
  161. }
  162. sc := setupScenarioContext(url)
  163. sc.userAuthTokenService = fakeAuthTokenService
  164. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  165. sc.context = c
  166. sc.context.UserId = userId
  167. sc.context.OrgId = TestOrgID
  168. sc.context.OrgRole = m.ROLE_ADMIN
  169. return hs.GetUserAuthTokens(c)
  170. })
  171. sc.m.Get(routePattern, sc.defaultHandler)
  172. fn(sc)
  173. })
  174. }
  175. func logoutUserFromAllDevicesInternalScenario(desc string, userId int64, fn scenarioFunc) {
  176. Convey(desc, func() {
  177. defer bus.ClearBusHandlers()
  178. hs := HTTPServer{
  179. Bus: bus.GetBus(),
  180. AuthTokenService: auth.NewFakeUserAuthTokenService(),
  181. }
  182. sc := setupScenarioContext("/")
  183. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  184. sc.context = c
  185. sc.context.UserId = TestUserID
  186. sc.context.OrgId = TestOrgID
  187. sc.context.OrgRole = m.ROLE_ADMIN
  188. return hs.logoutUserFromAllDevicesInternal(context.Background(), userId)
  189. })
  190. sc.m.Post("/", sc.defaultHandler)
  191. fn(sc)
  192. })
  193. }
  194. func revokeUserAuthTokenInternalScenario(desc string, cmd m.RevokeAuthTokenCmd, userId int64, token *m.UserToken, fn scenarioFunc) {
  195. Convey(desc, func() {
  196. defer bus.ClearBusHandlers()
  197. fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
  198. hs := HTTPServer{
  199. Bus: bus.GetBus(),
  200. AuthTokenService: fakeAuthTokenService,
  201. }
  202. sc := setupScenarioContext("/")
  203. sc.userAuthTokenService = fakeAuthTokenService
  204. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  205. sc.context = c
  206. sc.context.UserId = TestUserID
  207. sc.context.OrgId = TestOrgID
  208. sc.context.OrgRole = m.ROLE_ADMIN
  209. sc.context.UserToken = token
  210. return hs.revokeUserAuthTokenInternal(c, userId, cmd)
  211. })
  212. sc.m.Post("/", sc.defaultHandler)
  213. fn(sc)
  214. })
  215. }
  216. func getUserAuthTokensInternalScenario(desc string, token *m.UserToken, fn scenarioFunc) {
  217. Convey(desc, func() {
  218. defer bus.ClearBusHandlers()
  219. fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
  220. hs := HTTPServer{
  221. Bus: bus.GetBus(),
  222. AuthTokenService: fakeAuthTokenService,
  223. }
  224. sc := setupScenarioContext("/")
  225. sc.userAuthTokenService = fakeAuthTokenService
  226. sc.defaultHandler = Wrap(func(c *m.ReqContext) Response {
  227. sc.context = c
  228. sc.context.UserId = TestUserID
  229. sc.context.OrgId = TestOrgID
  230. sc.context.OrgRole = m.ROLE_ADMIN
  231. sc.context.UserToken = token
  232. return hs.getUserAuthTokensInternal(c, TestUserID)
  233. })
  234. sc.m.Get("/", sc.defaultHandler)
  235. fn(sc)
  236. })
  237. }