feat: new ValidateToken method for AuthService, based on code from the monolithic implementation of auth middleware;
feat: add detailed authentication error types;
This commit is contained in:
@@ -29,4 +29,10 @@ var (
|
|||||||
ErrInvalidCredentials = errors.New("Invalid username, password or TOTP code")
|
ErrInvalidCredentials = errors.New("Invalid username, password or TOTP code")
|
||||||
ErrInvalidToken = errors.New("Token is invalid or expired")
|
ErrInvalidToken = errors.New("Token is invalid or expired")
|
||||||
ErrServerError = errors.New("Internal server error")
|
ErrServerError = errors.New("Internal server error")
|
||||||
|
|
||||||
|
ErrTokenExpired = errors.New("Token is expired")
|
||||||
|
ErrTokenInvalid = errors.New("Token is invalid")
|
||||||
|
ErrWrongTokenType = errors.New("Invalid token type")
|
||||||
|
ErrSessionNotFound = errors.New("Could not find session in database")
|
||||||
|
ErrSessionTerminated = errors.New("Session is terminated")
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -601,7 +601,85 @@ func (a *authServiceImpl) Refresh(request models.RefreshRequest) (*models.Refres
|
|||||||
return nil, errs.ErrNotImplemented
|
return nil, errs.ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *authServiceImpl) ValidateToken(token string, tokenType enums.JwtTokenType) (*dto.SessionInfo, error) {
|
func (a *authServiceImpl) ValidateToken(jwtToken string, tokenType enums.JwtTokenType) (*dto.SessionInfo, error) {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
token, err := jwt.ParseWithClaims(
|
||||||
|
jwtToken,
|
||||||
|
&dto.UserClaims{},
|
||||||
|
func(token *jwt.Token) (any, error) {
|
||||||
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
|
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||||
|
}
|
||||||
|
return []byte(config.GetConfig().JwtSecret), nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, jwt.ErrTokenExpired) {
|
||||||
|
return nil, errs.ErrTokenExpired
|
||||||
|
}
|
||||||
|
return nil, errs.ErrInvalidToken
|
||||||
|
}
|
||||||
|
|
||||||
|
if claims, ok := token.Claims.(*dto.UserClaims); ok && token.Valid {
|
||||||
|
|
||||||
|
if claims.Type != tokenType {
|
||||||
|
return nil, errs.ErrWrongTokenType
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.TODO()
|
||||||
|
isTerminated, redisErr := a.redis.Get(ctx, fmt.Sprintf("session::%s::is_terminated", claims.Session)).Bool()
|
||||||
|
if redisErr != nil && redisErr != redis.Nil {
|
||||||
|
a.log.Error(
|
||||||
|
"Failed to lookup cache to check whether session is not terminated",
|
||||||
|
zap.Error(redisErr))
|
||||||
|
return nil, redisErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache if nil
|
||||||
|
if redisErr == redis.Nil {
|
||||||
|
db := database.NewDbHelper(a.dbctx)
|
||||||
|
|
||||||
|
session, err := db.Queries.GetSessionByGuid(db.CTX, claims.Session)
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
a.log.Warn(
|
||||||
|
"Session does not exist or was deleted",
|
||||||
|
zap.String("session", claims.Session))
|
||||||
|
return nil, errs.ErrSessionNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
a.log.Error(
|
||||||
|
"Failed to lookup session in database",
|
||||||
|
zap.String("session", claims.Session),
|
||||||
|
zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.redis.Set(
|
||||||
|
ctx,
|
||||||
|
fmt.Sprintf("session::%s::is_terminated", claims.Session),
|
||||||
|
session.Terminated,
|
||||||
|
time.Duration(8 * time.Hour), // XXX: magic number
|
||||||
|
).Err(); err != nil {
|
||||||
|
a.log.Error(
|
||||||
|
"Failed to cache session's is_terminated state",
|
||||||
|
zap.String("session", claims.Session),
|
||||||
|
zap.Error(err))
|
||||||
|
// c.AbortWithStatus(http.StatusInternalServerError)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
isTerminated = *session.Terminated
|
||||||
|
}
|
||||||
|
|
||||||
|
if isTerminated {
|
||||||
|
return nil, errs.ErrSessionTerminated
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil, errs.ErrNotImplemented
|
return nil, errs.ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user