381 lines
12 KiB
Go
381 lines
12 KiB
Go
package test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/kms/api-key-service/internal/auth"
|
|
"github.com/kms/api-key-service/internal/domain"
|
|
"github.com/kms/api-key-service/internal/services"
|
|
)
|
|
|
|
// MockConfig implements ConfigProvider for testing
|
|
type MockConfig struct {
|
|
values map[string]string
|
|
}
|
|
|
|
func NewMockConfig() *MockConfig {
|
|
return &MockConfig{
|
|
values: map[string]string{
|
|
"JWT_SECRET": "test-jwt-secret-for-testing-only",
|
|
},
|
|
}
|
|
}
|
|
|
|
func (m *MockConfig) GetString(key string) string {
|
|
return m.values[key]
|
|
}
|
|
|
|
func (m *MockConfig) GetInt(key string) int { return 0 }
|
|
func (m *MockConfig) GetBool(key string) bool { return false }
|
|
func (m *MockConfig) GetDuration(key string) time.Duration { return 0 }
|
|
func (m *MockConfig) GetStringSlice(key string) []string { return nil }
|
|
func (m *MockConfig) IsSet(key string) bool { return m.values[key] != "" }
|
|
func (m *MockConfig) Validate() error { return nil }
|
|
func (m *MockConfig) GetDatabaseDSN() string { return "" }
|
|
func (m *MockConfig) GetServerAddress() string { return "" }
|
|
func (m *MockConfig) GetMetricsAddress() string { return "" }
|
|
func (m *MockConfig) GetJWTSecret() string { return m.GetString("JWT_SECRET") }
|
|
func (m *MockConfig) IsDevelopment() bool { return true }
|
|
func (m *MockConfig) IsProduction() bool { return false }
|
|
|
|
func TestJWTManager_GenerateToken(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
jwtManager := auth.NewJWTManager(config, logger)
|
|
|
|
userToken := &domain.UserToken{
|
|
AppID: "test-app",
|
|
UserID: "test-user",
|
|
Permissions: []string{"read", "write"},
|
|
IssuedAt: time.Now(),
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
MaxValidAt: time.Now().Add(24 * time.Hour),
|
|
TokenType: domain.TokenTypeUser,
|
|
Claims: map[string]string{
|
|
"email": "test@example.com",
|
|
"name": "Test User",
|
|
},
|
|
}
|
|
|
|
tokenString, err := jwtManager.GenerateToken(userToken)
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, tokenString)
|
|
|
|
// Verify the token can be validated
|
|
claims, err := jwtManager.ValidateToken(tokenString)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, userToken.UserID, claims.UserID)
|
|
assert.Equal(t, userToken.AppID, claims.AppID)
|
|
assert.Equal(t, userToken.Permissions, claims.Permissions)
|
|
assert.Equal(t, userToken.TokenType, claims.TokenType)
|
|
assert.Equal(t, userToken.Claims, claims.Claims)
|
|
}
|
|
|
|
func TestJWTManager_ValidateToken(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
jwtManager := auth.NewJWTManager(config, logger)
|
|
|
|
userToken := &domain.UserToken{
|
|
AppID: "test-app",
|
|
UserID: "test-user",
|
|
Permissions: []string{"read"},
|
|
IssuedAt: time.Now(),
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
MaxValidAt: time.Now().Add(24 * time.Hour),
|
|
TokenType: domain.TokenTypeUser,
|
|
}
|
|
|
|
tokenString, err := jwtManager.GenerateToken(userToken)
|
|
require.NoError(t, err)
|
|
|
|
// Test valid token
|
|
claims, err := jwtManager.ValidateToken(tokenString)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, userToken.UserID, claims.UserID)
|
|
assert.Equal(t, userToken.AppID, claims.AppID)
|
|
|
|
// Test invalid token
|
|
_, err = jwtManager.ValidateToken("invalid-token")
|
|
assert.Error(t, err)
|
|
|
|
// Test empty token
|
|
_, err = jwtManager.ValidateToken("")
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestJWTManager_ExpiredToken(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
jwtManager := auth.NewJWTManager(config, logger)
|
|
|
|
// Create an expired token
|
|
userToken := &domain.UserToken{
|
|
AppID: "test-app",
|
|
UserID: "test-user",
|
|
Permissions: []string{"read"},
|
|
IssuedAt: time.Now().Add(-2 * time.Hour),
|
|
ExpiresAt: time.Now().Add(-time.Hour), // Expired 1 hour ago
|
|
MaxValidAt: time.Now().Add(24 * time.Hour),
|
|
TokenType: domain.TokenTypeUser,
|
|
}
|
|
|
|
tokenString, err := jwtManager.GenerateToken(userToken)
|
|
require.NoError(t, err)
|
|
|
|
// Validation should fail for expired token
|
|
_, err = jwtManager.ValidateToken(tokenString)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestJWTManager_MaxValidAtExpired(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
jwtManager := auth.NewJWTManager(config, logger)
|
|
|
|
// Create a token that's past max valid time
|
|
userToken := &domain.UserToken{
|
|
AppID: "test-app",
|
|
UserID: "test-user",
|
|
Permissions: []string{"read"},
|
|
IssuedAt: time.Now().Add(-2 * time.Hour),
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
MaxValidAt: time.Now().Add(-time.Hour), // Max valid time expired
|
|
TokenType: domain.TokenTypeUser,
|
|
}
|
|
|
|
tokenString, err := jwtManager.GenerateToken(userToken)
|
|
require.NoError(t, err)
|
|
|
|
// Validation should fail for token past max valid time
|
|
_, err = jwtManager.ValidateToken(tokenString)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestJWTManager_RefreshToken(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
jwtManager := auth.NewJWTManager(config, logger)
|
|
|
|
userToken := &domain.UserToken{
|
|
AppID: "test-app",
|
|
UserID: "test-user",
|
|
Permissions: []string{"read"},
|
|
IssuedAt: time.Now(),
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
MaxValidAt: time.Now().Add(24 * time.Hour),
|
|
TokenType: domain.TokenTypeUser,
|
|
}
|
|
|
|
originalToken, err := jwtManager.GenerateToken(userToken)
|
|
require.NoError(t, err)
|
|
|
|
// Refresh the token
|
|
newExpiration := time.Now().Add(2 * time.Hour)
|
|
refreshedToken, err := jwtManager.RefreshToken(originalToken, newExpiration)
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, refreshedToken)
|
|
assert.NotEqual(t, originalToken, refreshedToken)
|
|
|
|
// Validate the refreshed token
|
|
claims, err := jwtManager.ValidateToken(refreshedToken)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, userToken.UserID, claims.UserID)
|
|
assert.Equal(t, userToken.AppID, claims.AppID)
|
|
}
|
|
|
|
func TestJWTManager_ExtractClaims(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
jwtManager := auth.NewJWTManager(config, logger)
|
|
|
|
userToken := &domain.UserToken{
|
|
AppID: "test-app",
|
|
UserID: "test-user",
|
|
Permissions: []string{"read"},
|
|
IssuedAt: time.Now(),
|
|
ExpiresAt: time.Now().Add(-time.Hour), // Expired token
|
|
MaxValidAt: time.Now().Add(24 * time.Hour),
|
|
TokenType: domain.TokenTypeUser,
|
|
}
|
|
|
|
tokenString, err := jwtManager.GenerateToken(userToken)
|
|
require.NoError(t, err)
|
|
|
|
// Extract claims from expired token (should work)
|
|
claims, err := jwtManager.ExtractClaims(tokenString)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, userToken.UserID, claims.UserID)
|
|
assert.Equal(t, userToken.AppID, claims.AppID)
|
|
}
|
|
|
|
func TestJWTManager_GetTokenInfo(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
jwtManager := auth.NewJWTManager(config, logger)
|
|
|
|
userToken := &domain.UserToken{
|
|
AppID: "test-app",
|
|
UserID: "test-user",
|
|
Permissions: []string{"read"},
|
|
IssuedAt: time.Now(),
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
MaxValidAt: time.Now().Add(24 * time.Hour),
|
|
TokenType: domain.TokenTypeUser,
|
|
}
|
|
|
|
tokenString, err := jwtManager.GenerateToken(userToken)
|
|
require.NoError(t, err)
|
|
|
|
info := jwtManager.GetTokenInfo(tokenString)
|
|
assert.Equal(t, userToken.UserID, info["user_id"])
|
|
assert.Equal(t, userToken.AppID, info["app_id"])
|
|
assert.Equal(t, userToken.Permissions, info["permissions"])
|
|
assert.Equal(t, userToken.TokenType, info["token_type"])
|
|
}
|
|
|
|
func TestAuthenticationService_ValidateJWTToken(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
authService := services.NewAuthenticationService(config, logger)
|
|
|
|
userToken := &domain.UserToken{
|
|
AppID: "test-app",
|
|
UserID: "test-user",
|
|
Permissions: []string{"read", "write"},
|
|
IssuedAt: time.Now(),
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
MaxValidAt: time.Now().Add(24 * time.Hour),
|
|
TokenType: domain.TokenTypeUser,
|
|
Claims: map[string]string{
|
|
"email": "test@example.com",
|
|
},
|
|
}
|
|
|
|
// Generate token
|
|
tokenString, err := authService.GenerateJWTToken(context.Background(), userToken)
|
|
require.NoError(t, err)
|
|
|
|
// Validate token
|
|
authContext, err := authService.ValidateJWTToken(context.Background(), tokenString)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, userToken.UserID, authContext.UserID)
|
|
assert.Equal(t, userToken.AppID, authContext.AppID)
|
|
assert.Equal(t, userToken.Permissions, authContext.Permissions)
|
|
assert.Equal(t, userToken.TokenType, authContext.TokenType)
|
|
assert.Equal(t, userToken.Claims, authContext.Claims)
|
|
}
|
|
|
|
func TestAuthenticationService_GenerateJWTToken(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
authService := services.NewAuthenticationService(config, logger)
|
|
|
|
userToken := &domain.UserToken{
|
|
AppID: "test-app",
|
|
UserID: "test-user",
|
|
Permissions: []string{"read"},
|
|
IssuedAt: time.Now(),
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
MaxValidAt: time.Now().Add(24 * time.Hour),
|
|
TokenType: domain.TokenTypeUser,
|
|
}
|
|
|
|
tokenString, err := authService.GenerateJWTToken(context.Background(), userToken)
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, tokenString)
|
|
|
|
// Verify token can be validated
|
|
authContext, err := authService.ValidateJWTToken(context.Background(), tokenString)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, userToken.UserID, authContext.UserID)
|
|
}
|
|
|
|
func TestAuthenticationService_RefreshJWTToken(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
authService := services.NewAuthenticationService(config, logger)
|
|
|
|
userToken := &domain.UserToken{
|
|
AppID: "test-app",
|
|
UserID: "test-user",
|
|
Permissions: []string{"read"},
|
|
IssuedAt: time.Now(),
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
MaxValidAt: time.Now().Add(24 * time.Hour),
|
|
TokenType: domain.TokenTypeUser,
|
|
}
|
|
|
|
originalToken, err := authService.GenerateJWTToken(context.Background(), userToken)
|
|
require.NoError(t, err)
|
|
|
|
// Refresh token
|
|
newExpiration := time.Now().Add(2 * time.Hour)
|
|
refreshedToken, err := authService.RefreshJWTToken(context.Background(), originalToken, newExpiration)
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, refreshedToken)
|
|
assert.NotEqual(t, originalToken, refreshedToken)
|
|
|
|
// Validate refreshed token
|
|
authContext, err := authService.ValidateJWTToken(context.Background(), refreshedToken)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, userToken.UserID, authContext.UserID)
|
|
}
|
|
|
|
func TestJWTManager_InvalidSecret(t *testing.T) {
|
|
// Test with empty JWT secret
|
|
config := &MockConfig{values: map[string]string{"JWT_SECRET": ""}}
|
|
logger := zap.NewNop()
|
|
jwtManager := auth.NewJWTManager(config, logger)
|
|
|
|
userToken := &domain.UserToken{
|
|
AppID: "test-app",
|
|
UserID: "test-user",
|
|
Permissions: []string{"read"},
|
|
IssuedAt: time.Now(),
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
MaxValidAt: time.Now().Add(24 * time.Hour),
|
|
TokenType: domain.TokenTypeUser,
|
|
}
|
|
|
|
_, err := jwtManager.GenerateToken(userToken)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestJWTManager_TokenRevocation(t *testing.T) {
|
|
config := NewMockConfig()
|
|
logger := zap.NewNop()
|
|
jwtManager := auth.NewJWTManager(config, logger)
|
|
|
|
userToken := &domain.UserToken{
|
|
AppID: "test-app",
|
|
UserID: "test-user",
|
|
Permissions: []string{"read"},
|
|
IssuedAt: time.Now(),
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
MaxValidAt: time.Now().Add(24 * time.Hour),
|
|
TokenType: domain.TokenTypeUser,
|
|
}
|
|
|
|
tokenString, err := jwtManager.GenerateToken(userToken)
|
|
require.NoError(t, err)
|
|
|
|
// Check revocation status (should be false initially)
|
|
revoked, err := jwtManager.IsTokenRevoked(tokenString)
|
|
require.NoError(t, err)
|
|
assert.False(t, revoked)
|
|
|
|
// Revoke token (currently just logs, doesn't actually revoke)
|
|
err = jwtManager.RevokeToken(tokenString)
|
|
require.NoError(t, err)
|
|
|
|
// Note: Current implementation doesn't actually implement blacklisting,
|
|
// so this test just verifies the methods don't error
|
|
}
|