Auth: Attach external session info to Grafana session (#93849)
* initial from poc changes * wip * Remove public external session service * Update swagger * Fix merge * Cleanup * Add backgroud service for cleanup * Add auth_module to user_external_session * Add tests for token revocation functions * Add secret migration capabilities for user_external_session fields * Cleanup, refactor to address feedback * Fix test
This commit is contained in:
@@ -3,20 +3,25 @@ package authimpl
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/sync/singleflight"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
"github.com/grafana/grafana/pkg/services/auth/authtest"
|
||||
"github.com/grafana/grafana/pkg/services/quota"
|
||||
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tests/testsuite"
|
||||
@@ -36,8 +41,11 @@ func TestIntegrationUserAuthToken(t *testing.T) {
|
||||
|
||||
t.Run("When creating token", func(t *testing.T) {
|
||||
createToken := func() *auth.UserToken {
|
||||
userToken, err := ctx.tokenService.CreateToken(context.Background(), usr,
|
||||
net.ParseIP("192.168.10.11"), "some user agent")
|
||||
userToken, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: net.ParseIP("192.168.10.11"),
|
||||
UserAgent: "some user agent",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, userToken)
|
||||
require.False(t, userToken.AuthTokenSeen)
|
||||
@@ -109,8 +117,11 @@ func TestIntegrationUserAuthToken(t *testing.T) {
|
||||
userToken = createToken()
|
||||
|
||||
t.Run("When creating an additional token", func(t *testing.T) {
|
||||
userToken2, err := ctx.tokenService.CreateToken(context.Background(), usr,
|
||||
net.ParseIP("192.168.10.11"), "some user agent")
|
||||
userToken2, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: net.ParseIP("192.168.10.11"),
|
||||
UserAgent: "some user agent",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, userToken2)
|
||||
|
||||
@@ -156,8 +167,11 @@ func TestIntegrationUserAuthToken(t *testing.T) {
|
||||
for i := 0; i < 3; i++ {
|
||||
userId := usr.ID + int64(i+1)
|
||||
userIds = append(userIds, userId)
|
||||
_, err := ctx.tokenService.CreateToken(context.Background(), usr,
|
||||
net.ParseIP("192.168.10.11"), "some user agent")
|
||||
_, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: net.ParseIP("192.168.10.11"),
|
||||
UserAgent: "some user agent",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
@@ -173,10 +187,89 @@ func TestIntegrationUserAuthToken(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("When creating token with external session", func(t *testing.T) {
|
||||
createToken := func() *auth.UserToken {
|
||||
userToken, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: net.ParseIP("192.168.10.11"),
|
||||
UserAgent: "some user agent",
|
||||
ExternalSession: &auth.ExternalSession{UserID: usr.ID, AuthModule: "test", UserAuthID: 1},
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, userToken)
|
||||
require.False(t, userToken.AuthTokenSeen)
|
||||
return userToken
|
||||
}
|
||||
|
||||
userToken := createToken()
|
||||
|
||||
t.Run("soft revoking existing token should remove the associated external session", func(t *testing.T) {
|
||||
err := ctx.tokenService.RevokeToken(context.Background(), userToken, true)
|
||||
require.Nil(t, err)
|
||||
|
||||
model, err := ctx.getAuthTokenByID(userToken.Id)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, model)
|
||||
require.Greater(t, model.RevokedAt, int64(0))
|
||||
|
||||
extSess, err := ctx.getExternalSessionByID(userToken.ExternalSessionId)
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, extSess)
|
||||
})
|
||||
|
||||
t.Run("revoking existing token should also remove the associated external session", func(t *testing.T) {
|
||||
err := ctx.tokenService.RevokeToken(context.Background(), userToken, false)
|
||||
require.Nil(t, err)
|
||||
|
||||
model, err := ctx.getAuthTokenByID(userToken.Id)
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, model)
|
||||
|
||||
extSess, err := ctx.getExternalSessionByID(userToken.ExternalSessionId)
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, extSess)
|
||||
})
|
||||
|
||||
t.Run("When revoking users tokens in a batch", func(t *testing.T) {
|
||||
t.Run("Can revoke all users tokens and associated external sessions", func(t *testing.T) {
|
||||
userIds := []int64{}
|
||||
extSessionIds := []int64{}
|
||||
for i := 0; i < 3; i++ {
|
||||
userId := usr.ID + int64(i+1)
|
||||
userIds = append(userIds, userId)
|
||||
token, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: net.ParseIP("192.168.10.11"),
|
||||
UserAgent: "some user agent",
|
||||
ExternalSession: &auth.ExternalSession{UserID: userId, AuthModule: "test", UserAuthID: 1},
|
||||
})
|
||||
require.Nil(t, err)
|
||||
extSessionIds = append(extSessionIds, token.ExternalSessionId)
|
||||
}
|
||||
|
||||
err := ctx.tokenService.BatchRevokeAllUserTokens(context.Background(), userIds)
|
||||
require.Nil(t, err)
|
||||
|
||||
for i := 0; i < len(userIds); i++ {
|
||||
tokens, err := ctx.tokenService.GetUserTokens(context.Background(), userIds[i])
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, 0, len(tokens))
|
||||
|
||||
extSess, err := ctx.getExternalSessionByID(extSessionIds[i])
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, extSess)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("expires correctly", func(t *testing.T) {
|
||||
ctx := createTestContext(t)
|
||||
userToken, err := ctx.tokenService.CreateToken(context.Background(), usr,
|
||||
net.ParseIP("192.168.10.11"), "some user agent")
|
||||
userToken, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: net.ParseIP("192.168.10.11"),
|
||||
UserAgent: "some user agent",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
userToken, err = ctx.tokenService.LookupToken(context.Background(), userToken.UnhashedToken)
|
||||
@@ -262,7 +355,11 @@ func TestIntegrationUserAuthToken(t *testing.T) {
|
||||
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(), usr, net.ParseIP("192.168.10.11"), "some user agent")
|
||||
userToken, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: net.ParseIP("192.168.10.11"),
|
||||
UserAgent: "some user agent",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
prevToken := userToken.AuthToken
|
||||
@@ -335,8 +432,11 @@ func TestIntegrationUserAuthToken(t *testing.T) {
|
||||
|
||||
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(), usr,
|
||||
net.ParseIP("192.168.10.11"), "some user agent")
|
||||
userToken, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: net.ParseIP("192.168.10.11"),
|
||||
UserAgent: "some user agent",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, userToken)
|
||||
|
||||
@@ -368,8 +468,11 @@ func TestIntegrationUserAuthToken(t *testing.T) {
|
||||
})
|
||||
|
||||
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(), usr,
|
||||
net.ParseIP("192.168.10.11"), "some user agent")
|
||||
userToken, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: net.ParseIP("192.168.10.11"),
|
||||
UserAgent: "some user agent",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, userToken)
|
||||
|
||||
@@ -389,7 +492,11 @@ func TestIntegrationUserAuthToken(t *testing.T) {
|
||||
|
||||
t.Run("RotateToken", func(t *testing.T) {
|
||||
var prev string
|
||||
token, err := ctx.tokenService.CreateToken(context.Background(), usr, nil, "")
|
||||
token, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: nil,
|
||||
UserAgent: "",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
t.Run("should rotate token when called with current auth token", func(t *testing.T) {
|
||||
prev = token.UnhashedToken
|
||||
@@ -412,7 +519,11 @@ func TestIntegrationUserAuthToken(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("should return error when token is revoked", func(t *testing.T) {
|
||||
revokedToken, err := ctx.tokenService.CreateToken(context.Background(), usr, nil, "")
|
||||
revokedToken, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: nil,
|
||||
UserAgent: "",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
// mark token as revoked
|
||||
err = ctx.sqlstore.WithDbSession(context.Background(), func(sess *db.Session) error {
|
||||
@@ -426,7 +537,11 @@ func TestIntegrationUserAuthToken(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("should return error when token has expired", func(t *testing.T) {
|
||||
expiredToken, err := ctx.tokenService.CreateToken(context.Background(), usr, nil, "")
|
||||
expiredToken, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: nil,
|
||||
UserAgent: "",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
// mark token as expired
|
||||
err = ctx.sqlstore.WithDbSession(context.Background(), func(sess *db.Session) error {
|
||||
@@ -441,10 +556,18 @@ func TestIntegrationUserAuthToken(t *testing.T) {
|
||||
|
||||
t.Run("should only delete revoked tokens that are outside on specified window", func(t *testing.T) {
|
||||
usr := &user.User{ID: 100}
|
||||
token1, err := ctx.tokenService.CreateToken(context.Background(), usr, nil, "")
|
||||
token1, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: nil,
|
||||
UserAgent: "",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
token2, err := ctx.tokenService.CreateToken(context.Background(), usr, nil, "")
|
||||
token2, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: nil,
|
||||
UserAgent: "",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
getTime = func() time.Time {
|
||||
@@ -474,18 +597,19 @@ func TestIntegrationUserAuthToken(t *testing.T) {
|
||||
|
||||
t.Run("When populating userAuthToken from UserToken should copy all properties", func(t *testing.T) {
|
||||
ut := auth.UserToken{
|
||||
Id: 1,
|
||||
UserId: 2,
|
||||
AuthToken: "a",
|
||||
PrevAuthToken: "b",
|
||||
UserAgent: "c",
|
||||
ClientIp: "d",
|
||||
AuthTokenSeen: true,
|
||||
SeenAt: 3,
|
||||
RotatedAt: 4,
|
||||
CreatedAt: 5,
|
||||
UpdatedAt: 6,
|
||||
UnhashedToken: "e",
|
||||
Id: 1,
|
||||
UserId: 2,
|
||||
AuthToken: "a",
|
||||
PrevAuthToken: "b",
|
||||
UserAgent: "c",
|
||||
ClientIp: "d",
|
||||
AuthTokenSeen: true,
|
||||
SeenAt: 3,
|
||||
RotatedAt: 4,
|
||||
CreatedAt: 5,
|
||||
UpdatedAt: 6,
|
||||
UnhashedToken: "e",
|
||||
ExternalSessionId: 7,
|
||||
}
|
||||
utBytes, err := json.Marshal(ut)
|
||||
require.Nil(t, err)
|
||||
@@ -507,18 +631,19 @@ func TestIntegrationUserAuthToken(t *testing.T) {
|
||||
|
||||
t.Run("When populating userToken from userAuthToken should copy all properties", func(t *testing.T) {
|
||||
uat := userAuthToken{
|
||||
Id: 1,
|
||||
UserId: 2,
|
||||
AuthToken: "a",
|
||||
PrevAuthToken: "b",
|
||||
UserAgent: "c",
|
||||
ClientIp: "d",
|
||||
AuthTokenSeen: true,
|
||||
SeenAt: 3,
|
||||
RotatedAt: 4,
|
||||
CreatedAt: 5,
|
||||
UpdatedAt: 6,
|
||||
UnhashedToken: "e",
|
||||
Id: 1,
|
||||
UserId: 2,
|
||||
AuthToken: "a",
|
||||
PrevAuthToken: "b",
|
||||
UserAgent: "c",
|
||||
ClientIp: "d",
|
||||
AuthTokenSeen: true,
|
||||
SeenAt: 3,
|
||||
RotatedAt: 4,
|
||||
CreatedAt: 5,
|
||||
UpdatedAt: 6,
|
||||
UnhashedToken: "e",
|
||||
ExternalSessionId: 7,
|
||||
}
|
||||
uatBytes, err := json.Marshal(uat)
|
||||
require.Nil(t, err)
|
||||
@@ -551,22 +676,27 @@ func createTestContext(t *testing.T) *testContext {
|
||||
TokenRotationIntervalMinutes: 10,
|
||||
}
|
||||
|
||||
extSessionStore := provideExternalSessionStore(sqlstore, &fakes.FakeSecretsService{}, tracing.InitializeTracerForTest())
|
||||
|
||||
tokenService := &UserAuthTokenService{
|
||||
sqlStore: sqlstore,
|
||||
cfg: cfg,
|
||||
log: log.New("test-logger"),
|
||||
singleflight: new(singleflight.Group),
|
||||
sqlStore: sqlstore,
|
||||
cfg: cfg,
|
||||
log: log.New("test-logger"),
|
||||
singleflight: new(singleflight.Group),
|
||||
externalSessionStore: extSessionStore,
|
||||
}
|
||||
|
||||
return &testContext{
|
||||
sqlstore: sqlstore,
|
||||
tokenService: tokenService,
|
||||
sqlstore: sqlstore,
|
||||
tokenService: tokenService,
|
||||
extSessionStore: &extSessionStore,
|
||||
}
|
||||
}
|
||||
|
||||
type testContext struct {
|
||||
sqlstore db.DB
|
||||
tokenService *UserAuthTokenService
|
||||
sqlstore db.DB
|
||||
tokenService *UserAuthTokenService
|
||||
extSessionStore *auth.ExternalSessionStore
|
||||
}
|
||||
|
||||
func (c *testContext) getAuthTokenByID(id int64) (*userAuthToken, error) {
|
||||
@@ -585,6 +715,22 @@ func (c *testContext) getAuthTokenByID(id int64) (*userAuthToken, error) {
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (c *testContext) getExternalSessionByID(ID int64) (*auth.ExternalSession, error) {
|
||||
var res *auth.ExternalSession
|
||||
err := c.sqlstore.WithDbSession(context.Background(), func(sess *db.Session) error {
|
||||
var t auth.ExternalSession
|
||||
found, err := sess.ID(ID).Get(&t)
|
||||
if err != nil || !found {
|
||||
return err
|
||||
}
|
||||
|
||||
res = &t
|
||||
return nil
|
||||
})
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (c *testContext) updateRotatedAt(id, rotatedAt int64) (bool, error) {
|
||||
hasRowsAffected := false
|
||||
err := c.sqlstore.WithDbSession(context.Background(), func(sess *db.Session) error {
|
||||
@@ -609,8 +755,11 @@ func TestIntegrationTokenCount(t *testing.T) {
|
||||
user := &user.User{ID: int64(10)}
|
||||
|
||||
createToken := func() *auth.UserToken {
|
||||
userToken, err := ctx.tokenService.CreateToken(context.Background(), user,
|
||||
net.ParseIP("192.168.10.11"), "some user agent")
|
||||
userToken, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: user,
|
||||
ClientIP: net.ParseIP("192.168.10.11"),
|
||||
UserAgent: "some user agent",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, userToken)
|
||||
require.False(t, userToken.AuthTokenSeen)
|
||||
@@ -637,3 +786,108 @@ func TestIntegrationTokenCount(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, int64(0), count)
|
||||
}
|
||||
|
||||
func TestRevokeAllUserTokens(t *testing.T) {
|
||||
t.Run("should not fail if the external sessions could not be removed", func(t *testing.T) {
|
||||
ctx := createTestContext(t)
|
||||
usr := &user.User{ID: int64(10)}
|
||||
|
||||
// Mock the external session store to return an error
|
||||
mockExternalSessionStore := &authtest.MockExternalSessionStore{}
|
||||
|
||||
mockExternalSessionStore.On("Create", mock.Anything, mock.IsType(&auth.ExternalSession{})).Run(func(args mock.Arguments) {
|
||||
extSession := args.Get(1).(*auth.ExternalSession)
|
||||
extSession.ID = 1
|
||||
}).Return(nil)
|
||||
mockExternalSessionStore.On("DeleteExternalSessionsByUserID", mock.Anything, usr.ID).Return(errors.New("some error"))
|
||||
ctx.tokenService.externalSessionStore = mockExternalSessionStore
|
||||
|
||||
userToken, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: net.ParseIP("192.168.10.11"),
|
||||
UserAgent: "some user agent",
|
||||
ExternalSession: &auth.ExternalSession{UserID: usr.ID, AuthModule: "test", UserAuthID: 1},
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, userToken)
|
||||
|
||||
err = ctx.tokenService.RevokeAllUserTokens(context.Background(), usr.ID)
|
||||
require.Nil(t, err)
|
||||
|
||||
model, err := ctx.getAuthTokenByID(userToken.Id)
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, model)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRevokeToken(t *testing.T) {
|
||||
t.Run("should not fail if the external sessions could not be removed", func(t *testing.T) {
|
||||
ctx := createTestContext(t)
|
||||
usr := &user.User{ID: int64(10)}
|
||||
mockExternalSessionStore := &authtest.MockExternalSessionStore{}
|
||||
|
||||
mockExternalSessionStore.On("Create", mock.Anything, mock.IsType(&auth.ExternalSession{})).Run(func(args mock.Arguments) {
|
||||
extSession := args.Get(1).(*auth.ExternalSession)
|
||||
extSession.ID = 2
|
||||
}).Return(nil)
|
||||
mockExternalSessionStore.On("Delete", mock.Anything, int64(2)).Return(errors.New("some error"))
|
||||
ctx.tokenService.externalSessionStore = mockExternalSessionStore
|
||||
|
||||
userToken, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: net.ParseIP("192.168.10.11"),
|
||||
UserAgent: "some user agent",
|
||||
ExternalSession: &auth.ExternalSession{UserID: usr.ID, AuthModule: "test", UserAuthID: 1},
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, userToken)
|
||||
|
||||
err = ctx.tokenService.RevokeToken(context.Background(), userToken, false)
|
||||
require.Nil(t, err)
|
||||
|
||||
model, err := ctx.getAuthTokenByID(userToken.Id)
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, model)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBatchRevokeAllUserTokens(t *testing.T) {
|
||||
t.Run("should not fail if the external sessions could not be removed", func(t *testing.T) {
|
||||
ctx := createTestContext(t)
|
||||
userIds := []int64{1, 2, 3}
|
||||
mockExternalSessionStore := &authtest.MockExternalSessionStore{}
|
||||
|
||||
mockExternalSessionStore.On("BatchDeleteExternalSessionsByUserIDs", mock.Anything, userIds).Return(errors.New("some error"))
|
||||
ctr := int64(0)
|
||||
mockExternalSessionStore.On("Create", mock.Anything, mock.IsType(&auth.ExternalSession{})).Run(func(args mock.Arguments) {
|
||||
extSession := args.Get(1).(*auth.ExternalSession)
|
||||
ctr += 1
|
||||
extSession.ID = ctr
|
||||
}).Return(nil)
|
||||
|
||||
ctx.tokenService.externalSessionStore = mockExternalSessionStore
|
||||
|
||||
for _, userID := range userIds {
|
||||
usr := &user.User{ID: userID}
|
||||
userToken, err := ctx.tokenService.CreateToken(context.Background(), &auth.CreateTokenCommand{
|
||||
User: usr,
|
||||
ClientIP: net.ParseIP("192.168.10.11"),
|
||||
UserAgent: "some user agent",
|
||||
ExternalSession: &auth.ExternalSession{UserID: usr.ID, AuthModule: "test", UserAuthID: 1},
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, userToken)
|
||||
}
|
||||
|
||||
// Batch revoke all user tokens
|
||||
err := ctx.tokenService.BatchRevokeAllUserTokens(context.Background(), userIds)
|
||||
require.Nil(t, err)
|
||||
|
||||
// Verify that the tokens have been revoked
|
||||
for _, userID := range userIds {
|
||||
tokens, err := ctx.tokenService.GetUserTokens(context.Background(), userID)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, 0, len(tokens))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user