From 2073c03092d328e4b5fd19882ecfbe491dc8b5c7 Mon Sep 17 00:00:00 2001 From: Timshel Date: Sat, 29 Aug 2026 15:02:22 +0000 Subject: [PATCH] Add SSO_SIGNUPS_ALLOWED (#7272) * Add SSO_SIGNUPS_ALLOWED * Fix regression with domain_allowed in SSO onboarding --------- Co-authored-by: Timshel --- .env.template | 3 +++ src/api/identity.rs | 28 +++++++++++++++++++++++++++- src/config.rs | 13 +++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/.env.template b/.env.template index 9fc29989..5f6f374c 100644 --- a/.env.template +++ b/.env.template @@ -518,6 +518,9 @@ ## Prevent users from logging in directly without going through SSO # SSO_ONLY=false +## Allow SSO flow to create account. You probably want to disable it when using a public provider. +# SSO_SIGNUPS_ALLOWED=true + ## On SSO Signup if a user with a matching email already exists make the association # SSO_SIGNUPS_MATCH_EMAIL=true diff --git a/src/api/identity.rs b/src/api/identity.rs index 23411dc7..2b1ddfb1 100644 --- a/src/api/identity.rs +++ b/src/api/identity.rs @@ -234,6 +234,24 @@ async fn sso_login( } ) } + Some((user, None)) + if user.private_key.is_none() + && !CONFIG.sso_signups_allowed() + && !CONFIG.is_email_domain_allowed(&user.email) + && !CONFIG.mail_enabled() + && Invitation::find_by_mail(&user.email, conn).await.is_none() => + { + error!( + "Login failure ({}), no invitation with email ({}) was found", + user_infos.identifier, user.email + ); + err_silent!( + "Missing invitation", + ErrorEvent { + event: EventType::UserFailedLogIn + } + ) + } Some((user, None)) if user.private_key.is_some() && !CONFIG.sso_signups_match_email() => { error!( "Login failure ({}), existing non SSO user ({}) with same email ({}) and association is disabled", @@ -281,7 +299,15 @@ async fn sso_login( // Will trigger 2FA flow if needed let (user, mut device, twofactor_token, sso_user) = match user_with_sso { None => { - if !CONFIG.is_email_domain_allowed(&user_infos.email) { + if !CONFIG.is_sso_signup_allowed(&user_infos.email) { + if CONFIG.signups_domains_whitelist().is_empty() { + err!( + "Signups are disabled. You will need an invitation", + ErrorEvent { + event: EventType::UserFailedLogIn + } + ); + } err!( "Email domain not allowed", ErrorEvent { diff --git a/src/config.rs b/src/config.rs index 72b58252..2502dd02 100644 --- a/src/config.rs +++ b/src/config.rs @@ -817,6 +817,8 @@ make_config! { sso_enabled: bool, true, def, false; /// Only SSO login |> Disable Email+Master Password login sso_only: bool, true, def, false; + /// Allow SSO flow to create account |> You probably want to disable it when using a public provider + sso_signups_allowed: bool, true, def, true; /// Allow email association |> Associate existing non-SSO user based on email sso_signups_match_email: bool, true, def, true; /// Allow unknown email verification status |> Allowing this with `SSO_SIGNUPS_MATCH_EMAIL=true` open potential account takeover. @@ -1544,6 +1546,17 @@ impl Config { } } + /// Tests whether SSO signup is allowed for an email address, taking into + /// account the sso_signups_allowed and signups_domains_whitelist settings. + pub fn is_sso_signup_allowed(&self, email: &str) -> bool { + if self.signups_domains_whitelist().is_empty() { + self.sso_signups_allowed() + } else { + // The whitelist setting overrides the signups_allowed setting. + self.is_email_domain_allowed(email) + } + } + // The registration link should be hidden if // - Signup is not allowed and email whitelist is empty unless mail is disabled and invitations are allowed // - The SSO is activated and password login is disabled.