Add email_verified check for OIDC login
- Parse email_verified from ID token and UserInfo endpoint - Reject OIDC login if email is present and not verified - Only applies when email is in OIDC claims (not required otherwise)
This commit is contained in:
@@ -140,6 +140,7 @@ pub struct OidcTokenSet {
|
|||||||
pub struct OidcIdClaims {
|
pub struct OidcIdClaims {
|
||||||
pub sub: String,
|
pub sub: String,
|
||||||
pub email: Option<String>,
|
pub email: Option<String>,
|
||||||
|
pub email_verified: Option<bool>,
|
||||||
pub preferred_username: Option<String>,
|
pub preferred_username: Option<String>,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub groups: Vec<String>,
|
pub groups: Vec<String>,
|
||||||
|
|||||||
@@ -991,6 +991,7 @@ impl AuthApplicationService {
|
|||||||
email: user_info.email.or(claims.email),
|
email: user_info.email.or(claims.email),
|
||||||
preferred_username: user_info.preferred_username.or(claims.preferred_username),
|
preferred_username: user_info.preferred_username.or(claims.preferred_username),
|
||||||
name: user_info.name.or(claims.name),
|
name: user_info.name.or(claims.name),
|
||||||
|
email_verified: user_info.email_verified.or(claims.email_verified),
|
||||||
groups: if user_info.groups.is_empty() {
|
groups: if user_info.groups.is_empty() {
|
||||||
claims.groups
|
claims.groups
|
||||||
} else {
|
} else {
|
||||||
@@ -1011,6 +1012,22 @@ impl AuthApplicationService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let provider_name = oidc.provider_name().to_string();
|
let provider_name = oidc.provider_name().to_string();
|
||||||
|
// Check email_verified - only if email is present in claims
|
||||||
|
if let Some(email) = &claims.email {
|
||||||
|
let verified = claims.email_verified.unwrap_or(false);
|
||||||
|
if !verified {
|
||||||
|
tracing::warn!(
|
||||||
|
"OIDC login rejected: email not verified (provider: {}, email: {})",
|
||||||
|
provider_name,
|
||||||
|
email
|
||||||
|
);
|
||||||
|
return Err(DomainError::new(
|
||||||
|
ErrorKind::AccessDenied,
|
||||||
|
"OIDC",
|
||||||
|
"Email verification required. Please verify your email at the identity provider.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 4. Determine username and email
|
// 4. Determine username and email
|
||||||
let oidc_username = claims
|
let oidc_username = claims
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ struct TokenResponse {
|
|||||||
struct IdTokenClaims {
|
struct IdTokenClaims {
|
||||||
sub: String,
|
sub: String,
|
||||||
email: Option<String>,
|
email: Option<String>,
|
||||||
|
email_verified: Option<bool>,
|
||||||
preferred_username: Option<String>,
|
preferred_username: Option<String>,
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
groups: Option<Vec<String>>,
|
groups: Option<Vec<String>>,
|
||||||
@@ -81,6 +82,7 @@ struct IdTokenClaims {
|
|||||||
struct UserInfoResponse {
|
struct UserInfoResponse {
|
||||||
sub: String,
|
sub: String,
|
||||||
email: Option<String>,
|
email: Option<String>,
|
||||||
|
email_verified: Option<bool>,
|
||||||
preferred_username: Option<String>,
|
preferred_username: Option<String>,
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
groups: Option<Vec<String>>,
|
groups: Option<Vec<String>>,
|
||||||
@@ -437,6 +439,7 @@ impl OidcServicePort for OidcService {
|
|||||||
Ok(OidcIdClaims {
|
Ok(OidcIdClaims {
|
||||||
sub: claims.sub,
|
sub: claims.sub,
|
||||||
email: claims.email,
|
email: claims.email,
|
||||||
|
email_verified: claims.email_verified,
|
||||||
preferred_username: claims.preferred_username,
|
preferred_username: claims.preferred_username,
|
||||||
name: claims.name,
|
name: claims.name,
|
||||||
groups: claims.groups.unwrap_or_default(),
|
groups: claims.groups.unwrap_or_default(),
|
||||||
@@ -487,6 +490,7 @@ impl OidcServicePort for OidcService {
|
|||||||
Ok(OidcIdClaims {
|
Ok(OidcIdClaims {
|
||||||
sub: info.sub,
|
sub: info.sub,
|
||||||
email: info.email,
|
email: info.email,
|
||||||
|
email_verified: info.email_verified,
|
||||||
preferred_username: info.preferred_username,
|
preferred_username: info.preferred_username,
|
||||||
name: info.name,
|
name: info.name,
|
||||||
groups: info.groups.unwrap_or_default(),
|
groups: info.groups.unwrap_or_default(),
|
||||||
|
|||||||
Reference in New Issue
Block a user