-
This commit is contained in:
@ -45,3 +45,13 @@ func (d Duration) MarshalJSON() ([]byte, error) {
|
|||||||
func (d Duration) String() string {
|
func (d Duration) String() string {
|
||||||
return d.Duration.String()
|
return d.Duration.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Int64 returns the duration in nanoseconds for validator compatibility
|
||||||
|
func (d Duration) Int64() int64 {
|
||||||
|
return int64(d.Duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZero returns true if the duration is zero
|
||||||
|
func (d Duration) IsZero() bool {
|
||||||
|
return d.Duration == 0
|
||||||
|
}
|
||||||
|
|||||||
@ -159,8 +159,8 @@ type CreateApplicationRequest struct {
|
|||||||
Type []ApplicationType `json:"type" validate:"required,min=1,dive,oneof=static user"`
|
Type []ApplicationType `json:"type" validate:"required,min=1,dive,oneof=static user"`
|
||||||
CallbackURL string `json:"callback_url" validate:"required,url,max=500"`
|
CallbackURL string `json:"callback_url" validate:"required,url,max=500"`
|
||||||
TokenPrefix string `json:"token_prefix" validate:"omitempty,min=2,max=4,uppercase"`
|
TokenPrefix string `json:"token_prefix" validate:"omitempty,min=2,max=4,uppercase"`
|
||||||
TokenRenewalDuration Duration `json:"token_renewal_duration" validate:"required,min=1"`
|
TokenRenewalDuration Duration `json:"token_renewal_duration" validate:"required"`
|
||||||
MaxTokenDuration Duration `json:"max_token_duration" validate:"required,min=1"`
|
MaxTokenDuration Duration `json:"max_token_duration" validate:"required"`
|
||||||
Owner Owner `json:"owner" validate:"required"`
|
Owner Owner `json:"owner" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,8 +171,8 @@ type UpdateApplicationRequest struct {
|
|||||||
CallbackURL *string `json:"callback_url,omitempty" validate:"omitempty,url,max=500"`
|
CallbackURL *string `json:"callback_url,omitempty" validate:"omitempty,url,max=500"`
|
||||||
HMACKey *string `json:"hmac_key,omitempty" validate:"omitempty,min=1,max=255"`
|
HMACKey *string `json:"hmac_key,omitempty" validate:"omitempty,min=1,max=255"`
|
||||||
TokenPrefix *string `json:"token_prefix,omitempty" validate:"omitempty,min=2,max=4,uppercase"`
|
TokenPrefix *string `json:"token_prefix,omitempty" validate:"omitempty,min=2,max=4,uppercase"`
|
||||||
TokenRenewalDuration *Duration `json:"token_renewal_duration,omitempty" validate:"omitempty,min=1"`
|
TokenRenewalDuration *Duration `json:"token_renewal_duration,omitempty"`
|
||||||
MaxTokenDuration *Duration `json:"max_token_duration,omitempty" validate:"omitempty,min=1"`
|
MaxTokenDuration *Duration `json:"max_token_duration,omitempty"`
|
||||||
Owner *Owner `json:"owner,omitempty" validate:"omitempty"`
|
Owner *Owner `json:"owner,omitempty" validate:"omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -42,6 +42,14 @@ func (s *applicationService) Create(ctx context.Context, req *domain.CreateAppli
|
|||||||
return nil, fmt.Errorf("validation failed: %w", err)
|
return nil, fmt.Errorf("validation failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Manual validation for Duration fields
|
||||||
|
if req.TokenRenewalDuration.Duration <= 0 {
|
||||||
|
return nil, fmt.Errorf("token_renewal_duration must be greater than 0")
|
||||||
|
}
|
||||||
|
if req.MaxTokenDuration.Duration <= 0 {
|
||||||
|
return nil, fmt.Errorf("max_token_duration must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
// Basic permission validation - check if user can create applications
|
// Basic permission validation - check if user can create applications
|
||||||
// In a real system, this would check against user roles/permissions
|
// In a real system, this would check against user roles/permissions
|
||||||
if userID == "" {
|
if userID == "" {
|
||||||
@ -127,6 +135,14 @@ func (s *applicationService) Update(ctx context.Context, appID string, updates *
|
|||||||
return nil, fmt.Errorf("user authentication required")
|
return nil, fmt.Errorf("user authentication required")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Manual validation for Duration fields
|
||||||
|
if updates.TokenRenewalDuration != nil && updates.TokenRenewalDuration.Duration <= 0 {
|
||||||
|
return nil, fmt.Errorf("token_renewal_duration must be greater than 0")
|
||||||
|
}
|
||||||
|
if updates.MaxTokenDuration != nil && updates.MaxTokenDuration.Duration <= 0 {
|
||||||
|
return nil, fmt.Errorf("max_token_duration must be greater than 0")
|
||||||
|
}
|
||||||
|
|
||||||
// Additional business logic validation
|
// Additional business logic validation
|
||||||
if updates.TokenRenewalDuration != nil && updates.MaxTokenDuration != nil {
|
if updates.TokenRenewalDuration != nil && updates.MaxTokenDuration != nil {
|
||||||
if updates.TokenRenewalDuration.Duration > updates.MaxTokenDuration.Duration {
|
if updates.TokenRenewalDuration.Duration > updates.MaxTokenDuration.Duration {
|
||||||
|
|||||||
@ -19,7 +19,8 @@ import (
|
|||||||
func TestAuthenticationService_ValidateJWTToken(t *testing.T) {
|
func TestAuthenticationService_ValidateJWTToken(t *testing.T) {
|
||||||
config := NewMockConfig()
|
config := NewMockConfig()
|
||||||
logger := zap.NewNop()
|
logger := zap.NewNop()
|
||||||
authService := services.NewAuthenticationService(config, logger)
|
permRepo := NewMockPermissionRepository()
|
||||||
|
authService := services.NewAuthenticationService(config, logger, permRepo)
|
||||||
|
|
||||||
userToken := &domain.UserToken{
|
userToken := &domain.UserToken{
|
||||||
AppID: "test-app",
|
AppID: "test-app",
|
||||||
@ -51,7 +52,8 @@ func TestAuthenticationService_ValidateJWTToken(t *testing.T) {
|
|||||||
func TestAuthenticationService_GenerateJWTToken(t *testing.T) {
|
func TestAuthenticationService_GenerateJWTToken(t *testing.T) {
|
||||||
config := NewMockConfig()
|
config := NewMockConfig()
|
||||||
logger := zap.NewNop()
|
logger := zap.NewNop()
|
||||||
authService := services.NewAuthenticationService(config, logger)
|
permRepo := NewMockPermissionRepository()
|
||||||
|
authService := services.NewAuthenticationService(config, logger, permRepo)
|
||||||
|
|
||||||
userToken := &domain.UserToken{
|
userToken := &domain.UserToken{
|
||||||
AppID: "test-app",
|
AppID: "test-app",
|
||||||
@ -76,7 +78,8 @@ func TestAuthenticationService_GenerateJWTToken(t *testing.T) {
|
|||||||
func TestAuthenticationService_RefreshJWTToken(t *testing.T) {
|
func TestAuthenticationService_RefreshJWTToken(t *testing.T) {
|
||||||
config := NewMockConfig()
|
config := NewMockConfig()
|
||||||
logger := zap.NewNop()
|
logger := zap.NewNop()
|
||||||
authService := services.NewAuthenticationService(config, logger)
|
permRepo := NewMockPermissionRepository()
|
||||||
|
authService := services.NewAuthenticationService(config, logger, permRepo)
|
||||||
|
|
||||||
userToken := &domain.UserToken{
|
userToken := &domain.UserToken{
|
||||||
AppID: "test-app",
|
AppID: "test-app",
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
@ -54,6 +55,7 @@ func (suite *IntegrationTestSuite) SetupSuite() {
|
|||||||
"INTERNAL_HMAC_KEY": "test-hmac-key-for-integration-tests",
|
"INTERNAL_HMAC_KEY": "test-hmac-key-for-integration-tests",
|
||||||
"AUTH_PROVIDER": "header",
|
"AUTH_PROVIDER": "header",
|
||||||
"AUTH_HEADER_USER_EMAIL": "X-User-Email",
|
"AUTH_HEADER_USER_EMAIL": "X-User-Email",
|
||||||
|
"JWT_SECRET": "test-jwt-secret-for-integration-tests",
|
||||||
"RATE_LIMIT_ENABLED": "false", // Disable for tests
|
"RATE_LIMIT_ENABLED": "false", // Disable for tests
|
||||||
"METRICS_ENABLED": "false",
|
"METRICS_ENABLED": "false",
|
||||||
},
|
},
|
||||||
@ -97,7 +99,7 @@ func (suite *IntegrationTestSuite) setupServer() {
|
|||||||
// Initialize services
|
// Initialize services
|
||||||
appService := services.NewApplicationService(appRepo, logger)
|
appService := services.NewApplicationService(appRepo, logger)
|
||||||
tokenService := services.NewTokenService(tokenRepo, appRepo, permRepo, grantRepo, suite.cfg.GetString("INTERNAL_HMAC_KEY"), suite.cfg, logger)
|
tokenService := services.NewTokenService(tokenRepo, appRepo, permRepo, grantRepo, suite.cfg.GetString("INTERNAL_HMAC_KEY"), suite.cfg, logger)
|
||||||
authService := services.NewAuthenticationService(suite.cfg, logger)
|
authService := services.NewAuthenticationService(suite.cfg, logger, permRepo)
|
||||||
|
|
||||||
// Initialize handlers
|
// Initialize handlers
|
||||||
healthHandler := handlers.NewHealthHandler(suite.db, logger)
|
healthHandler := handlers.NewHealthHandler(suite.db, logger)
|
||||||
@ -396,7 +398,6 @@ func (suite *IntegrationTestSuite) TestStaticTokenWorkflow() {
|
|||||||
suite.T().Run("VerifyStaticToken", func(t *testing.T) {
|
suite.T().Run("VerifyStaticToken", func(t *testing.T) {
|
||||||
verifyReq := domain.VerifyRequest{
|
verifyReq := domain.VerifyRequest{
|
||||||
AppID: testApp.AppID,
|
AppID: testApp.AppID,
|
||||||
Type: domain.TokenTypeStatic,
|
|
||||||
Token: createdToken.Token,
|
Token: createdToken.Token,
|
||||||
Permissions: []string{"repo.read"},
|
Permissions: []string{"repo.read"},
|
||||||
}
|
}
|
||||||
@ -483,6 +484,14 @@ func (suite *IntegrationTestSuite) TestUserTokenWorkflow() {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// Debug: Print response body if not 200
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||||
|
resp.Body.Close()
|
||||||
|
resp.Body = io.NopCloser(bytes.NewReader(bodyBytes))
|
||||||
|
t.Logf("Login failed with status %d, body: %s", resp.StatusCode, string(bodyBytes))
|
||||||
|
}
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
|
||||||
// The response should contain either a token directly or a redirect URL
|
// The response should contain either a token directly or a redirect URL
|
||||||
|
|||||||
@ -337,6 +337,18 @@ func NewMockPermissionRepository() repository.PermissionRepository {
|
|||||||
UpdatedAt: time.Now(),
|
UpdatedAt: time.Now(),
|
||||||
UpdatedBy: "system",
|
UpdatedBy: "system",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ID: uuid.New(),
|
||||||
|
Scope: "app.read",
|
||||||
|
Name: "Application Read",
|
||||||
|
Description: "Read application data",
|
||||||
|
Category: "application",
|
||||||
|
IsSystem: false,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
CreatedBy: "system",
|
||||||
|
UpdatedAt: time.Now(),
|
||||||
|
UpdatedBy: "system",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, perm := range defaultPerms {
|
for _, perm := range defaultPerms {
|
||||||
|
|||||||
Reference in New Issue
Block a user