mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-06-05 22:44:17 +00:00
e64fc7f730
* Add redis support for distributed caching * Move towards the self-provided Redis connection pool and RESP protocol implementation. Official redis client library won't work with yaegi. * fixup! Move towards the self-provided Redis connection pool and RESP protocol implementation. Official redis client library won't work with yaegi. * fixup! fixup! Move towards the self-provided Redis connection pool and RESP protocol implementation. Official redis client library won't work with yaegi. * fixup! fixup! fixup! Move towards the self-provided Redis connection pool and RESP protocol implementation. Official redis client library won't work with yaegi. * fixup! fixup! fixup! fixup! Move towards the self-provided Redis connection pool and RESP protocol implementation. Official redis client library won't work with yaegi. * fixup! fixup! fixup! fixup! fixup! Move towards the self-provided Redis connection pool and RESP protocol implementation. Official redis client library won't work with yaegi. * ... and another all nighter. * fixup! ... and another all nighter. * fixup! fixup! ... and another all nighter. * fixup! fixup! fixup! ... and another all nighter. * Resolve issue #85 by adding ability to set custom claims in JWT tokens * Remove redundant validation in auth middleware ( issue #89 ) * Add ability to set cookie prefix for session cookies ( #87 ) * fixup! Add ability to set cookie prefix for session cookies ( #87 ) * Add ability to set cookie max age - issue #91 * Potential fix for code scanning alert no. 10: Size computation for allocation may overflow Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> * fixup! Merge main into 0.8.0-redis: resolve conflicts --------- Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
181 lines
4.9 KiB
Go
181 lines
4.9 KiB
Go
package traefikoidc
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
defaultBlacklistDuration = 24 * time.Hour
|
|
)
|
|
|
|
// CacheManager manages all caching components using the universal cache
|
|
type CacheManager struct {
|
|
manager *UniversalCacheManager
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
var (
|
|
globalCacheManagerInstance *CacheManager
|
|
cacheManagerInitOnce sync.Once
|
|
)
|
|
|
|
// GetGlobalCacheManager returns a singleton CacheManager instance
|
|
// Deprecated: Use GetGlobalCacheManagerWithConfig instead
|
|
func GetGlobalCacheManager(wg *sync.WaitGroup) *CacheManager {
|
|
return GetGlobalCacheManagerWithConfig(wg, nil)
|
|
}
|
|
|
|
// GetGlobalCacheManagerWithConfig returns a singleton CacheManager instance with optional Redis configuration
|
|
func GetGlobalCacheManagerWithConfig(wg *sync.WaitGroup, config *Config) *CacheManager {
|
|
cacheManagerInitOnce.Do(func() {
|
|
var redisConfig *RedisConfig
|
|
var logger *Logger
|
|
|
|
if config != nil {
|
|
logger = NewLogger(config.LogLevel)
|
|
|
|
// Initialize Redis config if not present
|
|
if config.Redis == nil {
|
|
config.Redis = &RedisConfig{}
|
|
}
|
|
|
|
// Apply environment variable fallbacks for fields not set in config
|
|
// This allows env vars to be used as optional overrides
|
|
config.Redis.ApplyEnvFallbacks()
|
|
|
|
// Apply defaults after env fallbacks
|
|
config.Redis.ApplyDefaults()
|
|
|
|
redisConfig = config.Redis
|
|
}
|
|
|
|
globalCacheManagerInstance = &CacheManager{
|
|
manager: GetUniversalCacheManagerWithConfig(logger, redisConfig),
|
|
}
|
|
})
|
|
return globalCacheManagerInstance
|
|
}
|
|
|
|
// GetSharedTokenBlacklist returns the shared token blacklist cache
|
|
func (cm *CacheManager) GetSharedTokenBlacklist() CacheInterface {
|
|
cm.mu.RLock()
|
|
defer cm.mu.RUnlock()
|
|
return &CacheInterfaceWrapper{cache: cm.manager.GetBlacklistCache()}
|
|
}
|
|
|
|
// GetSharedTokenCache returns the shared token cache
|
|
func (cm *CacheManager) GetSharedTokenCache() *TokenCache {
|
|
cm.mu.RLock()
|
|
defer cm.mu.RUnlock()
|
|
return &TokenCache{cache: cm.manager.GetTokenCache()}
|
|
}
|
|
|
|
// GetSharedMetadataCache returns the shared metadata cache
|
|
func (cm *CacheManager) GetSharedMetadataCache() *MetadataCache {
|
|
cm.mu.RLock()
|
|
defer cm.mu.RUnlock()
|
|
return &MetadataCache{
|
|
cache: cm.manager.GetMetadataCache(),
|
|
logger: cm.manager.logger,
|
|
}
|
|
}
|
|
|
|
// GetSharedJWKCache returns the shared JWK cache
|
|
func (cm *CacheManager) GetSharedJWKCache() JWKCacheInterface {
|
|
cm.mu.RLock()
|
|
defer cm.mu.RUnlock()
|
|
return &JWKCache{cache: cm.manager.GetJWKCache()}
|
|
}
|
|
|
|
// GetSharedIntrospectionCache returns the shared token introspection cache
|
|
// for caching OAuth 2.0 Token Introspection (RFC 7662) results
|
|
func (cm *CacheManager) GetSharedIntrospectionCache() CacheInterface {
|
|
cm.mu.RLock()
|
|
defer cm.mu.RUnlock()
|
|
return &CacheInterfaceWrapper{cache: cm.manager.GetIntrospectionCache()}
|
|
}
|
|
|
|
// GetSharedTokenTypeCache returns the shared token type cache
|
|
// for caching token type detection results to improve performance
|
|
func (cm *CacheManager) GetSharedTokenTypeCache() CacheInterface {
|
|
cm.mu.RLock()
|
|
defer cm.mu.RUnlock()
|
|
return &CacheInterfaceWrapper{cache: cm.manager.GetTokenTypeCache()}
|
|
}
|
|
|
|
// Close gracefully shuts down all cache components
|
|
func (cm *CacheManager) Close() error {
|
|
cm.mu.Lock()
|
|
defer cm.mu.Unlock()
|
|
return cm.manager.Close()
|
|
}
|
|
|
|
// CleanupGlobalCacheManager cleans up the global cache manager
|
|
func CleanupGlobalCacheManager() error {
|
|
if globalCacheManagerInstance != nil {
|
|
return globalCacheManagerInstance.Close()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CacheInterfaceWrapper wraps UniversalCache to implement CacheInterface
|
|
type CacheInterfaceWrapper struct {
|
|
cache *UniversalCache
|
|
}
|
|
|
|
// Set stores a value
|
|
func (c *CacheInterfaceWrapper) Set(key string, value interface{}, ttl time.Duration) {
|
|
_ = c.cache.Set(key, value, ttl) // Safe to ignore: cache set failures are non-critical
|
|
}
|
|
|
|
// Get retrieves a value
|
|
func (c *CacheInterfaceWrapper) Get(key string) (interface{}, bool) {
|
|
return c.cache.Get(key)
|
|
}
|
|
|
|
// Delete removes a key
|
|
func (c *CacheInterfaceWrapper) Delete(key string) {
|
|
c.cache.Delete(key)
|
|
}
|
|
|
|
// SetMaxSize updates the max size
|
|
func (c *CacheInterfaceWrapper) SetMaxSize(size int) {
|
|
c.cache.SetMaxSize(size)
|
|
}
|
|
|
|
// Cleanup triggers immediate cleanup of expired items
|
|
func (c *CacheInterfaceWrapper) Cleanup() {
|
|
c.cache.Cleanup()
|
|
}
|
|
|
|
// Close shuts down the cache
|
|
func (c *CacheInterfaceWrapper) Close() {
|
|
// Close the underlying cache to stop goroutines
|
|
if c.cache != nil {
|
|
_ = c.cache.Close() // Safe to ignore: closing cache is best-effort during shutdown
|
|
}
|
|
}
|
|
|
|
// Size returns the number of items
|
|
func (c *CacheInterfaceWrapper) Size() int {
|
|
return c.cache.Size()
|
|
}
|
|
|
|
// Clear removes all items
|
|
func (c *CacheInterfaceWrapper) Clear() {
|
|
c.cache.Clear()
|
|
}
|
|
|
|
// GetStats returns cache statistics
|
|
func (c *CacheInterfaceWrapper) GetStats() map[string]interface{} {
|
|
return c.cache.GetMetrics()
|
|
}
|
|
|
|
// SetMaxMemory sets the maximum memory limit
|
|
func (c *CacheInterfaceWrapper) SetMaxMemory(bytes int64) {
|
|
c.cache.mu.Lock()
|
|
defer c.cache.mu.Unlock()
|
|
c.cache.config.MaxMemoryBytes = bytes
|
|
}
|