mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-17 04:37:48 +00:00
Fix round-36 issues: DCR validation, auth-method default, shared metadata task, replay false-positive
Four verified fixes from the round-36 agent team (each confirmed against source before acting): - settings.go: Config.Validate now skips the client-credential block when Dynamic Client Registration is enabled and no clientID is pre-provisioned (RFC 7591 provides credentials at registration). Previously the unconditional 'clientID is required' made DCR unreachable via New. - dynamic_client_registration.go: default registered token_endpoint_auth_method to client_secret_post to match the plugin's runtime default; an enforcing IdP would otherwise reject the plugin's token exchange. - utilities.go: gate the shared per-provider singleton-metadata-refresh task stop on lastInstance (matching singleton-token-cleanup) so one instance's tear down no longer kills 2h metadata refresh for a surviving sibling. - token_manager.go: stop self-recording the JTI into the per-instance tokenBlacklist on every verify. On the cookie path the same valid token is re-presented per request; an LRU eviction of the raw-token cache (MaxSize 1000 / 5 MiB) then turned a legitimate cache miss into a false 'token replay detected'. Replay tracking stays in the shared shardedReplayCache. Regression tests: new review_r36_regression_test.go (4 tests); updated dynamic_client_registration_test.go and security_edge_cases_test.go which had encoded the old defaults. Verified: full source-order suite, full -race -count=1 -shuffle=on ./... (all packages), and golangci-lint run ./... (0 issues).
This commit is contained in:
+32
-25
@@ -422,34 +422,41 @@ func (c *Config) Validate() error {
|
||||
return fmt.Errorf("callbackURL must start with /")
|
||||
}
|
||||
|
||||
// Validate client credentials
|
||||
if c.ClientID == "" {
|
||||
return fmt.Errorf("clientID is required")
|
||||
}
|
||||
authMethod := c.ClientAuthMethod
|
||||
if authMethod == "" {
|
||||
authMethod = "client_secret_post"
|
||||
}
|
||||
switch authMethod {
|
||||
case "client_secret_post", "client_secret_basic":
|
||||
if c.ClientSecret == "" {
|
||||
return fmt.Errorf("clientSecret is required when clientAuthMethod is %q", authMethod)
|
||||
// Validate client credentials. With Dynamic Client Registration (RFC 7591)
|
||||
// enabled, clientID (and typically clientSecret) are not known at
|
||||
// construction time — the provider provisions them at registration. Skip
|
||||
// these checks in that case; the providerURL / callbackURL / session-key
|
||||
// checks above and below still run.
|
||||
dcrEnabled := c.DynamicClientRegistration != nil && c.DynamicClientRegistration.Enabled
|
||||
if !(dcrEnabled && c.ClientID == "") {
|
||||
if c.ClientID == "" {
|
||||
return fmt.Errorf("clientID is required")
|
||||
}
|
||||
case "private_key_jwt":
|
||||
if c.ClientAssertionPrivateKey == "" && c.ClientAssertionKeyPath == "" {
|
||||
return fmt.Errorf("clientAssertionPrivateKey or clientAssertionKeyPath is required when clientAuthMethod is private_key_jwt")
|
||||
authMethod := c.ClientAuthMethod
|
||||
if authMethod == "" {
|
||||
authMethod = "client_secret_post"
|
||||
}
|
||||
if c.ClientAssertionPrivateKey != "" && c.ClientAssertionKeyPath != "" {
|
||||
return fmt.Errorf("only one of clientAssertionPrivateKey or clientAssertionKeyPath may be set")
|
||||
switch authMethod {
|
||||
case "client_secret_post", "client_secret_basic":
|
||||
if c.ClientSecret == "" {
|
||||
return fmt.Errorf("clientSecret is required when clientAuthMethod is %q", authMethod)
|
||||
}
|
||||
case "private_key_jwt":
|
||||
if c.ClientAssertionPrivateKey == "" && c.ClientAssertionKeyPath == "" {
|
||||
return fmt.Errorf("clientAssertionPrivateKey or clientAssertionKeyPath is required when clientAuthMethod is private_key_jwt")
|
||||
}
|
||||
if c.ClientAssertionPrivateKey != "" && c.ClientAssertionKeyPath != "" {
|
||||
return fmt.Errorf("only one of clientAssertionPrivateKey or clientAssertionKeyPath may be set")
|
||||
}
|
||||
if c.ClientAssertionKeyID == "" {
|
||||
return fmt.Errorf("clientAssertionKeyID is required when clientAuthMethod is private_key_jwt")
|
||||
}
|
||||
if c.ClientAssertionAlg != "" && !isSupportedClientAssertionAlg(c.ClientAssertionAlg) {
|
||||
return fmt.Errorf("clientAssertionAlg %q is not supported (use RS256/384/512, PS256/384/512, or ES256/384/512)", c.ClientAssertionAlg)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("clientAuthMethod %q is not supported", authMethod)
|
||||
}
|
||||
if c.ClientAssertionKeyID == "" {
|
||||
return fmt.Errorf("clientAssertionKeyID is required when clientAuthMethod is private_key_jwt")
|
||||
}
|
||||
if c.ClientAssertionAlg != "" && !isSupportedClientAssertionAlg(c.ClientAssertionAlg) {
|
||||
return fmt.Errorf("clientAssertionAlg %q is not supported (use RS256/384/512, PS256/384/512, or ES256/384/512)", c.ClientAssertionAlg)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("clientAuthMethod %q is not supported", authMethod)
|
||||
}
|
||||
|
||||
// Validate session encryption key
|
||||
|
||||
Reference in New Issue
Block a user