1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-29 22:01:14 +03:00

Make the email verification state more configurable on upstream OAuth 2.0 registration

This also marks the email as primary
This commit is contained in:
Quentin Gliech
2023-08-31 11:31:06 +02:00
parent 8e5ebcd03f
commit ae3213fe87
8 changed files with 162 additions and 18 deletions

View File

@ -26,10 +26,10 @@ use tracing::{info, info_span, warn};
use crate::util::database_connection_from_config;
fn map_import_preference(
config: &mas_config::UpstreamOAuth2ImportPreference,
) -> mas_data_model::UpstreamOAuthProviderImportPreference {
let action = match &config.action {
fn map_import_action(
config: &mas_config::UpstreamOAuth2ImportAction,
) -> mas_data_model::UpstreamOAuthProviderImportAction {
match config {
mas_config::UpstreamOAuth2ImportAction::Ignore => {
mas_data_model::UpstreamOAuthProviderImportAction::Ignore
}
@ -42,9 +42,15 @@ fn map_import_preference(
mas_config::UpstreamOAuth2ImportAction::Require => {
mas_data_model::UpstreamOAuthProviderImportAction::Require
}
};
}
}
mas_data_model::UpstreamOAuthProviderImportPreference { action }
fn map_import_preference(
config: &mas_config::UpstreamOAuth2ImportPreference,
) -> mas_data_model::UpstreamOAuthProviderImportPreference {
mas_data_model::UpstreamOAuthProviderImportPreference {
action: map_import_action(&config.action),
}
}
fn map_claims_imports(
@ -64,7 +70,25 @@ fn map_claims_imports(
email: config
.email
.as_ref()
.map(map_import_preference)
.map(|c| mas_data_model::UpstreamOAuthProviderImportPreference {
action: map_import_action(&c.action),
})
.unwrap_or_default(),
// XXX: this is a bit ugly
verify_email: config
.email
.as_ref()
.map(|c| match c.set_email_verification {
mas_config::UpstreamOAuth2SetEmailVerification::Always => {
mas_data_model::UpsreamOAuthProviderSetEmailVerification::Always
}
mas_config::UpstreamOAuth2SetEmailVerification::Never => {
mas_data_model::UpsreamOAuthProviderSetEmailVerification::Never
}
mas_config::UpstreamOAuth2SetEmailVerification::Import => {
mas_data_model::UpsreamOAuthProviderSetEmailVerification::Import
}
})
.unwrap_or_default(),
}
}

View File

@ -49,8 +49,11 @@ pub use self::{
},
templates::TemplatesConfig,
upstream_oauth2::{
ClaimsImports as UpstreamOAuth2ClaimsImports, ImportAction as UpstreamOAuth2ImportAction,
ImportPreference as UpstreamOAuth2ImportPreference, UpstreamOAuth2Config,
ClaimsImports as UpstreamOAuth2ClaimsImports,
EmailImportPreference as UpstreamOAuth2EmailImportPreference,
ImportAction as UpstreamOAuth2ImportAction,
ImportPreference as UpstreamOAuth2ImportPreference,
SetEmailVerification as UpstreamOAuth2SetEmailVerification, UpstreamOAuth2Config,
},
};
use crate::util::ConfigurationSection;

View File

@ -104,6 +104,34 @@ pub struct ImportPreference {
pub action: ImportAction,
}
/// Should the email address be marked as verified
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum SetEmailVerification {
/// Mark the email address as verified
Always,
/// Don't mark the email address as verified
Never,
/// Mark the email address as verified if the upstream provider says it is
/// through the `email_verified` claim
#[default]
Import,
}
/// What should be done with the email claim
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, JsonSchema)]
pub struct EmailImportPreference {
/// How to handle the claim
#[serde(default)]
pub action: ImportAction,
/// Should the email address be marked as verified
#[serde(default)]
pub set_email_verification: SetEmailVerification,
}
/// How claims should be imported
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, JsonSchema)]
pub struct ClaimsImports {
@ -118,7 +146,7 @@ pub struct ClaimsImports {
/// Import the email address of the user based on the `email` and
/// `email_verified` claims
#[serde(default)]
pub email: Option<ImportPreference>,
pub email: Option<EmailImportPreference>,
}
#[skip_serializing_none]

View File

@ -46,9 +46,10 @@ pub use self::{
AccessToken, AccessTokenState, RefreshToken, RefreshTokenState, TokenFormatError, TokenType,
},
upstream_oauth2::{
UpstreamOAuthAuthorizationSession, UpstreamOAuthAuthorizationSessionState,
UpstreamOAuthLink, UpstreamOAuthProvider, UpstreamOAuthProviderClaimsImports,
UpstreamOAuthProviderImportAction, UpstreamOAuthProviderImportPreference,
UpsreamOAuthProviderSetEmailVerification, UpstreamOAuthAuthorizationSession,
UpstreamOAuthAuthorizationSessionState, UpstreamOAuthLink, UpstreamOAuthProvider,
UpstreamOAuthProviderClaimsImports, UpstreamOAuthProviderImportAction,
UpstreamOAuthProviderImportPreference,
},
users::{
Authentication, AuthenticationMethod, BrowserSession, Password, User, UserEmail,

View File

@ -21,7 +21,8 @@ pub use self::{
provider::{
ClaimsImports as UpstreamOAuthProviderClaimsImports,
ImportAction as UpstreamOAuthProviderImportAction,
ImportPreference as UpstreamOAuthProviderImportPreference, UpstreamOAuthProvider,
ImportPreference as UpstreamOAuthProviderImportPreference,
SetEmailVerification as UpsreamOAuthProviderSetEmailVerification, UpstreamOAuthProvider,
},
session::{UpstreamOAuthAuthorizationSession, UpstreamOAuthAuthorizationSessionState},
};

View File

@ -31,6 +31,32 @@ pub struct UpstreamOAuthProvider {
pub claims_imports: ClaimsImports,
}
/// Whether to set the email as verified when importing it from the upstream
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum SetEmailVerification {
/// Set the email as verified
Always,
/// Never set the email as verified
Never,
/// Set the email as verified if the upstream provider claims it is verified
#[default]
Import,
}
impl SetEmailVerification {
#[must_use]
pub fn should_mark_as_verified(&self, upstream_verified: bool) -> bool {
match self {
Self::Always => true,
Self::Never => false,
Self::Import => upstream_verified,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct ClaimsImports {
#[serde(default)]
@ -41,6 +67,9 @@ pub struct ClaimsImports {
#[serde(default)]
pub email: ImportPreference,
#[serde(default)]
pub verify_email: SetEmailVerification,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]

View File

@ -527,11 +527,19 @@ pub(crate) async fn post(
.add(&mut rng, &clock, &user, email)
.await?;
// Mark the email as verified if the upstream provider says it is.
if payload.email_verified {
repo.user_email()
// Mark the email as verified according to the policy and whether the provider
// claims it is, and make it the primary email.
if provider
.claims_imports
.verify_email
.should_mark_as_verified(payload.email_verified)
{
let user_email = repo
.user_email()
.mark_as_verified(&clock, user_email)
.await?;
repo.user_email().set_as_primary(&user_email).await?;
}
}