This commit is contained in:
2025-08-22 14:40:59 -04:00
parent 98a299e7b2
commit 141b1e936d
12 changed files with 1973 additions and 61 deletions

View File

@ -8,17 +8,19 @@ import (
"github.com/google/uuid"
"go.uber.org/zap"
"github.com/kms/api-key-service/internal/crypto"
"github.com/kms/api-key-service/internal/domain"
"github.com/kms/api-key-service/internal/repository"
)
// tokenService implements the TokenService interface
type tokenService struct {
tokenRepo repository.StaticTokenRepository
appRepo repository.ApplicationRepository
permRepo repository.PermissionRepository
grantRepo repository.GrantedPermissionRepository
logger *zap.Logger
tokenRepo repository.StaticTokenRepository
appRepo repository.ApplicationRepository
permRepo repository.PermissionRepository
grantRepo repository.GrantedPermissionRepository
tokenGen *crypto.TokenGenerator
logger *zap.Logger
}
// NewTokenService creates a new token service
@ -27,6 +29,7 @@ func NewTokenService(
appRepo repository.ApplicationRepository,
permRepo repository.PermissionRepository,
grantRepo repository.GrantedPermissionRepository,
hmacKey string,
logger *zap.Logger,
) TokenService {
return &tokenService{
@ -34,6 +37,7 @@ func NewTokenService(
appRepo: appRepo,
permRepo: permRepo,
grantRepo: grantRepo,
tokenGen: crypto.NewTokenGenerator(hmacKey),
logger: logger,
}
}
@ -42,10 +46,33 @@ func NewTokenService(
func (s *tokenService) CreateStaticToken(ctx context.Context, req *domain.CreateStaticTokenRequest, userID string) (*domain.CreateStaticTokenResponse, error) {
s.logger.Info("Creating static token", zap.String("app_id", req.AppID), zap.String("user_id", userID))
// TODO: Validate permissions
// TODO: Validate application exists
// TODO: Generate secure token
// TODO: Grant permissions
// Validate application exists
app, err := s.appRepo.GetByID(ctx, req.AppID)
if err != nil {
s.logger.Error("Failed to get application", zap.Error(err), zap.String("app_id", req.AppID))
return nil, fmt.Errorf("application not found: %w", err)
}
// Validate permissions exist
validPermissions, err := s.permRepo.ValidatePermissionScopes(ctx, req.Permissions)
if err != nil {
s.logger.Error("Failed to validate permissions", zap.Error(err))
return nil, fmt.Errorf("failed to validate permissions: %w", err)
}
if len(validPermissions) != len(req.Permissions) {
s.logger.Warn("Some permissions are invalid",
zap.Strings("requested", req.Permissions),
zap.Strings("valid", validPermissions))
return nil, fmt.Errorf("some requested permissions are invalid")
}
// Generate secure token
tokenInfo, err := s.tokenGen.GenerateTokenWithInfo()
if err != nil {
s.logger.Error("Failed to generate secure token", zap.Error(err))
return nil, fmt.Errorf("failed to generate token: %w", err)
}
tokenID := uuid.New()
now := time.Now()
@ -54,32 +81,62 @@ func (s *tokenService) CreateStaticToken(ctx context.Context, req *domain.Create
token := &domain.StaticToken{
ID: tokenID,
AppID: req.AppID,
Owner: domain.Owner{
Type: domain.OwnerTypeIndividual,
Name: userID,
Owner: userID,
},
KeyHash: "placeholder-hash-" + tokenID.String(),
Type: "hmac",
Owner: req.Owner,
KeyHash: tokenInfo.Hash,
Type: "hmac",
CreatedAt: now,
UpdatedAt: now,
}
// Save the token to the database
err := s.tokenRepo.Create(ctx, token)
err = s.tokenRepo.Create(ctx, token)
if err != nil {
s.logger.Error("Failed to create token in database", zap.Error(err), zap.String("token_id", tokenID.String()))
return nil, fmt.Errorf("failed to create token: %w", err)
}
// Grant permissions to the token
var grants []*domain.GrantedPermission
for _, permScope := range validPermissions {
// Get permission by scope to get the ID
perm, err := s.permRepo.GetAvailablePermissionByScope(ctx, permScope)
if err != nil {
s.logger.Error("Failed to get permission by scope", zap.Error(err), zap.String("scope", permScope))
continue
}
grant := &domain.GrantedPermission{
ID: uuid.New(),
TokenType: domain.TokenTypeStatic,
TokenID: tokenID,
PermissionID: perm.ID,
Scope: permScope,
CreatedBy: userID,
}
grants = append(grants, grant)
}
if len(grants) > 0 {
err = s.grantRepo.GrantPermissions(ctx, grants)
if err != nil {
s.logger.Error("Failed to grant permissions", zap.Error(err))
// Clean up the token if permission granting fails
s.tokenRepo.Delete(ctx, tokenID)
return nil, fmt.Errorf("failed to grant permissions: %w", err)
}
}
response := &domain.CreateStaticTokenResponse{
ID: tokenID,
Token: "static-token-placeholder-" + tokenID.String(),
Permissions: req.Permissions,
Token: tokenInfo.Token, // Return the actual token only once
Permissions: validPermissions,
CreatedAt: now,
}
s.logger.Info("Static token created successfully", zap.String("token_id", tokenID.String()))
s.logger.Info("Static token created successfully",
zap.String("token_id", tokenID.String()),
zap.String("app_id", app.AppID),
zap.Strings("permissions", validPermissions))
return response, nil
}