mirror of
https://github.com/nais/wonderwall.git
synced 2026-08-23 21:16:14 +00:00
refactor(config)!: rename id-token-signing-alg to jwks-fallback-alg
The flag never described id_token verification. It assigns an algorithm to provider JWKS keys that omit "alg", which is a compatibility shim for providers such as Azure and ID-porten. BREAKING CHANGE: openid.id-token-signing-alg is now openid.jwks-fallback-alg. A config file with the old key fails to start. The old environment variable is ignored and the value falls back to RS256.
This commit is contained in:
@@ -37,7 +37,7 @@ The following flags are available:
|
||||
| `openid.client-jwk` | string | | JWK containing the private key for the OpenID client in string format. If configured, this takes precedence over `openid.client-secret`. |
|
||||
| `openid.client-secret` | string | | Client secret for the OpenID client. Overridden by `openid.client-jwk`, if configured. |
|
||||
| `openid.domain-hint` | string | | Domain hint to include in authorization request for IdPs that support this parameter (e.g. Entra ID). |
|
||||
| `openid.id-token-signing-alg` | string | `RS256` | Expected JWA value (as defined in RFC 7518) of public keys for validating id_token signatures. This only applies where the key's `alg` header is not set. |
|
||||
| `openid.jwks-fallback-alg` | string | `RS256` | JWA value (as defined in RFC 7518) to assign to provider JWKS keys when their `alg` header is not set. |
|
||||
| `openid.new-client-auth-jwt-type` | bool | `false` | When enabled, sets the value of the \"typ\" header of the JWT used for client authentication equal to "client-authentication+jwt" in accordance with RFC7523bis. If not enabled, the value is set to "JWT". |
|
||||
| `openid.post-logout-redirect-uri` | string | | URI for redirecting the user after successful logout at the Identity Provider. |
|
||||
| `openid.provider` | string | `openid` | Provider configuration to load and use, either `openid`, `azure`, `idporten`. |
|
||||
|
||||
@@ -25,7 +25,7 @@ type OpenID struct {
|
||||
ClientJWK string `json:"client-jwk"`
|
||||
ClientSecret string `json:"client-secret"`
|
||||
DomainHint string `json:"domain-hint"`
|
||||
IDTokenSigningAlg string `json:"id-token-signing-alg"`
|
||||
JWKSFallbackAlg string `json:"jwks-fallback-alg"`
|
||||
NewClientAuthJWTType bool `json:"new-client-auth-jwt-type"`
|
||||
PostLogoutRedirectURI string `json:"post-logout-redirect-uri"`
|
||||
Provider Provider `json:"provider"`
|
||||
@@ -46,9 +46,9 @@ func (in OpenID) TrustedAudiences() map[string]bool {
|
||||
}
|
||||
|
||||
func (in OpenID) Validate() error {
|
||||
_, ok := jwa.LookupSignatureAlgorithm(in.IDTokenSigningAlg)
|
||||
_, ok := jwa.LookupSignatureAlgorithm(in.JWKSFallbackAlg)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid id_token signing algorithm: %q, must be one of %s", in.IDTokenSigningAlg, jwa.SignatureAlgorithms())
|
||||
return fmt.Errorf("invalid JWKS fallback algorithm: %q, must be one of %s", in.JWKSFallbackAlg, jwa.SignatureAlgorithms())
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -61,8 +61,8 @@ const (
|
||||
OpenIDClientJWK = "openid.client-jwk"
|
||||
OpenIDClientSecret = "openid.client-secret" // #nosec G101 -- configuration key, not a credential
|
||||
OpenIDDomainHint = "openid.domain-hint"
|
||||
OpenIDJWKSFallbackAlg = "openid.jwks-fallback-alg"
|
||||
OpenIDNewClientAuthJWTType = "openid.new-client-auth-jwt-type"
|
||||
OpenIDIDTokenSigningAlg = "openid.id-token-signing-alg" // #nosec G101 -- configuration key, not a credential
|
||||
OpenIDPostLogoutRedirectURI = "openid.post-logout-redirect-uri"
|
||||
OpenIDProvider = "openid.provider"
|
||||
OpenIDResourceIndicator = "openid.resource-indicator"
|
||||
@@ -78,7 +78,7 @@ func openidFlags() {
|
||||
flag.String(OpenIDClientJWK, "", "JWK containing the private key for the OpenID client in string format. If configured, this takes precedence over 'openid.client-secret'.")
|
||||
flag.String(OpenIDClientSecret, "", "Client secret for the OpenID client. Overridden by 'openid.client-jwk', if configured.")
|
||||
flag.String(OpenIDDomainHint, "", "Domain hint to include in authorization request for IdPs that support this parameter (e.g. Entra ID).")
|
||||
flag.String(OpenIDIDTokenSigningAlg, jwa.RS256().String(), "Expected JWA value (as defined in RFC 7518) of public keys for validating id_token signatures. This only applies where the key's 'alg' header is not set.")
|
||||
flag.String(OpenIDJWKSFallbackAlg, jwa.RS256().String(), "JWA value (as defined in RFC 7518) to assign to provider JWKS keys when their 'alg' header is not set.")
|
||||
flag.Bool(OpenIDNewClientAuthJWTType, false, "When enabled, sets the value of the \"typ\" header of the JWT used for client authentication equal to \"client-authentication+jwt\" in accordance with RFC7523bis. If not enabled, the value is set to \"JWT\".")
|
||||
flag.String(OpenIDPostLogoutRedirectURI, "", "URI for redirecting the user after successful logout at the Identity Provider.")
|
||||
flag.String(OpenIDProvider, string(ProviderOpenID), "Provider configuration to load and use, either 'openid', 'azure', 'idporten'.")
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ func Config() *config.Config {
|
||||
OpenID: config.OpenID{
|
||||
ACRValues: "idporten-loa-high",
|
||||
ClientID: "client-id",
|
||||
IDTokenSigningAlg: "RS256",
|
||||
JWKSFallbackAlg: "RS256",
|
||||
PostLogoutRedirectURI: "https://google.com",
|
||||
Provider: "test",
|
||||
Scopes: []string{"some-scope"},
|
||||
|
||||
@@ -58,7 +58,7 @@ func (t *TestProviderConfiguration) EndSessionEndpointURL() url.URL {
|
||||
return *u
|
||||
}
|
||||
|
||||
func (t *TestProviderConfiguration) IDTokenSigningAlg() jwa.KeyAlgorithm {
|
||||
func (t *TestProviderConfiguration) JwksFallbackAlg() jwa.KeyAlgorithm {
|
||||
return jwa.RS256()
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ type Provider interface {
|
||||
AuthorizationEndpoint() string
|
||||
AuthorizationResponseIssParameterSupported() bool
|
||||
EndSessionEndpointURL() url.URL
|
||||
IDTokenSigningAlg() jwa.KeyAlgorithm
|
||||
JwksFallbackAlg() jwa.KeyAlgorithm
|
||||
Issuer() string
|
||||
JwksURI() string
|
||||
PushedAuthorizationRequestEndpoint() string
|
||||
@@ -34,7 +34,7 @@ type Provider interface {
|
||||
|
||||
type provider struct {
|
||||
endSessionEndpointURL *url.URL
|
||||
idTokenSigningAlg jwa.KeyAlgorithm
|
||||
jwksFallbackAlg jwa.KeyAlgorithm
|
||||
metadata *ProviderMetadata
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ func (p *provider) TokenEndpoint() string {
|
||||
return p.metadata.TokenEndpoint
|
||||
}
|
||||
|
||||
func (p *provider) IDTokenSigningAlg() jwa.KeyAlgorithm {
|
||||
return p.idTokenSigningAlg
|
||||
func (p *provider) JwksFallbackAlg() jwa.KeyAlgorithm {
|
||||
return p.jwksFallbackAlg
|
||||
}
|
||||
|
||||
func (p *provider) Issuer() string {
|
||||
@@ -127,14 +127,14 @@ func NewProviderConfig(ctx context.Context, cfg *config.Config) (Provider, error
|
||||
|
||||
providerCfg.Print()
|
||||
|
||||
signingAlg, ok := jwa.LookupSignatureAlgorithm(cfg.OpenID.IDTokenSigningAlg)
|
||||
fallbackAlg, ok := jwa.LookupSignatureAlgorithm(cfg.OpenID.JWKSFallbackAlg)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid id_token signing algorithm: %q, must be one of %s", cfg.OpenID.IDTokenSigningAlg, jwa.SignatureAlgorithms())
|
||||
return nil, fmt.Errorf("invalid JWKS fallback algorithm: %q, must be one of %s", cfg.OpenID.JWKSFallbackAlg, jwa.SignatureAlgorithms())
|
||||
}
|
||||
|
||||
return &provider{
|
||||
endSessionEndpointURL: endSessionEndpointURL,
|
||||
idTokenSigningAlg: signingAlg,
|
||||
jwksFallbackAlg: fallbackAlg,
|
||||
metadata: providerCfg,
|
||||
}, nil
|
||||
}
|
||||
@@ -183,7 +183,7 @@ func (c *ProviderMetadata) Validate(cfg config.OpenID) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.validateIDTokenSigningAlg(cfg.IDTokenSigningAlg)
|
||||
err = c.validateJWKSFallbackAlg(cfg.JWKSFallbackAlg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -212,12 +212,13 @@ func (c *ProviderMetadata) validateLocaleValues(locale string) error {
|
||||
return fmt.Errorf("identity provider does not support '%s=%s', must be one of %s", config.OpenIDUILocales, locale, c.UILocalesSupported)
|
||||
}
|
||||
|
||||
func (c *ProviderMetadata) validateIDTokenSigningAlg(algorithm string) error {
|
||||
func (c *ProviderMetadata) validateJWKSFallbackAlg(algorithm string) error {
|
||||
// The JWKS is only used to verify id_tokens, so this is the right list.
|
||||
if slices.Contains(c.IDTokenSigningAlgValuesSupported, algorithm) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("identity provider does not support '%s=%s', must be one of %s", config.OpenIDIDTokenSigningAlg, algorithm, c.IDTokenSigningAlgValuesSupported)
|
||||
return fmt.Errorf("identity provider does not support '%s=%s', must be one of %s", config.OpenIDJWKSFallbackAlg, algorithm, c.IDTokenSigningAlgValuesSupported)
|
||||
}
|
||||
|
||||
type Supported []string
|
||||
|
||||
@@ -49,7 +49,7 @@ func TestProviderMetadata_Validate(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "invalid signing algorithm",
|
||||
config: config.OpenID{IDTokenSigningAlg: "HS256"},
|
||||
config: config.OpenID{JWKSFallbackAlg: "HS256"},
|
||||
assertion: assert.Error,
|
||||
},
|
||||
} {
|
||||
@@ -61,8 +61,8 @@ func TestProviderMetadata_Validate(t *testing.T) {
|
||||
if tt.config.UILocales != "" {
|
||||
cfg.OpenID.UILocales = tt.config.UILocales
|
||||
}
|
||||
if tt.config.IDTokenSigningAlg != "" {
|
||||
cfg.OpenID.IDTokenSigningAlg = tt.config.IDTokenSigningAlg
|
||||
if tt.config.JWKSFallbackAlg != "" {
|
||||
cfg.OpenID.JWKSFallbackAlg = tt.config.JWKSFallbackAlg
|
||||
}
|
||||
|
||||
err := metadata.Validate(cfg.OpenID)
|
||||
|
||||
@@ -36,7 +36,7 @@ func (p *JwksProvider) GetPublicJwkSet(ctx context.Context) (*jwk.Set, error) {
|
||||
return nil, fmt.Errorf("provider: fetching jwks: %w", err)
|
||||
}
|
||||
|
||||
set, err = ensureJwkSetWithAlg(set, p.config.IDTokenSigningAlg())
|
||||
set, err = ensureJwkSetWithAlg(set, p.config.JwksFallbackAlg())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("provider: mutating jwks: %w", err)
|
||||
}
|
||||
@@ -65,7 +65,7 @@ func (p *JwksProvider) RefreshPublicJwkSet(ctx context.Context) (*jwk.Set, error
|
||||
return nil, fmt.Errorf("provider: refreshing jwks: %w", err)
|
||||
}
|
||||
|
||||
set, err = ensureJwkSetWithAlg(set, p.config.IDTokenSigningAlg())
|
||||
set, err = ensureJwkSetWithAlg(set, p.config.JwksFallbackAlg())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("provider: mutating jwks: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user