More Provider refactoring & cleanup
This commit is contained in:
@@ -69,7 +69,7 @@ public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationF
|
||||
}
|
||||
if (exception instanceof BadCredentialsException
|
||||
|| exception instanceof UsernameNotFoundException) {
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?error=badcredentials");
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?error=badCredentials");
|
||||
return;
|
||||
}
|
||||
if (exception instanceof InternalAuthenticationServiceException
|
||||
|
||||
@@ -27,57 +27,42 @@ import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrin
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2;
|
||||
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
|
||||
import stirling.software.SPDF.model.provider.Provider;
|
||||
import stirling.software.SPDF.utils.UrlUtils;
|
||||
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
|
||||
|
||||
public static final String LOGOUT_PATH = "/login?logout=true";
|
||||
|
||||
private final ApplicationProperties applicationProperties;
|
||||
|
||||
@Override
|
||||
public void onLogoutSuccess(
|
||||
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||
throws IOException {
|
||||
|
||||
if (!response.isCommitted()) {
|
||||
// Handle user logout due to disabled account
|
||||
if (request.getParameter("userIsDisabled") != null) {
|
||||
response.sendRedirect(
|
||||
request.getContextPath() + "/login?erroroauth=userIsDisabled");
|
||||
return;
|
||||
}
|
||||
// Handle OAuth2 authentication error
|
||||
if (request.getParameter("oauth2AuthenticationErrorWeb") != null) {
|
||||
response.sendRedirect(
|
||||
request.getContextPath() + "/login?erroroauth=userAlreadyExistsWeb");
|
||||
return;
|
||||
}
|
||||
if (authentication != null) {
|
||||
// Handle SAML2 logout redirection
|
||||
if (authentication instanceof Saml2Authentication) {
|
||||
// Handle SAML2 logout redirection
|
||||
getRedirect_saml2(request, response, authentication);
|
||||
}
|
||||
// Handle OAuth2 logout redirection
|
||||
else if (authentication instanceof OAuth2AuthenticationToken) {
|
||||
} else if (authentication instanceof OAuth2AuthenticationToken) {
|
||||
// Handle OAuth2 logout redirection
|
||||
getRedirect_oauth2(request, response, authentication);
|
||||
}
|
||||
// Handle Username/Password logout
|
||||
else if (authentication instanceof UsernamePasswordAuthenticationToken) {
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?logout=true");
|
||||
}
|
||||
// Handle unknown authentication types
|
||||
else {
|
||||
getRedirectStrategy().sendRedirect(request, response, LOGOUT_PATH);
|
||||
} else {
|
||||
// Handle unknown authentication types
|
||||
log.error(
|
||||
"authentication class unknown: {}",
|
||||
"Authentication class unknown: {}",
|
||||
authentication.getClass().getSimpleName());
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?logout=true");
|
||||
getRedirectStrategy().sendRedirect(request, response, LOGOUT_PATH);
|
||||
}
|
||||
} else {
|
||||
// Redirect to login page after logout
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?logout=true");
|
||||
getRedirectStrategy().sendRedirect(request, response, LOGOUT_PATH);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,7 +123,7 @@ public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
|
||||
samlClient.redirectToIdentityProvider(response, null, nameIdValue);
|
||||
} catch (Exception e) {
|
||||
log.error(nameIdValue, e);
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?logout=true");
|
||||
getRedirectStrategy().sendRedirect(request, response, LOGOUT_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,87 +131,81 @@ public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
|
||||
private void getRedirect_oauth2(
|
||||
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||
throws IOException {
|
||||
String param = "logout=true";
|
||||
String registrationId = null;
|
||||
String issuer = null;
|
||||
String clientId = null;
|
||||
String registrationId;
|
||||
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||
String path = checkForErrors(request);
|
||||
|
||||
if (authentication instanceof OAuth2AuthenticationToken oauthToken) {
|
||||
registrationId = oauthToken.getAuthorizedClientRegistrationId();
|
||||
|
||||
try {
|
||||
// Get OAuth2 provider details from configuration
|
||||
Provider provider = oauth.getClient().get(registrationId);
|
||||
} catch (UnsupportedProviderException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
registrationId = oauth.getProvider() != null ? oauth.getProvider() : "";
|
||||
}
|
||||
|
||||
issuer = oauth.getIssuer();
|
||||
clientId = oauth.getClientId();
|
||||
String errorMessage = "";
|
||||
|
||||
// Handle different error scenarios during logout
|
||||
if (request.getParameter("oauth2AuthenticationErrorWeb") != null) {
|
||||
param = "erroroauth=oauth2AuthenticationErrorWeb";
|
||||
} else if ((errorMessage = request.getParameter("error")) != null) {
|
||||
param = "error=" + sanitizeInput(errorMessage);
|
||||
} else if ((errorMessage = request.getParameter("erroroauth")) != null) {
|
||||
param = "erroroauth=" + sanitizeInput(errorMessage);
|
||||
} else if (request.getParameter("oauth2AutoCreateDisabled") != null) {
|
||||
param = "error=oauth2AutoCreateDisabled";
|
||||
} else if (request.getParameter("oauth2_admin_blocked_user") != null) {
|
||||
param = "erroroauth=oauth2_admin_blocked_user";
|
||||
} else if (request.getParameter("userIsDisabled") != null) {
|
||||
param = "erroroauth=userIsDisabled";
|
||||
} else if (request.getParameter("badcredentials") != null) {
|
||||
param = "error=badcredentials";
|
||||
}
|
||||
|
||||
String redirect_url = UrlUtils.getOrigin(request) + "/login?" + param;
|
||||
String redirectUrl = UrlUtils.getOrigin(request) + "/login?" + path;
|
||||
|
||||
// Redirect based on OAuth2 provider
|
||||
switch (registrationId.toLowerCase()) {
|
||||
case "keycloak" -> {
|
||||
// Add Keycloak specific logout URL if needed
|
||||
String logoutUrl =
|
||||
issuer
|
||||
oauth.getIssuer()
|
||||
+ "/protocol/openid-connect/logout"
|
||||
+ "?client_id="
|
||||
+ clientId
|
||||
+ oauth.getClientId()
|
||||
+ "&post_logout_redirect_uri="
|
||||
+ response.encodeRedirectURL(redirect_url);
|
||||
log.info("Redirecting to Keycloak logout URL: " + logoutUrl);
|
||||
+ response.encodeRedirectURL(redirectUrl);
|
||||
log.info("Redirecting to Keycloak logout URL: {}", logoutUrl);
|
||||
response.sendRedirect(logoutUrl);
|
||||
}
|
||||
case "github" -> {
|
||||
// Add GitHub specific logout URL if needed
|
||||
// todo: why does the redirect go to github? shouldn't it come to Stirling PDF?
|
||||
String githubLogoutUrl = "https://github.com/logout";
|
||||
log.info("Redirecting to GitHub logout URL: " + redirect_url);
|
||||
response.sendRedirect(redirect_url);
|
||||
}
|
||||
case "google" -> {
|
||||
// Add Google specific logout URL if needed
|
||||
// String googleLogoutUrl =
|
||||
// "https://accounts.google.com/Logout?continue=https://appengine.google.com/_ah/logout?continue="
|
||||
// + response.encodeRedirectURL(redirect_url);
|
||||
log.info("Google does not have a specific logout URL");
|
||||
// log.info("Redirecting to Google logout URL: " + googleLogoutUrl);
|
||||
// response.sendRedirect(googleLogoutUrl);
|
||||
case "github", "google" -> {
|
||||
log.info(
|
||||
"No redirect URL for {} available. Redirecting to default logout URL: {}",
|
||||
registrationId,
|
||||
redirectUrl);
|
||||
response.sendRedirect(redirectUrl);
|
||||
}
|
||||
default -> {
|
||||
String defaultRedirectUrl = request.getContextPath() + "/login?" + param;
|
||||
log.info("Redirecting to default logout URL: {}", defaultRedirectUrl);
|
||||
response.sendRedirect(defaultRedirectUrl);
|
||||
log.info("Redirecting to default logout URL: {}", redirectUrl);
|
||||
response.sendRedirect(redirectUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sanitize input to avoid potential security vulnerabilities
|
||||
/**
|
||||
* Handles different error scenarios during logout. Will return a <code>String</code> containing
|
||||
* the error request parameter.
|
||||
*
|
||||
* @param request the user's <code>HttpServletRequest</code> request.
|
||||
* @return a <code>String</code> containing the error request parameter.
|
||||
*/
|
||||
private String checkForErrors(HttpServletRequest request) {
|
||||
String errorMessage;
|
||||
String path = "logout=true";
|
||||
|
||||
if (request.getParameter("oAuth2AuthenticationErrorWeb") != null) {
|
||||
path = "errorOAuth=userAlreadyExistsWeb";
|
||||
} else if ((errorMessage = request.getParameter("errorOAuth")) != null) {
|
||||
path = "errorOAuth=" + sanitizeInput(errorMessage);
|
||||
} else if (request.getParameter("oAuth2AutoCreateDisabled") != null) {
|
||||
path = "errorOAuth=oAuth2AutoCreateDisabled";
|
||||
} else if (request.getParameter("oAuth2AdminBlockedUser") != null) {
|
||||
path = "errorOAuth=oAuth2AdminBlockedUser";
|
||||
} else if (request.getParameter("userIsDisabled") != null) {
|
||||
path = "errorOAuth=userIsDisabled";
|
||||
} else if ((errorMessage = request.getParameter("error")) != null) {
|
||||
path = "errorOAuth=" + sanitizeInput(errorMessage);
|
||||
} else if (request.getParameter("badCredentials") != null) {
|
||||
path = "errorOAuth=badCredentials";
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize input to avoid potential security vulnerabilities. Will return a sanitised <code>
|
||||
* String</code>.
|
||||
*
|
||||
* @return a sanitised <code>String</code>
|
||||
*/
|
||||
private String sanitizeInput(String input) {
|
||||
return input.replaceAll("[^a-zA-Z0-9 ]", "");
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ public class SecurityConfiguration {
|
||||
.permitAll());
|
||||
}
|
||||
// Handle OAUTH2 Logins
|
||||
if (applicationProperties.getSecurity().isOauth2Activ()) {
|
||||
if (applicationProperties.getSecurity().isOauth2Active()) {
|
||||
http.oauth2Login(
|
||||
oauth2 ->
|
||||
oauth2.loginPage("/oauth2")
|
||||
@@ -258,7 +258,7 @@ public class SecurityConfiguration {
|
||||
.permitAll());
|
||||
}
|
||||
// Handle SAML
|
||||
if (applicationProperties.getSecurity().isSaml2Activ()) {
|
||||
if (applicationProperties.getSecurity().isSaml2Active()) {
|
||||
// && runningEE
|
||||
// Configure the authentication provider
|
||||
OpenSaml4AuthenticationProvider authenticationProvider =
|
||||
|
||||
@@ -177,7 +177,7 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
|
||||
if (blockRegistration && !isUserExists) {
|
||||
log.warn("Blocked registration for OAuth2/SAML user: {}", username);
|
||||
response.sendRedirect(
|
||||
request.getContextPath() + "/logout?oauth2_admin_blocked_user=true");
|
||||
request.getContextPath() + "/logout?oAuth2AdminBlockedUser=true");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
// 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;
|
||||
}
|
||||
if (isUserDisabled) {
|
||||
|
||||
@@ -29,7 +29,7 @@ public class CustomOAuth2AuthenticationFailureHandler
|
||||
|
||||
if (exception instanceof BadCredentialsException) {
|
||||
log.error("BadCredentialsException", exception);
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?error=badcredentials");
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?error=badCredentials");
|
||||
return;
|
||||
}
|
||||
if (exception instanceof DisabledException) {
|
||||
@@ -52,8 +52,7 @@ public class CustomOAuth2AuthenticationFailureHandler
|
||||
}
|
||||
log.error("OAuth2 Authentication error: " + errorCode);
|
||||
log.error("OAuth2AuthenticationException", exception);
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?erroroauth=" + errorCode);
|
||||
return;
|
||||
getRedirectStrategy().sendRedirect(request, response, "/login?errorOAuth=" + errorCode);
|
||||
}
|
||||
log.error("Unhandled authentication exception", exception);
|
||||
super.onAuthenticationFailure(request, response, exception);
|
||||
|
||||
@@ -26,13 +26,12 @@ import stirling.software.SPDF.utils.RequestUriUtils;
|
||||
public class CustomOAuth2AuthenticationSuccessHandler
|
||||
extends SavedRequestAwareAuthenticationSuccessHandler {
|
||||
|
||||
private LoginAttemptService loginAttemptService;
|
||||
|
||||
private ApplicationProperties applicationProperties;
|
||||
private UserService userService;
|
||||
private final LoginAttemptService loginAttemptService;
|
||||
private final ApplicationProperties applicationProperties;
|
||||
private final UserService userService;
|
||||
|
||||
public CustomOAuth2AuthenticationSuccessHandler(
|
||||
final LoginAttemptService loginAttemptService,
|
||||
LoginAttemptService loginAttemptService,
|
||||
ApplicationProperties applicationProperties,
|
||||
UserService userService) {
|
||||
this.applicationProperties = applicationProperties;
|
||||
@@ -76,23 +75,22 @@ public class CustomOAuth2AuthenticationSuccessHandler
|
||||
throw new LockedException(
|
||||
"Your account has been locked due to too many failed login attempts.");
|
||||
}
|
||||
|
||||
if (userService.isUserDisabled(username)) {
|
||||
getRedirectStrategy()
|
||||
.sendRedirect(request, response, "/logout?userIsDisabled=true");
|
||||
return;
|
||||
}
|
||||
if (userService.usernameExistsIgnoreCase(username)
|
||||
&& userService.hasPassword(username)
|
||||
&& !userService.isAuthenticationTypeByUsername(username, AuthenticationType.SSO)
|
||||
&& oAuth.getAutoCreateUser()) {
|
||||
response.sendRedirect(contextPath + "/logout?oauth2AuthenticationErrorWeb=true");
|
||||
return;
|
||||
response.sendRedirect(contextPath + "/logout?oAuth2AuthenticationErrorWeb=true");
|
||||
}
|
||||
|
||||
try {
|
||||
if (oAuth.getBlockRegistration()
|
||||
&& !userService.usernameExistsIgnoreCase(username)) {
|
||||
response.sendRedirect(contextPath + "/logout?oauth2_admin_blocked_user=true");
|
||||
return;
|
||||
response.sendRedirect(contextPath + "/logout?oAuth2AdminBlockedUser=true");
|
||||
}
|
||||
if (principal instanceof OAuth2User) {
|
||||
userService.processSSOPostLogin(username, oAuth.getAutoCreateUser());
|
||||
|
||||
@@ -25,11 +25,11 @@ public class CustomOAuth2UserService implements OAuth2UserService<OidcUserReques
|
||||
|
||||
private final OidcUserService delegate = new OidcUserService();
|
||||
|
||||
private UserService userService;
|
||||
private final UserService userService;
|
||||
|
||||
private LoginAttemptService loginAttemptService;
|
||||
private final LoginAttemptService loginAttemptService;
|
||||
|
||||
private ApplicationProperties applicationProperties;
|
||||
private final ApplicationProperties applicationProperties;
|
||||
|
||||
public CustomOAuth2UserService(
|
||||
ApplicationProperties applicationProperties,
|
||||
@@ -45,8 +45,9 @@ public class CustomOAuth2UserService implements OAuth2UserService<OidcUserReques
|
||||
OAUTH2 oauth2 = applicationProperties.getSecurity().getOauth2();
|
||||
String usernameAttribute = oauth2.getUseAsUsername();
|
||||
|
||||
if (usernameAttribute == null || usernameAttribute.trim().isEmpty()) {
|
||||
if (usernameAttribute == null || usernameAttribute.isEmpty()) {
|
||||
Client client = oauth2.getClient();
|
||||
|
||||
if (client != null && client.getKeycloak() != null) {
|
||||
usernameAttribute = client.getKeycloak().getUseAsUsername();
|
||||
} else {
|
||||
@@ -59,13 +60,14 @@ public class CustomOAuth2UserService implements OAuth2UserService<OidcUserReques
|
||||
String username = user.getUserInfo().getClaimAsString(usernameAttribute);
|
||||
|
||||
// Check if the username claim is null or empty
|
||||
if (username == null || username.trim().isEmpty()) {
|
||||
if (username == null || username.isBlank()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Claim '" + usernameAttribute + "' cannot be null or empty");
|
||||
}
|
||||
|
||||
Optional<User> duser = userService.findByUsernameIgnoreCase(username);
|
||||
if (duser.isPresent()) {
|
||||
Optional<User> internalUser = userService.findByUsernameIgnoreCase(username);
|
||||
|
||||
if (internalUser.isPresent()) {
|
||||
if (loginAttemptService.isBlocked(username)) {
|
||||
throw new LockedException(
|
||||
"Your account has been locked due to too many failed login attempts.");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package stirling.software.SPDF.config.security.oauth2;
|
||||
|
||||
import static org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE;
|
||||
import static stirling.software.SPDF.utils.validation.Validator.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
@@ -28,9 +29,11 @@ import stirling.software.SPDF.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
|
||||
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client;
|
||||
import stirling.software.SPDF.model.User;
|
||||
import stirling.software.SPDF.model.provider.GithubProvider;
|
||||
import stirling.software.SPDF.model.exception.NoProviderFoundException;
|
||||
import stirling.software.SPDF.model.provider.GitHubProvider;
|
||||
import stirling.software.SPDF.model.provider.GoogleProvider;
|
||||
import stirling.software.SPDF.model.provider.KeycloakProvider;
|
||||
import stirling.software.SPDF.model.provider.Provider;
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@@ -50,7 +53,8 @@ public class OAuth2Configuration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "security.oauth2.enabled", havingValue = "true")
|
||||
public ClientRegistrationRepository clientRegistrationRepository() {
|
||||
public ClientRegistrationRepository clientRegistrationRepository()
|
||||
throws NoProviderFoundException {
|
||||
List<ClientRegistration> registrations = new ArrayList<>();
|
||||
githubClientRegistration().ifPresent(registrations::add);
|
||||
oidcClientRegistration().ifPresent(registrations::add);
|
||||
@@ -58,54 +62,31 @@ public class OAuth2Configuration {
|
||||
keycloakClientRegistration().ifPresent(registrations::add);
|
||||
|
||||
if (registrations.isEmpty()) {
|
||||
log.error("At least one OAuth2 provider must be configured");
|
||||
System.exit(1);
|
||||
log.error("No OAuth2 provider registered");
|
||||
throw new NoProviderFoundException("At least one OAuth2 provider must be configured.");
|
||||
}
|
||||
|
||||
return new InMemoryClientRegistrationRepository(registrations);
|
||||
}
|
||||
|
||||
private Optional<ClientRegistration> googleClientRegistration() {
|
||||
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||
|
||||
if (oauth == null || !oauth.getEnabled()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Client client = oauth.getClient();
|
||||
|
||||
if (client == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
GoogleProvider google = client.getGoogle();
|
||||
return google != null && google.isSettingsValid()
|
||||
? Optional.of(
|
||||
ClientRegistration.withRegistrationId(google.getName())
|
||||
.clientId(google.getClientId())
|
||||
.clientSecret(google.getClientSecret())
|
||||
.scope(google.getScopes())
|
||||
.authorizationUri(google.getAuthorizationUri())
|
||||
.tokenUri(google.getTokenUri())
|
||||
.userInfoUri(google.getUserinfoUri())
|
||||
.userNameAttributeName(google.getUseAsUsername())
|
||||
.clientName(google.getClientName())
|
||||
.redirectUri(REDIRECT_URI_PATH + google.getName())
|
||||
.authorizationGrantType(AUTHORIZATION_CODE)
|
||||
.build())
|
||||
: Optional.empty();
|
||||
}
|
||||
|
||||
private Optional<ClientRegistration> keycloakClientRegistration() {
|
||||
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||
if (oauth == null || !oauth.getEnabled()) {
|
||||
OAUTH2 oauth2 = applicationProperties.getSecurity().getOauth2();
|
||||
|
||||
if (isOAuth2Enabled(oauth2) || isClientInitialised(oauth2)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
Client client = oauth.getClient();
|
||||
if (client == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
KeycloakProvider keycloak = client.getKeycloak();
|
||||
return keycloak != null && keycloak.isSettingsValid()
|
||||
|
||||
Client client = oauth2.getClient();
|
||||
KeycloakProvider keycloakClient = client.getKeycloak();
|
||||
Provider keycloak =
|
||||
new KeycloakProvider(
|
||||
keycloakClient.getIssuer(),
|
||||
keycloakClient.getClientId(),
|
||||
keycloakClient.getClientSecret(),
|
||||
keycloakClient.getScopes(),
|
||||
keycloakClient.getUseAsUsername());
|
||||
|
||||
return validateProvider(keycloak)
|
||||
? Optional.of(
|
||||
ClientRegistrations.fromIssuerLocation(keycloak.getIssuer())
|
||||
.registrationId(keycloak.getName())
|
||||
@@ -118,15 +99,56 @@ public class OAuth2Configuration {
|
||||
: Optional.empty();
|
||||
}
|
||||
|
||||
private Optional<ClientRegistration> githubClientRegistration() {
|
||||
if (isOauthOrClientEmpty()) {
|
||||
private Optional<ClientRegistration> googleClientRegistration() {
|
||||
OAUTH2 oAuth2 = applicationProperties.getSecurity().getOauth2();
|
||||
|
||||
if (isOAuth2Enabled(oAuth2) || isClientInitialised(oAuth2)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
GithubProvider github =
|
||||
applicationProperties.getSecurity().getOauth2().getClient().getGithub();
|
||||
Client client = oAuth2.getClient();
|
||||
GoogleProvider googleClient = client.getGoogle();
|
||||
Provider google =
|
||||
new GoogleProvider(
|
||||
googleClient.getClientId(),
|
||||
googleClient.getClientSecret(),
|
||||
googleClient.getScopes(),
|
||||
googleClient.getUseAsUsername());
|
||||
|
||||
return github != null && github.isSettingsValid()
|
||||
return validateProvider(google)
|
||||
? Optional.of(
|
||||
ClientRegistration.withRegistrationId(google.getName())
|
||||
.clientId(google.getClientId())
|
||||
.clientSecret(google.getClientSecret())
|
||||
.scope(google.getScopes())
|
||||
.authorizationUri(google.getAuthorizationUri())
|
||||
.tokenUri(google.getTokenUri())
|
||||
.userInfoUri(google.getUserInfoUri())
|
||||
.userNameAttributeName(google.getUseAsUsername())
|
||||
.clientName(google.getClientName())
|
||||
.redirectUri(REDIRECT_URI_PATH + google.getName())
|
||||
.authorizationGrantType(AUTHORIZATION_CODE)
|
||||
.build())
|
||||
: Optional.empty();
|
||||
}
|
||||
|
||||
private Optional<ClientRegistration> githubClientRegistration() {
|
||||
OAUTH2 oAuth2 = applicationProperties.getSecurity().getOauth2();
|
||||
|
||||
if (isOAuth2Enabled(oAuth2)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Client client = oAuth2.getClient();
|
||||
GitHubProvider githubClient = client.getGithub();
|
||||
Provider github =
|
||||
new GitHubProvider(
|
||||
githubClient.getClientId(),
|
||||
githubClient.getClientSecret(),
|
||||
githubClient.getScopes(),
|
||||
githubClient.getUseAsUsername());
|
||||
|
||||
return validateProvider(github)
|
||||
? Optional.of(
|
||||
ClientRegistration.withRegistrationId(github.getName())
|
||||
.clientId(github.getClientId())
|
||||
@@ -134,7 +156,7 @@ public class OAuth2Configuration {
|
||||
.scope(github.getScopes())
|
||||
.authorizationUri(github.getAuthorizationUri())
|
||||
.tokenUri(github.getTokenUri())
|
||||
.userInfoUri(github.getUserinfoUri())
|
||||
.userInfoUri(github.getUserInfoUri())
|
||||
.userNameAttributeName(github.getUseAsUsername())
|
||||
.clientName(github.getClientName())
|
||||
.redirectUri(REDIRECT_URI_PATH + github.getName())
|
||||
@@ -146,49 +168,49 @@ public class OAuth2Configuration {
|
||||
private Optional<ClientRegistration> oidcClientRegistration() {
|
||||
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||
|
||||
if (oauth == null
|
||||
|| oauth.getIssuer() == null
|
||||
|| oauth.getIssuer().isEmpty()
|
||||
|| oauth.getClientId() == null
|
||||
|| oauth.getClientId().isEmpty()
|
||||
|| oauth.getClientSecret() == null
|
||||
|| oauth.getClientSecret().isEmpty()
|
||||
|| oauth.getScopes() == null
|
||||
|| oauth.getScopes().isEmpty()
|
||||
|| oauth.getUseAsUsername() == null
|
||||
|| oauth.getUseAsUsername().isEmpty()) {
|
||||
if (isOAuth2Enabled(oauth) || isClientInitialised(oauth)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (isStringEmpty(oauth.getIssuer())
|
||||
|| isStringEmpty(oauth.getClientId())
|
||||
|| isStringEmpty(oauth.getClientSecret())
|
||||
|| isCollectionEmpty(oauth.getScopes())
|
||||
|| isStringEmpty(oauth.getUseAsUsername())) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String name = oauth.getProvider();
|
||||
String firstChar = String.valueOf(name.charAt(0));
|
||||
String clientName = name.replaceFirst(firstChar, firstChar.toUpperCase());
|
||||
|
||||
return Optional.of(
|
||||
ClientRegistrations.fromIssuerLocation(oauth.getIssuer())
|
||||
.registrationId("oidc")
|
||||
.registrationId(name)
|
||||
.clientId(oauth.getClientId())
|
||||
.clientSecret(oauth.getClientSecret())
|
||||
.scope(oauth.getScopes())
|
||||
.userNameAttributeName(oauth.getUseAsUsername())
|
||||
.clientName("OIDC")
|
||||
.redirectUri(REDIRECT_URI_PATH + "oidc")
|
||||
.clientName(clientName)
|
||||
.redirectUri(REDIRECT_URI_PATH + name)
|
||||
.authorizationGrantType(AUTHORIZATION_CODE)
|
||||
.build());
|
||||
}
|
||||
|
||||
private boolean isOauthOrClientEmpty() {
|
||||
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
|
||||
private boolean isOAuth2Enabled(OAUTH2 oAuth2) {
|
||||
return oAuth2 == null || !oAuth2.getEnabled();
|
||||
}
|
||||
|
||||
if (oauth == null || !oauth.getEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Client client = oauth.getClient();
|
||||
|
||||
return client != null;
|
||||
private boolean isClientInitialised(OAUTH2 oauth2) {
|
||||
Client client = oauth2.getClient();
|
||||
return client == null;
|
||||
}
|
||||
|
||||
/*
|
||||
This following function is to grant Authorities to the OAUTH2 user from the values stored in the database.
|
||||
This is required for the internal; 'hasRole()' function to give out the correct role.
|
||||
*/
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(
|
||||
value = "security.oauth2.enabled",
|
||||
@@ -213,11 +235,9 @@ public class OAuth2Configuration {
|
||||
(String) oauth2Auth.getAttributes().get(useAsUsername));
|
||||
if (userOpt.isPresent()) {
|
||||
User user = userOpt.get();
|
||||
if (user != null) {
|
||||
mappedAuthorities.add(
|
||||
new SimpleGrantedAuthority(
|
||||
userService.findRole(user).getAuthority()));
|
||||
}
|
||||
mappedAuthorities.add(
|
||||
new SimpleGrantedAuthority(
|
||||
userService.findRole(user).getAuthority()));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -26,13 +26,13 @@ public class CustomSaml2AuthenticationFailureHandler extends SimpleUrlAuthentica
|
||||
if (exception instanceof Saml2AuthenticationException) {
|
||||
Saml2Error error = ((Saml2AuthenticationException) exception).getSaml2Error();
|
||||
getRedirectStrategy()
|
||||
.sendRedirect(request, response, "/login?erroroauth=" + error.getErrorCode());
|
||||
.sendRedirect(request, response, "/login?errorOAuth=" + error.getErrorCode());
|
||||
} else if (exception instanceof ProviderNotFoundException) {
|
||||
getRedirectStrategy()
|
||||
.sendRedirect(
|
||||
request,
|
||||
response,
|
||||
"/login?erroroauth=not_authentication_provider_found");
|
||||
"/login?errorOAuth=not_authentication_provider_found");
|
||||
}
|
||||
log.error("AuthenticationException: " + exception);
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ public class CustomSaml2AuthenticationSuccessHandler
|
||||
"User {} exists with password but is not SSO user, redirecting to logout",
|
||||
username);
|
||||
response.sendRedirect(
|
||||
contextPath + "/logout?oauth2AuthenticationErrorWeb=true");
|
||||
contextPath + "/logout?oAuth2AuthenticationErrorWeb=true");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ public class CustomSaml2AuthenticationSuccessHandler
|
||||
if (saml2.getBlockRegistration() && !userExists) {
|
||||
log.debug("Registration blocked for new user: {}", username);
|
||||
response.sendRedirect(
|
||||
contextPath + "/login?erroroauth=oauth2_admin_blocked_user");
|
||||
contextPath + "/login?errorOAuth=oAuth2AdminBlockedUser");
|
||||
return;
|
||||
}
|
||||
log.debug("Processing SSO post-login for user: {}", username);
|
||||
|
||||
@@ -26,24 +26,17 @@ import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2;
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
@ConditionalOnProperty(
|
||||
value = "security.saml2.enabled",
|
||||
havingValue = "true",
|
||||
matchIfMissing = false)
|
||||
@ConditionalOnProperty(value = "security.saml2.enabled", havingValue = "true")
|
||||
public class SAML2Configuration {
|
||||
|
||||
private final ApplicationProperties applicationProperties;
|
||||
|
||||
public SAML2Configuration(ApplicationProperties applicationProperties) {
|
||||
|
||||
this.applicationProperties = applicationProperties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(
|
||||
name = "security.saml2.enabled",
|
||||
havingValue = "true",
|
||||
matchIfMissing = false)
|
||||
@ConditionalOnProperty(name = "security.saml2.enabled", havingValue = "true")
|
||||
public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception {
|
||||
SAML2 samlConf = applicationProperties.getSecurity().getSaml2();
|
||||
X509Certificate idpCert = CertificateUtils.readCertificate(samlConf.getidpCert());
|
||||
@@ -73,10 +66,7 @@ public class SAML2Configuration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(
|
||||
name = "security.saml2.enabled",
|
||||
havingValue = "true",
|
||||
matchIfMissing = false)
|
||||
@ConditionalOnProperty(name = "security.saml2.enabled", havingValue = "true")
|
||||
public OpenSaml4AuthenticationRequestResolver authenticationRequestResolver(
|
||||
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
|
||||
OpenSaml4AuthenticationRequestResolver resolver =
|
||||
|
||||
Reference in New Issue
Block a user