2022-11-18 09:56:06 +01:00
package authimpl
2019-02-02 12:11:30 +01:00
import (
2019-04-30 14:42:01 +02:00
"context"
2019-02-02 12:11:30 +01:00
"crypto/sha256"
"encoding/hex"
2023-03-23 14:39:04 +01:00
"errors"
2023-02-02 14:36:16 +01:00
"fmt"
2020-11-25 03:55:22 -03:00
"net"
2019-05-31 13:22:22 +03:00
"strings"
2019-02-02 12:11:30 +01:00
"time"
2023-02-02 14:36:16 +01:00
"golang.org/x/sync/singleflight"
2022-10-19 09:02:15 -04:00
"github.com/grafana/grafana/pkg/infra/db"
2019-05-13 14:45:54 +08:00
"github.com/grafana/grafana/pkg/infra/log"
2022-10-19 09:02:15 -04:00
"github.com/grafana/grafana/pkg/infra/serverlock"
2023-03-23 14:39:04 +01:00
"github.com/grafana/grafana/pkg/models/usertoken"
2022-11-18 09:56:06 +01:00
"github.com/grafana/grafana/pkg/services/auth"
2022-11-14 21:08:10 +02:00
"github.com/grafana/grafana/pkg/services/quota"
2022-06-28 14:32:25 +02:00
"github.com/grafana/grafana/pkg/services/user"
2019-02-02 12:11:30 +01:00
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
2023-03-23 14:39:04 +01:00
var (
getTime = time . Now
errTokenNotRotated = errors . New ( "token was not rotated" )
2023-09-11 10:24:57 +02:00
errUserIDInvalid = errors . New ( "invalid user ID" )
2023-03-23 14:39:04 +01:00
)
2019-02-02 12:11:30 +01:00
2022-12-07 09:55:48 +00:00
func ProvideUserAuthTokenService ( sqlStore db . DB ,
serverLockService * serverlock . ServerLockService ,
quotaService quota . Service ,
cfg * setting . Cfg ) ( * UserAuthTokenService , error ) {
2021-08-25 15:11:22 +02:00
s := & UserAuthTokenService {
2022-11-22 10:58:59 +01:00
sqlStore : sqlStore ,
serverLockService : serverLockService ,
cfg : cfg ,
2021-08-25 15:11:22 +02:00
log : log . New ( "auth" ) ,
2023-02-02 14:36:16 +01:00
singleflight : new ( singleflight . Group ) ,
2021-08-25 15:11:22 +02:00
}
2022-11-14 21:08:10 +02:00
defaultLimits , err := readQuotaConfig ( cfg )
if err != nil {
return s , err
}
if err := quotaService . RegisterQuotaReporter ( & quota . NewUsageReporter {
2022-11-18 09:56:06 +01:00
TargetSrv : auth . QuotaTargetSrv ,
2022-11-14 21:08:10 +02:00
DefaultLimits : defaultLimits ,
2022-11-22 10:58:59 +01:00
Reporter : s . reportActiveTokenCount ,
2022-11-14 21:08:10 +02:00
} ) ; err != nil {
return s , err
}
return s , nil
2022-07-29 16:30:46 +02:00
}
2022-11-22 10:58:59 +01:00
type UserAuthTokenService struct {
sqlStore db . DB
serverLockService * serverlock . ServerLockService
cfg * setting . Cfg
log log . Logger
2023-02-02 14:36:16 +01:00
singleflight * singleflight . Group
2019-02-11 21:12:01 +01:00
}
2022-11-18 09:56:06 +01:00
func ( s * UserAuthTokenService ) CreateToken ( ctx context . Context , user * user . User , clientIP net . IP , userAgent string ) ( * auth . UserToken , error ) {
2023-03-23 14:39:04 +01:00
token , hashedToken , err := generateAndHashToken ( )
2019-02-02 12:11:30 +01:00
if err != nil {
return nil , err
}
now := getTime ( ) . Unix ( )
2020-11-25 03:55:22 -03:00
clientIPStr := clientIP . String ( )
if len ( clientIP ) == 0 {
clientIPStr = ""
}
2019-02-02 12:11:30 +01:00
userAuthToken := userAuthToken {
2022-06-28 14:32:25 +02:00
UserId : user . ID ,
2019-02-02 12:11:30 +01:00
AuthToken : hashedToken ,
PrevAuthToken : hashedToken ,
2020-11-25 03:55:22 -03:00
ClientIp : clientIPStr ,
2019-02-02 12:11:30 +01:00
UserAgent : userAgent ,
RotatedAt : now ,
CreatedAt : now ,
UpdatedAt : now ,
SeenAt : 0 ,
2021-03-16 17:44:02 +01:00
RevokedAt : 0 ,
2019-02-02 12:11:30 +01:00
AuthTokenSeen : false ,
}
2019-04-30 14:42:01 +02:00
2022-11-22 10:58:59 +01:00
err = s . sqlStore . WithDbSession ( ctx , func ( dbSession * db . Session ) error {
2019-04-30 14:42:01 +02:00
_ , err = dbSession . Insert ( & userAuthToken )
return err
} )
2019-02-02 12:11:30 +01:00
if err != nil {
return nil , err
}
userAuthToken . UnhashedToken = token
2022-09-20 18:32:06 +02:00
ctxLogger := s . log . FromContext ( ctx )
2023-09-04 18:49:47 +02:00
ctxLogger . Debug ( "User auth token created" , "tokenId" , userAuthToken . Id , "userId" , userAuthToken . UserId , "clientIP" , userAuthToken . ClientIp , "userAgent" , userAuthToken . UserAgent , "authToken" , userAuthToken . AuthToken )
2019-02-02 12:11:30 +01:00
2022-11-18 09:56:06 +01:00
var userToken auth . UserToken
2019-02-06 16:21:16 +01:00
err = userAuthToken . toUserToken ( & userToken )
return & userToken , err
2019-02-02 12:11:30 +01:00
}
2022-11-18 09:56:06 +01:00
func ( s * UserAuthTokenService ) LookupToken ( ctx context . Context , unhashedToken string ) ( * auth . UserToken , error ) {
2019-02-02 12:11:30 +01:00
hashedToken := hashToken ( unhashedToken )
var model userAuthToken
2019-04-30 14:42:01 +02:00
var exists bool
var err error
2022-11-22 10:58:59 +01:00
err = s . sqlStore . WithDbSession ( ctx , func ( dbSession * db . Session ) error {
2021-01-19 17:55:53 +01:00
exists , err = dbSession . Where ( "(auth_token = ? OR prev_auth_token = ?)" ,
2019-04-30 14:42:01 +02:00
hashedToken ,
2021-01-19 17:55:53 +01:00
hashedToken ) .
2019-04-30 14:42:01 +02:00
Get ( & model )
return err
} )
2019-02-02 12:11:30 +01:00
if err != nil {
return nil , err
}
if ! exists {
2022-11-18 09:56:06 +01:00
return nil , auth . ErrUserTokenNotFound
2019-02-02 12:11:30 +01:00
}
2022-09-20 18:32:06 +02:00
ctxLogger := s . log . FromContext ( ctx )
2021-03-16 17:44:02 +01:00
if model . RevokedAt > 0 {
2023-09-04 18:49:47 +02:00
ctxLogger . Debug ( "User token has been revoked" , "user ID" , model . UserId , "token ID" , model . Id )
2022-11-18 09:56:06 +01:00
return nil , & auth . TokenRevokedError {
2021-03-16 17:44:02 +01:00
UserID : model . UserId ,
TokenID : model . Id ,
}
}
2021-01-19 17:55:53 +01:00
if model . CreatedAt <= s . createdAfterParam ( ) || model . RotatedAt <= s . rotatedAfterParam ( ) {
2023-09-04 18:49:47 +02:00
ctxLogger . Debug ( "User token has expired" , "user ID" , model . UserId , "token ID" , model . Id )
2022-11-18 09:56:06 +01:00
return nil , & auth . TokenExpiredError {
2021-01-19 17:55:53 +01:00
UserID : model . UserId ,
TokenID : model . Id ,
}
}
2023-02-02 14:36:16 +01:00
// Current incoming token is the previous auth token in the DB and the auth_token_seen is true
2019-02-02 12:11:30 +01:00
if model . AuthToken != hashedToken && model . PrevAuthToken == hashedToken && model . AuthTokenSeen {
2023-03-23 14:39:04 +01:00
model . AuthTokenSeen = false
model . RotatedAt = getTime ( ) . Add ( - usertoken . UrgentRotateTime ) . Unix ( )
2019-04-30 14:42:01 +02:00
var affectedRows int64
2022-11-22 10:58:59 +01:00
err = s . sqlStore . WithTransactionalDbSession ( ctx , func ( dbSession * db . Session ) error {
2019-04-30 14:42:01 +02:00
affectedRows , err = dbSession . Where ( "id = ? AND prev_auth_token = ? AND rotated_at < ?" ,
2023-03-23 14:39:04 +01:00
model . Id ,
model . PrevAuthToken ,
model . RotatedAt ) .
AllCols ( ) . Update ( & model )
2019-04-30 14:42:01 +02:00
return err
} )
2019-02-02 12:11:30 +01:00
if err != nil {
return nil , err
}
if affectedRows == 0 {
2023-09-04 18:49:47 +02:00
ctxLogger . Debug ( "Prev seen token unchanged" , "tokenId" , model . Id , "userId" , model . UserId , "clientIP" , model . ClientIp , "userAgent" , model . UserAgent , "authToken" , model . AuthToken )
2019-02-02 12:11:30 +01:00
} else {
2023-09-04 18:49:47 +02:00
ctxLogger . Debug ( "Prev seen token" , "tokenId" , model . Id , "userId" , model . UserId , "clientIP" , model . ClientIp , "userAgent" , model . UserAgent , "authToken" , model . AuthToken )
2019-02-02 12:11:30 +01:00
}
}
2023-02-02 14:36:16 +01:00
// Current incoming token is not seen and it is the latest valid auth token in the db
2019-02-02 12:11:30 +01:00
if ! model . AuthTokenSeen && model . AuthToken == hashedToken {
2023-03-23 14:39:04 +01:00
model . AuthTokenSeen = true
model . SeenAt = getTime ( ) . Unix ( )
2019-04-30 14:42:01 +02:00
var affectedRows int64
2022-11-22 10:58:59 +01:00
err = s . sqlStore . WithTransactionalDbSession ( ctx , func ( dbSession * db . Session ) error {
2019-04-30 14:42:01 +02:00
affectedRows , err = dbSession . Where ( "id = ? AND auth_token = ?" ,
2023-03-23 14:39:04 +01:00
model . Id ,
model . AuthToken ) .
AllCols ( ) . Update ( & model )
2019-04-30 14:42:01 +02:00
return err
} )
2019-02-02 12:11:30 +01:00
if err != nil {
return nil , err
}
if affectedRows == 0 {
2023-09-04 18:49:47 +02:00
ctxLogger . Debug ( "Seen wrong token" , "tokenId" , model . Id , "userId" , model . UserId , "clientIP" , model . ClientIp , "userAgent" , model . UserAgent , "authToken" , model . AuthToken )
2019-02-02 12:11:30 +01:00
} else {
2023-09-04 18:49:47 +02:00
ctxLogger . Debug ( "Seen token" , "tokenId" , model . Id , "userId" , model . UserId , "clientIP" , model . ClientIp , "userAgent" , model . UserAgent , "authToken" , model . AuthToken )
2019-02-02 12:11:30 +01:00
}
}
model . UnhashedToken = unhashedToken
2019-02-06 16:21:16 +01:00
2022-11-18 09:56:06 +01:00
var userToken auth . UserToken
2019-02-06 16:21:16 +01:00
err = model . toUserToken ( & userToken )
return & userToken , err
2019-02-02 12:11:30 +01:00
}
2023-03-23 14:39:04 +01:00
func ( s * UserAuthTokenService ) RotateToken ( ctx context . Context , cmd auth . RotateCommand ) ( * auth . UserToken , error ) {
if cmd . UnHashedToken == "" {
return nil , auth . ErrInvalidSessionToken
}
2023-08-30 08:46:47 -07:00
res , err , _ := s . singleflight . Do ( cmd . UnHashedToken , func ( ) ( any , error ) {
2023-03-23 14:39:04 +01:00
token , err := s . LookupToken ( ctx , cmd . UnHashedToken )
if err != nil {
return nil , err
}
newToken , err := s . rotateToken ( ctx , token , cmd . IP , cmd . UserAgent )
if errors . Is ( err , errTokenNotRotated ) {
return token , nil
}
if err != nil {
return nil , err
}
return newToken , nil
} )
if err != nil {
return nil , err
}
return res . ( * auth . UserToken ) , nil
}
func ( s * UserAuthTokenService ) rotateToken ( ctx context . Context , token * auth . UserToken , clientIP net . IP , userAgent string ) ( * auth . UserToken , error ) {
var clientIPStr string
if clientIP != nil {
clientIPStr = clientIP . String ( )
}
newToken , hashedToken , err := generateAndHashToken ( )
if err != nil {
return nil , err
}
sql := `
UPDATE user_auth_token
SET
seen_at = 0 ,
user_agent = ? ,
client_ip = ? ,
prev_auth_token = auth_token ,
auth_token = ? ,
auth_token_seen = ? ,
rotated_at = ?
WHERE id = ?
`
now := getTime ( )
var affected int64
err = s . sqlStore . WithTransactionalDbSession ( ctx , func ( dbSession * db . Session ) error {
res , err := dbSession . Exec ( sql , userAgent , clientIPStr , hashedToken , s . sqlStore . GetDialect ( ) . BooleanStr ( false ) , now . Unix ( ) , token . Id )
if err != nil {
return err
}
affected , err = res . RowsAffected ( )
return err
} )
if err != nil {
return nil , err
}
if affected < 1 {
return nil , errTokenNotRotated
}
token . PrevAuthToken = token . AuthToken
token . AuthToken = hashedToken
token . UnhashedToken = newToken
token . AuthTokenSeen = false
token . RotatedAt = now . Unix ( )
return token , nil
}
2022-11-18 09:56:06 +01:00
func ( s * UserAuthTokenService ) TryRotateToken ( ctx context . Context , token * auth . UserToken ,
2023-02-02 14:36:16 +01:00
clientIP net . IP , userAgent string ) ( bool , * auth . UserToken , error ) {
2019-02-02 12:11:30 +01:00
if token == nil {
2023-02-02 14:36:16 +01:00
return false , nil , nil
2019-02-02 12:11:30 +01:00
}
2019-10-22 14:08:18 +02:00
model , err := userAuthTokenFromUserToken ( token )
if err != nil {
2023-02-02 14:36:16 +01:00
return false , nil , err
2019-10-22 14:08:18 +02:00
}
2019-02-02 12:11:30 +01:00
now := getTime ( )
2023-02-02 14:36:16 +01:00
type rotationResult struct {
rotated bool
newToken * auth . UserToken
2019-02-02 12:11:30 +01:00
}
2023-08-30 08:46:47 -07:00
rotResult , err , _ := s . singleflight . Do ( fmt . Sprint ( model . Id ) , func ( ) ( any , error ) {
2023-02-02 14:36:16 +01:00
var needsRotation bool
rotatedAt := time . Unix ( model . RotatedAt , 0 )
if model . AuthTokenSeen {
needsRotation = rotatedAt . Before ( now . Add ( - time . Duration ( s . cfg . TokenRotationIntervalMinutes ) * time . Minute ) )
} else {
2023-03-23 14:39:04 +01:00
needsRotation = rotatedAt . Before ( now . Add ( - usertoken . UrgentRotateTime ) )
2023-02-02 14:36:16 +01:00
}
2019-02-02 12:11:30 +01:00
2023-02-02 14:36:16 +01:00
if ! needsRotation {
return & rotationResult { rotated : false } , nil
}
2019-02-02 12:11:30 +01:00
2023-02-02 14:36:16 +01:00
ctxLogger := s . log . FromContext ( ctx )
2023-09-04 18:49:47 +02:00
ctxLogger . Debug ( "Token needs rotation" , "tokenId" , model . Id , "authTokenSeen" , model . AuthTokenSeen , "rotatedAt" , rotatedAt )
2023-02-02 14:36:16 +01:00
clientIPStr := clientIP . String ( )
if len ( clientIP ) == 0 {
clientIPStr = ""
}
newToken , err := util . RandomHex ( 16 )
2019-04-30 14:42:01 +02:00
if err != nil {
2023-02-02 14:36:16 +01:00
return nil , err
}
hashedToken := hashToken ( newToken )
// very important that auth_token_seen is set after the prev_auth_token = case when ... for mysql to function correctly
sql := `
UPDATE user_auth_token
SET
seen_at = 0 ,
user_agent = ? ,
client_ip = ? ,
prev_auth_token = case when auth_token_seen = ? then auth_token else prev_auth_token end ,
auth_token = ? ,
auth_token_seen = ? ,
rotated_at = ?
WHERE id = ? AND ( auth_token_seen = ? OR rotated_at < ? ) `
var affected int64
err = s . sqlStore . WithTransactionalDbSession ( ctx , func ( dbSession * db . Session ) error {
res , err := dbSession . Exec ( sql , userAgent , clientIPStr , s . sqlStore . GetDialect ( ) . BooleanStr ( true ) , hashedToken ,
s . sqlStore . GetDialect ( ) . BooleanStr ( false ) , now . Unix ( ) , model . Id , s . sqlStore . GetDialect ( ) . BooleanStr ( true ) ,
now . Add ( - 30 * time . Second ) . Unix ( ) )
if err != nil {
return err
}
affected , err = res . RowsAffected ( )
2019-04-30 14:42:01 +02:00
return err
2023-02-02 14:36:16 +01:00
} )
if err != nil {
return nil , err
2019-04-30 14:42:01 +02:00
}
2023-02-02 14:36:16 +01:00
if affected > 0 {
2023-09-04 18:49:47 +02:00
ctxLogger . Debug ( "Auth token rotated" , "affected" , affected , "auth_token_id" , model . Id , "userId" , model . UserId )
2023-02-02 14:36:16 +01:00
model . UnhashedToken = newToken
var result auth . UserToken
if err := model . toUserToken ( & result ) ; err != nil {
return nil , err
}
return & rotationResult {
rotated : true ,
newToken : & result ,
} , nil
}
return & rotationResult { rotated : false } , nil
2019-04-30 14:42:01 +02:00
} )
2019-02-02 12:11:30 +01:00
if err != nil {
2023-02-02 14:36:16 +01:00
return false , nil , err
2019-02-02 12:11:30 +01:00
}
2023-02-02 14:36:16 +01:00
result := rotResult . ( * rotationResult )
2019-02-02 12:11:30 +01:00
2023-02-02 14:36:16 +01:00
return result . rotated , result . newToken , nil
2019-02-02 12:11:30 +01:00
}
2022-11-18 09:56:06 +01:00
func ( s * UserAuthTokenService ) RevokeToken ( ctx context . Context , token * auth . UserToken , soft bool ) error {
2019-02-02 12:11:30 +01:00
if token == nil {
2022-11-18 09:56:06 +01:00
return auth . ErrUserTokenNotFound
2019-02-02 12:11:30 +01:00
}
2019-10-22 14:08:18 +02:00
model , err := userAuthTokenFromUserToken ( token )
if err != nil {
return err
}
2019-02-02 12:11:30 +01:00
2019-04-30 14:42:01 +02:00
var rowsAffected int64
2021-03-16 17:44:02 +01:00
if soft {
model . RevokedAt = getTime ( ) . Unix ( )
2022-11-22 10:58:59 +01:00
err = s . sqlStore . WithDbSession ( ctx , func ( dbSession * db . Session ) error {
2021-03-16 17:44:02 +01:00
rowsAffected , err = dbSession . ID ( model . Id ) . Update ( model )
return err
} )
} else {
2022-11-22 10:58:59 +01:00
err = s . sqlStore . WithDbSession ( ctx , func ( dbSession * db . Session ) error {
2021-03-16 17:44:02 +01:00
rowsAffected , err = dbSession . Delete ( model )
return err
} )
}
2019-04-30 14:42:01 +02:00
2019-02-02 12:11:30 +01:00
if err != nil {
return err
}
2022-09-20 18:32:06 +02:00
ctxLogger := s . log . FromContext ( ctx )
2019-02-02 12:11:30 +01:00
if rowsAffected == 0 {
2023-09-04 18:49:47 +02:00
ctxLogger . Debug ( "User auth token not found/revoked" , "tokenId" , model . Id , "userId" , model . UserId , "clientIP" , model . ClientIp , "userAgent" , model . UserAgent )
2022-11-18 09:56:06 +01:00
return auth . ErrUserTokenNotFound
2019-02-02 12:11:30 +01:00
}
2023-09-04 18:49:47 +02:00
ctxLogger . Debug ( "User auth token revoked" , "tokenId" , model . Id , "userId" , model . UserId , "clientIP" , model . ClientIp , "userAgent" , model . UserAgent , "soft" , soft )
2019-02-02 12:11:30 +01:00
return nil
}
2019-04-30 14:42:01 +02:00
func ( s * UserAuthTokenService ) RevokeAllUserTokens ( ctx context . Context , userId int64 ) error {
2022-11-22 10:58:59 +01:00
return s . sqlStore . WithDbSession ( ctx , func ( dbSession * db . Session ) error {
2019-04-30 14:42:01 +02:00
sql := ` DELETE from user_auth_token WHERE user_id = ? `
res , err := dbSession . Exec ( sql , userId )
if err != nil {
return err
}
2019-03-08 15:15:17 +01:00
2019-04-30 14:42:01 +02:00
affected , err := res . RowsAffected ( )
if err != nil {
return err
}
2019-03-08 15:15:17 +01:00
2023-09-04 18:49:47 +02:00
s . log . FromContext ( ctx ) . Debug ( "All user tokens for user revoked" , "userId" , userId , "count" , affected )
2019-03-08 15:15:17 +01:00
2019-04-30 14:42:01 +02:00
return err
} )
2019-03-08 15:15:17 +01:00
}
2019-05-31 13:22:22 +03:00
func ( s * UserAuthTokenService ) BatchRevokeAllUserTokens ( ctx context . Context , userIds [ ] int64 ) error {
2022-11-22 10:58:59 +01:00
return s . sqlStore . WithTransactionalDbSession ( ctx , func ( dbSession * db . Session ) error {
2019-05-31 13:22:22 +03:00
if len ( userIds ) == 0 {
return nil
}
user_id_params := strings . Repeat ( ",?" , len ( userIds ) - 1 )
sql := "DELETE from user_auth_token WHERE user_id IN (?" + user_id_params + ")"
2023-08-30 08:46:47 -07:00
params := [ ] any { sql }
2019-05-31 13:22:22 +03:00
for _ , v := range userIds {
params = append ( params , v )
}
res , err := dbSession . Exec ( params ... )
if err != nil {
return err
}
affected , err := res . RowsAffected ( )
if err != nil {
return err
}
2023-09-04 18:49:47 +02:00
s . log . FromContext ( ctx ) . Debug ( "All user tokens for given users revoked" , "usersCount" , len ( userIds ) , "count" , affected )
2019-05-31 13:22:22 +03:00
return err
} )
}
2022-11-18 09:56:06 +01:00
func ( s * UserAuthTokenService ) GetUserToken ( ctx context . Context , userId , userTokenId int64 ) ( * auth . UserToken , error ) {
var result auth . UserToken
2022-11-22 10:58:59 +01:00
err := s . sqlStore . WithDbSession ( ctx , func ( dbSession * db . Session ) error {
2019-04-30 14:42:01 +02:00
var token userAuthToken
exists , err := dbSession . Where ( "id = ? AND user_id = ?" , userTokenId , userId ) . Get ( & token )
if err != nil {
return err
}
if ! exists {
2022-11-18 09:56:06 +01:00
return auth . ErrUserTokenNotFound
2019-04-30 14:42:01 +02:00
}
2019-10-22 14:08:18 +02:00
return token . toUserToken ( & result )
2019-04-30 14:42:01 +02:00
} )
2019-03-08 15:15:17 +01:00
2019-04-30 14:42:01 +02:00
return & result , err
2019-03-08 15:15:17 +01:00
}
2022-11-18 09:56:06 +01:00
func ( s * UserAuthTokenService ) GetUserTokens ( ctx context . Context , userId int64 ) ( [ ] * auth . UserToken , error ) {
result := [ ] * auth . UserToken { }
2022-11-22 10:58:59 +01:00
err := s . sqlStore . WithDbSession ( ctx , func ( dbSession * db . Session ) error {
2019-04-30 14:42:01 +02:00
var tokens [ ] * userAuthToken
2021-03-16 17:44:02 +01:00
err := dbSession . Where ( "user_id = ? AND created_at > ? AND rotated_at > ? AND revoked_at = 0" ,
2019-04-30 14:42:01 +02:00
userId ,
s . createdAfterParam ( ) ,
s . rotatedAfterParam ( ) ) .
Find ( & tokens )
if err != nil {
return err
}
for _ , token := range tokens {
2022-11-18 09:56:06 +01:00
var userToken auth . UserToken
2019-10-22 14:08:18 +02:00
if err := token . toUserToken ( & userToken ) ; err != nil {
return err
}
2019-04-30 14:42:01 +02:00
result = append ( result , & userToken )
}
return nil
} )
2019-03-08 15:15:17 +01:00
2019-04-30 14:42:01 +02:00
return result , err
2019-03-08 15:15:17 +01:00
}
2023-09-11 10:24:57 +02:00
// ActiveTokenCount returns the number of active tokens. If userID is nil, the count is for all users.
func ( s * UserAuthTokenService ) ActiveTokenCount ( ctx context . Context , userID * int64 ) ( int64 , error ) {
if userID != nil && * userID < 1 {
return 0 , errUserIDInvalid
}
var count int64
err := s . sqlStore . WithDbSession ( ctx , func ( dbSession * db . Session ) error {
query := ` SELECT COUNT(*) FROM user_auth_token WHERE created_at > ? AND rotated_at > ? AND revoked_at = 0 `
args := [ ] interface { } { s . createdAfterParam ( ) , s . rotatedAfterParam ( ) }
if userID != nil {
query += " AND user_id = ?"
args = append ( args , * userID )
}
_ , err := dbSession . SQL ( query , args ... ) . Get ( & count )
return err
} )
return count , err
}
2022-11-18 09:56:06 +01:00
func ( s * UserAuthTokenService ) GetUserRevokedTokens ( ctx context . Context , userId int64 ) ( [ ] * auth . UserToken , error ) {
result := [ ] * auth . UserToken { }
2022-11-22 10:58:59 +01:00
err := s . sqlStore . WithDbSession ( ctx , func ( dbSession * db . Session ) error {
2021-03-16 17:44:02 +01:00
var tokens [ ] * userAuthToken
err := dbSession . Where ( "user_id = ? AND revoked_at > 0" , userId ) . Find ( & tokens )
if err != nil {
return err
}
for _ , token := range tokens {
2022-11-18 09:56:06 +01:00
var userToken auth . UserToken
2021-03-16 17:44:02 +01:00
if err := token . toUserToken ( & userToken ) ; err != nil {
return err
}
result = append ( result , & userToken )
}
return nil
} )
return result , err
}
2022-11-22 10:58:59 +01:00
func ( s * UserAuthTokenService ) reportActiveTokenCount ( ctx context . Context , _ * quota . ScopeParameters ) ( * quota . Map , error ) {
2023-09-11 10:24:57 +02:00
count , err := s . ActiveTokenCount ( ctx , nil )
if err != nil {
return nil , err
}
2022-11-22 10:58:59 +01:00
tag , err := quota . NewTag ( auth . QuotaTargetSrv , auth . QuotaTarget , quota . GlobalScope )
if err != nil {
return nil , err
}
2023-09-11 10:24:57 +02:00
2022-11-22 10:58:59 +01:00
u := & quota . Map { }
u . Set ( tag , count )
return u , err
}
2019-02-11 21:12:01 +01:00
func ( s * UserAuthTokenService ) createdAfterParam ( ) int64 {
2022-11-22 10:58:59 +01:00
return getTime ( ) . Add ( - s . cfg . LoginMaxLifetime ) . Unix ( )
2019-02-11 21:12:01 +01:00
}
func ( s * UserAuthTokenService ) rotatedAfterParam ( ) int64 {
2022-11-22 10:58:59 +01:00
return getTime ( ) . Add ( - s . cfg . LoginMaxInactiveLifetime ) . Unix ( )
2019-02-11 21:12:01 +01:00
}
2023-03-23 14:39:04 +01:00
func createToken ( ) ( string , error ) {
token , err := util . RandomHex ( 16 )
if err != nil {
return "" , err
}
return token , nil
}
2019-02-02 12:11:30 +01:00
func hashToken ( token string ) string {
hashBytes := sha256 . Sum256 ( [ ] byte ( token + setting . SecretKey ) )
return hex . EncodeToString ( hashBytes [ : ] )
}
2022-11-14 21:08:10 +02:00
2023-03-23 14:39:04 +01:00
func generateAndHashToken ( ) ( string , string , error ) {
token , err := createToken ( )
if err != nil {
return "" , "" , err
}
return token , hashToken ( token ) , nil
}
2022-11-14 21:08:10 +02:00
func readQuotaConfig ( cfg * setting . Cfg ) ( * quota . Map , error ) {
limits := & quota . Map { }
if cfg == nil {
return limits , nil
}
2022-11-18 09:56:06 +01:00
globalQuotaTag , err := quota . NewTag ( auth . QuotaTargetSrv , auth . QuotaTarget , quota . GlobalScope )
2022-11-14 21:08:10 +02:00
if err != nil {
return limits , err
}
limits . Set ( globalQuotaTag , cfg . Quota . Global . Session )
return limits , nil
}