diff --git a/.changelog/11026.txt b/.changelog/11026.txt new file mode 100644 index 0000000000..6d01ddcd74 --- /dev/null +++ b/.changelog/11026.txt @@ -0,0 +1,3 @@ +```release-note:feature +sso/oidc: **(Enterprise only)** Add support for providing acr_values in OIDC auth flow +``` diff --git a/api/acl.go b/api/acl.go index ebb8e5a967..0535d6ca7c 100644 --- a/api/acl.go +++ b/api/acl.go @@ -388,6 +388,7 @@ type OIDCAuthMethodConfig struct { OIDCClientID string `json:",omitempty"` OIDCClientSecret string `json:",omitempty"` OIDCScopes []string `json:",omitempty"` + OIDCACRValues []string `json:",omitempty"` AllowedRedirectURIs []string `json:",omitempty"` VerboseOIDCLogging bool `json:",omitempty"` // just for type=jwt @@ -415,6 +416,7 @@ func (c *OIDCAuthMethodConfig) RenderToConfig() map[string]interface{} { "OIDCClientID": c.OIDCClientID, "OIDCClientSecret": c.OIDCClientSecret, "OIDCScopes": c.OIDCScopes, + "OIDCACRValues": c.OIDCACRValues, "AllowedRedirectURIs": c.AllowedRedirectURIs, "VerboseOIDCLogging": c.VerboseOIDCLogging, // just for type=jwt diff --git a/internal/go-sso/oidcauth/config.go b/internal/go-sso/oidcauth/config.go index f343b99816..49fec039d3 100644 --- a/internal/go-sso/oidcauth/config.go +++ b/internal/go-sso/oidcauth/config.go @@ -90,6 +90,11 @@ type Config struct { // Valid only if Type=oidc OIDCScopes []string + // Space-separated list of OIDC Authorization Context Class Reference values + // + // Valid only if Type=oidc + OIDCACRValues []string + // Comma-separated list of allowed values for redirect_uri // // Valid only if Type=oidc @@ -215,6 +220,8 @@ func (c *Config) Validate() error { return fmt.Errorf("'OIDCClientSecret' must not be set for type %q", c.Type) case len(c.OIDCScopes) != 0: return fmt.Errorf("'OIDCScopes' must not be set for type %q", c.Type) + case len(c.OIDCACRValues) != 0: + return fmt.Errorf("'OIDCACRValues' must not be set for type %q", c.Type) case len(c.AllowedRedirectURIs) != 0: return fmt.Errorf("'AllowedRedirectURIs' must not be set for type %q", c.Type) case c.VerboseOIDCLogging: diff --git a/internal/go-sso/oidcauth/config_test.go b/internal/go-sso/oidcauth/config_test.go index 0a2d0fd253..ec3e668dbc 100644 --- a/internal/go-sso/oidcauth/config_test.go +++ b/internal/go-sso/oidcauth/config_test.go @@ -371,6 +371,14 @@ func TestConfigValidate(t *testing.T) { }, expectErr: "must not be set for type", }, + "incompatible with OIDCACRValues": { + config: Config{ + Type: TypeJWT, + JWTValidationPubKeys: []string{testJWTPubKey}, + OIDCACRValues: []string{"acr1"}, + }, + expectErr: "must not be set for type", + }, "incompatible with AllowedRedirectURIs": { config: Config{ Type: TypeJWT, diff --git a/internal/go-sso/oidcauth/oidc.go b/internal/go-sso/oidcauth/oidc.go index 063e95d4c3..bd0f5ebd7f 100644 --- a/internal/go-sso/oidcauth/oidc.go +++ b/internal/go-sso/oidcauth/oidc.go @@ -56,6 +56,9 @@ func (a *Authenticator) GetAuthCodeURL(ctx context.Context, redirectURI string, authCodeOpts := []oauth2.AuthCodeOption{ oidc.Nonce(nonce), } + if len(a.config.OIDCACRValues) > 0 { + authCodeOpts = append(authCodeOpts, oauth2.SetAuthURLParam("acr_values", strings.Join(a.config.OIDCACRValues, " "))) + } return oauth2Config.AuthCodeURL(stateID, authCodeOpts...), nil } diff --git a/internal/go-sso/oidcauth/oidc_test.go b/internal/go-sso/oidcauth/oidc_test.go index ae1cd87b69..0de0997413 100644 --- a/internal/go-sso/oidcauth/oidc_test.go +++ b/internal/go-sso/oidcauth/oidc_test.go @@ -27,6 +27,7 @@ func setupForOIDC(t *testing.T) (*Authenticator, *oidcauthtest.Server) { OIDCDiscoveryCACert: srv.CACert(), OIDCClientID: "abc", OIDCClientSecret: "def", + OIDCACRValues: []string{"acr1", "acr2"}, JWTSupportedAlgs: []string{"ES256"}, BoundAudiences: []string{"abc"}, AllowedRedirectURIs: []string{"https://example.com"}, @@ -43,6 +44,7 @@ func setupForOIDC(t *testing.T) (*Authenticator, *oidcauthtest.Server) { "/nested/Groups": "groups", }, } + require.NoError(t, config.Validate()) oa, err := New(config, hclog.NewNullLogger()) @@ -72,6 +74,8 @@ func TestOIDC_AuthURL(t *testing.T) { "redirect_uri": "https://example.com", "response_type": "code", "scope": "openid", + // optional values + "acr_values": "acr1 acr2", } au, err := url.Parse(authURL) diff --git a/website/content/docs/security/acl/auth-methods/oidc.mdx b/website/content/docs/security/acl/auth-methods/oidc.mdx index a89357b4be..d260e6872d 100644 --- a/website/content/docs/security/acl/auth-methods/oidc.mdx +++ b/website/content/docs/security/acl/auth-methods/oidc.mdx @@ -70,6 +70,8 @@ parameters are required to properly configure an auth method of type - `OIDCScopes` `(array)` - A list of OIDC scopes. +- `OIDCACRValues` `(array)` - A list of Authentication Context Class Reference values to use for the authentication request. See [OIDC reference](https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1) for more info on this parameter. Added in v1.11.0. + - `JWTSupportedAlgs` `(array)` - JWTSupportedAlgs is a list of supported signing algorithms. Defaults to `RS256`. ([Available algorithms](https://github.com/hashicorp/consul/blob/main/vendor/github.com/coreos/go-oidc/jose.go#L7))