mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-14 04:07:46 +00:00
```
ok github.com/lukaszraczylo/traefikoidc 117.017s coverage: 72.6% of statements
ok github.com/lukaszraczylo/traefikoidc/auth 0.505s coverage: 87.1% of statements
ok github.com/lukaszraczylo/traefikoidc/circuit_breaker 0.283s coverage: 99.0% of statements
github.com/lukaszraczylo/traefikoidc/config coverage: 0.0% of statements
ok github.com/lukaszraczylo/traefikoidc/handlers 0.349s coverage: 98.2% of statements
ok github.com/lukaszraczylo/traefikoidc/internal/providers (cached) coverage: 94.3% of statements
ok github.com/lukaszraczylo/traefikoidc/middleware 0.808s coverage: 78.0% of statements
ok github.com/lukaszraczylo/traefikoidc/recovery 0.653s coverage: 100.0% of statements
ok github.com/lukaszraczylo/traefikoidc/session/chunking (cached) coverage: 87.8% of statements
ok github.com/lukaszraczylo/traefikoidc/session/core (cached) coverage: 85.6% of statements
ok github.com/lukaszraczylo/traefikoidc/session/crypto (cached) coverage: 81.8% of statements
ok github.com/lukaszraczylo/traefikoidc/session/storage (cached) coverage: 93.5% of statements
ok github.com/lukaszraczylo/traefikoidc/session/validators (cached) coverage: 98.8% of statements
````
152 lines
4.7 KiB
Go
152 lines
4.7 KiB
Go
// Package traefikoidc provides OIDC authentication middleware for Traefik.
|
|
package traefikoidc
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
defaultBlacklistDuration = 24 * time.Hour
|
|
defaultMaxBlacklistSize = 10000
|
|
)
|
|
|
|
var (
|
|
globalCacheManager *CacheManager
|
|
cacheManagerOnce sync.Once
|
|
cacheManagerMutex sync.RWMutex
|
|
)
|
|
|
|
// CacheManager manages all caching components for the OIDC middleware.
|
|
// It provides thread-safe access to token blacklist, token cache, metadata cache,
|
|
// and JWK cache. This centralizes cache management to ensure efficient memory
|
|
// usage and consistent cache behavior across the application.
|
|
type CacheManager struct {
|
|
tokenBlacklist CacheInterface
|
|
tokenCache *TokenCache
|
|
metadataCache *MetadataCache
|
|
jwkCache JWKCacheInterface
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
// GetGlobalCacheManager returns a singleton instance of CacheManager.
|
|
// It initializes all cache components on first call and reuses the same instance
|
|
// for subsequent calls. This ensures consistent cache state and efficient memory
|
|
// usage across the entire application lifecycle.
|
|
// Parameters:
|
|
// - wg: WaitGroup for coordinating cache cleanup during shutdown.
|
|
//
|
|
// Returns:
|
|
// - The global CacheManager instance.
|
|
func GetGlobalCacheManager(wg *sync.WaitGroup) *CacheManager {
|
|
cacheManagerOnce.Do(func() {
|
|
globalCacheManager = &CacheManager{
|
|
tokenBlacklist: func() CacheInterface {
|
|
config := DefaultUnifiedCacheConfig()
|
|
config.MaxSize = defaultMaxBlacklistSize
|
|
c := NewUnifiedCache(config)
|
|
return NewCacheAdapter(c)
|
|
}(),
|
|
tokenCache: NewTokenCache(),
|
|
metadataCache: NewMetadataCache(wg),
|
|
jwkCache: &JWKCache{},
|
|
}
|
|
})
|
|
return globalCacheManager
|
|
}
|
|
|
|
// GetSharedTokenBlacklist returns the shared token blacklist cache.
|
|
// This cache stores revoked or expired tokens to prevent replay attacks.
|
|
// Access is protected by read lock to ensure thread safety.
|
|
// Returns:
|
|
// - The shared token blacklist CacheInterface instance.
|
|
func (cm *CacheManager) GetSharedTokenBlacklist() CacheInterface {
|
|
cm.mu.RLock()
|
|
defer cm.mu.RUnlock()
|
|
return cm.tokenBlacklist
|
|
}
|
|
|
|
// GetSharedTokenCache returns the shared token cache for verified tokens.
|
|
// This cache stores claims from successfully verified tokens to avoid
|
|
// repeated verification of the same tokens.
|
|
// Access is protected by read lock to ensure thread safety.
|
|
// Returns:
|
|
// - The shared TokenCache instance.
|
|
func (cm *CacheManager) GetSharedTokenCache() *TokenCache {
|
|
cm.mu.RLock()
|
|
defer cm.mu.RUnlock()
|
|
return cm.tokenCache
|
|
}
|
|
|
|
// GetSharedMetadataCache returns the shared metadata cache.
|
|
// This cache stores OIDC provider metadata (endpoints, keys) to avoid
|
|
// repeated requests to the provider's .well-known configuration endpoint.
|
|
// Access is protected by read lock to ensure thread safety.
|
|
// Returns:
|
|
// - The shared MetadataCache instance.
|
|
func (cm *CacheManager) GetSharedMetadataCache() *MetadataCache {
|
|
cm.mu.RLock()
|
|
defer cm.mu.RUnlock()
|
|
return cm.metadataCache
|
|
}
|
|
|
|
// GetSharedJWKCache returns the shared JWK (JSON Web Key) cache.
|
|
// This cache stores public keys from the provider's JWKS endpoint
|
|
// for token signature verification.
|
|
// Access is protected by read lock to ensure thread safety.
|
|
// Returns:
|
|
// - The shared JWKCacheInterface instance.
|
|
func (cm *CacheManager) GetSharedJWKCache() JWKCacheInterface {
|
|
cm.mu.RLock()
|
|
defer cm.mu.RUnlock()
|
|
return cm.jwkCache
|
|
}
|
|
|
|
// Close gracefully shuts down all cache components and releases resources.
|
|
// It closes all individual caches and cleans up their associated goroutines.
|
|
// This method should be called when the middleware is shutting down.
|
|
// Safe to call multiple times.
|
|
// Returns:
|
|
// - An error if any cache fails to close properly, nil otherwise.
|
|
func (cm *CacheManager) Close() error {
|
|
cm.mu.Lock()
|
|
defer cm.mu.Unlock()
|
|
|
|
if cm.tokenBlacklist != nil {
|
|
cm.tokenBlacklist.Close()
|
|
cm.tokenBlacklist = nil
|
|
}
|
|
if cm.tokenCache != nil {
|
|
cm.tokenCache.Close()
|
|
cm.tokenCache = nil
|
|
}
|
|
if cm.metadataCache != nil {
|
|
cm.metadataCache.Close()
|
|
cm.metadataCache = nil
|
|
}
|
|
if cm.jwkCache != nil {
|
|
cm.jwkCache.Close()
|
|
cm.jwkCache = nil
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// CleanupGlobalCacheManager cleans up the global cache manager instance.
|
|
// It closes all cache components but does NOT reset the singleton for re-initialization
|
|
// to avoid race conditions with sync.Once. It's safe to call multiple times.
|
|
// Returns:
|
|
// - An error if cache cleanup fails, nil otherwise.
|
|
func CleanupGlobalCacheManager() error {
|
|
cacheManagerMutex.Lock()
|
|
defer cacheManagerMutex.Unlock()
|
|
|
|
if globalCacheManager != nil {
|
|
err := globalCacheManager.Close()
|
|
// Don't reset globalCacheManager to nil or cacheManagerOnce to avoid race conditions
|
|
// The cache manager remains closed and the Close() method handles multiple calls
|
|
return err
|
|
}
|
|
return nil
|
|
}
|