# Description of Changes * Refactoring of SSO code around OAuth & SAML 2 * Enabling auto-login with SAML 2 via the new `SSOAutoLogin` property * Correcting typos & general cleanup --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable) - [x] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md) (if applicable) - [x] I have performed a self-review of my own code - [x] My changes generate no new warnings ### Documentation - [x] 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) - [x] 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) ### 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) - [x] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing) for more details.
91 lines
3.6 KiB
Java
91 lines
3.6 KiB
Java
package stirling.software.SPDF.config.security;
|
|
|
|
import java.io.IOException;
|
|
import java.util.Optional;
|
|
|
|
import org.springframework.security.authentication.BadCredentialsException;
|
|
import org.springframework.security.authentication.DisabledException;
|
|
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
|
import org.springframework.security.authentication.LockedException;
|
|
import org.springframework.security.core.AuthenticationException;
|
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
|
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
|
|
|
import jakarta.servlet.ServletException;
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
import stirling.software.SPDF.model.User;
|
|
|
|
@Slf4j
|
|
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
|
|
|
|
private LoginAttemptService loginAttemptService;
|
|
|
|
private UserService userService;
|
|
|
|
public CustomAuthenticationFailureHandler(
|
|
final LoginAttemptService loginAttemptService, UserService userService) {
|
|
this.loginAttemptService = loginAttemptService;
|
|
this.userService = userService;
|
|
}
|
|
|
|
@Override
|
|
public void onAuthenticationFailure(
|
|
HttpServletRequest request,
|
|
HttpServletResponse response,
|
|
AuthenticationException exception)
|
|
throws IOException, ServletException {
|
|
|
|
if (exception instanceof DisabledException) {
|
|
log.error("User is deactivated: ", exception);
|
|
getRedirectStrategy().sendRedirect(request, response, "/logout?userIsDisabled=true");
|
|
return;
|
|
}
|
|
|
|
String ip = request.getRemoteAddr();
|
|
log.error("Failed login attempt from IP: {}", ip);
|
|
|
|
if (exception instanceof LockedException) {
|
|
getRedirectStrategy().sendRedirect(request, response, "/login?error=locked");
|
|
return;
|
|
}
|
|
|
|
String username = request.getParameter("username");
|
|
Optional<User> optUser = userService.findByUsernameIgnoreCase(username);
|
|
|
|
if (username != null && optUser.isPresent() && !isDemoUser(optUser)) {
|
|
log.info(
|
|
"Remaining attempts for user {}: {}",
|
|
username,
|
|
loginAttemptService.getRemainingAttempts(username));
|
|
loginAttemptService.loginFailed(username);
|
|
if (loginAttemptService.isBlocked(username) || exception instanceof LockedException) {
|
|
getRedirectStrategy().sendRedirect(request, response, "/login?error=locked");
|
|
return;
|
|
}
|
|
}
|
|
if (exception instanceof BadCredentialsException
|
|
|| exception instanceof UsernameNotFoundException) {
|
|
getRedirectStrategy().sendRedirect(request, response, "/login?error=badCredentials");
|
|
return;
|
|
}
|
|
if (exception instanceof InternalAuthenticationServiceException
|
|
|| "Password must not be null".equalsIgnoreCase(exception.getMessage())) {
|
|
getRedirectStrategy()
|
|
.sendRedirect(request, response, "/login?error=oauth2AuthenticationError");
|
|
return;
|
|
}
|
|
|
|
super.onAuthenticationFailure(request, response, exception);
|
|
}
|
|
|
|
private boolean isDemoUser(Optional<User> user) {
|
|
return user.isPresent()
|
|
&& user.get().getAuthorities().stream()
|
|
.anyMatch(authority -> "ROLE_DEMO_USER".equals(authority.getAuthority()));
|
|
}
|
|
}
|