diff --git a/defaults/krill-multi-user.conf b/defaults/krill-multi-user.conf index c11c43ba..e9509ec1 100644 --- a/defaults/krill-multi-user.conf +++ b/defaults/krill-multi-user.conf @@ -164,6 +164,7 @@ # insecure = false # extra_login_scopes = ["...", ...] # extra_login_params = ["...", ...] +# prompt_for_login = false # logout_url = "..." # # [auth_openidconnect.claims] @@ -218,14 +219,26 @@ # Connect Core 1.0 specification [*2] lists various # parameters that can be sent but the supported set # varies by provider. The prompt=login parameter is -# automatically sent by the provider and thus does -# not need to be provided using this setting. Can -# also be specified as a separate TOML table, e.g.: +# automatically sent by the provider (though this +# behavior can be disabled, see prompt_for_login +# below) and thus does not need to be provided +# using this setting. Can also be specified as a +# separate TOML table, e.g.: # # [openid_connect.extra_login_params] # display=popup # ui_locales="fr-CA fr en" # +# prompt_for_login No Defaults to true. Setting this to false will +# disable the default behaviour of sending the +# prompt=login parameter to the provider. This +# also allows a different prompt= to be +# specified using extra_login_params, from the set +# defined in Section 3.1.2.1. Authentication +# Request in the OpenID Connect Core 1.0 +# specification [*2]: "none", "login", "consent" +# or "select_account". +# # logout_url No A URL to direct the browser to redirect the user # to in order to logout. Ideally this is not needed # as the provider OpenID Connect Discovery response diff --git a/src/daemon/auth/providers/openid_connect/config.rs b/src/daemon/auth/providers/openid_connect/config.rs index e9d6b112..3c04d1eb 100644 --- a/src/daemon/auth/providers/openid_connect/config.rs +++ b/src/daemon/auth/providers/openid_connect/config.rs @@ -22,12 +22,21 @@ pub struct ConfigAuthOpenIDConnect { #[serde(default)] pub extra_login_params: HashMap, + #[serde(default = "default_prompt_for_login")] + pub prompt_for_login: bool, + #[serde(default)] pub logout_url: Option, #[serde(default)] pub insecure: bool, } + +fn default_prompt_for_login() -> bool { + // On by default for backward compatability. See: https://github.com/NLnetLabs/krill/issues/614 + true +} + #[derive(Clone, Debug, Deserialize)] pub struct ConfigAuthOpenIDConnectClaim { pub source: Option, diff --git a/src/daemon/auth/providers/openid_connect/provider.rs b/src/daemon/auth/providers/openid_connect/provider.rs index 0b229fa0..4dbdb2cc 100644 --- a/src/daemon/auth/providers/openid_connect/provider.rs +++ b/src/daemon/auth/providers/openid_connect/provider.rs @@ -1304,6 +1304,10 @@ impl AuthProvider for OpenIDConnectAuthProvider { || Nonce::new(base64::encode_config(nonce_hash, base64::URL_SAFE_NO_PAD)), ); + // This unwrap is safe as we check in new() that the OpenID Connect + // config exists. + let oidc_conf = self.oidc_conf()?; + // From https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest: // "prompt: login - The Authorization Server SHOULD prompt the // End-User for re-authentication. If it cannot re-authenticate the @@ -1313,7 +1317,11 @@ impl AuthProvider for OpenIDConnectAuthProvider { // to specify who to login as, we don't want the provider somehow // automatically completing the login process because it has some notion // of an existing login session. - request = request.add_prompt(CoreAuthPrompt::Login); + + // https://github.com/NLnetLabs/krill/issues/614 + if oidc_conf.prompt_for_login { + request = request.add_prompt(CoreAuthPrompt::Login); + } // The "openid" scope that OpenID Connect: providers are required to // check for is sent automatically by the openidconnect crate. We can @@ -1333,10 +1341,6 @@ impl AuthProvider for OpenIDConnectAuthProvider { // TODO: use request.set_pkce_challenge() ? - // This unwrap is safe as we check in new() that the OpenID Connect - // config exists. - let oidc_conf = self.oidc_conf()?; - for scope in &oidc_conf.extra_login_scopes { request = request.add_scope(Scope::new(scope.clone())); } diff --git a/test-resources/krill-init-multi-user.conf b/test-resources/krill-init-multi-user.conf index e40a5a92..045ac9d5 100644 --- a/test-resources/krill-init-multi-user.conf +++ b/test-resources/krill-init-multi-user.conf @@ -418,6 +418,7 @@ service_uri = "https://localhost:3001/" # insecure = false # extra_login_scopes = ["...", ...] # extra_login_params = ["...", ...] +# prompt_for_login = false # logout_url = "..." # # [auth_openidconnect.claims] @@ -472,14 +473,26 @@ service_uri = "https://localhost:3001/" # Connect Core 1.0 specification [*2] lists various # parameters that can be sent but the supported set # varies by provider. The prompt=login parameter is -# automatically sent by the provider and thus does -# not need to be provided using this setting. Can -# also be specified as a separate TOML table, e.g.: +# automatically sent by the provider (though this +# behavior can be disabled, see prompt_for_login +# below) and thus does not need to be provided +# using this setting. Can also be specified as a +# separate TOML table, e.g.: # # [openid_connect.extra_login_params] # display=popup # ui_locales="fr-CA fr en" # +# prompt_for_login No Defaults to true. Setting this to false will +# disable the default behaviour of sending the +# prompt=login parameter to the provider. This +# also allows a different prompt= to be +# specified using extra_login_params, from the set +# defined in Section 3.1.2.1. Authentication +# Request in the OpenID Connect Core 1.0 +# specification [*2]: "none", "login", "consent" +# or "select_account". +# # logout_url No A URL to direct the browser to redirect the user # to in order to logout. Ideally this is not needed # as the provider OpenID Connect Discovery response diff --git a/test-resources/ui/multi_user_openid_connect.conf b/test-resources/ui/multi_user_openid_connect.conf index d11156f3..521a0026 100644 --- a/test-resources/ui/multi_user_openid_connect.conf +++ b/test-resources/ui/multi_user_openid_connect.conf @@ -16,6 +16,11 @@ issuer_url = "https://localhost:1818" client_id = "client-id-123" client_secret = "some-secret" +# custom prompt= behaviour is ignored by the OpenID Connect mock, this is just here to exercise the config parser and +# for manually observing that the prompt query param in the requests to the mock change as expected. +prompt_for_login = false +extra_login_params = { prompt = "none" } + [auth_openidconnect.claims] # recap_demo = { jmespath = "recap(nonce, '([A-Z]+)')", dest = "boing" } # resub_demo = { jmespath = "resub(nonce, '^[A-Z]+.*', '')" }