Files
traefikoidc/config/compatibility.go
T
lukaszraczylo e64fc7f730 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>
2025-11-30 02:18:46 +00:00

259 lines
8.0 KiB
Go

// 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
}