Chore: Refactor GoConvey in auth package (#40850)

* refactor goconvey in auth package

* make linter happy
This commit is contained in:
Serge Zaitsev
2021-10-27 16:08:21 +02:00
committed by GitHub
parent 37cbed4b48
commit 995afa2221
2 changed files with 500 additions and 491 deletions

View File

@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"net"
"reflect"
"testing"
"time"
@@ -13,442 +14,454 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/require"
)
func TestUserAuthToken(t *testing.T) {
Convey("Test user auth token", t, func() {
ctx := createTestContext(t)
userAuthTokenService := ctx.tokenService
user := &models.User{Id: int64(10)}
userID := user.Id
// userID := user.Id
t := time.Date(2018, 12, 13, 13, 45, 0, 0, time.UTC)
getTime = func() time.Time {
return t
now := time.Date(2018, 12, 13, 13, 45, 0, 0, time.UTC)
getTime = func() time.Time { return now }
defer func() { getTime = time.Now }()
t.Run("When creating token", func(t *testing.T) {
createToken := func() *models.UserToken {
userToken, err := ctx.tokenService.CreateToken(context.Background(), user,
net.ParseIP("192.168.10.11"), "some user agent")
require.Nil(t, err)
require.NotNil(t, userToken)
require.False(t, userToken.AuthTokenSeen)
return userToken
}
Convey("When creating token", func() {
userToken, err := userAuthTokenService.CreateToken(context.Background(), user,
net.ParseIP("192.168.10.11"), "some user agent")
So(err, ShouldBeNil)
So(userToken, ShouldNotBeNil)
So(userToken.AuthTokenSeen, ShouldBeFalse)
userToken := createToken()
Convey("Can count active tokens", func() {
count, err := userAuthTokenService.ActiveTokenCount(context.Background())
So(err, ShouldBeNil)
So(count, ShouldEqual, 1)
t.Run("Can count active tokens", func(t *testing.T) {
count, err := ctx.tokenService.ActiveTokenCount(context.Background())
require.Nil(t, err)
require.Equal(t, int64(1), count)
})
Convey("When lookup unhashed token should return user auth token", func() {
userToken, err := userAuthTokenService.LookupToken(context.Background(), userToken.UnhashedToken)
So(err, ShouldBeNil)
So(userToken, ShouldNotBeNil)
So(userToken.UserId, ShouldEqual, userID)
So(userToken.AuthTokenSeen, ShouldBeTrue)
t.Run("When lookup unhashed token should return user auth token", func(t *testing.T) {
userToken, err := ctx.tokenService.LookupToken(context.Background(), userToken.UnhashedToken)
require.Nil(t, err)
require.NotNil(t, userToken)
require.Equal(t, user.Id, userToken.UserId)
require.True(t, userToken.AuthTokenSeen)
storedAuthToken, err := ctx.getAuthTokenByID(userToken.Id)
So(err, ShouldBeNil)
So(storedAuthToken, ShouldNotBeNil)
So(storedAuthToken.AuthTokenSeen, ShouldBeTrue)
require.Nil(t, err)
require.NotNil(t, storedAuthToken)
require.True(t, storedAuthToken.AuthTokenSeen)
})
Convey("When lookup hashed token should return user auth token not found error", func() {
userToken, err := userAuthTokenService.LookupToken(context.Background(), userToken.AuthToken)
So(err, ShouldEqual, models.ErrUserTokenNotFound)
So(userToken, ShouldBeNil)
t.Run("When lookup hashed token should return user auth token not found error", func(t *testing.T) {
userToken, err := ctx.tokenService.LookupToken(context.Background(), userToken.AuthToken)
require.Equal(t, models.ErrUserTokenNotFound, err)
require.Nil(t, userToken)
})
Convey("soft revoking existing token should not delete it", func() {
err = userAuthTokenService.RevokeToken(context.Background(), userToken, true)
So(err, ShouldBeNil)
t.Run("soft revoking existing token should not delete it", func(t *testing.T) {
err := ctx.tokenService.RevokeToken(context.Background(), userToken, true)
require.Nil(t, err)
model, err := ctx.getAuthTokenByID(userToken.Id)
So(err, ShouldBeNil)
So(model, ShouldNotBeNil)
So(model.RevokedAt, ShouldBeGreaterThan, 0)
require.Nil(t, err)
require.NotNil(t, model)
require.Greater(t, model.RevokedAt, int64(0))
})
Convey("revoking existing token should delete it", func() {
err = userAuthTokenService.RevokeToken(context.Background(), userToken, false)
So(err, ShouldBeNil)
t.Run("revoking existing token should delete it", func(t *testing.T) {
err := ctx.tokenService.RevokeToken(context.Background(), userToken, false)
require.Nil(t, err)
model, err := ctx.getAuthTokenByID(userToken.Id)
So(err, ShouldBeNil)
So(model, ShouldBeNil)
require.Nil(t, err)
require.Nil(t, model)
})
Convey("revoking nil token should return error", func() {
err = userAuthTokenService.RevokeToken(context.Background(), nil, false)
So(err, ShouldEqual, models.ErrUserTokenNotFound)
t.Run("revoking nil token should return error", func(t *testing.T) {
err := ctx.tokenService.RevokeToken(context.Background(), nil, false)
require.Equal(t, models.ErrUserTokenNotFound, err)
})
Convey("revoking non-existing token should return error", func() {
t.Run("revoking non-existing token should return error", func(t *testing.T) {
userToken.Id = 1000
err = userAuthTokenService.RevokeToken(context.Background(), userToken, false)
So(err, ShouldEqual, models.ErrUserTokenNotFound)
err := ctx.tokenService.RevokeToken(context.Background(), userToken, false)
require.Equal(t, models.ErrUserTokenNotFound, err)
})
Convey("When creating an additional token", func() {
userToken2, err := userAuthTokenService.CreateToken(context.Background(), user,
ctx = createTestContext(t)
userToken = createToken()
t.Run("When creating an additional token", func(t *testing.T) {
userToken2, err := ctx.tokenService.CreateToken(context.Background(), user,
net.ParseIP("192.168.10.11"), "some user agent")
So(err, ShouldBeNil)
So(userToken2, ShouldNotBeNil)
require.Nil(t, err)
require.NotNil(t, userToken2)
Convey("Can get first user token", func() {
token, err := userAuthTokenService.GetUserToken(context.Background(), userID, userToken.Id)
So(err, ShouldBeNil)
So(token, ShouldNotBeNil)
So(token.Id, ShouldEqual, userToken.Id)
t.Run("Can get first user token", func(t *testing.T) {
token, err := ctx.tokenService.GetUserToken(context.Background(), user.Id, userToken.Id)
require.Nil(t, err)
require.NotNil(t, token)
require.Equal(t, userToken.Id, token.Id)
})
Convey("Can get second user token", func() {
token, err := userAuthTokenService.GetUserToken(context.Background(), userID, userToken2.Id)
So(err, ShouldBeNil)
So(token, ShouldNotBeNil)
So(token.Id, ShouldEqual, userToken2.Id)
t.Run("Can get second user token", func(t *testing.T) {
token, err := ctx.tokenService.GetUserToken(context.Background(), user.Id, userToken2.Id)
require.Nil(t, err)
require.NotNil(t, token)
require.Equal(t, userToken2.Id, token.Id)
})
Convey("Can get user tokens", func() {
tokens, err := userAuthTokenService.GetUserTokens(context.Background(), userID)
So(err, ShouldBeNil)
So(tokens, ShouldHaveLength, 2)
So(tokens[0].Id, ShouldEqual, userToken.Id)
So(tokens[1].Id, ShouldEqual, userToken2.Id)
t.Run("Can get user tokens", func(t *testing.T) {
tokens, err := ctx.tokenService.GetUserTokens(context.Background(), user.Id)
require.Nil(t, err)
require.Equal(t, 2, len(tokens))
require.Equal(t, userToken.Id, tokens[0].Id)
require.Equal(t, userToken2.Id, tokens[1].Id)
})
Convey("Can revoke all user tokens", func() {
err := userAuthTokenService.RevokeAllUserTokens(context.Background(), userID)
So(err, ShouldBeNil)
t.Run("Can revoke all user tokens", func(t *testing.T) {
err := ctx.tokenService.RevokeAllUserTokens(context.Background(), user.Id)
require.Nil(t, err)
model, err := ctx.getAuthTokenByID(userToken.Id)
So(err, ShouldBeNil)
So(model, ShouldBeNil)
require.Nil(t, err)
require.Nil(t, model)
model2, err := ctx.getAuthTokenByID(userToken2.Id)
So(err, ShouldBeNil)
So(model2, ShouldBeNil)
require.Nil(t, err)
require.Nil(t, model2)
})
})
Convey("When revoking users tokens in a batch", func() {
Convey("Can revoke all users tokens", func() {
t.Run("When revoking users tokens in a batch", func(t *testing.T) {
t.Run("Can revoke all users tokens", func(t *testing.T) {
userIds := []int64{}
for i := 0; i < 3; i++ {
userId := userID + int64(i+1)
userId := user.Id + int64(i+1)
userIds = append(userIds, userId)
_, err := userAuthTokenService.CreateToken(context.Background(), user,
_, err := ctx.tokenService.CreateToken(context.Background(), user,
net.ParseIP("192.168.10.11"), "some user agent")
So(err, ShouldBeNil)
require.Nil(t, err)
}
err := userAuthTokenService.BatchRevokeAllUserTokens(context.Background(), userIds)
So(err, ShouldBeNil)
err := ctx.tokenService.BatchRevokeAllUserTokens(context.Background(), userIds)
require.Nil(t, err)
for _, v := range userIds {
tokens, err := userAuthTokenService.GetUserTokens(context.Background(), v)
So(err, ShouldBeNil)
So(len(tokens), ShouldEqual, 0)
tokens, err := ctx.tokenService.GetUserTokens(context.Background(), v)
require.Nil(t, err)
require.Equal(t, 0, len(tokens))
}
})
})
})
Convey("expires correctly", func() {
userToken, err := userAuthTokenService.CreateToken(context.Background(), user,
t.Run("expires correctly", func(t *testing.T) {
ctx := createTestContext(t)
userToken, err := ctx.tokenService.CreateToken(context.Background(), user,
net.ParseIP("192.168.10.11"), "some user agent")
So(err, ShouldBeNil)
require.Nil(t, err)
userToken, err = userAuthTokenService.LookupToken(context.Background(), userToken.UnhashedToken)
So(err, ShouldBeNil)
userToken, err = ctx.tokenService.LookupToken(context.Background(), userToken.UnhashedToken)
require.Nil(t, err)
getTime = func() time.Time {
return t.Add(time.Hour)
}
getTime = func() time.Time { return now.Add(time.Hour) }
rotated, err := userAuthTokenService.TryRotateToken(context.Background(), userToken,
rotated, err := ctx.tokenService.TryRotateToken(context.Background(), userToken,
net.ParseIP("192.168.10.11"), "some user agent")
So(err, ShouldBeNil)
So(rotated, ShouldBeTrue)
require.Nil(t, err)
require.True(t, rotated)
userToken, err = userAuthTokenService.LookupToken(context.Background(), userToken.UnhashedToken)
So(err, ShouldBeNil)
userToken, err = ctx.tokenService.LookupToken(context.Background(), userToken.UnhashedToken)
require.Nil(t, err)
stillGood, err := userAuthTokenService.LookupToken(context.Background(), userToken.UnhashedToken)
So(err, ShouldBeNil)
So(stillGood, ShouldNotBeNil)
stillGood, err := ctx.tokenService.LookupToken(context.Background(), userToken.UnhashedToken)
require.Nil(t, err)
require.NotNil(t, stillGood)
model, err := ctx.getAuthTokenByID(userToken.Id)
So(err, ShouldBeNil)
require.Nil(t, err)
Convey("when rotated_at is 6:59:59 ago should find token", func() {
t.Run("when rotated_at is 6:59:59 ago should find token", func(t *testing.T) {
getTime = func() time.Time {
return time.Unix(model.RotatedAt, 0).Add(24 * 7 * time.Hour).Add(-time.Second)
}
stillGood, err = userAuthTokenService.LookupToken(context.Background(), stillGood.UnhashedToken)
So(err, ShouldBeNil)
So(stillGood, ShouldNotBeNil)
stillGood, err = ctx.tokenService.LookupToken(context.Background(), stillGood.UnhashedToken)
require.Nil(t, err)
require.NotNil(t, stillGood)
})
Convey("when rotated_at is 7:00:00 ago should return token expired error", func() {
t.Run("when rotated_at is 7:00:00 ago should return token expired error", func(t *testing.T) {
getTime = func() time.Time {
return time.Unix(model.RotatedAt, 0).Add(24 * 7 * time.Hour)
}
notGood, err := userAuthTokenService.LookupToken(context.Background(), userToken.UnhashedToken)
So(err, ShouldHaveSameTypeAs, &models.TokenExpiredError{})
So(notGood, ShouldBeNil)
notGood, err := ctx.tokenService.LookupToken(context.Background(), userToken.UnhashedToken)
require.Equal(t, reflect.TypeOf(err), reflect.TypeOf(&models.TokenExpiredError{}))
require.Nil(t, notGood)
Convey("should not find active token when expired", func() {
count, err := userAuthTokenService.ActiveTokenCount(context.Background())
So(err, ShouldBeNil)
So(count, ShouldEqual, 0)
t.Run("should not find active token when expired", func(t *testing.T) {
count, err := ctx.tokenService.ActiveTokenCount(context.Background())
require.Nil(t, err)
require.Equal(t, int64(0), count)
})
})
Convey("when rotated_at is 5 days ago and created_at is 29 days and 23:59:59 ago should not find token", func() {
t.Run("when rotated_at is 5 days ago and created_at is 29 days and 23:59:59 ago should not find token", func(t *testing.T) {
updated, err := ctx.updateRotatedAt(model.Id, time.Unix(model.CreatedAt, 0).Add(24*25*time.Hour).Unix())
So(err, ShouldBeNil)
So(updated, ShouldBeTrue)
require.Nil(t, err)
require.True(t, updated)
getTime = func() time.Time {
return time.Unix(model.CreatedAt, 0).Add(24 * 30 * time.Hour).Add(-time.Second)
}
stillGood, err = userAuthTokenService.LookupToken(context.Background(), stillGood.UnhashedToken)
So(err, ShouldBeNil)
So(stillGood, ShouldNotBeNil)
stillGood, err = ctx.tokenService.LookupToken(context.Background(), stillGood.UnhashedToken)
require.Nil(t, err)
require.NotNil(t, stillGood)
})
Convey("when rotated_at is 5 days ago and created_at is 30 days ago should return token expired error", func() {
t.Run("when rotated_at is 5 days ago and created_at is 30 days ago should return token expired error", func(t *testing.T) {
updated, err := ctx.updateRotatedAt(model.Id, time.Unix(model.CreatedAt, 0).Add(24*25*time.Hour).Unix())
So(err, ShouldBeNil)
So(updated, ShouldBeTrue)
require.Nil(t, err)
require.True(t, updated)
getTime = func() time.Time {
return time.Unix(model.CreatedAt, 0).Add(24 * 30 * time.Hour)
}
notGood, err := userAuthTokenService.LookupToken(context.Background(), userToken.UnhashedToken)
So(err, ShouldHaveSameTypeAs, &models.TokenExpiredError{})
So(notGood, ShouldBeNil)
notGood, err := ctx.tokenService.LookupToken(context.Background(), userToken.UnhashedToken)
require.Equal(t, reflect.TypeOf(err), reflect.TypeOf(&models.TokenExpiredError{}))
require.Nil(t, notGood)
})
})
Convey("can properly rotate tokens", func() {
userToken, err := userAuthTokenService.CreateToken(context.Background(), user,
t.Run("can properly rotate tokens", func(t *testing.T) {
getTime = func() time.Time { return now }
ctx := createTestContext(t)
userToken, err := ctx.tokenService.CreateToken(context.Background(), user,
net.ParseIP("192.168.10.11"), "some user agent")
So(err, ShouldBeNil)
require.Nil(t, err)
prevToken := userToken.AuthToken
unhashedPrev := userToken.UnhashedToken
rotated, err := userAuthTokenService.TryRotateToken(context.Background(), userToken,
rotated, err := ctx.tokenService.TryRotateToken(context.Background(), userToken,
net.ParseIP("192.168.10.12"), "a new user agent")
So(err, ShouldBeNil)
So(rotated, ShouldBeFalse)
require.Nil(t, err)
require.False(t, rotated)
updated, err := ctx.markAuthTokenAsSeen(userToken.Id)
So(err, ShouldBeNil)
So(updated, ShouldBeTrue)
require.Nil(t, err)
require.True(t, updated)
model, err := ctx.getAuthTokenByID(userToken.Id)
So(err, ShouldBeNil)
require.Nil(t, err)
var tok models.UserToken
err = model.toUserToken(&tok)
So(err, ShouldBeNil)
require.Nil(t, err)
getTime = func() time.Time {
return t.Add(time.Hour)
}
getTime = func() time.Time { return now.Add(time.Hour) }
rotated, err = userAuthTokenService.TryRotateToken(context.Background(), &tok,
rotated, err = ctx.tokenService.TryRotateToken(context.Background(), &tok,
net.ParseIP("192.168.10.12"), "a new user agent")
So(err, ShouldBeNil)
So(rotated, ShouldBeTrue)
require.Nil(t, err)
require.True(t, rotated)
unhashedToken := tok.UnhashedToken
model, err = ctx.getAuthTokenByID(tok.Id)
So(err, ShouldBeNil)
require.Nil(t, err)
model.UnhashedToken = unhashedToken
So(model.RotatedAt, ShouldEqual, getTime().Unix())
So(model.ClientIp, ShouldEqual, "192.168.10.12")
So(model.UserAgent, ShouldEqual, "a new user agent")
So(model.AuthTokenSeen, ShouldBeFalse)
So(model.SeenAt, ShouldEqual, 0)
So(model.PrevAuthToken, ShouldEqual, prevToken)
require.Equal(t, getTime().Unix(), model.RotatedAt)
require.Equal(t, "192.168.10.12", model.ClientIp)
require.Equal(t, "a new user agent", model.UserAgent)
require.False(t, model.AuthTokenSeen)
require.Equal(t, int64(0), model.SeenAt)
require.Equal(t, prevToken, model.PrevAuthToken)
// ability to auth using an old token
lookedUpUserToken, err := userAuthTokenService.LookupToken(context.Background(), model.UnhashedToken)
So(err, ShouldBeNil)
So(lookedUpUserToken, ShouldNotBeNil)
So(lookedUpUserToken.AuthTokenSeen, ShouldBeTrue)
So(lookedUpUserToken.SeenAt, ShouldEqual, getTime().Unix())
lookedUpUserToken, err := ctx.tokenService.LookupToken(context.Background(), model.UnhashedToken)
require.Nil(t, err)
require.NotNil(t, lookedUpUserToken)
require.True(t, lookedUpUserToken.AuthTokenSeen)
require.Equal(t, getTime().Unix(), lookedUpUserToken.SeenAt)
lookedUpUserToken, err = userAuthTokenService.LookupToken(context.Background(), unhashedPrev)
So(err, ShouldBeNil)
So(lookedUpUserToken, ShouldNotBeNil)
So(lookedUpUserToken.Id, ShouldEqual, model.Id)
So(lookedUpUserToken.AuthTokenSeen, ShouldBeTrue)
lookedUpUserToken, err = ctx.tokenService.LookupToken(context.Background(), unhashedPrev)
require.Nil(t, err)
require.NotNil(t, lookedUpUserToken)
require.Equal(t, model.Id, lookedUpUserToken.Id)
require.True(t, lookedUpUserToken.AuthTokenSeen)
getTime = func() time.Time {
return t.Add(time.Hour + (2 * time.Minute))
return now.Add(time.Hour + (2 * time.Minute))
}
lookedUpUserToken, err = userAuthTokenService.LookupToken(context.Background(), unhashedPrev)
So(err, ShouldBeNil)
So(lookedUpUserToken, ShouldNotBeNil)
So(lookedUpUserToken.AuthTokenSeen, ShouldBeTrue)
lookedUpUserToken, err = ctx.tokenService.LookupToken(context.Background(), unhashedPrev)
require.Nil(t, err)
require.NotNil(t, lookedUpUserToken)
require.True(t, lookedUpUserToken.AuthTokenSeen)
lookedUpModel, err := ctx.getAuthTokenByID(lookedUpUserToken.Id)
So(err, ShouldBeNil)
So(lookedUpModel, ShouldNotBeNil)
So(lookedUpModel.AuthTokenSeen, ShouldBeFalse)
require.Nil(t, err)
require.NotNil(t, lookedUpModel)
require.False(t, lookedUpModel.AuthTokenSeen)
rotated, err = userAuthTokenService.TryRotateToken(context.Background(), userToken,
rotated, err = ctx.tokenService.TryRotateToken(context.Background(), userToken,
net.ParseIP("192.168.10.12"), "a new user agent")
So(err, ShouldBeNil)
So(rotated, ShouldBeTrue)
require.Nil(t, err)
require.True(t, rotated)
model, err = ctx.getAuthTokenByID(userToken.Id)
So(err, ShouldBeNil)
So(model, ShouldNotBeNil)
So(model.SeenAt, ShouldEqual, 0)
require.Nil(t, err)
require.NotNil(t, model)
require.Equal(t, int64(0), model.SeenAt)
})
Convey("keeps prev token valid for 1 minute after it is confirmed", func() {
userToken, err := userAuthTokenService.CreateToken(context.Background(), user,
t.Run("keeps prev token valid for 1 minute after it is confirmed", func(t *testing.T) {
getTime = func() time.Time { return now }
userToken, err := ctx.tokenService.CreateToken(context.Background(), user,
net.ParseIP("192.168.10.11"), "some user agent")
So(err, ShouldBeNil)
So(userToken, ShouldNotBeNil)
require.Nil(t, err)
require.NotNil(t, userToken)
lookedUpUserToken, err := userAuthTokenService.LookupToken(context.Background(), userToken.UnhashedToken)
So(err, ShouldBeNil)
So(lookedUpUserToken, ShouldNotBeNil)
lookedUpUserToken, err := ctx.tokenService.LookupToken(context.Background(), userToken.UnhashedToken)
require.Nil(t, err)
require.NotNil(t, lookedUpUserToken)
getTime = func() time.Time {
return t.Add(10 * time.Minute)
}
getTime = func() time.Time { return now.Add(10 * time.Minute) }
prevToken := userToken.UnhashedToken
rotated, err := userAuthTokenService.TryRotateToken(context.Background(), userToken,
rotated, err := ctx.tokenService.TryRotateToken(context.Background(), userToken,
net.ParseIP("1.1.1.1"), "firefox")
So(err, ShouldBeNil)
So(rotated, ShouldBeTrue)
require.Nil(t, err)
require.True(t, rotated)
getTime = func() time.Time {
return t.Add(20 * time.Minute)
return now.Add(20 * time.Minute)
}
currentUserToken, err := userAuthTokenService.LookupToken(context.Background(), userToken.UnhashedToken)
So(err, ShouldBeNil)
So(currentUserToken, ShouldNotBeNil)
currentUserToken, err := ctx.tokenService.LookupToken(context.Background(), userToken.UnhashedToken)
require.Nil(t, err)
require.NotNil(t, currentUserToken)
prevUserToken, err := userAuthTokenService.LookupToken(context.Background(), prevToken)
So(err, ShouldBeNil)
So(prevUserToken, ShouldNotBeNil)
prevUserToken, err := ctx.tokenService.LookupToken(context.Background(), prevToken)
require.Nil(t, err)
require.NotNil(t, prevUserToken)
})
Convey("will not mark token unseen when prev and current are the same", func() {
userToken, err := userAuthTokenService.CreateToken(context.Background(), user,
t.Run("will not mark token unseen when prev and current are the same", func(t *testing.T) {
userToken, err := ctx.tokenService.CreateToken(context.Background(), user,
net.ParseIP("192.168.10.11"), "some user agent")
So(err, ShouldBeNil)
So(userToken, ShouldNotBeNil)
require.Nil(t, err)
require.NotNil(t, userToken)
lookedUpUserToken, err := userAuthTokenService.LookupToken(context.Background(), userToken.UnhashedToken)
So(err, ShouldBeNil)
So(lookedUpUserToken, ShouldNotBeNil)
lookedUpUserToken, err := ctx.tokenService.LookupToken(context.Background(), userToken.UnhashedToken)
require.Nil(t, err)
require.NotNil(t, lookedUpUserToken)
lookedUpUserToken, err = userAuthTokenService.LookupToken(context.Background(), userToken.UnhashedToken)
So(err, ShouldBeNil)
So(lookedUpUserToken, ShouldNotBeNil)
lookedUpUserToken, err = ctx.tokenService.LookupToken(context.Background(), userToken.UnhashedToken)
require.Nil(t, err)
require.NotNil(t, lookedUpUserToken)
lookedUpModel, err := ctx.getAuthTokenByID(lookedUpUserToken.Id)
So(err, ShouldBeNil)
So(lookedUpModel, ShouldNotBeNil)
So(lookedUpModel.AuthTokenSeen, ShouldBeTrue)
require.Nil(t, err)
require.NotNil(t, lookedUpModel)
require.True(t, lookedUpModel.AuthTokenSeen)
})
Convey("Rotate token", func() {
userToken, err := userAuthTokenService.CreateToken(context.Background(), user,
t.Run("Rotate token", func(t *testing.T) {
t.Run("Should rotate current token and previous token when auth token seen", func(t *testing.T) {
getTime = func() time.Time { return now }
userToken, err := ctx.tokenService.CreateToken(context.Background(), user,
net.ParseIP("192.168.10.11"), "some user agent")
So(err, ShouldBeNil)
So(userToken, ShouldNotBeNil)
require.Nil(t, err)
require.NotNil(t, userToken)
prevToken := userToken.AuthToken
Convey("Should rotate current token and previous token when auth token seen", func() {
updated, err := ctx.markAuthTokenAsSeen(userToken.Id)
So(err, ShouldBeNil)
So(updated, ShouldBeTrue)
require.Nil(t, err)
require.True(t, updated)
getTime = func() time.Time {
return t.Add(10 * time.Minute)
return now.Add(10 * time.Minute)
}
rotated, err := userAuthTokenService.TryRotateToken(context.Background(), userToken,
rotated, err := ctx.tokenService.TryRotateToken(context.Background(), userToken,
net.ParseIP("1.1.1.1"), "firefox")
So(err, ShouldBeNil)
So(rotated, ShouldBeTrue)
require.Nil(t, err)
require.True(t, rotated)
storedToken, err := ctx.getAuthTokenByID(userToken.Id)
So(err, ShouldBeNil)
So(storedToken, ShouldNotBeNil)
So(storedToken.AuthTokenSeen, ShouldBeFalse)
So(storedToken.PrevAuthToken, ShouldEqual, prevToken)
So(storedToken.AuthToken, ShouldNotEqual, prevToken)
require.Nil(t, err)
require.NotNil(t, storedToken)
require.False(t, storedToken.AuthTokenSeen)
require.Equal(t, prevToken, storedToken.PrevAuthToken)
require.NotEqual(t, prevToken, storedToken.AuthToken)
prevToken = storedToken.AuthToken
updated, err = ctx.markAuthTokenAsSeen(userToken.Id)
So(err, ShouldBeNil)
So(updated, ShouldBeTrue)
require.Nil(t, err)
require.True(t, updated)
getTime = func() time.Time {
return t.Add(20 * time.Minute)
return now.Add(20 * time.Minute)
}
rotated, err = userAuthTokenService.TryRotateToken(context.Background(), userToken,
rotated, err = ctx.tokenService.TryRotateToken(context.Background(), userToken,
net.ParseIP("1.1.1.1"), "firefox")
So(err, ShouldBeNil)
So(rotated, ShouldBeTrue)
require.Nil(t, err)
require.True(t, rotated)
storedToken, err = ctx.getAuthTokenByID(userToken.Id)
So(err, ShouldBeNil)
So(storedToken, ShouldNotBeNil)
So(storedToken.AuthTokenSeen, ShouldBeFalse)
So(storedToken.PrevAuthToken, ShouldEqual, prevToken)
So(storedToken.AuthToken, ShouldNotEqual, prevToken)
require.Nil(t, err)
require.NotNil(t, storedToken)
require.False(t, storedToken.AuthTokenSeen)
require.Equal(t, prevToken, storedToken.PrevAuthToken)
require.NotEqual(t, prevToken, storedToken.AuthToken)
})
Convey("Should rotate current token, but keep previous token when auth token not seen", func() {
userToken.RotatedAt = getTime().Add(-2 * time.Minute).Unix()
t.Run("Should rotate current token, but keep previous token when auth token not seen", func(t *testing.T) {
getTime = func() time.Time { return now }
userToken, err := ctx.tokenService.CreateToken(context.Background(), user,
net.ParseIP("192.168.10.11"), "some user agent")
require.Nil(t, err)
require.NotNil(t, userToken)
prevToken := userToken.AuthToken
userToken.RotatedAt = now.Add(-2 * time.Minute).Unix()
getTime = func() time.Time {
return t.Add(2 * time.Minute)
return now.Add(2 * time.Minute)
}
rotated, err := userAuthTokenService.TryRotateToken(context.Background(), userToken,
rotated, err := ctx.tokenService.TryRotateToken(context.Background(), userToken,
net.ParseIP("1.1.1.1"), "firefox")
So(err, ShouldBeNil)
So(rotated, ShouldBeTrue)
require.Nil(t, err)
require.True(t, rotated)
storedToken, err := ctx.getAuthTokenByID(userToken.Id)
So(err, ShouldBeNil)
So(storedToken, ShouldNotBeNil)
So(storedToken.AuthTokenSeen, ShouldBeFalse)
So(storedToken.PrevAuthToken, ShouldEqual, prevToken)
So(storedToken.AuthToken, ShouldNotEqual, prevToken)
require.Nil(t, err)
require.NotNil(t, storedToken)
require.False(t, storedToken.AuthTokenSeen)
require.Equal(t, prevToken, storedToken.PrevAuthToken)
require.NotEqual(t, prevToken, storedToken.AuthToken)
})
})
Convey("When populating userAuthToken from UserToken should copy all properties", func() {
t.Run("When populating userAuthToken from UserToken should copy all properties", func(t *testing.T) {
ut := models.UserToken{
Id: 1,
UserId: 2,
@@ -464,24 +477,24 @@ func TestUserAuthToken(t *testing.T) {
UnhashedToken: "e",
}
utBytes, err := json.Marshal(ut)
So(err, ShouldBeNil)
require.Nil(t, err)
utJSON, err := simplejson.NewJson(utBytes)
So(err, ShouldBeNil)
require.Nil(t, err)
utMap := utJSON.MustMap()
var uat userAuthToken
err = uat.fromUserToken(&ut)
So(err, ShouldBeNil)
require.Nil(t, err)
uatBytes, err := json.Marshal(uat)
So(err, ShouldBeNil)
require.Nil(t, err)
uatJSON, err := simplejson.NewJson(uatBytes)
So(err, ShouldBeNil)
require.Nil(t, err)
uatMap := uatJSON.MustMap()
So(uatMap, ShouldResemble, utMap)
require.True(t, reflect.DeepEqual(uatMap, utMap))
})
Convey("When populating userToken from userAuthToken should copy all properties", func() {
t.Run("When populating userToken from userAuthToken should copy all properties", func(t *testing.T) {
uat := userAuthToken{
Id: 1,
UserId: 2,
@@ -497,26 +510,21 @@ func TestUserAuthToken(t *testing.T) {
UnhashedToken: "e",
}
uatBytes, err := json.Marshal(uat)
So(err, ShouldBeNil)
require.Nil(t, err)
uatJSON, err := simplejson.NewJson(uatBytes)
So(err, ShouldBeNil)
require.Nil(t, err)
uatMap := uatJSON.MustMap()
var ut models.UserToken
err = uat.toUserToken(&ut)
So(err, ShouldBeNil)
require.Nil(t, err)
utBytes, err := json.Marshal(ut)
So(err, ShouldBeNil)
require.Nil(t, err)
utJSON, err := simplejson.NewJson(utBytes)
So(err, ShouldBeNil)
require.Nil(t, err)
utMap := utJSON.MustMap()
So(utMap, ShouldResemble, uatMap)
})
Reset(func() {
getTime = time.Now
})
require.True(t, reflect.DeepEqual(utMap, uatMap))
})
}

View File

@@ -6,65 +6,66 @@ import (
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/require"
)
func TestUserAuthTokenCleanup(t *testing.T) {
Convey("Test user auth token cleanup", t, func() {
setup := func() *testContext {
ctx := createTestContext(t)
maxInactiveLifetime, _ := time.ParseDuration("168h")
maxLifetime, _ := time.ParseDuration("720h")
ctx.tokenService.Cfg.LoginMaxInactiveLifetime = maxInactiveLifetime
ctx.tokenService.Cfg.LoginMaxLifetime = maxLifetime
return ctx
}
insertToken := func(token string, prev string, createdAt, rotatedAt int64) {
insertToken := func(ctx *testContext, token string, prev string, createdAt, rotatedAt int64) {
ut := userAuthToken{AuthToken: token, PrevAuthToken: prev, CreatedAt: createdAt, RotatedAt: rotatedAt, UserAgent: "", ClientIp: ""}
_, err := ctx.sqlstore.NewSession(context.Background()).Insert(&ut)
So(err, ShouldBeNil)
require.Nil(t, err)
}
t := time.Date(2018, 12, 13, 13, 45, 0, 0, time.UTC)
getTime = func() time.Time {
return t
}
now := time.Date(2018, 12, 13, 13, 45, 0, 0, time.UTC)
getTime = func() time.Time { return now }
Convey("should delete tokens where token rotation age is older than or equal 7 days", func() {
from := t.Add(-168 * time.Hour)
t.Run("should delete tokens where token rotation age is older than or equal 7 days", func(t *testing.T) {
ctx := setup()
from := now.Add(-168 * time.Hour)
// insert three old tokens that should be deleted
for i := 0; i < 3; i++ {
insertToken(fmt.Sprintf("oldA%d", i), fmt.Sprintf("oldB%d", i), from.Unix(), from.Unix())
insertToken(ctx, fmt.Sprintf("oldA%d", i), fmt.Sprintf("oldB%d", i), from.Unix(), from.Unix())
}
// insert three active tokens that should not be deleted
for i := 0; i < 3; i++ {
from = from.Add(time.Second)
insertToken(fmt.Sprintf("newA%d", i), fmt.Sprintf("newB%d", i), from.Unix(), from.Unix())
insertToken(ctx, fmt.Sprintf("newA%d", i), fmt.Sprintf("newB%d", i), from.Unix(), from.Unix())
}
affected, err := ctx.tokenService.deleteExpiredTokens(context.Background(), 168*time.Hour, 30*24*time.Hour)
So(err, ShouldBeNil)
So(affected, ShouldEqual, 3)
require.Nil(t, err)
require.Equal(t, int64(3), affected)
})
Convey("should delete tokens where token age is older than or equal 30 days", func() {
from := t.Add(-30 * 24 * time.Hour)
fromRotate := t.Add(-time.Second)
t.Run("should delete tokens where token age is older than or equal 30 days", func(t *testing.T) {
ctx := setup()
from := now.Add(-30 * 24 * time.Hour)
fromRotate := now.Add(-time.Second)
// insert three old tokens that should be deleted
for i := 0; i < 3; i++ {
insertToken(fmt.Sprintf("oldA%d", i), fmt.Sprintf("oldB%d", i), from.Unix(), fromRotate.Unix())
insertToken(ctx, fmt.Sprintf("oldA%d", i), fmt.Sprintf("oldB%d", i), from.Unix(), fromRotate.Unix())
}
// insert three active tokens that should not be deleted
for i := 0; i < 3; i++ {
from = from.Add(time.Second)
insertToken(fmt.Sprintf("newA%d", i), fmt.Sprintf("newB%d", i), from.Unix(), fromRotate.Unix())
insertToken(ctx, fmt.Sprintf("newA%d", i), fmt.Sprintf("newB%d", i), from.Unix(), fromRotate.Unix())
}
affected, err := ctx.tokenService.deleteExpiredTokens(context.Background(), 7*24*time.Hour, 30*24*time.Hour)
So(err, ShouldBeNil)
So(affected, ShouldEqual, 3)
})
require.Nil(t, err)
require.Equal(t, int64(3), affected)
})
}