auth_token_test.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. package auth
  2. import (
  3. "testing"
  4. "time"
  5. "github.com/grafana/grafana/pkg/setting"
  6. "github.com/grafana/grafana/pkg/log"
  7. "github.com/grafana/grafana/pkg/services/sqlstore"
  8. . "github.com/smartystreets/goconvey/convey"
  9. )
  10. func TestUserAuthToken(t *testing.T) {
  11. Convey("Test user auth token", t, func() {
  12. ctx := createTestContext(t)
  13. userAuthTokenService := ctx.tokenService
  14. userID := int64(10)
  15. t := time.Date(2018, 12, 13, 13, 45, 0, 0, time.UTC)
  16. getTime = func() time.Time {
  17. return t
  18. }
  19. Convey("When creating token", func() {
  20. token, err := userAuthTokenService.CreateToken(userID, "192.168.10.11:1234", "some user agent")
  21. So(err, ShouldBeNil)
  22. So(token, ShouldNotBeNil)
  23. So(token.AuthTokenSeen, ShouldBeFalse)
  24. Convey("When lookup unhashed token should return user auth token", func() {
  25. LookupToken, err := userAuthTokenService.LookupToken(token.UnhashedToken)
  26. So(err, ShouldBeNil)
  27. So(LookupToken, ShouldNotBeNil)
  28. So(LookupToken.UserId, ShouldEqual, userID)
  29. So(LookupToken.AuthTokenSeen, ShouldBeTrue)
  30. storedAuthToken, err := ctx.getAuthTokenByID(LookupToken.Id)
  31. So(err, ShouldBeNil)
  32. So(storedAuthToken, ShouldNotBeNil)
  33. So(storedAuthToken.AuthTokenSeen, ShouldBeTrue)
  34. })
  35. Convey("When lookup hashed token should return user auth token not found error", func() {
  36. LookupToken, err := userAuthTokenService.LookupToken(token.AuthToken)
  37. So(err, ShouldEqual, ErrAuthTokenNotFound)
  38. So(LookupToken, ShouldBeNil)
  39. })
  40. })
  41. Convey("expires correctly", func() {
  42. token, err := userAuthTokenService.CreateToken(userID, "192.168.10.11:1234", "some user agent")
  43. So(err, ShouldBeNil)
  44. So(token, ShouldNotBeNil)
  45. _, err = userAuthTokenService.LookupToken(token.UnhashedToken)
  46. So(err, ShouldBeNil)
  47. token, err = ctx.getAuthTokenByID(token.Id)
  48. So(err, ShouldBeNil)
  49. getTime = func() time.Time {
  50. return t.Add(time.Hour)
  51. }
  52. refreshed, err := userAuthTokenService.RefreshToken(token, "192.168.10.11:1234", "some user agent")
  53. So(err, ShouldBeNil)
  54. So(refreshed, ShouldBeTrue)
  55. _, err = userAuthTokenService.LookupToken(token.UnhashedToken)
  56. So(err, ShouldBeNil)
  57. stillGood, err := userAuthTokenService.LookupToken(token.UnhashedToken)
  58. So(err, ShouldBeNil)
  59. So(stillGood, ShouldNotBeNil)
  60. getTime = func() time.Time {
  61. return t.Add(24 * 7 * time.Hour)
  62. }
  63. notGood, err := userAuthTokenService.LookupToken(token.UnhashedToken)
  64. So(err, ShouldEqual, ErrAuthTokenNotFound)
  65. So(notGood, ShouldBeNil)
  66. })
  67. Convey("can properly rotate tokens", func() {
  68. token, err := userAuthTokenService.CreateToken(userID, "192.168.10.11:1234", "some user agent")
  69. So(err, ShouldBeNil)
  70. So(token, ShouldNotBeNil)
  71. prevToken := token.AuthToken
  72. unhashedPrev := token.UnhashedToken
  73. refreshed, err := userAuthTokenService.RefreshToken(token, "192.168.10.12:1234", "a new user agent")
  74. So(err, ShouldBeNil)
  75. So(refreshed, ShouldBeFalse)
  76. updated, err := ctx.markAuthTokenAsSeen(token.Id)
  77. So(err, ShouldBeNil)
  78. So(updated, ShouldBeTrue)
  79. token, err = ctx.getAuthTokenByID(token.Id)
  80. So(err, ShouldBeNil)
  81. getTime = func() time.Time {
  82. return t.Add(time.Hour)
  83. }
  84. refreshed, err = userAuthTokenService.RefreshToken(token, "192.168.10.12:1234", "a new user agent")
  85. So(err, ShouldBeNil)
  86. So(refreshed, ShouldBeTrue)
  87. unhashedToken := token.UnhashedToken
  88. token, err = ctx.getAuthTokenByID(token.Id)
  89. So(err, ShouldBeNil)
  90. token.UnhashedToken = unhashedToken
  91. So(token.RotatedAt, ShouldEqual, getTime().Unix())
  92. So(token.ClientIp, ShouldEqual, "192.168.10.12")
  93. So(token.UserAgent, ShouldEqual, "a new user agent")
  94. So(token.AuthTokenSeen, ShouldBeFalse)
  95. So(token.SeenAt, ShouldEqual, 0)
  96. So(token.PrevAuthToken, ShouldEqual, prevToken)
  97. // ability to auth using an old token
  98. lookedUp, err := userAuthTokenService.LookupToken(token.UnhashedToken)
  99. So(err, ShouldBeNil)
  100. So(lookedUp, ShouldNotBeNil)
  101. So(lookedUp.AuthTokenSeen, ShouldBeTrue)
  102. So(lookedUp.SeenAt, ShouldEqual, getTime().Unix())
  103. lookedUp, err = userAuthTokenService.LookupToken(unhashedPrev)
  104. So(err, ShouldBeNil)
  105. So(lookedUp, ShouldNotBeNil)
  106. So(lookedUp.Id, ShouldEqual, token.Id)
  107. So(lookedUp.AuthTokenSeen, ShouldBeTrue)
  108. getTime = func() time.Time {
  109. return t.Add(time.Hour + (2 * time.Minute))
  110. }
  111. lookedUp, err = userAuthTokenService.LookupToken(unhashedPrev)
  112. So(err, ShouldBeNil)
  113. So(lookedUp, ShouldNotBeNil)
  114. So(lookedUp.AuthTokenSeen, ShouldBeTrue)
  115. lookedUp, err = ctx.getAuthTokenByID(lookedUp.Id)
  116. So(err, ShouldBeNil)
  117. So(lookedUp, ShouldNotBeNil)
  118. So(lookedUp.AuthTokenSeen, ShouldBeFalse)
  119. refreshed, err = userAuthTokenService.RefreshToken(token, "192.168.10.12:1234", "a new user agent")
  120. So(err, ShouldBeNil)
  121. So(refreshed, ShouldBeTrue)
  122. token, err = ctx.getAuthTokenByID(token.Id)
  123. So(err, ShouldBeNil)
  124. So(token, ShouldNotBeNil)
  125. So(token.SeenAt, ShouldEqual, 0)
  126. })
  127. Convey("keeps prev token valid for 1 minute after it is confirmed", func() {
  128. token, err := userAuthTokenService.CreateToken(userID, "192.168.10.11:1234", "some user agent")
  129. So(err, ShouldBeNil)
  130. So(token, ShouldNotBeNil)
  131. lookedUp, err := userAuthTokenService.LookupToken(token.UnhashedToken)
  132. So(err, ShouldBeNil)
  133. So(lookedUp, ShouldNotBeNil)
  134. getTime = func() time.Time {
  135. return t.Add(10 * time.Minute)
  136. }
  137. prevToken := token.UnhashedToken
  138. refreshed, err := userAuthTokenService.RefreshToken(token, "1.1.1.1", "firefox")
  139. So(err, ShouldBeNil)
  140. So(refreshed, ShouldBeTrue)
  141. getTime = func() time.Time {
  142. return t.Add(20 * time.Minute)
  143. }
  144. current, err := userAuthTokenService.LookupToken(token.UnhashedToken)
  145. So(err, ShouldBeNil)
  146. So(current, ShouldNotBeNil)
  147. prev, err := userAuthTokenService.LookupToken(prevToken)
  148. So(err, ShouldBeNil)
  149. So(prev, ShouldNotBeNil)
  150. })
  151. Convey("will not mark token unseen when prev and current are the same", func() {
  152. token, err := userAuthTokenService.CreateToken(userID, "192.168.10.11:1234", "some user agent")
  153. So(err, ShouldBeNil)
  154. So(token, ShouldNotBeNil)
  155. lookedUp, err := userAuthTokenService.LookupToken(token.UnhashedToken)
  156. So(err, ShouldBeNil)
  157. So(lookedUp, ShouldNotBeNil)
  158. lookedUp, err = userAuthTokenService.LookupToken(token.UnhashedToken)
  159. So(err, ShouldBeNil)
  160. So(lookedUp, ShouldNotBeNil)
  161. lookedUp, err = ctx.getAuthTokenByID(lookedUp.Id)
  162. So(err, ShouldBeNil)
  163. So(lookedUp, ShouldNotBeNil)
  164. So(lookedUp.AuthTokenSeen, ShouldBeTrue)
  165. })
  166. Convey("Rotate token", func() {
  167. token, err := userAuthTokenService.CreateToken(userID, "192.168.10.11:1234", "some user agent")
  168. So(err, ShouldBeNil)
  169. So(token, ShouldNotBeNil)
  170. prevToken := token.AuthToken
  171. Convey("Should rotate current token and previous token when auth token seen", func() {
  172. updated, err := ctx.markAuthTokenAsSeen(token.Id)
  173. So(err, ShouldBeNil)
  174. So(updated, ShouldBeTrue)
  175. getTime = func() time.Time {
  176. return t.Add(10 * time.Minute)
  177. }
  178. refreshed, err := userAuthTokenService.RefreshToken(token, "1.1.1.1", "firefox")
  179. So(err, ShouldBeNil)
  180. So(refreshed, ShouldBeTrue)
  181. storedToken, err := ctx.getAuthTokenByID(token.Id)
  182. So(err, ShouldBeNil)
  183. So(storedToken, ShouldNotBeNil)
  184. So(storedToken.AuthTokenSeen, ShouldBeFalse)
  185. So(storedToken.PrevAuthToken, ShouldEqual, prevToken)
  186. So(storedToken.AuthToken, ShouldNotEqual, prevToken)
  187. prevToken = storedToken.AuthToken
  188. updated, err = ctx.markAuthTokenAsSeen(token.Id)
  189. So(err, ShouldBeNil)
  190. So(updated, ShouldBeTrue)
  191. getTime = func() time.Time {
  192. return t.Add(20 * time.Minute)
  193. }
  194. refreshed, err = userAuthTokenService.RefreshToken(token, "1.1.1.1", "firefox")
  195. So(err, ShouldBeNil)
  196. So(refreshed, ShouldBeTrue)
  197. storedToken, err = ctx.getAuthTokenByID(token.Id)
  198. So(err, ShouldBeNil)
  199. So(storedToken, ShouldNotBeNil)
  200. So(storedToken.AuthTokenSeen, ShouldBeFalse)
  201. So(storedToken.PrevAuthToken, ShouldEqual, prevToken)
  202. So(storedToken.AuthToken, ShouldNotEqual, prevToken)
  203. })
  204. Convey("Should rotate current token, but keep previous token when auth token not seen", func() {
  205. token.RotatedAt = getTime().Add(-2 * time.Minute).Unix()
  206. getTime = func() time.Time {
  207. return t.Add(2 * time.Minute)
  208. }
  209. refreshed, err := userAuthTokenService.RefreshToken(token, "1.1.1.1", "firefox")
  210. So(err, ShouldBeNil)
  211. So(refreshed, ShouldBeTrue)
  212. storedToken, err := ctx.getAuthTokenByID(token.Id)
  213. So(err, ShouldBeNil)
  214. So(storedToken, ShouldNotBeNil)
  215. So(storedToken.AuthTokenSeen, ShouldBeFalse)
  216. So(storedToken.PrevAuthToken, ShouldEqual, prevToken)
  217. So(storedToken.AuthToken, ShouldNotEqual, prevToken)
  218. })
  219. })
  220. Reset(func() {
  221. getTime = time.Now
  222. })
  223. })
  224. }
  225. func createTestContext(t *testing.T) *testContext {
  226. t.Helper()
  227. sqlstore := sqlstore.InitTestDB(t)
  228. tokenService := &UserAuthTokenServiceImpl{
  229. SQLStore: sqlstore,
  230. log: log.New("test-logger"),
  231. }
  232. RotateTime = 10 * time.Minute
  233. UrgentRotateTime = time.Minute
  234. setting.LogInRememberDays = 7
  235. return &testContext{
  236. sqlstore: sqlstore,
  237. tokenService: tokenService,
  238. }
  239. }
  240. type testContext struct {
  241. sqlstore *sqlstore.SqlStore
  242. tokenService *UserAuthTokenServiceImpl
  243. }
  244. func (c *testContext) getAuthTokenByID(id int64) (*userAuthToken, error) {
  245. sess := c.sqlstore.NewSession()
  246. var t userAuthToken
  247. found, err := sess.ID(id).Get(&t)
  248. if err != nil || !found {
  249. return nil, err
  250. }
  251. return &t, nil
  252. }
  253. func (c *testContext) markAuthTokenAsSeen(id int64) (bool, error) {
  254. sess := c.sqlstore.NewSession()
  255. res, err := sess.Exec("UPDATE user_auth_token SET auth_token_seen = ? WHERE id = ?", c.sqlstore.Dialect.BooleanStr(true), id)
  256. if err != nil {
  257. return false, err
  258. }
  259. rowsAffected, err := res.RowsAffected()
  260. if err != nil {
  261. return false, err
  262. }
  263. return rowsAffected == 1, nil
  264. }