Fieldalignment

This commit is contained in:
2025-06-20 08:07:03 +01:00
parent c233aa92ef
commit d8d1b74175
21 changed files with 226 additions and 401 deletions
+3 -14
View File
@@ -23,24 +23,13 @@ type lruEntry struct {
// Cache provides a thread-safe in-memory caching mechanism with expiration support.
// It implements an LRU (Least Recently Used) eviction policy using a doubly-linked list for efficiency.
type Cache struct {
// items stores the cached data with string keys.
items map[string]CacheItem
// order maintains the usage order; most recently used items are at the back.
order *list.List
// elems maps keys to their corresponding list elements for O(1) access.
elems map[string]*list.Element
// mutex protects concurrent access to the cache.
mutex sync.RWMutex
// maxSize is the maximum number of items allowed in the cache.
maxSize int
// autoCleanupInterval defines how often Cleanup is called automatically.
autoCleanupInterval time.Duration
// stopCleanup channel to terminate the auto cleanup goroutine.
stopCleanup chan struct{}
maxSize int
autoCleanupInterval time.Duration
mutex sync.RWMutex
}
// DefaultMaxSize is the default maximum number of items in the cache.
+13 -28
View File
@@ -26,25 +26,18 @@ const (
// CircuitBreaker implements the circuit breaker pattern for external service calls
type CircuitBreaker struct {
// Configuration
maxFailures int // Maximum failures before opening
timeout time.Duration // How long to wait before trying again
resetTimeout time.Duration // How long to wait in half-open state
// State
state CircuitBreakerState
failures int64
lastFailureTime time.Time
lastSuccessTime time.Time
mutex sync.RWMutex
// Metrics
logger *Logger
maxFailures int
timeout time.Duration
resetTimeout time.Duration
state CircuitBreakerState
failures int64
totalRequests int64
totalFailures int64
totalSuccesses int64
// Logger
logger *Logger
mutex sync.RWMutex
}
// CircuitBreakerConfig holds configuration for circuit breakers
@@ -193,12 +186,12 @@ func (cb *CircuitBreaker) GetMetrics() map[string]any {
// RetryConfig holds configuration for retry mechanisms
type RetryConfig struct {
RetryableErrors []string `json:"retryable_errors"`
MaxAttempts int `json:"max_attempts"`
InitialDelay time.Duration `json:"initial_delay"`
MaxDelay time.Duration `json:"max_delay"`
BackoffFactor float64 `json:"backoff_factor"`
EnableJitter bool `json:"enable_jitter"`
RetryableErrors []string `json:"retryable_errors"`
}
// DefaultRetryConfig returns default retry configuration
@@ -220,8 +213,8 @@ func DefaultRetryConfig() RetryConfig {
// RetryExecutor implements retry logic with exponential backoff
type RetryExecutor struct {
config RetryConfig
logger *Logger
config RetryConfig
}
// NewRetryExecutor creates a new retry executor
@@ -344,8 +337,8 @@ func (re *RetryExecutor) calculateDelay(attempt int) time.Duration {
// HTTPError represents an HTTP error with status code
type HTTPError struct {
StatusCode int
Message string
StatusCode int
}
// Error implements the error interface
@@ -355,20 +348,12 @@ func (e *HTTPError) Error() string {
// GracefulDegradation implements graceful degradation patterns
type GracefulDegradation struct {
// Fallback functions for different operations
fallbacks map[string]func() (any, error)
// Health checks for dependencies
healthChecks map[string]func() bool
// Configuration
config GracefulDegradationConfig
// State tracking
degradedServices map[string]time.Time
mutex sync.RWMutex
logger *Logger
config GracefulDegradationConfig
mutex sync.RWMutex
}
// GracefulDegradationConfig holds configuration for graceful degradation
@@ -537,8 +522,8 @@ type ErrorRecoveryManager struct {
circuitBreakers map[string]*CircuitBreaker
retryExecutor *RetryExecutor
gracefulDegradation *GracefulDegradation
mutex sync.RWMutex
logger *Logger
mutex sync.RWMutex
}
// NewErrorRecoveryManager creates a new error recovery manager
+1 -10
View File
@@ -72,20 +72,11 @@ func deriveCodeChallenge(codeVerifier string) string {
// It contains the various tokens and metadata returned after successful
// code exchange or token refresh operations.
type TokenResponse struct {
// IDToken is the OIDC ID token containing user claims
IDToken string `json:"id_token"`
// AccessToken is the OAuth 2.0 access token for API access
AccessToken string `json:"access_token"`
// RefreshToken is the OAuth 2.0 refresh token for obtaining new tokens
RefreshToken string `json:"refresh_token"`
// ExpiresIn is the lifetime in seconds of the access token
ExpiresIn int `json:"expires_in"`
// TokenType is the type of token, typically "Bearer"
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
}
// exchangeTokens performs the OAuth 2.0 token exchange with the OIDC provider's token endpoint.
+15 -21
View File
@@ -11,35 +11,29 @@ import (
// InputValidator provides comprehensive input validation and sanitization
type InputValidator struct {
// Configuration
maxTokenLength int
maxURLLength int
maxHeaderLength int
maxClaimLength int
maxEmailLength int
maxUsernameLength int
// Compiled regex patterns
emailRegex *regexp.Regexp
urlRegex *regexp.Regexp
tokenRegex *regexp.Regexp
usernameRegex *regexp.Regexp
// Security patterns to detect
sqlInjectionPatterns []string
xssPatterns []string
pathTraversalPatterns []string
tokenRegex *regexp.Regexp
logger *Logger
urlRegex *regexp.Regexp
emailRegex *regexp.Regexp
sqlInjectionPatterns []string
pathTraversalPatterns []string
xssPatterns []string
maxUsernameLength int
maxURLLength int
maxTokenLength int
maxEmailLength int
maxClaimLength int
maxHeaderLength int
}
// ValidationResult represents the result of input validation
type ValidationResult struct {
IsValid bool `json:"is_valid"`
Errors []string `json:"errors,omitempty"`
Warnings []string `json:"warnings,omitempty"`
SanitizedValue string `json:"sanitized_value,omitempty"`
SecurityRisk string `json:"security_risk,omitempty"`
Errors []string `json:"errors,omitempty"`
Warnings []string `json:"warnings,omitempty"`
IsValid bool `json:"is_valid"`
}
// InputValidationConfig holds configuration for input validation
+1 -1
View File
@@ -204,8 +204,8 @@ func TestSanitizeInput(t *testing.T) {
tests := []struct {
name string
input string
maxLen int
expected string
maxLen int
}{
{
name: "Normal text",
+4 -5
View File
@@ -33,13 +33,12 @@ type JWKSet struct {
}
type JWKCache struct {
jwks *JWKSet
expiresAt time.Time
mutex sync.RWMutex
// CacheLifetime is configurable to determine how long the JWKS is cached.
jwks *JWKSet
internalCache *Cache
CacheLifetime time.Duration
internalCache *Cache // To hold the closable Cache instance from cache.go
maxSize int // Maximum number of items in the cache
maxSize int
mutex sync.RWMutex
}
type JWKCacheInterface interface {
+1 -1
View File
@@ -89,8 +89,8 @@ var ClockSkewTolerance = ClockSkewToleranceFuture
type JWT struct {
Header map[string]any
Claims map[string]any
Signature []byte
Token string
Signature []byte
}
// parseJWT decodes a raw JWT string into its constituent parts: header, claims, and signature.
+38 -40
View File
@@ -196,52 +196,51 @@ type TokenExchanger interface {
// TraefikOidc is the main struct for the OIDC middleware
type TraefikOidc struct {
jwkCache JWKCacheInterface
jwtVerifier JWTVerifier
ctx context.Context
tokenVerifier TokenVerifier
next http.Handler
tokenExchanger TokenExchanger
initComplete chan struct{}
limiter *rate.Limiter
tokenBlacklist *Cache
headerTemplates map[string]*template.Template
sessionManager *SessionManager
tokenCleanupStopChan chan struct{}
excludedURLs map[string]struct{}
extractClaimsFunc func(tokenString string) (map[string]any, error)
initiateAuthenticationFunc func(rw http.ResponseWriter, req *http.Request, session *SessionData, redirectURL string)
metadataCache *MetadataCache
allowedRolesAndGroups map[string]struct{}
allowedUsers map[string]struct{}
allowedUserDomains map[string]struct{}
tokenCache *TokenCache
httpClient *http.Client
tokenHTTPClient *http.Client
logger *Logger
metadataRefreshStopChan chan struct{}
cancelFunc context.CancelFunc
clientSecret string
clientID string
name string
redirURLPath string
logoutURLPath string
issuerURL string
revocationURL string
jwkCache JWKCacheInterface
metadataCache *MetadataCache
tokenBlacklist *Cache // Replaced TokenBlacklist with generic Cache
jwksURL string
clientID string
clientSecret string
authURL string
tokenURL string
scopes []string
limiter *rate.Limiter
forceHTTPS bool
enablePKCE bool
scheme string
tokenCache *TokenCache
httpClient *http.Client
tokenHTTPClient *http.Client // Reusable HTTP client for token operations
logger *Logger
tokenVerifier TokenVerifier
jwtVerifier JWTVerifier
excludedURLs map[string]struct{}
allowedUserDomains map[string]struct{}
allowedUsers map[string]struct{} // Map for case-insensitive lookup of allowed email addresses
allowedRolesAndGroups map[string]struct{}
initiateAuthenticationFunc func(rw http.ResponseWriter, req *http.Request, session *SessionData, redirectURL string)
// exchangeCodeForTokenFunc func(code string, redirectURL string, codeVerifier string) (*TokenResponse, error) // Replaced by interface
extractClaimsFunc func(tokenString string) (map[string]any, error)
initComplete chan struct{}
authURL string
endSessionURL string
postLogoutRedirectURI string
sessionManager *SessionManager
tokenExchanger TokenExchanger // Added field for mocking
refreshGracePeriod time.Duration // Configurable grace period for proactive refresh
headerTemplates map[string]*template.Template // Parsed templates for custom headers
tokenCleanupStopChan chan struct{} // Channel to stop token cleanup goroutine
metadataRefreshStopChan chan struct{} // Channel to stop metadata refresh goroutine
goroutineWG sync.WaitGroup // WaitGroup to track background goroutines
ctx context.Context
cancelFunc context.CancelFunc
scheme string
jwksURL string
issuerURL string
revocationURL string
scopes []string
goroutineWG sync.WaitGroup
refreshGracePeriod time.Duration
shutdownOnce sync.Once
suppressDiagnosticLogs bool // Flag to suppress diagnostic logs during tests
forceHTTPS bool
enablePKCE bool
suppressDiagnosticLogs bool
}
// ProviderMetadata holds OIDC provider metadata
@@ -1195,11 +1194,10 @@ func (t *TraefikOidc) processAuthorizedRequest(rw http.ResponseWriter, req *http
// Create template data context with available tokens and claims
// Fields must be exported (uppercase) to be accessible in templates
templateData := struct {
// These fields need to be exported (uppercase) for template access
Claims map[string]any
AccessToken string
IdToken string
RefreshToken string
Claims map[string]any
}{
AccessToken: session.GetAccessToken(), // Provide AccessToken for templates if needed
IdToken: session.GetIDToken(),
+33 -33
View File
@@ -30,8 +30,8 @@ type TestSuite struct {
ecPrivateKey *ecdsa.PrivateKey
tOidc *TraefikOidc
mockJWKCache *MockJWKCache
token string
sessionManager *SessionManager
token string
}
// Setup initializes the test suite
@@ -410,15 +410,15 @@ func TestServeHTTP(t *testing.T) {
}
tests := []struct {
name string
requestPath string
sessionValues map[any]any
expectedStatus int
expectedBody string
setupSession func(*SessionData)
mockRefreshTokenFunc func(originalFunc func(refreshToken string) (*TokenResponse, error)) func(refreshToken string) (*TokenResponse, error)
assertSessionAfterRequest func(t *testing.T, rr *httptest.ResponseRecorder, req *http.Request, sessionManager *SessionManager) // Added for post-request checks
requestHeaders map[string]string // Added for setting headers like Accept
assertSessionAfterRequest func(t *testing.T, rr *httptest.ResponseRecorder, req *http.Request, sessionManager *SessionManager)
requestHeaders map[string]string
name string
requestPath string
expectedBody string
expectedStatus int
}{
{
name: "Excluded URL",
@@ -873,10 +873,10 @@ func TestJWKToPEM(t *testing.T) {
ts.Setup()
tests := []struct {
name string
jwk *JWK
expectError bool
name string
errorContains string
expectError bool
}{
{
name: "Unsupported Key Type",
@@ -928,8 +928,8 @@ func TestParseJWT(t *testing.T) {
tests := []struct {
name string
token string
expectError bool
errorContains string
expectError bool
}{
{
name: "Invalid Format",
@@ -989,11 +989,11 @@ func TestHandleCallback(t *testing.T) {
redirectURL := "http://example.com/"
tests := []struct {
name string
queryParams string
exchangeCodeForToken func(code string, redirectURL string, codeVerifier string) (*TokenResponse, error)
extractClaimsFunc func(tokenString string) (map[string]any, error)
sessionSetupFunc func(*SessionData)
name string
queryParams string
expectedStatus int
}{
{
@@ -1256,12 +1256,12 @@ func TestIsAllowedDomain(t *testing.T) {
ts.Setup()
tests := []struct {
name string
email string
allowedDomains map[string]struct{}
allowedUsers map[string]struct{}
name string
email string
expectedLogOutput string
allowed bool
expectedLogOutput string // For testing log messages
}{
{
name: "Allowed domain",
@@ -1343,11 +1343,11 @@ func TestOIDCHandler(t *testing.T) {
ts.token = "valid.jwt.token"
tests := []struct {
name string
queryParams string
exchangeCodeForToken func(code string, redirectURL string, codeVerifier string) (*TokenResponse, error)
extractClaimsFunc func(tokenString string) (map[string]any, error)
sessionSetupFunc func(session *sessions.Session)
name string
queryParams string
expectedStatus int
blacklist bool
rateLimit bool
@@ -1504,12 +1504,12 @@ func TestHandleLogout(t *testing.T) {
defer mockRevocationServer.Close()
tests := []struct {
name string
setupSession func(*SessionData)
name string
endSessionURL string
expectedStatus int
expectedURL string
host string
expectedStatus int
}{
{
name: "Successful logout with end session endpoint",
@@ -2104,12 +2104,12 @@ func TestServeHTTPRolesAndGroups(t *testing.T) {
nbf := now.Add(-2 * time.Minute).Unix() // Account for clock skew
tests := []struct {
name string
allowedRolesAndGroups map[string]struct{}
claims map[string]any
setupSession func(*SessionData)
expectedStatus int
expectedHeaders map[string]string
name string
expectedStatus int
}{
{
name: "User with allowed role",
@@ -2313,10 +2313,10 @@ func TestExchangeTokensWithRedirects(t *testing.T) {
ts.Setup()
tests := []struct {
name string
setupServer func() *httptest.Server
expectError bool
name string
errorContains string
expectError bool
}{
{
name: "Successful token exchange with redirects",
@@ -2424,9 +2424,9 @@ func TestBuildAuthURL(t *testing.T) {
redirectURL string
state string
nonce string
enablePKCE bool
codeChallenge string
expectedPrefix string
enablePKCE bool
checkPKCE bool
}{
{
@@ -2574,10 +2574,10 @@ func TestExchangeCodeForToken(t *testing.T) {
ts.Setup()
tests := []struct {
name string
enablePKCE bool
codeVerifier string
setupMock func(t *testing.T) *httptest.Server
name string
codeVerifier string
enablePKCE bool
}{
{
name: "With PKCE Enabled and Code Verifier",
@@ -2883,10 +2883,10 @@ func TestJWTVerifyWithSkipReplayCheck(t *testing.T) {
tests := []struct {
name string
errorContains string
skipReplayCheck bool
firstCall bool
expectError bool
errorContains string
}{
{
name: "First verification with skipReplayCheck=false should succeed",
@@ -3339,10 +3339,10 @@ func TestJTIBlacklistBehavior(t *testing.T) {
// Test JTI blacklist behavior
tests := []struct {
name string
action func() error
expectError bool
name string
description string
expectError bool
}{
{
name: "Initial verification adds JTI to blacklist",
@@ -3495,9 +3495,9 @@ func TestEdgeCasesWithDifferentTokenTypes(t *testing.T) {
nbf := now.Unix()
tests := []struct {
claims map[string]any
name string
tokenType string
claims map[string]any
expectError bool
}{
{
@@ -3697,10 +3697,10 @@ func TestScopeMergingEdgeCases(t *testing.T) {
tests := []struct {
name string
description string
defaultScopes []string
userScopes []string
expectedScopes []string
description string
}{
{
name: "Case sensitivity preserved",
@@ -3974,8 +3974,8 @@ func TestBuildAuthURLWithMergedScopes(t *testing.T) {
tests := []struct {
name string
scopes []string
expectedScopes string
scopes []string
}{
{
name: "Default scopes only",
+3 -3
View File
@@ -8,11 +8,11 @@ import (
)
type MetadataCache struct {
metadata *ProviderMetadata
expiresAt time.Time
mutex sync.RWMutex
autoCleanupInterval time.Duration
metadata *ProviderMetadata
stopCleanup chan struct{}
autoCleanupInterval time.Duration
mutex sync.RWMutex
}
// NewMetadataCache creates a new MetadataCache instance.
+25 -57
View File
@@ -10,61 +10,41 @@ import (
// PerformanceMetrics tracks various performance-related metrics
type PerformanceMetrics struct {
// Cache metrics
cacheHits int64
cacheMisses int64
cacheEvictions int64
cacheSize int64
// Token operation metrics
tokenVerifications int64
tokenValidations int64
tokenRefreshes int64
// Success/failure tracking
startTime time.Time
logger *Logger
verificationTimes []time.Duration
refreshTimes []time.Duration
validationTimes []time.Duration
memoryUsage int64
heapSize int64
successfulVerifications int64
successfulValidations int64
successfulRefreshes int64
failedVerifications int64
failedValidations int64
failedRefreshes int64
// Timing metrics
avgVerificationTime time.Duration
avgValidationTime time.Duration
avgRefreshTime time.Duration
// Resource metrics
memoryUsage int64
cacheHits int64
goroutineCount int64
memoryPressure int64 // Memory pressure level (0-100)
gcPauseTime int64 // Last GC pause time in nanoseconds
heapSize int64 // Current heap size
heapInUse int64 // Heap memory in use
// Error metrics (kept for backward compatibility)
memoryPressure int64
gcPauseTime int64
tokenRefreshes int64
heapInUse int64
verificationErrors int64
validationErrors int64
refreshErrors int64
// Rate limiting metrics
rateLimitedRequests int64
// Session metrics
activeSessions int64
sessionCreations int64
sessionDeletions int64
// Timing tracking
cacheMisses int64
tokenValidations int64
tokenVerifications int64
cacheSize int64
cacheEvictions int64
timingMutex sync.RWMutex
verificationTimes []time.Duration
validationTimes []time.Duration
refreshTimes []time.Duration
// Start time for uptime calculation
startTime time.Time
logger *Logger
}
// NewPerformanceMetrics creates a new performance metrics tracker
@@ -441,38 +421,26 @@ func (pm *PerformanceMetrics) calculateTimingStats(times []time.Duration) map[st
// ResourceMonitor tracks resource usage and limits
type ResourceMonitor struct {
// Memory limits
maxMemoryBytes int64
// Cache limits
maxCacheSize int64
// Session limits
maxSessions int64
// Cache size tracking
cacheSizes map[string]int64
cacheMutex sync.RWMutex
// Monitoring state
alertThresholds map[string]float64
alerts []ResourceAlert
alertsMutex sync.RWMutex
// Performance metrics reference
perfMetrics *PerformanceMetrics
logger *Logger
alerts []ResourceAlert
maxMemoryBytes int64
maxCacheSize int64
maxSessions int64
cacheMutex sync.RWMutex
alertsMutex sync.RWMutex
}
// ResourceAlert represents a resource usage alert
type ResourceAlert struct {
Timestamp time.Time `json:"timestamp"`
Type string `json:"type"`
Message string `json:"message"`
Severity string `json:"severity"`
Threshold float64 `json:"threshold"`
CurrentValue float64 `json:"current_value"`
Timestamp time.Time `json:"timestamp"`
Severity string `json:"severity"`
}
// NewResourceMonitor creates a new resource monitor
+1 -1
View File
@@ -390,8 +390,8 @@ func TestMissingClaims(t *testing.T) {
// Test cases for missing claims
testCases := []struct {
name string
omittedClaims []string
expectedError string
omittedClaims []string
}{
{
name: "Missing Issuer",
+19 -42
View File
@@ -13,66 +13,50 @@ import (
// SecurityEvent represents a security-related event that should be logged and monitored
type SecurityEvent struct {
Timestamp time.Time `json:"timestamp"`
Details map[string]any `json:"details,omitempty"`
Type string `json:"type"`
Severity string `json:"severity"`
Timestamp time.Time `json:"timestamp"`
ClientIP string `json:"client_ip"`
UserAgent string `json:"user_agent"`
RequestPath string `json:"request_path"`
Message string `json:"message"`
Details map[string]any `json:"details,omitempty"`
}
// SecurityMonitor tracks security events and suspicious activity patterns
type SecurityMonitor struct {
// Event counters
ipFailures map[string]*IPFailureTracker
patternDetector *SuspiciousPatternDetector
logger *Logger
eventHandlers []SecurityEventHandler
config SecurityMonitorConfig
authFailures int64
tokenValidationFails int64
rateLimitHits int64
suspiciousRequests int64
// IP-based tracking
ipFailures map[string]*IPFailureTracker
ipMutex sync.RWMutex
// Pattern detection
patternDetector *SuspiciousPatternDetector
// Event handlers
eventHandlers []SecurityEventHandler
// Configuration
config SecurityMonitorConfig
// Logger
logger *Logger
}
// IPFailureTracker tracks failures for a specific IP address
type IPFailureTracker struct {
FailureCount int64
LastFailure time.Time
FirstFailure time.Time
FailureTypes map[string]int64
IsBlocked bool
BlockedUntil time.Time
FailureTypes map[string]int64
FailureCount int64
mutex sync.RWMutex
IsBlocked bool
}
// SuspiciousPatternDetector identifies patterns that may indicate attacks
type SuspiciousPatternDetector struct {
// Time-based windows for pattern detection
shortWindow time.Duration // 1 minute
mediumWindow time.Duration // 5 minutes
longWindow time.Duration // 15 minutes
// Pattern thresholds
rapidFailureThreshold int // failures in short window
distributedAttackThreshold int // failures across IPs in medium window
persistentAttackThreshold int // failures in long window
// Pattern tracking
recentEvents []SecurityEvent
shortWindow time.Duration
mediumWindow time.Duration
longWindow time.Duration
rapidFailureThreshold int
distributedAttackThreshold int
persistentAttackThreshold int
eventsMutex sync.RWMutex
}
@@ -83,22 +67,15 @@ type SecurityEventHandler interface {
// SecurityMonitorConfig contains configuration for the security monitor
type SecurityMonitorConfig struct {
// Failure thresholds
MaxFailuresPerIP int `json:"max_failures_per_ip"`
FailureWindowMinutes int `json:"failure_window_minutes"`
BlockDurationMinutes int `json:"block_duration_minutes"`
// Pattern detection settings
EnablePatternDetection bool `json:"enable_pattern_detection"`
RapidFailureThreshold int `json:"rapid_failure_threshold"`
// Monitoring settings
EnableDetailedLogging bool `json:"enable_detailed_logging"`
LogSuspiciousOnly bool `json:"log_suspicious_only"`
// Cleanup settings
CleanupIntervalMinutes int `json:"cleanup_interval_minutes"`
RetentionHours int `json:"retention_hours"`
EnablePatternDetection bool `json:"enable_pattern_detection"`
EnableDetailedLogging bool `json:"enable_detailed_logging"`
LogSuspiciousOnly bool `json:"log_suspicious_only"`
}
// DefaultSecurityMonitorConfig returns a default configuration
+3 -10
View File
@@ -213,17 +213,10 @@ func decompressTokenInternal(compressed string) string {
// It provides functionality for storing and retrieving authentication state, tokens,
// and other session-related data across multiple cookies.
type SessionManager struct {
// store is the underlying session store for cookie management.
store sessions.Store
// forceHTTPS enforces secure cookie attributes regardless of request scheme.
forceHTTPS bool
// logger provides structured logging capabilities.
logger *Logger
// sessionPool is a sync.Pool for reusing SessionData objects.
sessionPool sync.Pool
store sessions.Store
logger *Logger
forceHTTPS bool
}
// NewSessionManager creates a new session manager with the specified configuration.
+1 -1
View File
@@ -441,8 +441,8 @@ func TestTokenChunkingCorruptionResistance(t *testing.T) {
}
tests := []struct {
name string
corruptChunk func(chunks map[int]*sessions.Session)
name string
expectEmpty bool
}{
{
+19 -88
View File
@@ -26,96 +26,27 @@ type TemplatedHeader struct {
// It provides all necessary settings to configure OpenID Connect authentication
// with various providers like Auth0, Logto, or any standard OIDC provider.
type Config struct {
// ProviderURL is the base URL of the OIDC provider (required)
// Example: https://accounts.google.com
ProviderURL string `json:"providerURL"`
// RevocationURL is the endpoint for revoking tokens (optional)
// If not provided, it will be discovered from provider metadata
RevocationURL string `json:"revocationURL"`
// EnablePKCE enables Proof Key for Code Exchange (PKCE) for the authorization code flow (optional)
// This enhances security but might not be supported by all OIDC providers
// Default: false
EnablePKCE bool `json:"enablePKCE"`
// CallbackURL is the path where the OIDC provider will redirect after authentication (required)
// Example: /oauth2/callback
CallbackURL string `json:"callbackURL"`
// LogoutURL is the path for handling logout requests (optional)
// If not provided, it will be set to CallbackURL + "/logout"
LogoutURL string `json:"logoutURL"`
// ClientID is the OAuth 2.0 client identifier (required)
ClientID string `json:"clientID"`
// ClientSecret is the OAuth 2.0 client secret (required)
ClientSecret string `json:"clientSecret"`
// Scopes defines the OAuth 2.0 scopes to request (optional)
// Defaults to ["openid", "profile", "email"] if not provided
Scopes []string `json:"scopes"`
// LogLevel sets the logging verbosity (optional)
// Valid values: "debug", "info", "error"
// Default: "info"
LogLevel string `json:"logLevel"`
// SessionEncryptionKey is used to encrypt session data (required)
// Must be a secure random string
SessionEncryptionKey string `json:"sessionEncryptionKey"`
// ForceHTTPS forces the use of HTTPS for all URLs (optional)
// Default: false
ForceHTTPS bool `json:"forceHTTPS"`
// RateLimit sets the maximum number of requests per second (optional)
// Default: 100
RateLimit int `json:"rateLimit"`
// ExcludedURLs lists paths that bypass authentication (optional)
// Example: ["/health", "/metrics"]
ExcludedURLs []string `json:"excludedURLs"`
// AllowedUserDomains restricts access to specific email domains (optional)
// Example: ["company.com", "subsidiary.com"]
AllowedUserDomains []string `json:"allowedUserDomains"`
// AllowedUsers restricts access to specific email addresses (optional)
// Example: ["[email protected]", "[email protected]"]
AllowedUsers []string `json:"allowedUsers"`
// AllowedRolesAndGroups restricts access to users with specific roles or groups (optional)
// Example: ["admin", "developer"]
AllowedRolesAndGroups []string `json:"allowedRolesAndGroups"`
// OIDCEndSessionURL is the provider's end session endpoint (optional)
// If not provided, it will be discovered from provider metadata
OIDCEndSessionURL string `json:"oidcEndSessionURL"`
// PostLogoutRedirectURI is the URL to redirect to after logout (optional)
// Default: "/"
PostLogoutRedirectURI string `json:"postLogoutRedirectURI"`
// HTTPClient allows customizing the HTTP client used for OIDC operations (optional)
HTTPClient *http.Client
// RefreshGracePeriodSeconds defines how many seconds before a token expires
// the plugin should attempt to refresh it proactively (optional)
// Default: 60
RefreshGracePeriodSeconds int `json:"refreshGracePeriodSeconds"`
// Headers defines custom HTTP headers to set with templated values (optional)
// Values can reference tokens and claims using Go templates with the following variables:
// - {{.AccessToken}} - The access token (ID token)
// - {{.IdToken}} - Same as AccessToken (for consistency)
// - {{.RefreshToken}} - The refresh token
// - {{.Claims.email}} - Access token claims (use proper case for claim names)
// Examples:
//
// [{Name: "X-Forwarded-Email", Value: "{{.Claims.email}}"}]
// [{Name: "Authorization", Value: "Bearer {{.AccessToken}}"}]
ProviderURL string `json:"providerURL"`
RevocationURL string `json:"revocationURL"`
CallbackURL string `json:"callbackURL"`
LogoutURL string `json:"logoutURL"`
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
PostLogoutRedirectURI string `json:"postLogoutRedirectURI"`
LogLevel string `json:"logLevel"`
SessionEncryptionKey string `json:"sessionEncryptionKey"`
OIDCEndSessionURL string `json:"oidcEndSessionURL"`
AllowedRolesAndGroups []string `json:"allowedRolesAndGroups"`
ExcludedURLs []string `json:"excludedURLs"`
AllowedUserDomains []string `json:"allowedUserDomains"`
AllowedUsers []string `json:"allowedUsers"`
Scopes []string `json:"scopes"`
Headers []TemplatedHeader `json:"headers"`
RateLimit int `json:"rateLimit"`
RefreshGracePeriodSeconds int `json:"refreshGracePeriodSeconds"`
ForceHTTPS bool `json:"forceHTTPS"`
EnablePKCE bool `json:"enablePKCE"`
}
const (
+4 -4
View File
@@ -254,10 +254,10 @@ func TestLogger(t *testing.T) {
var debugBuf, infoBuf, errorBuf bytes.Buffer
tests := []struct {
name string
logLevel string
testFunc func(*Logger)
checkFunc func(t *testing.T, debugOut, infoOut, errorOut string)
name string
logLevel string
}{
{
name: "Debug Level",
@@ -405,9 +405,9 @@ func TestHandleError(t *testing.T) {
// Test helper types
type testResponseRecorder struct {
statusCode int
body string
headers map[string][]string
body string
statusCode int
}
func (r *testResponseRecorder) Header() http.Header {
+1 -1
View File
@@ -178,10 +178,10 @@ func TestTemplateExecution(t *testing.T) {
func TestTemplateExecutionContext(t *testing.T) {
// Define a test struct that matches the one used in processAuthorizedRequest
type templateData struct {
Claims map[string]any
AccessToken string
IdToken string
RefreshToken string
Claims map[string]any
}
// Test cases
+3 -3
View File
@@ -20,12 +20,12 @@ func TestTemplatedHeadersIntegration(t *testing.T) {
ts.Setup()
tests := []struct {
name string
headers []TemplatedHeader
sessionSetup func(*SessionData)
claims map[string]any
expectedHeaders map[string]string
interceptedHeaders map[string]string
name string
headers []TemplatedHeader
}{
{
name: "Basic Email Header",
@@ -423,9 +423,9 @@ func TestEdgeCaseTemplatedHeaders(t *testing.T) {
ts.Setup()
tests := []struct {
claims map[string]any
name string
headers []TemplatedHeader
claims map[string]any
shouldExecuteCheck bool
}{
{
+3 -3
View File
@@ -28,11 +28,11 @@ func TestTokenCorruptionScenario(t *testing.T) {
validJWT := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImV4cCI6OTk5OTk5OTk5OX0.signature"
tests := []struct {
corruptionScenario func(*SessionData)
name string
tokenSize int
iterations int
expectConsistent bool
corruptionScenario func(*SessionData) // Function to simulate corruption
}{
{
name: "Small token - multiple retrievals",
@@ -207,8 +207,8 @@ func TestChunkReassemblyEdgeCases(t *testing.T) {
// Test various corruption scenarios
corruptionTests := []struct {
name string
corruption func(map[int]*sessions.Session)
name string
expectEmpty bool
}{
{
@@ -367,8 +367,8 @@ func TestRaceConditionProtection(t *testing.T) {
// TestMemoryExhaustionProtection tests protection against memory exhaustion attacks
func TestMemoryExhaustionProtection(t *testing.T) {
tests := []struct {
name string
setupCorruption func() string
name string
expectRejection bool
}{
{
+2 -2
View File
@@ -19,10 +19,10 @@ import (
func TestTokenTypeDistinction(t *testing.T) {
// Define test data where AccessToken and IdToken are deliberately different
type templateData struct {
Claims map[string]any
AccessToken string
IdToken string
RefreshToken string
Claims map[string]any
}
testData := templateData{
@@ -323,12 +323,12 @@ func TestTokenCorruptionIntegrationFlows(t *testing.T) {
}
tests := []struct {
corruptAction func(*SessionData)
name string
accessToken string
refreshToken string
idToken string
expectSuccess bool
corruptAction func(*SessionData) // Function to corrupt session after storage
}{
{
name: "Normal flow - small tokens",