From d4d4538630738336e669587d7e97fdbe909f7bc7 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Mon, 12 Jan 2026 19:38:02 +0000 Subject: [PATCH] hide login if login type disabled (#5438) # Description of Changes --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --- .../api/ProprietaryUIDataController.java | 6 +++- .../controller/api/AuthController.java | 13 ++++++++ frontend/src/proprietary/routes/Login.tsx | 33 ++++++++++++------- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ProprietaryUIDataController.java b/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ProprietaryUIDataController.java index d44655832..ee07879b5 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ProprietaryUIDataController.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/controller/api/ProprietaryUIDataController.java @@ -169,7 +169,10 @@ public class ProprietaryUIDataController { OAUTH2 oauth = securityProps.getOauth2(); - if (oauth != null && oauth.getEnabled()) { + // Only add OAuth2 providers if loginMethod allows it + if (oauth != null + && oauth.getEnabled() + && securityProps.isOauth2Active()) { // This checks loginMethod if (oauth.isSettingsValid()) { String firstChar = String.valueOf(oauth.getProvider().charAt(0)); String clientName = @@ -201,6 +204,7 @@ public class ProprietaryUIDataController { } SAML2 saml2 = securityProps.getSaml2(); + // Only add SAML2 providers if loginMethod allows it if (securityProps.isSaml2Active() && applicationProperties.getPremium().isEnabled()) { String samlIdp = saml2.getProvider(); String saml2AuthenticationPath = "/saml2/authenticate/" + saml2.getRegistrationId(); diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/AuthController.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/AuthController.java index c3e11c3ab..e2e62ccf1 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/AuthController.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/AuthController.java @@ -21,6 +21,7 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import stirling.software.common.model.ApplicationProperties; import stirling.software.proprietary.audit.AuditEventType; import stirling.software.proprietary.audit.AuditLevel; import stirling.software.proprietary.audit.Audited; @@ -44,6 +45,7 @@ public class AuthController { private final JwtServiceInterface jwtService; private final CustomUserDetailsService userDetailsService; private final LoginAttemptService loginAttemptService; + private final ApplicationProperties.Security securityProperties; /** * Login endpoint - replaces Supabase signInWithPassword @@ -60,6 +62,17 @@ public class AuthController { HttpServletRequest httpRequest, HttpServletResponse response) { try { + // Check if username/password authentication is allowed + if (!securityProperties.isUserPass()) { + log.warn( + "Username/password login attempted but not allowed by current login method configuration"); + return ResponseEntity.status(HttpStatus.FORBIDDEN) + .body( + Map.of( + "error", + "Username/password authentication is not enabled. Please use the configured authentication method.")); + } + // Validate input parameters if (request.getUsername() == null || request.getUsername().trim().isEmpty()) { log.warn("Login attempt with null or empty username"); diff --git a/frontend/src/proprietary/routes/Login.tsx b/frontend/src/proprietary/routes/Login.tsx index d25b70c58..5de88239a 100644 --- a/frontend/src/proprietary/routes/Login.tsx +++ b/frontend/src/proprietary/routes/Login.tsx @@ -36,6 +36,7 @@ export default function Login() { const [enabledProviders, setEnabledProviders] = useState([]); const [hasSSOProviders, setHasSSOProviders] = useState(false); const [_enableLogin, setEnableLogin] = useState(null); + const [loginMethod, setLoginMethod] = useState('all'); const backendProbe = useBackendProbe(); const [isFirstTimeSetup, setIsFirstTimeSetup] = useState(false); const [showDefaultCredentials, setShowDefaultCredentials] = useState(false); @@ -115,6 +116,7 @@ export default function Login() { const providerPaths = Object.keys(data.providerList || {}); setEnabledProviders(providerPaths); + setLoginMethod(data.loginMethod || 'all'); } catch (err) { console.error('[Login] Failed to fetch enabled providers:', err); } @@ -125,18 +127,25 @@ export default function Login() { } }, [navigate, backendProbe.status, backendProbe.loginDisabled]); - // Update hasSSOProviders and showEmailForm when enabledProviders changes + // Update hasSSOProviders and showEmailForm when enabledProviders or loginMethod changes useEffect(() => { // In debug mode, check if any providers exist in the config const hasProviders = DEBUG_SHOW_ALL_PROVIDERS ? Object.keys(oauthProviderConfig).length > 0 : enabledProviders.length > 0; setHasSSOProviders(hasProviders); - // If no SSO providers, show email form by default - if (!hasProviders) { + + // Check if username/password authentication is allowed + const isUserPassAllowed = loginMethod === 'all' || loginMethod === 'normal'; + + // Show email form if no SSO providers exist AND username/password is allowed + if (!hasProviders && isUserPassAllowed) { setShowEmailForm(true); + } else if (!isUserPassAllowed) { + // Hide email form if username/password auth is not allowed + setShowEmailForm(false); } - }, [enabledProviders]); + }, [enabledProviders, loginMethod]); // Handle query params (email prefill, success messages, and session expiry) useEffect(() => { @@ -326,13 +335,13 @@ export default function Login() { enabledProviders={enabledProviders} /> - {/* Divider between OAuth and Email - only show if SSO is available */} - {hasSSOProviders && ( + {/* Divider between OAuth and Email - only show if SSO is available and username/password is allowed */} + {hasSSOProviders && (loginMethod === 'all' || loginMethod === 'normal') && ( )} - {/* Sign in with email button - only show if SSO providers exist */} - {hasSSOProviders && !showEmailForm && ( + {/* Sign in with email button - only show if SSO providers exist and username/password is allowed */} + {hasSSOProviders && !showEmailForm && (loginMethod === 'all' || loginMethod === 'normal') && (