mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-14 04:07:46 +00:00
Add redis support for distributed caching (#83)
* 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>
This commit is contained in:
co-authored by
Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
parent
5fcbd54955
commit
e64fc7f730
@@ -0,0 +1,258 @@
|
||||
// Package config provides backward compatibility for legacy configuration
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/lukaszraczylo/traefikoidc/internal/compat"
|
||||
"github.com/lukaszraczylo/traefikoidc/internal/features"
|
||||
)
|
||||
|
||||
// LegacyAdapter provides backward compatibility for old Config struct
|
||||
type LegacyAdapter struct {
|
||||
unified *UnifiedConfig
|
||||
adapter *compat.ConfigAdapter
|
||||
}
|
||||
|
||||
// NewLegacyAdapter creates a new legacy adapter from unified config
|
||||
func NewLegacyAdapter(unified *UnifiedConfig) *LegacyAdapter {
|
||||
adapter := compat.NewConfigAdapter(unified)
|
||||
|
||||
// Register getters for commonly used fields
|
||||
adapter.RegisterGetter("ProviderURL", func() interface{} {
|
||||
return unified.Provider.IssuerURL
|
||||
})
|
||||
adapter.RegisterGetter("ClientID", func() interface{} {
|
||||
return unified.Provider.ClientID
|
||||
})
|
||||
adapter.RegisterGetter("ClientSecret", func() interface{} {
|
||||
return unified.Provider.ClientSecret
|
||||
})
|
||||
adapter.RegisterGetter("CallbackURL", func() interface{} {
|
||||
return unified.Provider.RedirectURL
|
||||
})
|
||||
adapter.RegisterGetter("LogoutURL", func() interface{} {
|
||||
return unified.Provider.LogoutURL
|
||||
})
|
||||
adapter.RegisterGetter("PostLogoutRedirectURI", func() interface{} {
|
||||
return unified.Provider.PostLogoutRedirectURI
|
||||
})
|
||||
adapter.RegisterGetter("SessionEncryptionKey", func() interface{} {
|
||||
return unified.Session.EncryptionKey
|
||||
})
|
||||
adapter.RegisterGetter("ForceHTTPS", func() interface{} {
|
||||
return unified.Security.ForceHTTPS
|
||||
})
|
||||
adapter.RegisterGetter("LogLevel", func() interface{} {
|
||||
return unified.Logging.Level
|
||||
})
|
||||
adapter.RegisterGetter("Scopes", func() interface{} {
|
||||
return unified.Provider.Scopes
|
||||
})
|
||||
adapter.RegisterGetter("OverrideScopes", func() interface{} {
|
||||
return unified.Provider.OverrideScopes
|
||||
})
|
||||
adapter.RegisterGetter("AllowedUsers", func() interface{} {
|
||||
return unified.Security.AllowedUsers
|
||||
})
|
||||
adapter.RegisterGetter("AllowedUserDomains", func() interface{} {
|
||||
return unified.Security.AllowedUserDomains
|
||||
})
|
||||
adapter.RegisterGetter("AllowedRolesAndGroups", func() interface{} {
|
||||
return unified.Security.AllowedRolesAndGroups
|
||||
})
|
||||
adapter.RegisterGetter("ExcludedURLs", func() interface{} {
|
||||
return unified.Security.ExcludedURLs
|
||||
})
|
||||
adapter.RegisterGetter("EnablePKCE", func() interface{} {
|
||||
return unified.Security.EnablePKCE
|
||||
})
|
||||
adapter.RegisterGetter("RateLimit", func() interface{} {
|
||||
return unified.RateLimit.RequestsPerSecond
|
||||
})
|
||||
adapter.RegisterGetter("RefreshGracePeriodSeconds", func() interface{} {
|
||||
return int(unified.Token.RefreshGracePeriod.Seconds())
|
||||
})
|
||||
adapter.RegisterGetter("CookieDomain", func() interface{} {
|
||||
return unified.Session.Domain
|
||||
})
|
||||
adapter.RegisterGetter("SecurityHeaders", func() interface{} {
|
||||
return unified.Security.Headers
|
||||
})
|
||||
|
||||
return &LegacyAdapter{
|
||||
unified: unified,
|
||||
adapter: adapter,
|
||||
}
|
||||
}
|
||||
|
||||
// ToOldConfig converts unified config to old Config struct format
|
||||
func (la *LegacyAdapter) ToOldConfig() *Config {
|
||||
// Use feature flags to determine behavior
|
||||
if !features.IsUnifiedConfigEnabled() {
|
||||
// Return existing Config if unified config not enabled
|
||||
return CreateConfig()
|
||||
}
|
||||
|
||||
cfg := &Config{
|
||||
ProviderURL: la.unified.Provider.IssuerURL,
|
||||
ClientID: la.unified.Provider.ClientID,
|
||||
ClientSecret: la.unified.Provider.ClientSecret,
|
||||
CallbackURL: la.unified.Provider.RedirectURL,
|
||||
LogoutURL: la.unified.Provider.LogoutURL,
|
||||
PostLogoutRedirectURI: la.unified.Provider.PostLogoutRedirectURI,
|
||||
SessionEncryptionKey: la.unified.Session.EncryptionKey,
|
||||
ForceHTTPS: la.unified.Security.ForceHTTPS,
|
||||
LogLevel: la.unified.Logging.Level,
|
||||
Scopes: la.unified.Provider.Scopes,
|
||||
OverrideScopes: la.unified.Provider.OverrideScopes,
|
||||
AllowedUsers: la.unified.Security.AllowedUsers,
|
||||
AllowedUserDomains: la.unified.Security.AllowedUserDomains,
|
||||
AllowedRolesAndGroups: la.unified.Security.AllowedRolesAndGroups,
|
||||
ExcludedURLs: la.unified.Security.ExcludedURLs,
|
||||
EnablePKCE: la.unified.Security.EnablePKCE,
|
||||
RateLimit: la.unified.RateLimit.RequestsPerSecond,
|
||||
RefreshGracePeriodSeconds: int(la.unified.Token.RefreshGracePeriod.Seconds()),
|
||||
Headers: la.convertHeaders(),
|
||||
CookieDomain: la.unified.Session.Domain,
|
||||
SecurityHeaders: la.unified.Security.Headers,
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
// convertHeaders converts unified header config to old format
|
||||
func (la *LegacyAdapter) convertHeaders() []HeaderConfig {
|
||||
headers := make([]HeaderConfig, 0)
|
||||
|
||||
for name, value := range la.unified.Middleware.CustomHeaders {
|
||||
headers = append(headers, HeaderConfig{
|
||||
Name: name,
|
||||
Value: value,
|
||||
})
|
||||
}
|
||||
|
||||
return headers
|
||||
}
|
||||
|
||||
// FromOldConfig creates unified config from old Config struct
|
||||
func FromOldConfig(old *Config) *UnifiedConfig {
|
||||
unified := NewUnifiedConfig()
|
||||
|
||||
// Map provider settings
|
||||
unified.Provider.IssuerURL = old.ProviderURL
|
||||
unified.Provider.ClientID = old.ClientID
|
||||
unified.Provider.ClientSecret = old.ClientSecret
|
||||
unified.Provider.RedirectURL = old.CallbackURL
|
||||
unified.Provider.LogoutURL = old.LogoutURL
|
||||
unified.Provider.PostLogoutRedirectURI = old.PostLogoutRedirectURI
|
||||
unified.Provider.Scopes = old.Scopes
|
||||
unified.Provider.OverrideScopes = old.OverrideScopes
|
||||
|
||||
// Map session settings
|
||||
unified.Session.EncryptionKey = old.SessionEncryptionKey
|
||||
unified.Session.Domain = old.CookieDomain
|
||||
|
||||
// Map security settings
|
||||
unified.Security.ForceHTTPS = old.ForceHTTPS
|
||||
unified.Security.EnablePKCE = old.EnablePKCE
|
||||
unified.Security.AllowedUsers = old.AllowedUsers
|
||||
unified.Security.AllowedUserDomains = old.AllowedUserDomains
|
||||
unified.Security.AllowedRolesAndGroups = old.AllowedRolesAndGroups
|
||||
unified.Security.ExcludedURLs = old.ExcludedURLs
|
||||
unified.Security.Headers = old.SecurityHeaders
|
||||
|
||||
// Map rate limiting
|
||||
unified.RateLimit.RequestsPerSecond = old.RateLimit
|
||||
unified.RateLimit.Enabled = old.RateLimit > 0
|
||||
|
||||
// Map token settings
|
||||
unified.Token.RefreshGracePeriod = timeSecondsToDuration(old.RefreshGracePeriodSeconds)
|
||||
|
||||
// Map logging
|
||||
unified.Logging.Level = old.LogLevel
|
||||
|
||||
// Map custom headers
|
||||
if len(old.Headers) > 0 {
|
||||
unified.Middleware.CustomHeaders = make(map[string]string)
|
||||
for _, header := range old.Headers {
|
||||
unified.Middleware.CustomHeaders[header.Name] = header.Value
|
||||
}
|
||||
}
|
||||
|
||||
// Store original config in legacy field for reference
|
||||
unified.Legacy["original"] = old
|
||||
|
||||
return unified
|
||||
}
|
||||
|
||||
// timeSecondsToDuration converts seconds to time.Duration
|
||||
func timeSecondsToDuration(seconds int) time.Duration {
|
||||
return time.Duration(seconds) * time.Second
|
||||
}
|
||||
|
||||
// GetConfigInterface returns appropriate config based on feature flag
|
||||
func GetConfigInterface() interface{} {
|
||||
if features.IsUnifiedConfigEnabled() {
|
||||
return NewUnifiedConfig()
|
||||
}
|
||||
return CreateConfig()
|
||||
}
|
||||
|
||||
// ValidateConfig validates config based on feature flag
|
||||
func ValidateConfig(cfg interface{}) error {
|
||||
if features.IsUnifiedConfigEnabled() {
|
||||
if unified, ok := cfg.(*UnifiedConfig); ok {
|
||||
return unified.Validate()
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to old validation if available
|
||||
if old, ok := cfg.(*Config); ok {
|
||||
return old.Validate()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add Validate method to old Config for compatibility
|
||||
func (c *Config) Validate() error {
|
||||
var errors ValidationErrors
|
||||
|
||||
// Basic validation for old config
|
||||
if c.ProviderURL == "" {
|
||||
errors = append(errors, ValidationError{
|
||||
Field: "ProviderURL",
|
||||
Message: "provider URL is required",
|
||||
})
|
||||
}
|
||||
|
||||
if c.ClientID == "" {
|
||||
errors = append(errors, ValidationError{
|
||||
Field: "ClientID",
|
||||
Message: "client ID is required",
|
||||
})
|
||||
}
|
||||
|
||||
if c.ClientSecret == "" && !c.EnablePKCE {
|
||||
errors = append(errors, ValidationError{
|
||||
Field: "ClientSecret",
|
||||
Message: "client secret is required (or enable PKCE)",
|
||||
})
|
||||
}
|
||||
|
||||
if c.SessionEncryptionKey != "" && len(c.SessionEncryptionKey) < minEncryptionKeyLength {
|
||||
errors = append(errors, ValidationError{
|
||||
Field: "SessionEncryptionKey",
|
||||
Message: fmt.Sprintf("encryption key must be at least %d characters", minEncryptionKeyLength),
|
||||
Value: len(c.SessionEncryptionKey),
|
||||
})
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return errors
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user