From 336ec34125523b9f5e83e4da457f64f233f95633 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Mon, 15 Dec 2025 21:55:58 +0000 Subject: [PATCH] V2 Handle SSO account restrictions in account settings (#5225) ## Summary - hide password and username update controls for SSO accounts and show a managed-account notice - prevent account update handlers from calling APIs when the user authenticates via SSO - expose authenticationType on the user session model and add translations for new SSO messaging ## Testing - not run (not requested) ------ [Codex Task](https://chatgpt.com/codex/tasks/task_b_693ae8144148832888ecf128e66cd3ca) --- .../public/locales/en-GB/translation.toml | 2 + .../src/proprietary/auth/springAuthClient.ts | 1 + .../config/configSections/AccountSection.tsx | 63 ++++++++++++++----- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/frontend/public/locales/en-GB/translation.toml b/frontend/public/locales/en-GB/translation.toml index 7743ca9b1..4f81d64a3 100644 --- a/frontend/public/locales/en-GB/translation.toml +++ b/frontend/public/locales/en-GB/translation.toml @@ -449,6 +449,7 @@ required = "All fields are required." mismatch = "New passwords do not match." error = "Unable to update password. Please verify your current password and try again." success = "Password updated successfully. Please sign in again." +ssoDisabled = "Password changes are managed by your identity provider." current = "Current password" currentPlaceholder = "Enter your current password" new = "New password" @@ -510,6 +511,7 @@ low = "Low" title = "Change Credentials" header = "Update Your Account Details" changePassword = "You are using default login credentials. Please enter a new password" +ssoManaged = "Your account is managed by your identity provider." newUsername = "New Username" oldPassword = "Current Password" newPassword = "New Password" diff --git a/frontend/src/proprietary/auth/springAuthClient.ts b/frontend/src/proprietary/auth/springAuthClient.ts index 646b71182..be404ffb4 100644 --- a/frontend/src/proprietary/auth/springAuthClient.ts +++ b/frontend/src/proprietary/auth/springAuthClient.ts @@ -60,6 +60,7 @@ export interface User { enabled?: boolean; is_anonymous?: boolean; isFirstLogin?: boolean; + authenticationType?: string; app_metadata?: Record; } diff --git a/frontend/src/proprietary/components/shared/config/configSections/AccountSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/AccountSection.tsx index f627302b4..95a9ee57f 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/AccountSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/AccountSection.tsx @@ -24,6 +24,17 @@ const AccountSection: React.FC = () => { const [usernameError, setUsernameError] = useState(''); const [usernameSubmitting, setUsernameSubmitting] = useState(false); + const authTypeFromMetadata = useMemo(() => { + const metadata = user?.app_metadata as { authType?: string; authenticationType?: string } | undefined; + return metadata?.authenticationType ?? metadata?.authType; + }, [user?.app_metadata]); + + const normalizedAuthType = useMemo( + () => (user?.authenticationType ?? authTypeFromMetadata ?? '').toLowerCase(), + [authTypeFromMetadata, user?.authenticationType] + ); + const isSsoUser = useMemo(() => ['sso', 'oauth2', 'saml2'].includes(normalizedAuthType), [normalizedAuthType]); + const userIdentifier = useMemo(() => user?.email || user?.username || '', [user?.email, user?.username]); const redirectToLogin = useCallback(() => { @@ -41,6 +52,11 @@ const AccountSection: React.FC = () => { const handlePasswordSubmit = async (event: React.FormEvent) => { event.preventDefault(); + if (isSsoUser) { + setPasswordError(t('settings.security.password.ssoDisabled', 'Password changes are managed by your identity provider.')); + return; + } + if (!currentPassword || !newPassword || !confirmPassword) { setPasswordError(t('settings.security.password.required', 'All fields are required.')); return; @@ -81,6 +97,11 @@ const AccountSection: React.FC = () => { const handleUsernameSubmit = async (event: React.FormEvent) => { event.preventDefault(); + if (isSsoUser) { + setUsernameError(t('changeCreds.ssoManaged', 'Your account is managed by your identity provider.')); + return; + } + if (!currentPasswordForUsername || !newUsername) { setUsernameError(t('settings.security.password.required', 'All fields are required.')); return; @@ -132,23 +153,35 @@ const AccountSection: React.FC = () => { : t('account.accountSettings', 'Account Settings')} - - + + {isSsoUser && ( + } color="blue" variant="light"> + {t('changeCreds.ssoManaged', 'Your account is managed by your identity provider.')} + + )} - + + {!isSsoUser && ( + + )} - - + {!isSsoUser && ( + + )} + + + +