diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java index fc73d778e..00e89ec2e 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java @@ -112,6 +112,16 @@ public class ConfigController { "showSettingsWhenNoLogin", applicationProperties.getSystem().isShowSettingsWhenNoLogin()); + // SSO Provider settings + boolean enableOAuth = + applicationProperties.getSecurity().getOauth2() != null + && applicationProperties.getSecurity().getOauth2().getEnabled(); + boolean enableSaml = + applicationProperties.getSecurity().getSaml2() != null + && applicationProperties.getSecurity().getSaml2().getEnabled(); + configData.put("enableOAuth", enableOAuth); + configData.put("enableSaml", enableSaml); + // Mail settings - check both SMTP enabled AND invites enabled boolean smtpEnabled = applicationProperties.getMail().isEnabled(); boolean invitesEnabled = applicationProperties.getMail().isEnableInvites(); diff --git a/frontend/public/locales/en-GB/translation.toml b/frontend/public/locales/en-GB/translation.toml index ed02b6284..a42565ae9 100644 --- a/frontend/public/locales/en-GB/translation.toml +++ b/frontend/public/locales/en-GB/translation.toml @@ -5797,9 +5797,11 @@ username = "Username (Email)" usernamePlaceholder = "user@example.com" password = "Password" passwordPlaceholder = "Enter password" +passwordRequired = "Password is required" role = "Role" team = "Team (Optional)" teamPlaceholder = "Select a team" +authType = "Authentication Type" forcePasswordChange = "Force password change on first login" cancel = "Cancel" submit = "Add Member" @@ -5808,6 +5810,12 @@ passwordTooShort = "Password must be at least 6 characters" success = "User created successfully" error = "Failed to create user" +[workspace.people.authType] +password = "Password" +oauth = "OAuth2" +saml = "SAML2" +ssoDescription = "User will authenticate via SSO provider" + [workspace.people.editMember] title = "Edit Member" editing = "Editing:" diff --git a/frontend/src/core/contexts/AppConfigContext.tsx b/frontend/src/core/contexts/AppConfigContext.tsx index edc996536..5bec5b7b2 100644 --- a/frontend/src/core/contexts/AppConfigContext.tsx +++ b/frontend/src/core/contexts/AppConfigContext.tsx @@ -26,6 +26,8 @@ export interface AppConfig { enableLogin?: boolean; showSettingsWhenNoLogin?: boolean; enableEmailInvites?: boolean; + enableOAuth?: boolean; + enableSaml?: boolean; isAdmin?: boolean; enableAlphaFunctionality?: boolean; enableAnalytics?: boolean | null; diff --git a/frontend/src/proprietary/components/shared/InviteMembersModal.tsx b/frontend/src/proprietary/components/shared/InviteMembersModal.tsx index f583f3cb7..70e5e09a0 100644 --- a/frontend/src/proprietary/components/shared/InviteMembersModal.tsx +++ b/frontend/src/proprietary/components/shared/InviteMembersModal.tsx @@ -56,6 +56,7 @@ export default function InviteMembersModal({ opened, onClose, onSuccess }: Invit password: '', role: 'ROLE_USER', teamId: undefined as number | undefined, + authType: 'WEB' as 'WEB' | 'OAUTH2' | 'SAML2', forceChange: false, }); @@ -120,11 +121,17 @@ export default function InviteMembersModal({ opened, onClose, onSuccess }: Invit })); const handleInviteUser = async () => { - if (!inviteForm.username || !inviteForm.password) { + if (!inviteForm.username) { alert({ alertType: 'error', title: t('workspace.people.addMember.usernameRequired') }); return; } + // Password is only required for WEB auth type + if (inviteForm.authType === 'WEB' && !inviteForm.password) { + alert({ alertType: 'error', title: t('workspace.people.addMember.passwordRequired', 'Password is required') }); + return; + } + try { setProcessing(true); await userManagementService.createUser({ @@ -132,7 +139,7 @@ export default function InviteMembersModal({ opened, onClose, onSuccess }: Invit password: inviteForm.password, role: inviteForm.role, teamId: inviteForm.teamId, - authType: 'password', + authType: inviteForm.authType, forceChange: inviteForm.forceChange, }); alert({ alertType: 'success', title: t('workspace.people.addMember.success') }); @@ -144,6 +151,7 @@ export default function InviteMembersModal({ opened, onClose, onSuccess }: Invit password: '', role: 'ROLE_USER', teamId: undefined, + authType: 'WEB', forceChange: false, }); } catch (error: any) { @@ -243,6 +251,7 @@ export default function InviteMembersModal({ opened, onClose, onSuccess }: Invit password: '', role: 'ROLE_USER', teamId: undefined, + authType: 'WEB', forceChange: false, }); setEmailInviteForm({ @@ -501,14 +510,42 @@ export default function InviteMembersModal({ opened, onClose, onSuccess }: Invit onChange={(e) => setInviteForm({ ...inviteForm, username: e.currentTarget.value })} required /> - setInviteForm({ ...inviteForm, password: e.currentTarget.value })} - required - /> + + {/* Auth Type Selector - only show if SSO is enabled */} + {(config?.enableOAuth || config?.enableSaml) && ( + - setInviteForm({ ...inviteForm, forceChange: e.currentTarget.checked })} - /> )} diff --git a/frontend/src/proprietary/services/userManagementService.ts b/frontend/src/proprietary/services/userManagementService.ts index 25d89056f..b26434aa2 100644 --- a/frontend/src/proprietary/services/userManagementService.ts +++ b/frontend/src/proprietary/services/userManagementService.ts @@ -45,7 +45,7 @@ export interface CreateUserRequest { password?: string; role: string; teamId?: number; - authType: 'password' | 'SSO'; + authType: 'WEB' | 'OAUTH2' | 'SAML2'; forceChange?: boolean; }