-
This commit is contained in:
@ -8,6 +8,8 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/kms/api-key-service/internal/auth"
|
||||
"github.com/kms/api-key-service/internal/config"
|
||||
"github.com/kms/api-key-service/internal/crypto"
|
||||
"github.com/kms/api-key-service/internal/domain"
|
||||
"github.com/kms/api-key-service/internal/repository"
|
||||
@ -20,6 +22,7 @@ type tokenService struct {
|
||||
permRepo repository.PermissionRepository
|
||||
grantRepo repository.GrantedPermissionRepository
|
||||
tokenGen *crypto.TokenGenerator
|
||||
jwtManager *auth.JWTManager
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
@ -30,15 +33,17 @@ func NewTokenService(
|
||||
permRepo repository.PermissionRepository,
|
||||
grantRepo repository.GrantedPermissionRepository,
|
||||
hmacKey string,
|
||||
config config.ConfigProvider,
|
||||
logger *zap.Logger,
|
||||
) TokenService {
|
||||
return &tokenService{
|
||||
tokenRepo: tokenRepo,
|
||||
appRepo: appRepo,
|
||||
permRepo: permRepo,
|
||||
grantRepo: grantRepo,
|
||||
tokenGen: crypto.NewTokenGenerator(hmacKey),
|
||||
logger: logger,
|
||||
tokenRepo: tokenRepo,
|
||||
appRepo: appRepo,
|
||||
permRepo: permRepo,
|
||||
grantRepo: grantRepo,
|
||||
tokenGen: crypto.NewTokenGenerator(hmacKey),
|
||||
jwtManager: auth.NewJWTManager(config, logger),
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,11 +202,57 @@ func (s *tokenService) Delete(ctx context.Context, tokenID uuid.UUID, userID str
|
||||
func (s *tokenService) GenerateUserToken(ctx context.Context, appID, userID string, permissions []string) (string, error) {
|
||||
s.logger.Info("Generating user token", zap.String("app_id", appID), zap.String("user_id", userID))
|
||||
|
||||
// TODO: Validate application
|
||||
// TODO: Validate permissions
|
||||
// TODO: Generate JWT token
|
||||
// Validate application exists
|
||||
app, err := s.appRepo.GetByID(ctx, appID)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get application", zap.Error(err), zap.String("app_id", appID))
|
||||
return "", fmt.Errorf("application not found: %w", err)
|
||||
}
|
||||
|
||||
return "user-token-placeholder-" + userID, nil
|
||||
// Validate permissions exist (if any provided)
|
||||
var validPermissions []string
|
||||
if len(permissions) > 0 {
|
||||
validPermissions, err = s.permRepo.ValidatePermissionScopes(ctx, permissions)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to validate permissions", zap.Error(err))
|
||||
return "", fmt.Errorf("failed to validate permissions: %w", err)
|
||||
}
|
||||
|
||||
if len(validPermissions) != len(permissions) {
|
||||
s.logger.Warn("Some permissions are invalid",
|
||||
zap.Strings("requested", permissions),
|
||||
zap.Strings("valid", validPermissions))
|
||||
return "", fmt.Errorf("some requested permissions are invalid")
|
||||
}
|
||||
}
|
||||
|
||||
// Create user token with proper timing
|
||||
now := time.Now()
|
||||
userToken := &domain.UserToken{
|
||||
AppID: appID,
|
||||
UserID: userID,
|
||||
Permissions: validPermissions,
|
||||
IssuedAt: now,
|
||||
ExpiresAt: now.Add(app.TokenRenewalDuration.Duration),
|
||||
MaxValidAt: now.Add(app.MaxTokenDuration.Duration),
|
||||
TokenType: domain.TokenTypeUser,
|
||||
}
|
||||
|
||||
// Generate JWT token using JWT manager
|
||||
tokenString, err := s.jwtManager.GenerateToken(userToken)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to generate JWT token", zap.Error(err))
|
||||
return "", fmt.Errorf("failed to generate token: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("User token generated successfully",
|
||||
zap.String("app_id", appID),
|
||||
zap.String("user_id", userID),
|
||||
zap.Strings("permissions", validPermissions),
|
||||
zap.Time("expires_at", userToken.ExpiresAt),
|
||||
zap.Time("max_valid_at", userToken.MaxValidAt))
|
||||
|
||||
return tokenString, nil
|
||||
}
|
||||
|
||||
// VerifyToken verifies a token and returns verification response
|
||||
@ -338,12 +389,101 @@ func (s *tokenService) verifyStaticToken(ctx context.Context, req *domain.Verify
|
||||
func (s *tokenService) verifyUserToken(ctx context.Context, req *domain.VerifyRequest, app *domain.Application) (*domain.VerifyResponse, error) {
|
||||
s.logger.Debug("Verifying user token", zap.String("app_id", req.AppID))
|
||||
|
||||
// TODO: Implement JWT token verification
|
||||
// For now, return an error since user tokens are not fully implemented
|
||||
// Check if token is revoked first
|
||||
isRevoked, err := s.jwtManager.IsTokenRevoked(req.Token)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to check token revocation status", zap.Error(err))
|
||||
return &domain.VerifyResponse{
|
||||
Valid: false,
|
||||
Permitted: false,
|
||||
Error: "Token verification failed",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if isRevoked {
|
||||
s.logger.Warn("Token is revoked", zap.String("app_id", req.AppID))
|
||||
return &domain.VerifyResponse{
|
||||
Valid: false,
|
||||
Permitted: false,
|
||||
Error: "Token has been revoked",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Validate JWT token
|
||||
claims, err := s.jwtManager.ValidateToken(req.Token)
|
||||
if err != nil {
|
||||
s.logger.Warn("JWT token validation failed", zap.Error(err), zap.String("app_id", req.AppID))
|
||||
return &domain.VerifyResponse{
|
||||
Valid: false,
|
||||
Permitted: false,
|
||||
Error: "Invalid token",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Verify the token is for the correct application
|
||||
if claims.AppID != req.AppID {
|
||||
s.logger.Warn("Token app_id mismatch",
|
||||
zap.String("expected", req.AppID),
|
||||
zap.String("actual", claims.AppID))
|
||||
return &domain.VerifyResponse{
|
||||
Valid: false,
|
||||
Permitted: false,
|
||||
Error: "Token not valid for this application",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Check specific permissions if requested
|
||||
var permissionResults map[string]bool
|
||||
var permitted bool = true // Default to true if no specific permissions requested
|
||||
|
||||
if len(req.Permissions) > 0 {
|
||||
permissionResults = make(map[string]bool)
|
||||
|
||||
// Check each requested permission against token permissions
|
||||
for _, requestedPerm := range req.Permissions {
|
||||
hasPermission := false
|
||||
for _, tokenPerm := range claims.Permissions {
|
||||
if tokenPerm == requestedPerm {
|
||||
hasPermission = true
|
||||
break
|
||||
}
|
||||
}
|
||||
permissionResults[requestedPerm] = hasPermission
|
||||
|
||||
// If any permission is missing, set permitted to false
|
||||
if !hasPermission {
|
||||
permitted = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert timestamps
|
||||
var expiresAt, maxValidAt *time.Time
|
||||
if claims.ExpiresAt != nil {
|
||||
expTime := claims.ExpiresAt.Time
|
||||
expiresAt = &expTime
|
||||
}
|
||||
if claims.MaxValidAt > 0 {
|
||||
maxTime := time.Unix(claims.MaxValidAt, 0)
|
||||
maxValidAt = &maxTime
|
||||
}
|
||||
|
||||
s.logger.Info("User token verified successfully",
|
||||
zap.String("user_id", claims.UserID),
|
||||
zap.String("app_id", req.AppID),
|
||||
zap.Strings("permissions", claims.Permissions),
|
||||
zap.Bool("permitted", permitted))
|
||||
|
||||
return &domain.VerifyResponse{
|
||||
Valid: false,
|
||||
Permitted: false,
|
||||
Error: "User token verification not yet implemented",
|
||||
Valid: true,
|
||||
Permitted: permitted,
|
||||
UserID: claims.UserID,
|
||||
Permissions: claims.Permissions,
|
||||
PermissionResults: permissionResults,
|
||||
ExpiresAt: expiresAt,
|
||||
MaxValidAt: maxValidAt,
|
||||
TokenType: domain.TokenTypeUser,
|
||||
Claims: claims.Claims,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user