From 0db9c3cd88d83bc11dd334fd3b9e8124e2083af5 Mon Sep 17 00:00:00 2001 From: Jan Wiebe Date: Sat, 21 Feb 2026 20:26:21 +0100 Subject: [PATCH] feat(auth): expose auth_provider in UserDto and guard password ops for OIDC users - Add auth_provider field to UserDto, derived from oidc_provider ("local" for password users, provider name for OIDC users) - Block change_password() for OIDC users with clear error message - Block admin_reset_password() for OIDC users Fixes #122, Fixes #123 Co-Authored-By: Claude Opus 4.6 --- src/application/dtos/user_dto.rs | 5 +++++ .../services/auth_application_service.rs | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/application/dtos/user_dto.rs b/src/application/dtos/user_dto.rs index ee6aa295..2c66e532 100644 --- a/src/application/dtos/user_dto.rs +++ b/src/application/dtos/user_dto.rs @@ -14,6 +14,7 @@ pub struct UserDto { pub updated_at: DateTime, pub last_login_at: Option>, pub active: bool, + pub auth_provider: String, } impl From for UserDto { @@ -29,6 +30,10 @@ impl From for UserDto { updated_at: user.updated_at(), last_login_at: user.last_login_at(), active: user.is_active(), + auth_provider: user + .oidc_provider() + .unwrap_or("local") + .to_string(), } } } diff --git a/src/application/services/auth_application_service.rs b/src/application/services/auth_application_service.rs index 57b585bf..832e8e1c 100644 --- a/src/application/services/auth_application_service.rs +++ b/src/application/services/auth_application_service.rs @@ -490,6 +490,15 @@ impl AuthApplicationService { // Get user let mut user = self.user_storage.get_user_by_id(user_id).await?; + // Block password changes for OIDC-provisioned users + if user.is_oidc_user() { + return Err(DomainError::new( + ErrorKind::AccessDenied, + "Auth", + "Password changes are not available for SSO/OIDC accounts. Your password is managed by your identity provider.", + )); + } + // Verify current password using the injected hasher let is_valid = self .password_hasher @@ -780,6 +789,16 @@ impl AuthApplicationService { user_id: &str, new_password: &str, ) -> Result<(), DomainError> { + // Block password reset for OIDC-provisioned users + let user = self.user_storage.get_user_by_id(user_id).await?; + if user.is_oidc_user() { + return Err(DomainError::new( + ErrorKind::InvalidInput, + "Auth", + "Cannot reset password for SSO/OIDC accounts. The user's password is managed by their identity provider.", + )); + } + if new_password.len() < 8 { return Err(DomainError::new( ErrorKind::InvalidInput,