mirror of
				https://github.com/Frooodle/Stirling-PDF.git
				synced 2025-10-25 11:17:28 +02:00 
			
		
		
		
	Fixes SSO login rejection (#2566)
# Description ## Checklist - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] I have performed a self-review of my own code - [ ] I have attached images of the change if it is UI based - [x] I have commented my code, particularly in hard-to-understand areas - [ ] If my code has heavily changed functionality I have updated relevant docs on [Stirling-PDFs doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) - [x] My changes generate no new warnings - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only)
This commit is contained in:
		
							parent
							
								
									d5faddbc85
								
							
						
					
					
						commit
						f45de05c99
					
				| @ -22,22 +22,31 @@ import jakarta.servlet.FilterChain; | |||||||
| import jakarta.servlet.ServletException; | import jakarta.servlet.ServletException; | ||||||
| import jakarta.servlet.http.HttpServletRequest; | import jakarta.servlet.http.HttpServletRequest; | ||||||
| import jakarta.servlet.http.HttpServletResponse; | import jakarta.servlet.http.HttpServletResponse; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
| import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal; | import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrincipal; | ||||||
| import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; | import stirling.software.SPDF.config.security.session.SessionPersistentRegistry; | ||||||
| import stirling.software.SPDF.model.ApiKeyAuthenticationToken; | import stirling.software.SPDF.model.ApiKeyAuthenticationToken; | ||||||
|  | import stirling.software.SPDF.model.ApplicationProperties; | ||||||
|  | import stirling.software.SPDF.model.ApplicationProperties.Security; | ||||||
|  | import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2; | ||||||
|  | import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2; | ||||||
| import stirling.software.SPDF.model.User; | import stirling.software.SPDF.model.User; | ||||||
| 
 | 
 | ||||||
|  | @Slf4j | ||||||
| @Component | @Component | ||||||
| public class UserAuthenticationFilter extends OncePerRequestFilter { | public class UserAuthenticationFilter extends OncePerRequestFilter { | ||||||
| 
 | 
 | ||||||
|  |     private final ApplicationProperties applicationProperties; | ||||||
|     private final UserService userService; |     private final UserService userService; | ||||||
|     private final SessionPersistentRegistry sessionPersistentRegistry; |     private final SessionPersistentRegistry sessionPersistentRegistry; | ||||||
|     private final boolean loginEnabledValue; |     private final boolean loginEnabledValue; | ||||||
| 
 | 
 | ||||||
|     public UserAuthenticationFilter( |     public UserAuthenticationFilter( | ||||||
|  |             @Lazy ApplicationProperties applicationProperties, | ||||||
|             @Lazy UserService userService, |             @Lazy UserService userService, | ||||||
|             SessionPersistentRegistry sessionPersistentRegistry, |             SessionPersistentRegistry sessionPersistentRegistry, | ||||||
|             @Qualifier("loginEnabled") boolean loginEnabledValue) { |             @Qualifier("loginEnabled") boolean loginEnabledValue) { | ||||||
|  |         this.applicationProperties = applicationProperties; | ||||||
|         this.userService = userService; |         this.userService = userService; | ||||||
|         this.sessionPersistentRegistry = sessionPersistentRegistry; |         this.sessionPersistentRegistry = sessionPersistentRegistry; | ||||||
|         this.loginEnabledValue = loginEnabledValue; |         this.loginEnabledValue = loginEnabledValue; | ||||||
| @ -121,33 +130,67 @@ public class UserAuthenticationFilter extends OncePerRequestFilter { | |||||||
| 
 | 
 | ||||||
|         // Check if the authenticated user is disabled and invalidate their session if so |         // Check if the authenticated user is disabled and invalidate their session if so | ||||||
|         if (authentication != null && authentication.isAuthenticated()) { |         if (authentication != null && authentication.isAuthenticated()) { | ||||||
|  | 
 | ||||||
|  |             Security securityProp = applicationProperties.getSecurity(); | ||||||
|  |             LoginMethod loginMethod = LoginMethod.UNKNOWN; | ||||||
|  | 
 | ||||||
|  |             boolean blockRegistration = false; | ||||||
|  | 
 | ||||||
|  |             // Extract username and determine the login method | ||||||
|             Object principal = authentication.getPrincipal(); |             Object principal = authentication.getPrincipal(); | ||||||
|             String username = null; |             String username = null; | ||||||
|             if (principal instanceof UserDetails) { |             if (principal instanceof UserDetails) { | ||||||
|                 username = ((UserDetails) principal).getUsername(); |                 username = ((UserDetails) principal).getUsername(); | ||||||
|  |                 loginMethod = LoginMethod.USERDETAILS; | ||||||
|             } else if (principal instanceof OAuth2User) { |             } else if (principal instanceof OAuth2User) { | ||||||
|                 username = ((OAuth2User) principal).getName(); |                 username = ((OAuth2User) principal).getName(); | ||||||
|  |                 loginMethod = LoginMethod.OAUTH2USER; | ||||||
|  |                 OAUTH2 oAuth = securityProp.getOauth2(); | ||||||
|  |                 blockRegistration = oAuth != null && oAuth.getBlockRegistration(); | ||||||
|             } else if (principal instanceof CustomSaml2AuthenticatedPrincipal) { |             } else if (principal instanceof CustomSaml2AuthenticatedPrincipal) { | ||||||
|                 username = ((CustomSaml2AuthenticatedPrincipal) principal).getName(); |                 username = ((CustomSaml2AuthenticatedPrincipal) principal).getName(); | ||||||
|  |                 loginMethod = LoginMethod.SAML2USER; | ||||||
|  |                 SAML2 saml2 = securityProp.getSaml2(); | ||||||
|  |                 blockRegistration = saml2 != null && saml2.getBlockRegistration(); | ||||||
|             } else if (principal instanceof String) { |             } else if (principal instanceof String) { | ||||||
|                 username = (String) principal; |                 username = (String) principal; | ||||||
|  |                 loginMethod = LoginMethod.STRINGUSER; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             // Retrieve all active sessions for the user | ||||||
|             List<SessionInformation> sessionsInformations = |             List<SessionInformation> sessionsInformations = | ||||||
|                     sessionPersistentRegistry.getAllSessions(principal, false); |                     sessionPersistentRegistry.getAllSessions(principal, false); | ||||||
| 
 | 
 | ||||||
|  |             // Check if the user exists, is disabled, or needs session invalidation | ||||||
|             if (username != null) { |             if (username != null) { | ||||||
|  |                 log.debug("Validating user: {}", username); | ||||||
|                 boolean isUserExists = userService.usernameExistsIgnoreCase(username); |                 boolean isUserExists = userService.usernameExistsIgnoreCase(username); | ||||||
|                 boolean isUserDisabled = userService.isUserDisabled(username); |                 boolean isUserDisabled = userService.isUserDisabled(username); | ||||||
| 
 | 
 | ||||||
|  |                 boolean notSsoLogin = | ||||||
|  |                         !loginMethod.equals(LoginMethod.OAUTH2USER) | ||||||
|  |                                 && !loginMethod.equals(LoginMethod.SAML2USER); | ||||||
|  | 
 | ||||||
|  |                 // Block user registration if not allowed by configuration | ||||||
|  |                 if (blockRegistration && !isUserExists) { | ||||||
|  |                     log.warn("Blocked registration for OAuth2/SAML user: {}", username); | ||||||
|  |                     response.sendRedirect( | ||||||
|  |                             request.getContextPath() + "/logout?oauth2_admin_blocked_user=true"); | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 // Expire sessions and logout if the user does not exist or is disabled | ||||||
|                 if (!isUserExists || isUserDisabled) { |                 if (!isUserExists || isUserDisabled) { | ||||||
|  |                     log.info( | ||||||
|  |                             "Invalidating session for disabled or non-existent user: {}", username); | ||||||
|                     for (SessionInformation sessionsInformation : sessionsInformations) { |                     for (SessionInformation sessionsInformation : sessionsInformations) { | ||||||
|                         sessionsInformation.expireNow(); |                         sessionsInformation.expireNow(); | ||||||
|                         sessionPersistentRegistry.expireSession(sessionsInformation.getSessionId()); |                         sessionPersistentRegistry.expireSession(sessionsInformation.getSessionId()); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (!isUserExists) { |                 // Redirect to logout if credentials are invalid | ||||||
|  |                 if (!isUserExists && notSsoLogin) { | ||||||
|                     response.sendRedirect(request.getContextPath() + "/logout?badcredentials=true"); |                     response.sendRedirect(request.getContextPath() + "/logout?badcredentials=true"); | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
| @ -161,6 +204,25 @@ public class UserAuthenticationFilter extends OncePerRequestFilter { | |||||||
|         filterChain.doFilter(request, response); |         filterChain.doFilter(request, response); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private enum LoginMethod { | ||||||
|  |         USERDETAILS("UserDetails"), | ||||||
|  |         OAUTH2USER("OAuth2User"), | ||||||
|  |         STRINGUSER("StringUser"), | ||||||
|  |         UNKNOWN("Unknown"), | ||||||
|  |         SAML2USER("Saml2User"); | ||||||
|  | 
 | ||||||
|  |         private String method; | ||||||
|  | 
 | ||||||
|  |         LoginMethod(String method) { | ||||||
|  |             this.method = method; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         public String toString() { | ||||||
|  |             return method; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { |     protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { | ||||||
|         String uri = request.getRequestURI(); |         String uri = request.getRequestURI(); | ||||||
|  | |||||||
| @ -163,6 +163,9 @@ public class AccountWebController { | |||||||
|                 case "invalid_destination": |                 case "invalid_destination": | ||||||
|                     erroroauth = "login.invalid_destination"; |                     erroroauth = "login.invalid_destination"; | ||||||
|                     break; |                     break; | ||||||
|  |                 case "relying_party_registration_not_found": | ||||||
|  |                     erroroauth = "login.relyingPartyRegistrationNotFound"; | ||||||
|  |                     break; | ||||||
|                 // Valid InResponseTo was not available from the validation context, unable to |                 // Valid InResponseTo was not available from the validation context, unable to | ||||||
|                 // evaluate |                 // evaluate | ||||||
|                 case "invalid_in_response_to": |                 case "invalid_in_response_to": | ||||||
|  | |||||||
| @ -561,6 +561,7 @@ login.oauth2invalidRequest=Invalid Request | |||||||
| login.oauth2AccessDenied=Access Denied | login.oauth2AccessDenied=Access Denied | ||||||
| login.oauth2InvalidTokenResponse=Invalid Token Response | login.oauth2InvalidTokenResponse=Invalid Token Response | ||||||
| login.oauth2InvalidIdToken=Invalid Id Token | login.oauth2InvalidIdToken=Invalid Id Token | ||||||
|  | login.relyingPartyRegistrationNotFound=No relying party registration found | ||||||
| login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. | login.userIsDisabled=User is deactivated, login is currently blocked with this username. Please contact the administrator. | ||||||
| login.alreadyLoggedIn=You are already logged in to | login.alreadyLoggedIn=You are already logged in to | ||||||
| login.alreadyLoggedIn2=devices. Please log out of the devices and try again. | login.alreadyLoggedIn2=devices. Please log out of the devices and try again. | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user