feat: add user role support to database and queries;
fix: add max length validation for refresh token in RefreshRequest; refactor: use named constants for cache durations in AuthService; refactor: select all user columns in GetValidUserByLoginCredentials query;
This commit is contained in:
@@ -38,6 +38,11 @@ import (
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var (
|
||||
AuthTerminatedSessionCacheDuration = time.Duration(8 * time.Hour)
|
||||
AuthRegistrationCooldownCacheDuration = time.Duration(10 * time.Minute)
|
||||
)
|
||||
|
||||
type AuthService interface {
|
||||
RegistrationBegin(request models.RegistrationBeginRequest) (bool, error)
|
||||
RegistrationComplete(cinfo dto.ClientInfo, request models.RegistrationCompleteRequest) (*models.RegistrationCompleteResponse, error)
|
||||
@@ -87,7 +92,7 @@ func NewAuthService(_log *zap.Logger, _dbctx database.DbContext, _redis *redis.C
|
||||
pipe := _redis.Pipeline()
|
||||
for _, guid := range guids {
|
||||
key := fmt.Sprintf("session::%s::is_terminated", guid)
|
||||
pipe.Set(ctx, key, true, time.Duration(8 * time.Hour)) // XXX: magic number
|
||||
pipe.Set(ctx, key, true, AuthTerminatedSessionCacheDuration)
|
||||
}
|
||||
|
||||
if _, err := pipe.Exec(ctx); err != nil {
|
||||
@@ -122,7 +127,12 @@ func (a *authServiceImpl) terminateAllSessionsForUser(ctx context.Context, usern
|
||||
|
||||
pipe := a.redis.Pipeline()
|
||||
for _, guid := range sessionGuids {
|
||||
pipe.Set(ctx, fmt.Sprintf("session::%s::is_terminated", guid), true, time.Duration(8 * time.Hour)) // XXX: magic number
|
||||
pipe.Set(
|
||||
ctx,
|
||||
fmt.Sprintf("session::%s::is_terminated", guid),
|
||||
true,
|
||||
AuthTerminatedSessionCacheDuration,
|
||||
)
|
||||
}
|
||||
|
||||
if _, err := pipe.Exec(ctx); err != nil {
|
||||
@@ -219,7 +229,7 @@ func (a *authServiceImpl) RegistrationBegin(request models.RegistrationBeginRequ
|
||||
context.TODO(),
|
||||
fmt.Sprintf("email::%s::registration_in_progress", request.Email),
|
||||
true,
|
||||
time.Duration(10*time.Minute), // XXX: magic number
|
||||
AuthRegistrationCooldownCacheDuration,
|
||||
).Err(); err != nil {
|
||||
a.log.Error(
|
||||
"Failed to falsely set cache registration_in_progress state for email as a measure to prevent email enumeration",
|
||||
@@ -324,7 +334,7 @@ func (a *authServiceImpl) RegistrationBegin(request models.RegistrationBeginRequ
|
||||
context.TODO(),
|
||||
fmt.Sprintf("email::%s::registration_in_progress", request.Email),
|
||||
true,
|
||||
time.Duration(10*time.Minute), // XXX: magic number
|
||||
AuthTerminatedSessionCacheDuration,
|
||||
).Err(); err != nil {
|
||||
a.log.Error(
|
||||
"Failed to cache registration_in_progress state for email",
|
||||
@@ -453,8 +463,7 @@ func (a *authServiceImpl) RegistrationComplete(cinfo dto.ClientInfo, request mod
|
||||
return nil, errs.ErrServerError
|
||||
}
|
||||
|
||||
// TODO: get user role
|
||||
accessToken, refreshToken, err = utils.GenerateTokens(user.Username, session.Guid.String(), enums.UserRole)
|
||||
accessToken, refreshToken, err = utils.GenerateTokens(user.Username, session.Guid.String(), enums.Role(user.Role))
|
||||
|
||||
if err != nil {
|
||||
a.log.Error(
|
||||
@@ -483,7 +492,6 @@ func (a *authServiceImpl) RegistrationComplete(cinfo dto.ClientInfo, request mod
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// TODO: totp
|
||||
func (a *authServiceImpl) Login(cinfo dto.ClientInfo, request models.LoginRequest) (*models.LoginResponse, error) {
|
||||
var userRow database.GetValidUserByLoginCredentialsRow
|
||||
var err error
|
||||
@@ -500,12 +508,7 @@ func (a *authServiceImpl) Login(cinfo dto.ClientInfo, request models.LoginReques
|
||||
userRow, err = db.TXQueries.GetValidUserByLoginCredentials(db.CTX, database.GetValidUserByLoginCredentialsParams{
|
||||
Username: request.Username,
|
||||
Password: request.Password,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
a.log.Warn(
|
||||
"Failed login attempt",
|
||||
zap.Error(err))
|
||||
}); if err != nil {
|
||||
|
||||
var returnedError error
|
||||
|
||||
@@ -516,6 +519,9 @@ func (a *authServiceImpl) Login(cinfo dto.ClientInfo, request models.LoginReques
|
||||
returnedError = errs.ErrServerError
|
||||
}
|
||||
|
||||
a.log.Warn(
|
||||
"Failed login attempt",
|
||||
zap.Error(err))
|
||||
return nil, returnedError
|
||||
}
|
||||
|
||||
@@ -532,9 +538,11 @@ func (a *authServiceImpl) Login(cinfo dto.ClientInfo, request models.LoginReques
|
||||
return nil, errs.ErrServerError
|
||||
}
|
||||
|
||||
// TODO: get user role
|
||||
accessToken, refreshToken, err := utils.GenerateTokens(userRow.Username, session.Guid.String(), enums.UserRole)
|
||||
if err != nil {
|
||||
accessToken, refreshToken, err := utils.GenerateTokens(
|
||||
userRow.Username,
|
||||
session.Guid.String(),
|
||||
enums.Role(userRow.Role),
|
||||
); if err != nil {
|
||||
a.log.Error(
|
||||
"Failed to generate tokens for a new login",
|
||||
zap.String("username", userRow.Username),
|
||||
@@ -666,7 +674,7 @@ func (a *authServiceImpl) ValidateToken(jwtToken string, tokenType enums.JwtToke
|
||||
ctx,
|
||||
fmt.Sprintf("session::%s::is_terminated", claims.Session),
|
||||
*session.Terminated,
|
||||
time.Duration(8*time.Hour), // XXX: magic number
|
||||
AuthTerminatedSessionCacheDuration,
|
||||
).Err(); err != nil {
|
||||
a.log.Error(
|
||||
"Failed to cache session's is_terminated state",
|
||||
@@ -902,8 +910,11 @@ func (a *authServiceImpl) PasswordResetComplete(request models.PasswordResetComp
|
||||
zap.Error(err))
|
||||
}
|
||||
|
||||
// TODO: get user role
|
||||
if accessToken, refreshToken, err = utils.GenerateTokens(user.Username, session.Guid.String(), enums.UserRole); err != nil {
|
||||
if accessToken, refreshToken, err = utils.GenerateTokens(
|
||||
user.Username,
|
||||
session.Guid.String(),
|
||||
enums.UserRole,
|
||||
); err != nil {
|
||||
a.log.Error(
|
||||
"Failed to generate tokens as part of user password reset",
|
||||
zap.String("email", request.Email),
|
||||
|
||||
Reference in New Issue
Block a user