Files
traefikoidc/internal/providers/validation.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

152 lines
4.1 KiB
Go

package providers
import (
"fmt"
"net/url"
"strings"
)
// ConfigValidator provides common configuration validation utilities for providers.
type ConfigValidator struct{}
// NewConfigValidator creates a new configuration validator.
func NewConfigValidator() *ConfigValidator {
return &ConfigValidator{}
}
// ValidateIssuerURL validates that an issuer URL is properly formatted and accessible.
func (v *ConfigValidator) ValidateIssuerURL(issuerURL string) error {
if issuerURL == "" {
return fmt.Errorf("issuer URL cannot be empty")
}
parsedURL, err := url.Parse(issuerURL)
if err != nil {
return fmt.Errorf("invalid issuer URL format: %w", err)
}
if parsedURL.Scheme == "" {
return fmt.Errorf("issuer URL must include scheme (http/https)")
}
if parsedURL.Scheme != "http" && parsedURL.Scheme != "https" {
return fmt.Errorf("issuer URL scheme must be http or https")
}
if parsedURL.Host == "" {
return fmt.Errorf("issuer URL must include host")
}
return nil
}
// ValidateClientID validates that a client ID is properly formatted.
func (v *ConfigValidator) ValidateClientID(clientID string) error {
if clientID == "" {
return fmt.Errorf("client ID cannot be empty")
}
if len(clientID) < 3 {
return fmt.Errorf("client ID appears to be too short")
}
return nil
}
// ValidateScopes validates that the provided scopes are reasonable.
func (v *ConfigValidator) ValidateScopes(scopes []string) error {
if len(scopes) == 0 {
return fmt.Errorf("at least one scope must be provided")
}
hasOpenIDScope := false
for _, scope := range scopes {
if strings.TrimSpace(scope) == ScopeOpenID {
hasOpenIDScope = true
break
}
}
if !hasOpenIDScope {
return fmt.Errorf("'openid' scope is required for OIDC authentication")
}
return nil
}
// ValidateRedirectURL validates that a redirect URL is properly formatted.
func (v *ConfigValidator) ValidateRedirectURL(redirectURL string) error {
if redirectURL == "" {
return fmt.Errorf("redirect URL cannot be empty")
}
parsedURL, err := url.Parse(redirectURL)
if err != nil {
return fmt.Errorf("invalid redirect URL format: %w", err)
}
if parsedURL.Scheme == "" {
return fmt.Errorf("redirect URL must include scheme (http/https)")
}
return nil
}
// ValidateProviderSpecificConfig performs provider-specific validation.
func (v *ConfigValidator) ValidateProviderSpecificConfig(provider OIDCProvider, config map[string]interface{}) error {
switch provider.GetType() {
case ProviderTypeGoogle:
return v.validateGoogleConfig(config)
case ProviderTypeAzure:
return v.validateAzureConfig(config)
case ProviderTypeGeneric:
return v.validateGenericConfig(config)
default:
return fmt.Errorf("unknown provider type: %d", provider.GetType())
}
}
// validateGoogleConfig validates Google-specific configuration.
func (v *ConfigValidator) validateGoogleConfig(config map[string]interface{}) error {
if issuerURL, ok := config["issuer_url"].(string); ok {
if !strings.Contains(issuerURL, "accounts.google.com") {
return fmt.Errorf("google provider requires issuer URL to contain accounts.google.com")
}
}
return nil
}
// validateAzureConfig validates Azure-specific configuration.
func (v *ConfigValidator) validateAzureConfig(config map[string]interface{}) error {
if issuerURL, ok := config["issuer_url"].(string); ok {
if !strings.Contains(issuerURL, "login.microsoftonline.com") && !strings.Contains(issuerURL, "sts.windows.net") {
return fmt.Errorf("azure provider requires issuer URL to contain login.microsoftonline.com or sts.windows.net")
}
}
if issuerURL, ok := config["issuer_url"].(string); ok {
parsedURL, err := url.Parse(issuerURL)
if err == nil {
pathParts := strings.Split(parsedURL.Path, "/")
hasTenantID := false
for _, part := range pathParts {
if len(part) == 36 && strings.Count(part, "-") == 4 {
hasTenantID = true
break
}
}
if !hasTenantID {
return fmt.Errorf("azure issuer URL should include tenant ID")
}
}
}
return nil
}
// validateGenericConfig validates generic OIDC provider configuration.
func (v *ConfigValidator) validateGenericConfig(config map[string]interface{}) error {
return nil
}