v0
This commit is contained in:
126
internal/services/application_service.go
Normal file
126
internal/services/application_service.go
Normal file
@ -0,0 +1,126 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/kms/api-key-service/internal/domain"
|
||||
"github.com/kms/api-key-service/internal/repository"
|
||||
)
|
||||
|
||||
// applicationService implements the ApplicationService interface
|
||||
type applicationService struct {
|
||||
appRepo repository.ApplicationRepository
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewApplicationService creates a new application service
|
||||
func NewApplicationService(appRepo repository.ApplicationRepository, logger *zap.Logger) ApplicationService {
|
||||
return &applicationService{
|
||||
appRepo: appRepo,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Create creates a new application
|
||||
func (s *applicationService) Create(ctx context.Context, req *domain.CreateApplicationRequest, userID string) (*domain.Application, error) {
|
||||
s.logger.Info("Creating application", zap.String("app_id", req.AppID), zap.String("user_id", userID))
|
||||
|
||||
// TODO: Add permission validation
|
||||
// TODO: Add input validation using validator
|
||||
|
||||
app := &domain.Application{
|
||||
AppID: req.AppID,
|
||||
AppLink: req.AppLink,
|
||||
Type: req.Type,
|
||||
CallbackURL: req.CallbackURL,
|
||||
HMACKey: generateHMACKey(), // TODO: Use proper key generation
|
||||
TokenRenewalDuration: req.TokenRenewalDuration,
|
||||
MaxTokenDuration: req.MaxTokenDuration,
|
||||
Owner: req.Owner,
|
||||
}
|
||||
|
||||
if err := s.appRepo.Create(ctx, app); err != nil {
|
||||
s.logger.Error("Failed to create application", zap.Error(err), zap.String("app_id", req.AppID))
|
||||
return nil, fmt.Errorf("failed to create application: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("Application created successfully", zap.String("app_id", app.AppID))
|
||||
return app, nil
|
||||
}
|
||||
|
||||
// GetByID retrieves an application by its ID
|
||||
func (s *applicationService) GetByID(ctx context.Context, appID string) (*domain.Application, error) {
|
||||
s.logger.Debug("Getting application by ID", zap.String("app_id", appID))
|
||||
|
||||
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 nil, fmt.Errorf("failed to get application: %w", err)
|
||||
}
|
||||
|
||||
return app, nil
|
||||
}
|
||||
|
||||
// List retrieves applications with pagination
|
||||
func (s *applicationService) List(ctx context.Context, limit, offset int) ([]*domain.Application, error) {
|
||||
s.logger.Debug("Listing applications", zap.Int("limit", limit), zap.Int("offset", offset))
|
||||
|
||||
if limit <= 0 {
|
||||
limit = 50 // Default limit
|
||||
}
|
||||
if limit > 100 {
|
||||
limit = 100 // Max limit
|
||||
}
|
||||
|
||||
apps, err := s.appRepo.List(ctx, limit, offset)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to list applications", zap.Error(err))
|
||||
return nil, fmt.Errorf("failed to list applications: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Debug("Listed applications", zap.Int("count", len(apps)))
|
||||
return apps, nil
|
||||
}
|
||||
|
||||
// Update updates an existing application
|
||||
func (s *applicationService) Update(ctx context.Context, appID string, updates *domain.UpdateApplicationRequest, userID string) (*domain.Application, error) {
|
||||
s.logger.Info("Updating application", zap.String("app_id", appID), zap.String("user_id", userID))
|
||||
|
||||
// TODO: Add permission validation
|
||||
// TODO: Add input validation
|
||||
|
||||
app, err := s.appRepo.Update(ctx, appID, updates)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to update application", zap.Error(err), zap.String("app_id", appID))
|
||||
return nil, fmt.Errorf("failed to update application: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("Application updated successfully", zap.String("app_id", appID))
|
||||
return app, nil
|
||||
}
|
||||
|
||||
// Delete deletes an application
|
||||
func (s *applicationService) Delete(ctx context.Context, appID string, userID string) error {
|
||||
s.logger.Info("Deleting application", zap.String("app_id", appID), zap.String("user_id", userID))
|
||||
|
||||
// TODO: Add permission validation
|
||||
// TODO: Check for existing tokens and handle appropriately
|
||||
|
||||
if err := s.appRepo.Delete(ctx, appID); err != nil {
|
||||
s.logger.Error("Failed to delete application", zap.Error(err), zap.String("app_id", appID))
|
||||
return fmt.Errorf("failed to delete application: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("Application deleted successfully", zap.String("app_id", appID))
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateHMACKey generates a secure HMAC key
|
||||
// TODO: Replace with proper cryptographic key generation
|
||||
func generateHMACKey() string {
|
||||
// This is a placeholder - should use proper crypto/rand
|
||||
return "generated-hmac-key-placeholder"
|
||||
}
|
||||
65
internal/services/auth_service.go
Normal file
65
internal/services/auth_service.go
Normal file
@ -0,0 +1,65 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/kms/api-key-service/internal/config"
|
||||
)
|
||||
|
||||
// authenticationService implements the AuthenticationService interface
|
||||
type authenticationService struct {
|
||||
config config.ConfigProvider
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewAuthenticationService creates a new authentication service
|
||||
func NewAuthenticationService(config config.ConfigProvider, logger *zap.Logger) AuthenticationService {
|
||||
return &authenticationService{
|
||||
config: config,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// GetUserID extracts user ID from context
|
||||
func (s *authenticationService) GetUserID(ctx context.Context) (string, error) {
|
||||
// For now, this is a simple implementation
|
||||
// In a real implementation, this would extract from JWT tokens, session, etc.
|
||||
|
||||
if userID, ok := ctx.Value("user_id").(string); ok {
|
||||
return userID, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("user ID not found in context")
|
||||
}
|
||||
|
||||
// ValidatePermissions checks if user has required permissions
|
||||
func (s *authenticationService) ValidatePermissions(ctx context.Context, userID string, appID string, requiredPermissions []string) error {
|
||||
s.logger.Debug("Validating permissions",
|
||||
zap.String("user_id", userID),
|
||||
zap.String("app_id", appID),
|
||||
zap.Strings("required_permissions", requiredPermissions))
|
||||
|
||||
// TODO: Implement actual permission validation
|
||||
// For now, we'll just allow all requests
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUserClaims retrieves user claims
|
||||
func (s *authenticationService) GetUserClaims(ctx context.Context, userID string) (map[string]string, error) {
|
||||
s.logger.Debug("Getting user claims", zap.String("user_id", userID))
|
||||
|
||||
// TODO: Implement actual claims retrieval
|
||||
// For now, return basic claims
|
||||
|
||||
claims := map[string]string{
|
||||
"user_id": userID,
|
||||
"email": userID, // Assuming user_id is email for now
|
||||
"name": "Test User",
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
}
|
||||
59
internal/services/interfaces.go
Normal file
59
internal/services/interfaces.go
Normal file
@ -0,0 +1,59 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/kms/api-key-service/internal/domain"
|
||||
)
|
||||
|
||||
// ApplicationService defines the interface for application business logic
|
||||
type ApplicationService interface {
|
||||
// Create creates a new application
|
||||
Create(ctx context.Context, req *domain.CreateApplicationRequest, userID string) (*domain.Application, error)
|
||||
|
||||
// GetByID retrieves an application by its ID
|
||||
GetByID(ctx context.Context, appID string) (*domain.Application, error)
|
||||
|
||||
// List retrieves applications with pagination
|
||||
List(ctx context.Context, limit, offset int) ([]*domain.Application, error)
|
||||
|
||||
// Update updates an existing application
|
||||
Update(ctx context.Context, appID string, updates *domain.UpdateApplicationRequest, userID string) (*domain.Application, error)
|
||||
|
||||
// Delete deletes an application
|
||||
Delete(ctx context.Context, appID string, userID string) error
|
||||
}
|
||||
|
||||
// TokenService defines the interface for token business logic
|
||||
type TokenService interface {
|
||||
// CreateStaticToken creates a new static token
|
||||
CreateStaticToken(ctx context.Context, req *domain.CreateStaticTokenRequest, userID string) (*domain.CreateStaticTokenResponse, error)
|
||||
|
||||
// ListByApp lists all tokens for an application
|
||||
ListByApp(ctx context.Context, appID string, limit, offset int) ([]*domain.StaticToken, error)
|
||||
|
||||
// Delete deletes a token
|
||||
Delete(ctx context.Context, tokenID uuid.UUID, userID string) error
|
||||
|
||||
// GenerateUserToken generates a user token
|
||||
GenerateUserToken(ctx context.Context, appID, userID string, permissions []string) (string, error)
|
||||
|
||||
// VerifyToken verifies a token and returns verification response
|
||||
VerifyToken(ctx context.Context, req *domain.VerifyRequest) (*domain.VerifyResponse, error)
|
||||
|
||||
// RenewUserToken renews a user token
|
||||
RenewUserToken(ctx context.Context, req *domain.RenewRequest) (*domain.RenewResponse, error)
|
||||
}
|
||||
|
||||
// AuthenticationService defines the interface for authentication business logic
|
||||
type AuthenticationService interface {
|
||||
// GetUserID extracts user ID from context
|
||||
GetUserID(ctx context.Context) (string, error)
|
||||
|
||||
// ValidatePermissions checks if user has required permissions
|
||||
ValidatePermissions(ctx context.Context, userID string, appID string, requiredPermissions []string) error
|
||||
|
||||
// GetUserClaims retrieves user claims
|
||||
GetUserClaims(ctx context.Context, userID string) (map[string]string, error)
|
||||
}
|
||||
162
internal/services/token_service.go
Normal file
162
internal/services/token_service.go
Normal file
@ -0,0 +1,162 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
// NewTokenService creates a new token service
|
||||
func NewTokenService(
|
||||
tokenRepo repository.StaticTokenRepository,
|
||||
appRepo repository.ApplicationRepository,
|
||||
permRepo repository.PermissionRepository,
|
||||
grantRepo repository.GrantedPermissionRepository,
|
||||
logger *zap.Logger,
|
||||
) TokenService {
|
||||
return &tokenService{
|
||||
tokenRepo: tokenRepo,
|
||||
appRepo: appRepo,
|
||||
permRepo: permRepo,
|
||||
grantRepo: grantRepo,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateStaticToken creates a new static token
|
||||
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
|
||||
|
||||
tokenID := uuid.New()
|
||||
now := time.Now()
|
||||
|
||||
// Create the token entity
|
||||
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",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
|
||||
// Save the token to the database
|
||||
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)
|
||||
}
|
||||
|
||||
response := &domain.CreateStaticTokenResponse{
|
||||
ID: tokenID,
|
||||
Token: "static-token-placeholder-" + tokenID.String(),
|
||||
Permissions: req.Permissions,
|
||||
CreatedAt: now,
|
||||
}
|
||||
|
||||
s.logger.Info("Static token created successfully", zap.String("token_id", tokenID.String()))
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// ListByApp lists all tokens for an application
|
||||
func (s *tokenService) ListByApp(ctx context.Context, appID string, limit, offset int) ([]*domain.StaticToken, error) {
|
||||
s.logger.Debug("Listing tokens for application", zap.String("app_id", appID))
|
||||
|
||||
// TODO: Implement actual token listing
|
||||
return []*domain.StaticToken{}, nil
|
||||
}
|
||||
|
||||
// Delete deletes a token
|
||||
func (s *tokenService) Delete(ctx context.Context, tokenID uuid.UUID, userID string) error {
|
||||
s.logger.Info("Deleting token", zap.String("token_id", tokenID.String()), zap.String("user_id", userID))
|
||||
|
||||
// Check if token exists
|
||||
exists, err := s.tokenRepo.Exists(ctx, tokenID)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to check token existence", zap.Error(err), zap.String("token_id", tokenID.String()))
|
||||
return err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
s.logger.Error("Token not found", zap.String("token_id", tokenID.String()))
|
||||
return fmt.Errorf("token with ID '%s' not found", tokenID.String())
|
||||
}
|
||||
|
||||
// Delete the token
|
||||
err = s.tokenRepo.Delete(ctx, tokenID)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to delete token", zap.Error(err), zap.String("token_id", tokenID.String()))
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Revoke associated permissions
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateUserToken generates a user token
|
||||
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
|
||||
|
||||
return "user-token-placeholder-" + userID, nil
|
||||
}
|
||||
|
||||
// VerifyToken verifies a token and returns verification response
|
||||
func (s *tokenService) VerifyToken(ctx context.Context, req *domain.VerifyRequest) (*domain.VerifyResponse, error) {
|
||||
s.logger.Debug("Verifying token", zap.String("app_id", req.AppID), zap.String("type", string(req.Type)))
|
||||
|
||||
// TODO: Implement actual token verification logic
|
||||
response := &domain.VerifyResponse{
|
||||
Valid: true,
|
||||
UserID: req.UserID,
|
||||
Permissions: []string{"basic"},
|
||||
TokenType: req.Type,
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// RenewUserToken renews a user token
|
||||
func (s *tokenService) RenewUserToken(ctx context.Context, req *domain.RenewRequest) (*domain.RenewResponse, error) {
|
||||
s.logger.Info("Renewing user token", zap.String("app_id", req.AppID), zap.String("user_id", req.UserID))
|
||||
|
||||
// TODO: Validate current token
|
||||
// TODO: Generate new token with extended expiry but same max valid date
|
||||
|
||||
response := &domain.RenewResponse{
|
||||
Token: "renewed-token-placeholder",
|
||||
ExpiresAt: time.Now().Add(7 * 24 * time.Hour),
|
||||
MaxValidAt: time.Now().Add(30 * 24 * time.Hour),
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
Reference in New Issue
Block a user