wip - testing different name attributes for SSO

This commit is contained in:
DarioGii 2025-01-30 18:42:32 +00:00 committed by Dario Ghunney Ware
parent d3cfc813e7
commit acabb69e1f
9 changed files with 51 additions and 36 deletions

View File

@ -169,7 +169,9 @@ public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
} }
/** /**
* Handles different error scenarios during logout. Will return a <code>String</code> containing the error request parameter. * 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. * @param request the user's <code>HttpServletRequest</code> request.
* @return a <code>String</code> containing the error request parameter. * @return a <code>String</code> containing the error request parameter.
*/ */

View File

@ -24,11 +24,11 @@ public class CustomOAuth2UserService implements OAuth2UserService<OidcUserReques
private final OidcUserService delegate = new OidcUserService(); 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( public CustomOAuth2UserService(
ApplicationProperties applicationProperties, ApplicationProperties applicationProperties,
@ -44,8 +44,9 @@ public class CustomOAuth2UserService implements OAuth2UserService<OidcUserReques
OAUTH2 oauth2 = applicationProperties.getSecurity().getOauth2(); OAUTH2 oauth2 = applicationProperties.getSecurity().getOauth2();
String usernameAttribute = oauth2.getUseAsUsername(); String usernameAttribute = oauth2.getUseAsUsername();
if (usernameAttribute == null || usernameAttribute.trim().isEmpty()) { if (usernameAttribute == null || usernameAttribute.isEmpty()) {
Client client = oauth2.getClient(); Client client = oauth2.getClient();
if (client != null && client.getKeycloak() != null) { if (client != null && client.getKeycloak() != null) {
usernameAttribute = client.getKeycloak().getUseAsUsername(); usernameAttribute = client.getKeycloak().getUseAsUsername();
} else { } else {
@ -58,13 +59,14 @@ public class CustomOAuth2UserService implements OAuth2UserService<OidcUserReques
String username = user.getUserInfo().getClaimAsString(usernameAttribute); String username = user.getUserInfo().getClaimAsString(usernameAttribute);
// Check if the username claim is null or empty // Check if the username claim is null or empty
if (username == null || username.trim().isEmpty()) { if (username == null || username.isBlank()) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Claim '" + usernameAttribute + "' cannot be null or empty"); "Claim '" + usernameAttribute + "' cannot be null or empty");
} }
Optional<User> duser = userService.findByUsernameIgnoreCase(username); Optional<User> internalUser = userService.findByUsernameIgnoreCase(username);
if (duser.isPresent()) {
if (internalUser.isPresent()) {
if (loginAttemptService.isBlocked(username)) { if (loginAttemptService.isBlocked(username)) {
throw new LockedException( throw new LockedException(
"Your account has been locked due to too many failed login attempts."); "Your account has been locked due to too many failed login attempts.");

View File

@ -28,6 +28,7 @@ import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2; import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client; import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client;
import stirling.software.SPDF.model.User; import stirling.software.SPDF.model.User;
import stirling.software.SPDF.model.exception.NoProviderFoundException;
import stirling.software.SPDF.model.provider.GitHubProvider; import stirling.software.SPDF.model.provider.GitHubProvider;
import stirling.software.SPDF.model.provider.GoogleProvider; import stirling.software.SPDF.model.provider.GoogleProvider;
import stirling.software.SPDF.model.provider.KeycloakProvider; import stirling.software.SPDF.model.provider.KeycloakProvider;
@ -51,7 +52,8 @@ public class OAuth2Configuration {
@Bean @Bean
@ConditionalOnProperty(value = "security.oauth2.enabled", havingValue = "true") @ConditionalOnProperty(value = "security.oauth2.enabled", havingValue = "true")
public ClientRegistrationRepository clientRegistrationRepository() { public ClientRegistrationRepository clientRegistrationRepository()
throws NoProviderFoundException {
List<ClientRegistration> registrations = new ArrayList<>(); List<ClientRegistration> registrations = new ArrayList<>();
githubClientRegistration().ifPresent(registrations::add); githubClientRegistration().ifPresent(registrations::add);
oidcClientRegistration().ifPresent(registrations::add); oidcClientRegistration().ifPresent(registrations::add);
@ -59,8 +61,8 @@ public class OAuth2Configuration {
keycloakClientRegistration().ifPresent(registrations::add); keycloakClientRegistration().ifPresent(registrations::add);
if (registrations.isEmpty()) { if (registrations.isEmpty()) {
log.error("At least one OAuth2 provider must be configured"); log.error("No OAuth2 provider registered");
System.exit(1); throw new NoProviderFoundException("At least one OAuth2 provider must be configured.");
} }
return new InMemoryClientRegistrationRepository(registrations); return new InMemoryClientRegistrationRepository(registrations);
@ -69,7 +71,7 @@ public class OAuth2Configuration {
private Optional<ClientRegistration> keycloakClientRegistration() { private Optional<ClientRegistration> keycloakClientRegistration() {
OAUTH2 oauth2 = applicationProperties.getSecurity().getOauth2(); OAUTH2 oauth2 = applicationProperties.getSecurity().getOauth2();
if (isOauthOrClientEmpty(oauth2)) { if (isOAuth2Enabled(oauth2) || isClientInitialised(oauth2)) {
return Optional.empty(); return Optional.empty();
} }
@ -97,13 +99,13 @@ public class OAuth2Configuration {
} }
private Optional<ClientRegistration> googleClientRegistration() { private Optional<ClientRegistration> googleClientRegistration() {
OAUTH2 oauth2 = applicationProperties.getSecurity().getOauth2(); OAUTH2 oAuth2 = applicationProperties.getSecurity().getOauth2();
if (isOauthOrClientEmpty(oauth2)) { if (isOAuth2Enabled(oAuth2) || isClientInitialised(oAuth2)) {
return Optional.empty(); return Optional.empty();
} }
Client client = oauth2.getClient(); Client client = oAuth2.getClient();
GoogleProvider googleClient = client.getGoogle(); GoogleProvider googleClient = client.getGoogle();
Provider google = Provider google =
new GoogleProvider( new GoogleProvider(
@ -130,13 +132,13 @@ public class OAuth2Configuration {
} }
private Optional<ClientRegistration> githubClientRegistration() { private Optional<ClientRegistration> githubClientRegistration() {
OAUTH2 oauth2 = applicationProperties.getSecurity().getOauth2(); OAUTH2 oAuth2 = applicationProperties.getSecurity().getOauth2();
if (isOauthOrClientEmpty(oauth2)) { if (isOAuth2Enabled(oAuth2)) {
return Optional.empty(); return Optional.empty();
} }
Client client = oauth2.getClient(); Client client = oAuth2.getClient();
GitHubProvider githubClient = client.getGithub(); GitHubProvider githubClient = client.getGithub();
Provider github = Provider github =
new GitHubProvider( new GitHubProvider(
@ -165,7 +167,7 @@ public class OAuth2Configuration {
private Optional<ClientRegistration> oidcClientRegistration() { private Optional<ClientRegistration> oidcClientRegistration() {
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
if (isOauthOrClientEmpty(oauth)) { if (isOAuth2Enabled(oauth) || isClientInitialised(oauth)) {
return Optional.empty(); return Optional.empty();
} }
@ -194,12 +196,12 @@ public class OAuth2Configuration {
.build()); .build());
} }
private boolean isOauthOrClientEmpty(OAUTH2 oauth) { private boolean isOAuth2Enabled(OAUTH2 oAuth2) {
if (oauth == null || !oauth.getEnabled()) { return oAuth2 == null || !oAuth2.getEnabled();
return false; }
}
Client client = oauth.getClient(); private boolean isClientInitialised(OAUTH2 oauth2) {
Client client = oauth2.getClient();
return client == null; return client == null;
} }

View File

@ -114,7 +114,7 @@ public class AccountWebController {
providerList providerList
.entrySet() .entrySet()
.removeIf(entry -> entry.getKey() == null || entry.getValue() == null); .removeIf(entry -> entry.getKey() == null || entry.getValue() == null);
model.addAttribute("providerlist", providerList); model.addAttribute("providerList", providerList);
model.addAttribute("loginMethod", securityProps.getLoginMethod()); model.addAttribute("loginMethod", securityProps.getLoginMethod());
boolean altLogin = !providerList.isEmpty() ? securityProps.isAltLogin() : false; boolean altLogin = !providerList.isEmpty() ? securityProps.isAltLogin() : false;

View File

@ -245,11 +245,11 @@ public class ApplicationProperties {
} }
public boolean isSettingsValid() { public boolean isSettingsValid() {
return isStringEmpty(this.getIssuer()) return !isStringEmpty(this.getIssuer())
&& isStringEmpty(this.getClientId()) && !isStringEmpty(this.getClientId())
&& isStringEmpty(this.getClientSecret()) && !isStringEmpty(this.getClientSecret())
&& isCollectionEmpty(this.getScopes()) && !isCollectionEmpty(this.getScopes())
&& isStringEmpty(this.getUseAsUsername()); && !isStringEmpty(this.getUseAsUsername());
} }
@Data @Data

View File

@ -0,0 +1,11 @@
package stirling.software.SPDF.model.exception;
public class NoProviderFoundException extends Exception {
public NoProviderFoundException(String message) {
super(message);
}
public NoProviderFoundException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -57,9 +57,7 @@ public class Provider {
@Override @Override
public String toString() { public String toString() {
return "Provider [issuer=" return "Provider [name="
+ getIssuer()
+ ", name="
+ getName() + getName()
+ ", clientName=" + ", clientName="
+ getClientName() + getClientName()

View File

@ -32,7 +32,7 @@ security:
google: google:
clientId: '' # client ID for Google OAuth2 clientId: '' # client ID for Google OAuth2
clientSecret: '' # client secret for Google OAuth2 clientSecret: '' # client secret for Google OAuth2
scopes: https://www.googleapis.com/auth/userinfo.email, https://www.googleapis.com/auth/userinfo.profile # scopes for Google OAuth2 scopes: email, profile # scopes for Google OAuth2
useAsUsername: email # field to use as the username for Google OAuth2 useAsUsername: email # field to use as the username for Google OAuth2
github: github:
clientId: '' # client ID for GitHub OAuth2 clientId: '' # client ID for GitHub OAuth2

View File

@ -42,7 +42,7 @@
const runningEE = /*[[${@runningEE}]]*/ false; const runningEE = /*[[${@runningEE}]]*/ false;
const SSOAutoLogin = /*[[${@SSOAutoLogin}]]*/ false; const SSOAutoLogin = /*[[${@SSOAutoLogin}]]*/ false;
const loginMethod = /*[[${loginMethod}]]*/ 'normal'; const loginMethod = /*[[${loginMethod}]]*/ 'normal';
const providerList = /*[[${providerlist}]]*/ {}; const providerList = /*[[${providerList}]]*/ {};
const shouldAutoRedirect = !hasRedirectError && const shouldAutoRedirect = !hasRedirectError &&
!hasLogout && !hasLogout &&
!hasMessage && !hasMessage &&
@ -164,7 +164,7 @@
</button> </button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="mb-3" th:each="provider : ${providerlist}"> <div class="mb-3" th:each="provider : ${providerList}">
<a th:href="@{|${provider.key}|}" th:text="${provider.value}" class="w-100 btn btn-lg btn-primary">Login Provider</a> <a th:href="@{|${provider.key}|}" th:text="${provider.value}" class="w-100 btn btn-lg btn-primary">Login Provider</a>
</div> </div>
</div> </div>