More Provider refactoring & cleanup

This commit is contained in:
Dario Ghunney Ware 2025-01-24 18:14:15 +00:00
parent 06a5ba892c
commit 8954990afb
64 changed files with 866 additions and 511 deletions

View File

@ -20,7 +20,7 @@ public class CleanUrlInterceptor implements HandlerInterceptor {
"endpoints", "endpoints",
"logout", "logout",
"error", "error",
"erroroauth", "errorOAuth",
"file", "file",
"messageType", "messageType",
"infoMessage"); "infoMessage");

View File

@ -69,7 +69,7 @@ public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationF
} }
if (exception instanceof BadCredentialsException if (exception instanceof BadCredentialsException
|| exception instanceof UsernameNotFoundException) { || exception instanceof UsernameNotFoundException) {
getRedirectStrategy().sendRedirect(request, response, "/login?error=badcredentials"); getRedirectStrategy().sendRedirect(request, response, "/login?error=badCredentials");
return; return;
} }
if (exception instanceof InternalAuthenticationServiceException if (exception instanceof InternalAuthenticationServiceException

View File

@ -27,57 +27,42 @@ import stirling.software.SPDF.config.security.saml2.CustomSaml2AuthenticatedPrin
import stirling.software.SPDF.model.ApplicationProperties; 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.SAML2; 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; import stirling.software.SPDF.utils.UrlUtils;
@Slf4j @Slf4j
@AllArgsConstructor @AllArgsConstructor
public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler { public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
public static final String LOGOUT_PATH = "/login?logout=true";
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
@Override @Override
public void onLogoutSuccess( public void onLogoutSuccess(
HttpServletRequest request, HttpServletResponse response, Authentication authentication) HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException { throws IOException {
if (!response.isCommitted()) { 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) { if (authentication != null) {
// Handle SAML2 logout redirection
if (authentication instanceof Saml2Authentication) { if (authentication instanceof Saml2Authentication) {
// Handle SAML2 logout redirection
getRedirect_saml2(request, response, authentication); getRedirect_saml2(request, response, authentication);
} } else if (authentication instanceof OAuth2AuthenticationToken) {
// Handle OAuth2 logout redirection // Handle OAuth2 logout redirection
else if (authentication instanceof OAuth2AuthenticationToken) {
getRedirect_oauth2(request, response, authentication); getRedirect_oauth2(request, response, authentication);
} }
// Handle Username/Password logout // Handle Username/Password logout
else if (authentication instanceof UsernamePasswordAuthenticationToken) { else if (authentication instanceof UsernamePasswordAuthenticationToken) {
getRedirectStrategy().sendRedirect(request, response, "/login?logout=true"); getRedirectStrategy().sendRedirect(request, response, LOGOUT_PATH);
} } else {
// Handle unknown authentication types // Handle unknown authentication types
else {
log.error( log.error(
"authentication class unknown: {}", "Authentication class unknown: {}",
authentication.getClass().getSimpleName()); authentication.getClass().getSimpleName());
getRedirectStrategy().sendRedirect(request, response, "/login?logout=true"); getRedirectStrategy().sendRedirect(request, response, LOGOUT_PATH);
} }
} else { } else {
// Redirect to login page after logout // 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); samlClient.redirectToIdentityProvider(response, null, nameIdValue);
} catch (Exception e) { } catch (Exception e) {
log.error(nameIdValue, 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( private void getRedirect_oauth2(
HttpServletRequest request, HttpServletResponse response, Authentication authentication) HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException { throws IOException {
String param = "logout=true"; String registrationId;
String registrationId = null;
String issuer = null;
String clientId = null;
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
String path = checkForErrors(request);
if (authentication instanceof OAuth2AuthenticationToken oauthToken) { if (authentication instanceof OAuth2AuthenticationToken oauthToken) {
registrationId = oauthToken.getAuthorizedClientRegistrationId(); registrationId = oauthToken.getAuthorizedClientRegistrationId();
try {
// Get OAuth2 provider details from configuration
Provider provider = oauth.getClient().get(registrationId);
} catch (UnsupportedProviderException e) {
log.error(e.getMessage());
}
} else { } else {
registrationId = oauth.getProvider() != null ? oauth.getProvider() : ""; registrationId = oauth.getProvider() != null ? oauth.getProvider() : "";
} }
issuer = oauth.getIssuer(); String redirectUrl = UrlUtils.getOrigin(request) + "/login?" + path;
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;
// Redirect based on OAuth2 provider // Redirect based on OAuth2 provider
switch (registrationId.toLowerCase()) { switch (registrationId.toLowerCase()) {
case "keycloak" -> { case "keycloak" -> {
// Add Keycloak specific logout URL if needed
String logoutUrl = String logoutUrl =
issuer oauth.getIssuer()
+ "/protocol/openid-connect/logout" + "/protocol/openid-connect/logout"
+ "?client_id=" + "?client_id="
+ clientId + oauth.getClientId()
+ "&post_logout_redirect_uri=" + "&post_logout_redirect_uri="
+ response.encodeRedirectURL(redirect_url); + response.encodeRedirectURL(redirectUrl);
log.info("Redirecting to Keycloak logout URL: " + logoutUrl); log.info("Redirecting to Keycloak logout URL: {}", logoutUrl);
response.sendRedirect(logoutUrl); response.sendRedirect(logoutUrl);
} }
case "github" -> { case "github", "google" -> {
// Add GitHub specific logout URL if needed log.info(
// todo: why does the redirect go to github? shouldn't it come to Stirling PDF? "No redirect URL for {} available. Redirecting to default logout URL: {}",
String githubLogoutUrl = "https://github.com/logout"; registrationId,
log.info("Redirecting to GitHub logout URL: " + redirect_url); redirectUrl);
response.sendRedirect(redirect_url); response.sendRedirect(redirectUrl);
}
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);
} }
default -> { default -> {
String defaultRedirectUrl = request.getContextPath() + "/login?" + param; log.info("Redirecting to default logout URL: {}", redirectUrl);
log.info("Redirecting to default logout URL: {}", defaultRedirectUrl); response.sendRedirect(redirectUrl);
response.sendRedirect(defaultRedirectUrl);
} }
} }
} }
// 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) { private String sanitizeInput(String input) {
return input.replaceAll("[^a-zA-Z0-9 ]", ""); return input.replaceAll("[^a-zA-Z0-9 ]", "");
} }

View File

@ -227,7 +227,7 @@ public class SecurityConfiguration {
.permitAll()); .permitAll());
} }
// Handle OAUTH2 Logins // Handle OAUTH2 Logins
if (applicationProperties.getSecurity().isOauth2Activ()) { if (applicationProperties.getSecurity().isOauth2Active()) {
http.oauth2Login( http.oauth2Login(
oauth2 -> oauth2 ->
oauth2.loginPage("/oauth2") oauth2.loginPage("/oauth2")
@ -258,7 +258,7 @@ public class SecurityConfiguration {
.permitAll()); .permitAll());
} }
// Handle SAML // Handle SAML
if (applicationProperties.getSecurity().isSaml2Activ()) { if (applicationProperties.getSecurity().isSaml2Active()) {
// && runningEE // && runningEE
// Configure the authentication provider // Configure the authentication provider
OpenSaml4AuthenticationProvider authenticationProvider = OpenSaml4AuthenticationProvider authenticationProvider =

View File

@ -177,7 +177,7 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
if (blockRegistration && !isUserExists) { if (blockRegistration && !isUserExists) {
log.warn("Blocked registration for OAuth2/SAML user: {}", username); log.warn("Blocked registration for OAuth2/SAML user: {}", username);
response.sendRedirect( response.sendRedirect(
request.getContextPath() + "/logout?oauth2_admin_blocked_user=true"); request.getContextPath() + "/logout?oAuth2AdminBlockedUser=true");
return; return;
} }
@ -193,7 +193,7 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
// Redirect to logout if credentials are invalid // Redirect to logout if credentials are invalid
if (!isUserExists && notSsoLogin) { if (!isUserExists && notSsoLogin) {
response.sendRedirect(request.getContextPath() + "/logout?badcredentials=true"); response.sendRedirect(request.getContextPath() + "/logout?badCredentials=true");
return; return;
} }
if (isUserDisabled) { if (isUserDisabled) {

View File

@ -29,7 +29,7 @@ public class CustomOAuth2AuthenticationFailureHandler
if (exception instanceof BadCredentialsException) { if (exception instanceof BadCredentialsException) {
log.error("BadCredentialsException", exception); log.error("BadCredentialsException", exception);
getRedirectStrategy().sendRedirect(request, response, "/login?error=badcredentials"); getRedirectStrategy().sendRedirect(request, response, "/login?error=badCredentials");
return; return;
} }
if (exception instanceof DisabledException) { if (exception instanceof DisabledException) {
@ -52,8 +52,7 @@ public class CustomOAuth2AuthenticationFailureHandler
} }
log.error("OAuth2 Authentication error: " + errorCode); log.error("OAuth2 Authentication error: " + errorCode);
log.error("OAuth2AuthenticationException", exception); log.error("OAuth2AuthenticationException", exception);
getRedirectStrategy().sendRedirect(request, response, "/login?erroroauth=" + errorCode); getRedirectStrategy().sendRedirect(request, response, "/login?errorOAuth=" + errorCode);
return;
} }
log.error("Unhandled authentication exception", exception); log.error("Unhandled authentication exception", exception);
super.onAuthenticationFailure(request, response, exception); super.onAuthenticationFailure(request, response, exception);

View File

@ -26,13 +26,12 @@ import stirling.software.SPDF.utils.RequestUriUtils;
public class CustomOAuth2AuthenticationSuccessHandler public class CustomOAuth2AuthenticationSuccessHandler
extends SavedRequestAwareAuthenticationSuccessHandler { extends SavedRequestAwareAuthenticationSuccessHandler {
private LoginAttemptService loginAttemptService; private final LoginAttemptService loginAttemptService;
private final ApplicationProperties applicationProperties;
private ApplicationProperties applicationProperties; private final UserService userService;
private UserService userService;
public CustomOAuth2AuthenticationSuccessHandler( public CustomOAuth2AuthenticationSuccessHandler(
final LoginAttemptService loginAttemptService, LoginAttemptService loginAttemptService,
ApplicationProperties applicationProperties, ApplicationProperties applicationProperties,
UserService userService) { UserService userService) {
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
@ -76,23 +75,22 @@ public class CustomOAuth2AuthenticationSuccessHandler
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.");
} }
if (userService.isUserDisabled(username)) { if (userService.isUserDisabled(username)) {
getRedirectStrategy() getRedirectStrategy()
.sendRedirect(request, response, "/logout?userIsDisabled=true"); .sendRedirect(request, response, "/logout?userIsDisabled=true");
return;
} }
if (userService.usernameExistsIgnoreCase(username) if (userService.usernameExistsIgnoreCase(username)
&& userService.hasPassword(username) && userService.hasPassword(username)
&& !userService.isAuthenticationTypeByUsername(username, AuthenticationType.SSO) && !userService.isAuthenticationTypeByUsername(username, AuthenticationType.SSO)
&& oAuth.getAutoCreateUser()) { && oAuth.getAutoCreateUser()) {
response.sendRedirect(contextPath + "/logout?oauth2AuthenticationErrorWeb=true"); response.sendRedirect(contextPath + "/logout?oAuth2AuthenticationErrorWeb=true");
return;
} }
try { try {
if (oAuth.getBlockRegistration() if (oAuth.getBlockRegistration()
&& !userService.usernameExistsIgnoreCase(username)) { && !userService.usernameExistsIgnoreCase(username)) {
response.sendRedirect(contextPath + "/logout?oauth2_admin_blocked_user=true"); response.sendRedirect(contextPath + "/logout?oAuth2AdminBlockedUser=true");
return;
} }
if (principal instanceof OAuth2User) { if (principal instanceof OAuth2User) {
userService.processSSOPostLogin(username, oAuth.getAutoCreateUser()); userService.processSSOPostLogin(username, oAuth.getAutoCreateUser());

View File

@ -25,11 +25,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,
@ -45,8 +45,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 {
@ -59,13 +60,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

@ -1,6 +1,7 @@
package stirling.software.SPDF.config.security.oauth2; package stirling.software.SPDF.config.security.oauth2;
import static org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE; 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.ArrayList;
import java.util.HashSet; 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;
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.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.GoogleProvider;
import stirling.software.SPDF.model.provider.KeycloakProvider; import stirling.software.SPDF.model.provider.KeycloakProvider;
import stirling.software.SPDF.model.provider.Provider;
@Slf4j @Slf4j
@Configuration @Configuration
@ -50,7 +53,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);
@ -58,54 +62,31 @@ 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);
} }
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() { private Optional<ClientRegistration> keycloakClientRegistration() {
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); OAUTH2 oauth2 = applicationProperties.getSecurity().getOauth2();
if (oauth == null || !oauth.getEnabled()) {
if (isOAuth2Enabled(oauth2) || isClientInitialised(oauth2)) {
return Optional.empty(); return Optional.empty();
} }
Client client = oauth.getClient();
if (client == null) { Client client = oauth2.getClient();
return Optional.empty(); KeycloakProvider keycloakClient = client.getKeycloak();
} Provider keycloak =
KeycloakProvider keycloak = client.getKeycloak(); new KeycloakProvider(
return keycloak != null && keycloak.isSettingsValid() keycloakClient.getIssuer(),
keycloakClient.getClientId(),
keycloakClient.getClientSecret(),
keycloakClient.getScopes(),
keycloakClient.getUseAsUsername());
return validateProvider(keycloak)
? Optional.of( ? Optional.of(
ClientRegistrations.fromIssuerLocation(keycloak.getIssuer()) ClientRegistrations.fromIssuerLocation(keycloak.getIssuer())
.registrationId(keycloak.getName()) .registrationId(keycloak.getName())
@ -118,15 +99,56 @@ public class OAuth2Configuration {
: Optional.empty(); : Optional.empty();
} }
private Optional<ClientRegistration> githubClientRegistration() { private Optional<ClientRegistration> googleClientRegistration() {
if (isOauthOrClientEmpty()) { OAUTH2 oAuth2 = applicationProperties.getSecurity().getOauth2();
if (isOAuth2Enabled(oAuth2) || isClientInitialised(oAuth2)) {
return Optional.empty(); return Optional.empty();
} }
GithubProvider github = Client client = oAuth2.getClient();
applicationProperties.getSecurity().getOauth2().getClient().getGithub(); 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( ? Optional.of(
ClientRegistration.withRegistrationId(github.getName()) ClientRegistration.withRegistrationId(github.getName())
.clientId(github.getClientId()) .clientId(github.getClientId())
@ -134,7 +156,7 @@ public class OAuth2Configuration {
.scope(github.getScopes()) .scope(github.getScopes())
.authorizationUri(github.getAuthorizationUri()) .authorizationUri(github.getAuthorizationUri())
.tokenUri(github.getTokenUri()) .tokenUri(github.getTokenUri())
.userInfoUri(github.getUserinfoUri()) .userInfoUri(github.getUserInfoUri())
.userNameAttributeName(github.getUseAsUsername()) .userNameAttributeName(github.getUseAsUsername())
.clientName(github.getClientName()) .clientName(github.getClientName())
.redirectUri(REDIRECT_URI_PATH + github.getName()) .redirectUri(REDIRECT_URI_PATH + github.getName())
@ -146,49 +168,49 @@ public class OAuth2Configuration {
private Optional<ClientRegistration> oidcClientRegistration() { private Optional<ClientRegistration> oidcClientRegistration() {
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); OAUTH2 oauth = applicationProperties.getSecurity().getOauth2();
if (oauth == null if (isOAuth2Enabled(oauth) || isClientInitialised(oauth)) {
|| 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()) {
return Optional.empty(); 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( return Optional.of(
ClientRegistrations.fromIssuerLocation(oauth.getIssuer()) ClientRegistrations.fromIssuerLocation(oauth.getIssuer())
.registrationId("oidc") .registrationId(name)
.clientId(oauth.getClientId()) .clientId(oauth.getClientId())
.clientSecret(oauth.getClientSecret()) .clientSecret(oauth.getClientSecret())
.scope(oauth.getScopes()) .scope(oauth.getScopes())
.userNameAttributeName(oauth.getUseAsUsername()) .userNameAttributeName(oauth.getUseAsUsername())
.clientName("OIDC") .clientName(clientName)
.redirectUri(REDIRECT_URI_PATH + "oidc") .redirectUri(REDIRECT_URI_PATH + name)
.authorizationGrantType(AUTHORIZATION_CODE) .authorizationGrantType(AUTHORIZATION_CODE)
.build()); .build());
} }
private boolean isOauthOrClientEmpty() { private boolean isOAuth2Enabled(OAUTH2 oAuth2) {
OAUTH2 oauth = applicationProperties.getSecurity().getOauth2(); return oAuth2 == null || !oAuth2.getEnabled();
if (oauth == null || !oauth.getEnabled()) {
return false;
} }
Client client = oauth.getClient(); private boolean isClientInitialised(OAUTH2 oauth2) {
Client client = oauth2.getClient();
return client != null; return client == null;
} }
/* /*
This following function is to grant Authorities to the OAUTH2 user from the values stored in the database. 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. This is required for the internal; 'hasRole()' function to give out the correct role.
*/ */
@Bean @Bean
@ConditionalOnProperty( @ConditionalOnProperty(
value = "security.oauth2.enabled", value = "security.oauth2.enabled",
@ -213,13 +235,11 @@ public class OAuth2Configuration {
(String) oauth2Auth.getAttributes().get(useAsUsername)); (String) oauth2Auth.getAttributes().get(useAsUsername));
if (userOpt.isPresent()) { if (userOpt.isPresent()) {
User user = userOpt.get(); User user = userOpt.get();
if (user != null) {
mappedAuthorities.add( mappedAuthorities.add(
new SimpleGrantedAuthority( new SimpleGrantedAuthority(
userService.findRole(user).getAuthority())); userService.findRole(user).getAuthority()));
} }
} }
}
}); });
return mappedAuthorities; return mappedAuthorities;
}; };

View File

@ -26,13 +26,13 @@ public class CustomSaml2AuthenticationFailureHandler extends SimpleUrlAuthentica
if (exception instanceof Saml2AuthenticationException) { if (exception instanceof Saml2AuthenticationException) {
Saml2Error error = ((Saml2AuthenticationException) exception).getSaml2Error(); Saml2Error error = ((Saml2AuthenticationException) exception).getSaml2Error();
getRedirectStrategy() getRedirectStrategy()
.sendRedirect(request, response, "/login?erroroauth=" + error.getErrorCode()); .sendRedirect(request, response, "/login?errorOAuth=" + error.getErrorCode());
} else if (exception instanceof ProviderNotFoundException) { } else if (exception instanceof ProviderNotFoundException) {
getRedirectStrategy() getRedirectStrategy()
.sendRedirect( .sendRedirect(
request, request,
response, response,
"/login?erroroauth=not_authentication_provider_found"); "/login?errorOAuth=not_authentication_provider_found");
} }
log.error("AuthenticationException: " + exception); log.error("AuthenticationException: " + exception);
} }

View File

@ -97,7 +97,7 @@ public class CustomSaml2AuthenticationSuccessHandler
"User {} exists with password but is not SSO user, redirecting to logout", "User {} exists with password but is not SSO user, redirecting to logout",
username); username);
response.sendRedirect( response.sendRedirect(
contextPath + "/logout?oauth2AuthenticationErrorWeb=true"); contextPath + "/logout?oAuth2AuthenticationErrorWeb=true");
return; return;
} }
@ -105,7 +105,7 @@ public class CustomSaml2AuthenticationSuccessHandler
if (saml2.getBlockRegistration() && !userExists) { if (saml2.getBlockRegistration() && !userExists) {
log.debug("Registration blocked for new user: {}", username); log.debug("Registration blocked for new user: {}", username);
response.sendRedirect( response.sendRedirect(
contextPath + "/login?erroroauth=oauth2_admin_blocked_user"); contextPath + "/login?errorOAuth=oAuth2AdminBlockedUser");
return; return;
} }
log.debug("Processing SSO post-login for user: {}", username); log.debug("Processing SSO post-login for user: {}", username);

View File

@ -26,24 +26,17 @@ import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2;
@Configuration @Configuration
@Slf4j @Slf4j
@ConditionalOnProperty( @ConditionalOnProperty(value = "security.saml2.enabled", havingValue = "true")
value = "security.saml2.enabled",
havingValue = "true",
matchIfMissing = false)
public class SAML2Configuration { public class SAML2Configuration {
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
public SAML2Configuration(ApplicationProperties applicationProperties) { public SAML2Configuration(ApplicationProperties applicationProperties) {
this.applicationProperties = applicationProperties; this.applicationProperties = applicationProperties;
} }
@Bean @Bean
@ConditionalOnProperty( @ConditionalOnProperty(name = "security.saml2.enabled", havingValue = "true")
name = "security.saml2.enabled",
havingValue = "true",
matchIfMissing = false)
public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception { public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception {
SAML2 samlConf = applicationProperties.getSecurity().getSaml2(); SAML2 samlConf = applicationProperties.getSecurity().getSaml2();
X509Certificate idpCert = CertificateUtils.readCertificate(samlConf.getidpCert()); X509Certificate idpCert = CertificateUtils.readCertificate(samlConf.getidpCert());
@ -73,10 +66,7 @@ public class SAML2Configuration {
} }
@Bean @Bean
@ConditionalOnProperty( @ConditionalOnProperty(name = "security.saml2.enabled", havingValue = "true")
name = "security.saml2.enabled",
havingValue = "true",
matchIfMissing = false)
public OpenSaml4AuthenticationRequestResolver authenticationRequestResolver( public OpenSaml4AuthenticationRequestResolver authenticationRequestResolver(
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) { RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
OpenSaml4AuthenticationRequestResolver resolver = OpenSaml4AuthenticationRequestResolver resolver =

View File

@ -1,5 +1,7 @@
package stirling.software.SPDF.controller.web; package stirling.software.SPDF.controller.web;
import static stirling.software.SPDF.utils.validation.Validator.validateProvider;
import java.time.Instant; import java.time.Instant;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.*; import java.util.*;
@ -29,7 +31,7 @@ import stirling.software.SPDF.model.ApplicationProperties.Security;
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.ApplicationProperties.Security.SAML2; import stirling.software.SPDF.model.ApplicationProperties.Security.SAML2;
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;
import stirling.software.SPDF.repository.UserRepository; import stirling.software.SPDF.repository.UserRepository;
@ -40,12 +42,11 @@ import stirling.software.SPDF.repository.UserRepository;
public class AccountWebController { public class AccountWebController {
public static final String OAUTH_2_AUTHORIZATION = "/oauth2/authorization/"; public static final String OAUTH_2_AUTHORIZATION = "/oauth2/authorization/";
private final ApplicationProperties applicationProperties; private final ApplicationProperties applicationProperties;
private final SessionPersistentRegistry sessionPersistentRegistry; private final SessionPersistentRegistry sessionPersistentRegistry;
// Assuming you have a repository for user operations
private final UserRepository // Assuming you have a repository for user operations private final UserRepository userRepository;
userRepository;
public AccountWebController( public AccountWebController(
ApplicationProperties applicationProperties, ApplicationProperties applicationProperties,
@ -62,28 +63,40 @@ public class AccountWebController {
if (authentication != null && authentication.isAuthenticated()) { if (authentication != null && authentication.isAuthenticated()) {
return "redirect:/"; return "redirect:/";
} }
Map<String, String> providerList = new HashMap<>(); Map<String, String> providerList = new HashMap<>();
Security securityProps = applicationProperties.getSecurity(); Security securityProps = applicationProperties.getSecurity();
OAUTH2 oauth = securityProps.getOauth2(); OAUTH2 oauth = securityProps.getOauth2();
if (oauth != null) { if (oauth != null) {
if (oauth.getEnabled()) { if (oauth.getEnabled()) {
if (oauth.isSettingsValid()) { if (oauth.isSettingsValid()) {
providerList.put(OAUTH_2_AUTHORIZATION + "oidc", oauth.getProvider()); String firstChar = String.valueOf(oauth.getProvider().charAt(0));
String clientName =
oauth.getProvider().replaceFirst(firstChar, firstChar.toUpperCase());
providerList.put(OAUTH_2_AUTHORIZATION + "oidc", clientName);
} }
Client client = oauth.getClient(); Client client = oauth.getClient();
if (client != null) { if (client != null) {
GoogleProvider google = client.getGoogle(); GoogleProvider google = client.getGoogle();
if (google.isSettingsValid()) {
if (validateProvider(google)) {
providerList.put( providerList.put(
OAUTH_2_AUTHORIZATION + google.getName(), google.getClientName()); OAUTH_2_AUTHORIZATION + google.getName(), google.getClientName());
} }
GithubProvider github = client.getGithub();
if (github.isSettingsValid()) { GitHubProvider github = client.getGithub();
if (validateProvider(github)) {
providerList.put( providerList.put(
OAUTH_2_AUTHORIZATION + github.getName(), github.getClientName()); OAUTH_2_AUTHORIZATION + github.getName(), github.getClientName());
} }
KeycloakProvider keycloak = client.getKeycloak(); KeycloakProvider keycloak = client.getKeycloak();
if (keycloak.isSettingsValid()) {
if (validateProvider(keycloak)) {
providerList.put( providerList.put(
OAUTH_2_AUTHORIZATION + keycloak.getName(), OAUTH_2_AUTHORIZATION + keycloak.getName(),
keycloak.getClientName()); keycloak.getClientName());
@ -91,101 +104,74 @@ public class AccountWebController {
} }
} }
} }
SAML2 saml2 = securityProps.getSaml2(); SAML2 saml2 = securityProps.getSaml2();
if (securityProps.isSaml2Activ()
if (securityProps.isSaml2Active()
&& applicationProperties.getSystem().getEnableAlphaFunctionality()) { && applicationProperties.getSystem().getEnableAlphaFunctionality()) {
providerList.put("/saml2/authenticate/" + saml2.getRegistrationId(), "SAML 2"); providerList.put("/saml2/authenticate/" + saml2.getRegistrationId(), "SAML 2");
} }
// Remove any null keys/values from the providerList // Remove any null keys/values from the providerList
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;
model.addAttribute("altLogin", altLogin); model.addAttribute("altLogin", altLogin);
model.addAttribute("currentPage", "login"); model.addAttribute("currentPage", "login");
String error = request.getParameter("error"); String error = request.getParameter("error");
if (error != null) { if (error != null) {
switch (error) { switch (error) {
case "badcredentials": case "badCredentials" -> error = "login.invalid";
error = "login.invalid"; case "locked" -> error = "login.locked";
break; case "oauth2AuthenticationError" -> error = "userAlreadyExistsOAuthMessage";
case "locked":
error = "login.locked";
break;
case "oauth2AuthenticationError":
error = "userAlreadyExistsOAuthMessage";
break;
default:
break;
} }
model.addAttribute("error", error); model.addAttribute("error", error);
} }
String erroroauth = request.getParameter("erroroauth"); String errorOAuth = request.getParameter("errorOAuth");
if (erroroauth != null) { if (errorOAuth != null) {
switch (erroroauth) { switch (errorOAuth) {
case "oauth2AutoCreateDisabled": case "oAuth2AutoCreateDisabled" -> errorOAuth = "login.oAuth2AutoCreateDisabled";
erroroauth = "login.oauth2AutoCreateDisabled"; case "invalidUsername" -> errorOAuth = "login.invalid";
break; case "userAlreadyExistsWeb" -> errorOAuth = "userAlreadyExistsWebMessage";
case "invalidUsername": case "oAuth2AuthenticationErrorWeb" -> errorOAuth = "login.oauth2InvalidUserType";
erroroauth = "login.invalid"; case "invalid_token_response" -> errorOAuth = "login.oauth2InvalidTokenResponse";
break; case "authorization_request_not_found" ->
case "userAlreadyExistsWeb": errorOAuth = "login.oauth2RequestNotFound";
erroroauth = "userAlreadyExistsWebMessage"; case "access_denied" -> errorOAuth = "login.oauth2AccessDenied";
break; case "invalid_user_info_response" ->
case "oauth2AuthenticationErrorWeb": errorOAuth = "login.oauth2InvalidUserInfoResponse";
erroroauth = "login.oauth2InvalidUserType"; case "invalid_request" -> errorOAuth = "login.oauth2invalidRequest";
break; case "invalid_id_token" -> errorOAuth = "login.oauth2InvalidIdToken";
case "invalid_token_response": case "oAuth2AdminBlockedUser" -> errorOAuth = "login.oAuth2AdminBlockedUser";
erroroauth = "login.oauth2InvalidTokenResponse"; case "userIsDisabled" -> errorOAuth = "login.userIsDisabled";
break; case "invalid_destination" -> errorOAuth = "login.invalid_destination";
case "authorization_request_not_found": case "relying_party_registration_not_found" ->
erroroauth = "login.oauth2RequestNotFound"; errorOAuth = "login.relyingPartyRegistrationNotFound";
break;
case "access_denied":
erroroauth = "login.oauth2AccessDenied";
break;
case "invalid_user_info_response":
erroroauth = "login.oauth2InvalidUserInfoResponse";
break;
case "invalid_request":
erroroauth = "login.oauth2invalidRequest";
break;
case "invalid_id_token":
erroroauth = "login.oauth2InvalidIdToken";
break;
case "oauth2_admin_blocked_user":
erroroauth = "login.oauth2AdminBlockedUser";
break;
case "userIsDisabled":
erroroauth = "login.userIsDisabled";
break;
case "invalid_destination":
erroroauth = "login.invalid_destination";
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" -> errorOAuth = "login.invalid_in_response_to";
erroroauth = "login.invalid_in_response_to"; case "not_authentication_provider_found" ->
break; errorOAuth = "login.not_authentication_provider_found";
case "not_authentication_provider_found":
erroroauth = "login.not_authentication_provider_found";
break;
default:
break;
} }
model.addAttribute("erroroauth", erroroauth);
model.addAttribute("errorOAuth", errorOAuth);
} }
if (request.getParameter("messageType") != null) { if (request.getParameter("messageType") != null) {
model.addAttribute("messageType", "changedCredsMessage"); model.addAttribute("messageType", "changedCredsMessage");
} }
if (request.getParameter("logout") != null) { if (request.getParameter("logout") != null) {
model.addAttribute("logoutMessage", "You have been logged out."); model.addAttribute("logoutMessage", "You have been logged out.");
} }
return "login"; return "login";
} }
@ -339,40 +325,28 @@ public class AccountWebController {
if (authentication != null && authentication.isAuthenticated()) { if (authentication != null && authentication.isAuthenticated()) {
Object principal = authentication.getPrincipal(); Object principal = authentication.getPrincipal();
String username = null; String username = null;
if (principal instanceof UserDetails) { if (principal instanceof UserDetails userDetails) {
// Cast the principal object to UserDetails
UserDetails userDetails = (UserDetails) principal;
// Retrieve username and other attributes // Retrieve username and other attributes
username = userDetails.getUsername(); username = userDetails.getUsername();
// Add oAuth2 Login attributes to the model // Add oAuth2 Login attributes to the model
model.addAttribute("oAuth2Login", false); model.addAttribute("oAuth2Login", false);
} }
if (principal instanceof OAuth2User) { if (principal instanceof OAuth2User userDetails) {
// Cast the principal object to OAuth2User
OAuth2User userDetails = (OAuth2User) principal;
// Retrieve username and other attributes // Retrieve username and other attributes
username = username = userDetails.getName();
userDetails.getAttribute(
applicationProperties.getSecurity().getOauth2().getUseAsUsername());
// Add oAuth2 Login attributes to the model // Add oAuth2 Login attributes to the model
model.addAttribute("oAuth2Login", true); model.addAttribute("oAuth2Login", true);
} }
if (principal instanceof CustomSaml2AuthenticatedPrincipal) { if (principal instanceof CustomSaml2AuthenticatedPrincipal userDetails) {
// Cast the principal object to OAuth2User
CustomSaml2AuthenticatedPrincipal userDetails =
(CustomSaml2AuthenticatedPrincipal) principal;
// Retrieve username and other attributes // Retrieve username and other attributes
username = userDetails.getName(); username = userDetails.getName();
// Add oAuth2 Login attributes to the model // Add oAuth2 Login attributes to the model
model.addAttribute("oAuth2Login", true); model.addAttribute("oAuth2Login", true);
} }
if (username != null) { if (username != null) {
// Fetch user details from the database // Fetch user details from the database, assuming findByUsername method exists
Optional<User> user = Optional<User> user = userRepository.findByUsernameIgnoreCaseWithSettings(username);
userRepository
.findByUsernameIgnoreCaseWithSettings( // Assuming findByUsername
// method exists
username);
if (!user.isPresent()) { if (!user.isPresent()) {
return "redirect:/error"; return "redirect:/error";
} }
@ -386,31 +360,20 @@ public class AccountWebController {
log.error("exception", e); log.error("exception", e);
return "redirect:/error"; return "redirect:/error";
} }
String messageType = request.getParameter("messageType"); String messageType = request.getParameter("messageType");
if (messageType != null) { if (messageType != null) {
switch (messageType) { switch (messageType) {
case "notAuthenticated": case "notAuthenticated" -> messageType = "notAuthenticatedMessage";
messageType = "notAuthenticatedMessage"; case "userNotFound" -> messageType = "userNotFoundMessage";
break; case "incorrectPassword" -> messageType = "incorrectPasswordMessage";
case "userNotFound": case "usernameExists" -> messageType = "usernameExistsMessage";
messageType = "userNotFoundMessage"; case "invalidUsername" -> messageType = "invalidUsernameMessage";
break;
case "incorrectPassword":
messageType = "incorrectPasswordMessage";
break;
case "usernameExists":
messageType = "usernameExistsMessage";
break;
case "invalidUsername":
messageType = "invalidUsernameMessage";
break;
default:
break;
} }
model.addAttribute("messageType", messageType);
} }
// Add attributes to the model // Add attributes to the model
model.addAttribute("username", username); model.addAttribute("username", username);
model.addAttribute("messageType", messageType);
model.addAttribute("role", user.get().getRolesAsString()); model.addAttribute("role", user.get().getRolesAsString());
model.addAttribute("settings", settingsJson); model.addAttribute("settings", settingsJson);
model.addAttribute("changeCredsFlag", user.get().isFirstLogin()); model.addAttribute("changeCredsFlag", user.get().isFirstLogin());

View File

@ -1,5 +1,7 @@
package stirling.software.SPDF.model; package stirling.software.SPDF.model;
import static stirling.software.SPDF.utils.validation.Validator.*;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
@ -35,7 +37,7 @@ import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.InstallationPathConfig; import stirling.software.SPDF.config.InstallationPathConfig;
import stirling.software.SPDF.config.YamlPropertySourceFactory; import stirling.software.SPDF.config.YamlPropertySourceFactory;
import stirling.software.SPDF.model.exception.UnsupportedProviderException; import stirling.software.SPDF.model.exception.UnsupportedProviderException;
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;
import stirling.software.SPDF.model.provider.Provider; import stirling.software.SPDF.model.provider.Provider;
@ -244,17 +246,17 @@ public class ApplicationProperties {
} }
public boolean isSettingsValid() { public boolean isSettingsValid() {
return isValid(this.getIssuer(), "issuer") return !isStringEmpty(this.getIssuer())
&& isValid(this.getClientId(), "clientId") && !isStringEmpty(this.getClientId())
&& isValid(this.getClientSecret(), "clientSecret") && !isStringEmpty(this.getClientSecret())
&& isValid(this.getScopes(), "scopes") && !isCollectionEmpty(this.getScopes())
&& isValid(this.getUseAsUsername(), "useAsUsername"); && !isStringEmpty(this.getUseAsUsername());
} }
@Data @Data
public static class Client { public static class Client {
private GoogleProvider google = new GoogleProvider(); private GoogleProvider google = new GoogleProvider();
private GithubProvider github = new GithubProvider(); private GitHubProvider github = new GitHubProvider();
private KeycloakProvider keycloak = new KeycloakProvider(); private KeycloakProvider keycloak = new KeycloakProvider();
public Provider get(String registrationId) throws UnsupportedProviderException { public Provider get(String registrationId) throws UnsupportedProviderException {
@ -262,8 +264,10 @@ public class ApplicationProperties {
case "google" -> getGoogle(); case "google" -> getGoogle();
case "github" -> getGithub(); case "github" -> getGithub();
case "keycloak" -> getKeycloak(); case "keycloak" -> getKeycloak();
default -> throw new UnsupportedProviderException( default ->
"Logout from the provider is not supported. Report it at https://github.com/Stirling-Tools/Stirling-PDF/issues"); throw new UnsupportedProviderException(
"Logout from the provider " + registrationId + " is not supported. "
+ "Report it at https://github.com/Stirling-Tools/Stirling-PDF/issues");
}; };
} }
} }

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

@ -5,9 +5,8 @@ import java.util.Collection;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
// @Setter
@NoArgsConstructor @NoArgsConstructor
public class GithubProvider extends Provider { public class GitHubProvider extends Provider {
private static final String NAME = "github"; private static final String NAME = "github";
private static final String CLIENT_NAME = "GitHub"; private static final String CLIENT_NAME = "GitHub";
@ -15,51 +14,68 @@ public class GithubProvider extends Provider {
private static final String TOKEN_URI = "https://github.com/login/oauth/access_token"; private static final String TOKEN_URI = "https://github.com/login/oauth/access_token";
private static final String USER_INFO_URI = "https://api.github.com/user"; private static final String USER_INFO_URI = "https://api.github.com/user";
private String clientId; public GitHubProvider(
private String clientSecret;
private Collection<String> scopes = new ArrayList<>();
private String useAsUsername = "login";
public GithubProvider(
String clientId, String clientSecret, Collection<String> scopes, String useAsUsername) { String clientId, String clientSecret, Collection<String> scopes, String useAsUsername) {
super(null, NAME, CLIENT_NAME, clientId, clientSecret, scopes, useAsUsername); super(
this.clientId = clientId; null,
this.clientSecret = clientSecret; NAME,
this.scopes = scopes; CLIENT_NAME,
this.useAsUsername = useAsUsername; clientId,
clientSecret,
scopes,
useAsUsername != null ? useAsUsername : "login",
AUTHORIZATION_URI,
TOKEN_URI,
USER_INFO_URI);
} }
@Override
public String getAuthorizationUri() { public String getAuthorizationUri() {
return AUTHORIZATION_URI; return AUTHORIZATION_URI;
} }
@Override
public String getTokenUri() { public String getTokenUri() {
return TOKEN_URI; return TOKEN_URI;
} }
public String getUserinfoUri() { @Override
public String getUserInfoUri() {
return USER_INFO_URI; return USER_INFO_URI;
} }
@Override
public String getName() {
return NAME;
}
@Override
public String getClientName() {
return CLIENT_NAME;
}
@Override @Override
public Collection<String> getScopes() { public Collection<String> getScopes() {
Collection<String> scopes = super.getScopes();
if (scopes == null || scopes.isEmpty()) { if (scopes == null || scopes.isEmpty()) {
scopes = new ArrayList<>(); scopes = new ArrayList<>();
scopes.add("read:user"); scopes.add("read:user");
} }
return scopes; return scopes;
} }
@Override @Override
public String toString() { public String toString() {
return "GitHub [clientId=" return "GitHub [clientId="
+ clientId + getClientId()
+ ", clientSecret=" + ", clientSecret="
+ (clientSecret != null && !clientSecret.isEmpty() ? "MASKED" : "NULL") + (getClientSecret() != null && !getClientSecret().isEmpty() ? "*****" : "NULL")
+ ", scopes=" + ", scopes="
+ scopes + getScopes()
+ ", useAsUsername=" + ", useAsUsername="
+ useAsUsername + getUseAsUsername()
+ "]"; + "]";
} }
} }

View File

@ -5,7 +5,6 @@ import java.util.Collection;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
// @Setter
@NoArgsConstructor @NoArgsConstructor
public class GoogleProvider extends Provider { public class GoogleProvider extends Provider {
@ -16,18 +15,19 @@ public class GoogleProvider extends Provider {
private static final String USER_INFO_URI = private static final String USER_INFO_URI =
"https://www.googleapis.com/oauth2/v3/userinfo?alt=json"; "https://www.googleapis.com/oauth2/v3/userinfo?alt=json";
private String clientId;
private String clientSecret;
private Collection<String> scopes = new ArrayList<>();
private String useAsUsername = "email";
public GoogleProvider( public GoogleProvider(
String clientId, String clientSecret, Collection<String> scopes, String useAsUsername) { String clientId, String clientSecret, Collection<String> scopes, String useAsUsername) {
super(null, NAME, CLIENT_NAME, clientId, clientSecret, scopes, useAsUsername); super(
this.clientId = clientId; null,
this.clientSecret = clientSecret; NAME,
this.scopes = scopes; CLIENT_NAME,
this.useAsUsername = useAsUsername; clientId,
clientSecret,
scopes,
useAsUsername,
AUTHORIZATION_URI,
TOKEN_URI,
USER_INFO_URI);
} }
public String getAuthorizationUri() { public String getAuthorizationUri() {
@ -42,26 +42,39 @@ public class GoogleProvider extends Provider {
return USER_INFO_URI; return USER_INFO_URI;
} }
@Override
public String getName() {
return NAME;
}
@Override
public String getClientName() {
return CLIENT_NAME;
}
@Override @Override
public Collection<String> getScopes() { public Collection<String> getScopes() {
Collection<String> scopes = super.getScopes();
if (scopes == null || scopes.isEmpty()) { if (scopes == null || scopes.isEmpty()) {
scopes = new ArrayList<>(); scopes = new ArrayList<>();
scopes.add("https://www.googleapis.com/auth/userinfo.email"); scopes.add("https://www.googleapis.com/auth/userinfo.email");
scopes.add("https://www.googleapis.com/auth/userinfo.profile"); scopes.add("https://www.googleapis.com/auth/userinfo.profile");
} }
return scopes; return scopes;
} }
@Override @Override
public String toString() { public String toString() {
return "Google [clientId=" return "Google [clientId="
+ clientId + getClientId()
+ ", clientSecret=" + ", clientSecret="
+ (clientSecret != null && !clientSecret.isEmpty() ? "MASKED" : "NULL") + (getClientSecret() != null && !getClientSecret().isEmpty() ? "*****" : "NULL")
+ ", scopes=" + ", scopes="
+ scopes + getScopes()
+ ", useAsUsername=" + ", useAsUsername="
+ useAsUsername + getUseAsUsername()
+ "]"; + "]";
} }
} }

View File

@ -5,36 +5,44 @@ import java.util.Collection;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
// @Setter
@NoArgsConstructor @NoArgsConstructor
public class KeycloakProvider extends Provider { public class KeycloakProvider extends Provider {
private static final String NAME = "keycloak"; private static final String NAME = "keycloak";
private static final String CLIENT_NAME = "Keycloak"; private static final String CLIENT_NAME = "Keycloak";
private String issuer;
private String clientId;
private String clientSecret;
private Collection<String> scopes;
private String useAsUsername = "email";
public KeycloakProvider( public KeycloakProvider(
String issuer, String issuer,
String clientId, String clientId,
String clientSecret, String clientSecret,
Collection<String> scopes, Collection<String> scopes,
String useAsUsername) { String useAsUsername) {
super(issuer, NAME, CLIENT_NAME, clientId, clientSecret, scopes, useAsUsername); super(
this.useAsUsername = useAsUsername; issuer,
this.issuer = issuer; NAME,
this.clientId = clientId; CLIENT_NAME,
this.clientSecret = clientSecret; clientId,
this.scopes = scopes; clientSecret,
scopes,
useAsUsername,
null,
null,
null);
}
@Override
public String getName() {
return NAME;
}
@Override
public String getClientName() {
return CLIENT_NAME;
} }
@Override @Override
public Collection<String> getScopes() { public Collection<String> getScopes() {
var scopes = super.getScopes(); Collection<String> scopes = super.getScopes();
if (scopes == null || scopes.isEmpty()) { if (scopes == null || scopes.isEmpty()) {
scopes = new ArrayList<>(); scopes = new ArrayList<>();
@ -48,15 +56,15 @@ public class KeycloakProvider extends Provider {
@Override @Override
public String toString() { public String toString() {
return "Keycloak [issuer=" return "Keycloak [issuer="
+ issuer + getIssuer()
+ ", clientId=" + ", clientId="
+ clientId + getClientId()
+ ", clientSecret=" + ", clientSecret="
+ (clientSecret != null && !clientSecret.isBlank() ? "MASKED" : "NULL") + (getClientSecret() != null && !getClientSecret().isBlank() ? "*****" : "NULL")
+ ", scopes=" + ", scopes="
+ scopes + getScopes()
+ ", useAsUsername=" + ", useAsUsername="
+ useAsUsername + getUseAsUsername()
+ "]"; + "]";
} }
} }

View File

@ -1,15 +1,18 @@
package stirling.software.SPDF.model.provider; package stirling.software.SPDF.model.provider;
import static stirling.software.SPDF.utils.validation.Validator.isStringEmpty;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.Getter; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@Getter @Data
@NoArgsConstructor @NoArgsConstructor
public abstract class Provider { public class Provider {
private String issuer; private String issuer;
private String name; private String name;
@ -18,6 +21,9 @@ public abstract class Provider {
private String clientSecret; private String clientSecret;
private Collection<String> scopes; private Collection<String> scopes;
private String useAsUsername; private String useAsUsername;
private String authorizationUri;
private String tokenUri;
private String userInfoUri;
public Provider( public Provider(
String issuer, String issuer,
@ -26,59 +32,43 @@ public abstract class Provider {
String clientId, String clientId,
String clientSecret, String clientSecret,
Collection<String> scopes, Collection<String> scopes,
String useAsUsername) { String useAsUsername,
String authorizationUri,
String tokenUri,
String userInfoUri) {
this.issuer = issuer; this.issuer = issuer;
this.name = name; this.name = name;
this.clientName = clientName; this.clientName = clientName;
this.clientId = clientId; this.clientId = clientId;
this.clientSecret = clientSecret; this.clientSecret = clientSecret;
this.scopes = scopes; this.scopes = scopes == null ? new ArrayList<>() : scopes;
this.useAsUsername = !useAsUsername.isBlank() ? useAsUsername : "email"; this.useAsUsername = isStringEmpty(useAsUsername) ? "email" : useAsUsername;
} this.authorizationUri = authorizationUri;
this.tokenUri = tokenUri;
// todo: why are we passing name here if it's not used? this.userInfoUri = userInfoUri;
public boolean isSettingsValid() {
return isValid(this.getIssuer(), "issuer")
&& isValid(this.getClientId(), "clientId")
&& isValid(this.getClientSecret(), "clientSecret")
&& isValid(this.getScopes(), "scopes")
&& isValid(this.getUseAsUsername(), "useAsUsername");
}
private boolean isValid(String value, String name) {
return value != null && !value.isBlank();
}
private boolean isValid(Collection<String> value, String name) {
return value != null && !value.isEmpty();
}
public void setIssuer(String issuer) {
this.issuer = issuer;
}
public void setName(String name) {
this.name = name;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
} }
public void setScopes(String scopes) { public void setScopes(String scopes) {
if (scopes != null && !scopes.isBlank()) {
this.scopes = this.scopes =
Arrays.stream(scopes.split(",")).map(String::trim).collect(Collectors.toList()); Arrays.stream(scopes.split(",")).map(String::trim).collect(Collectors.toList());
} }
}
public void setUseAsUsername(String useAsUsername) { @Override
this.useAsUsername = useAsUsername; public String toString() {
return "Provider [name="
+ getName()
+ ", clientName="
+ getClientName()
+ ", clientId="
+ getClientId()
+ ", clientSecret="
+ (getClientSecret() != null && !getClientSecret().isEmpty() ? "*****" : "NULL")
+ ", scopes="
+ getScopes()
+ ", useAsUsername="
+ getUseAsUsername()
+ "]";
} }
} }

View File

@ -7,8 +7,6 @@ import jakarta.servlet.http.HttpServletRequest;
public class UrlUtils { public class UrlUtils {
private UrlUtils() {}
public static String getOrigin(HttpServletRequest request) { public static String getOrigin(HttpServletRequest request) {
String scheme = request.getScheme(); // http or https String scheme = request.getScheme(); // http or https
String serverName = request.getServerName(); // localhost String serverName = request.getServerName(); // localhost

View File

@ -0,0 +1,40 @@
package stirling.software.SPDF.utils.validation;
import java.util.Collection;
import stirling.software.SPDF.model.provider.Provider;
public class Validator {
public static boolean validateProvider(Provider provider) {
if (provider == null) {
return false;
}
if (isStringEmpty(provider.getClientId())) {
return false;
}
if (isStringEmpty(provider.getClientSecret())) {
return false;
}
if (isCollectionEmpty(provider.getScopes())) {
return false;
}
if (isStringEmpty(provider.getUseAsUsername())) {
return false;
}
return true;
}
public static boolean isStringEmpty(String input) {
return input == null || input.isBlank();
}
public static boolean isCollectionEmpty(Collection<String> input) {
return input == null || input.isEmpty();
}
}

View File

@ -572,8 +572,8 @@ login.invalid=اسم المستخدم أو كلمة المرور غير صالح
login.locked=تم قفل حسابك. login.locked=تم قفل حسابك.
login.signinTitle=الرجاء تسجيل الدخول login.signinTitle=الرجاء تسجيل الدخول
login.ssoSignIn=تسجيل الدخول عبر تسجيل الدخول الأحادي login.ssoSignIn=تسجيل الدخول عبر تسجيل الدخول الأحادي
login.oauth2AutoCreateDisabled=تم تعطيل الإنشاء التلقائي لمستخدم OAuth2 login.oAuth2AutoCreateDisabled=تم تعطيل الإنشاء التلقائي لمستخدم OAuth2
login.oauth2AdminBlockedUser=تم حظر تسجيل أو تسجيل دخول المستخدمين غير المسجلين حاليًا. يرجى الاتصال بالمسؤول. login.oAuth2AdminBlockedUser=تم حظر تسجيل أو تسجيل دخول المستخدمين غير المسجلين حاليًا. يرجى الاتصال بالمسؤول.
login.oauth2RequestNotFound=لم يتم العثور على طلب التفويض login.oauth2RequestNotFound=لم يتم العثور على طلب التفويض
login.oauth2InvalidUserInfoResponse=استجابة معلومات المستخدم غير صالحة login.oauth2InvalidUserInfoResponse=استجابة معلومات المستخدم غير صالحة
login.oauth2invalidRequest=طلب غير صالح login.oauth2invalidRequest=طلب غير صالح

View File

@ -572,8 +572,8 @@ login.invalid=Etibarsız istifadəçi adı və ya şifr.
login.locked=Sizin hesabınız kilidlənmişdir. login.locked=Sizin hesabınız kilidlənmişdir.
login.signinTitle=Zəhmət olmasa, daxil olun login.signinTitle=Zəhmət olmasa, daxil olun
login.ssoSignIn=Single Sign-on vasitəsilə daxil olun login.ssoSignIn=Single Sign-on vasitəsilə daxil olun
login.oauth2AutoCreateDisabled=OAUTH2 Auto-Create İstifadəçisi Deaktivləşdirilmişdir login.oAuth2AutoCreateDisabled=OAUTH2 Auto-Create İstifadəçisi Deaktivləşdirilmişdir
login.oauth2AdminBlockedUser=Qeydiyyatdan keçməmiş istifadəçilərin qeydiyyatı və daxil olması hal-hazırda bloklanmışdır. Zəhmət olmasa, administratorla əlaqə saxlayın. login.oAuth2AdminBlockedUser=Qeydiyyatdan keçməmiş istifadəçilərin qeydiyyatı və daxil olması hal-hazırda bloklanmışdır. Zəhmət olmasa, administratorla əlaqə saxlayın.
login.oauth2RequestNotFound=Təsdiqlənmə sorğusu tapılmadı login.oauth2RequestNotFound=Təsdiqlənmə sorğusu tapılmadı
login.oauth2InvalidUserInfoResponse=Yanlış İstifadəçi Məlumatı Cavabı login.oauth2InvalidUserInfoResponse=Yanlış İstifadəçi Məlumatı Cavabı
login.oauth2invalidRequest=Etibarsız Sorğu login.oauth2invalidRequest=Etibarsız Sorğu

View File

@ -572,8 +572,8 @@ login.invalid=Невалидно потребителско име или пар
login.locked=Вашият акаунт е заключен. login.locked=Вашият акаунт е заключен.
login.signinTitle=Моля впишете се login.signinTitle=Моля впишете се
login.ssoSignIn=Влизане чрез еднократно влизане login.ssoSignIn=Влизане чрез еднократно влизане
login.oauth2AutoCreateDisabled=OAUTH2 Автоматично създаване на потребител е деактивирано login.oAuth2AutoCreateDisabled=OAUTH2 Автоматично създаване на потребител е деактивирано
login.oauth2AdminBlockedUser=Регистрацията или влизането на нерегистрирани потребители в момента е блокирано. Моля, свържете се с администратора. login.oAuth2AdminBlockedUser=Регистрацията или влизането на нерегистрирани потребители в момента е блокирано. Моля, свържете се с администратора.
login.oauth2RequestNotFound=Заявката за оторизация не е намерена login.oauth2RequestNotFound=Заявката за оторизация не е намерена
login.oauth2InvalidUserInfoResponse=Невалидна информация за потребителя login.oauth2InvalidUserInfoResponse=Невалидна информация за потребителя
login.oauth2invalidRequest=Невалидна заявка login.oauth2invalidRequest=Невалидна заявка

View File

@ -572,8 +572,8 @@ login.invalid=Nom d'usuari/contrasenya no vàlid
login.locked=Compte bloquejat login.locked=Compte bloquejat
login.signinTitle=Autenticat login.signinTitle=Autenticat
login.ssoSignIn=Inicia sessió mitjançant inici de sessió únic login.ssoSignIn=Inicia sessió mitjançant inici de sessió únic
login.oauth2AutoCreateDisabled=La creació automàtica d'usuaris OAUTH2 està desactivada login.oAuth2AutoCreateDisabled=La creació automàtica d'usuaris OAUTH2 està desactivada
login.oauth2AdminBlockedUser=El registre o inici de sessió d'usuaris no registrats està actualment bloquejat. Si us plau, contacta amb l'administrador. login.oAuth2AdminBlockedUser=El registre o inici de sessió d'usuaris no registrats està actualment bloquejat. Si us plau, contacta amb l'administrador.
login.oauth2RequestNotFound=Sol·licitud d'autorització no trobada login.oauth2RequestNotFound=Sol·licitud d'autorització no trobada
login.oauth2InvalidUserInfoResponse=Resposta d'informació d'usuari no vàlida login.oauth2InvalidUserInfoResponse=Resposta d'informació d'usuari no vàlida
login.oauth2invalidRequest=Sol·licitud no vàlida login.oauth2invalidRequest=Sol·licitud no vàlida

View File

@ -572,8 +572,8 @@ login.invalid=Neplatné uživatelské jméno nebo heslo.
login.locked=Váš účet byl uzamčen. login.locked=Váš účet byl uzamčen.
login.signinTitle=Prosím přihlaste se login.signinTitle=Prosím přihlaste se
login.ssoSignIn=Přihlásit se přes Single Sign-on login.ssoSignIn=Přihlásit se přes Single Sign-on
login.oauth2AutoCreateDisabled=Automatické vytváření OAUTH2 uživatelů je zakázáno login.oAuth2AutoCreateDisabled=Automatické vytváření OAUTH2 uživatelů je zakázáno
login.oauth2AdminBlockedUser=Registrace nebo přihlášení neregistrovaných uživatelů je momentálně blokováno. Kontaktujte prosím správce. login.oAuth2AdminBlockedUser=Registrace nebo přihlášení neregistrovaných uživatelů je momentálně blokováno. Kontaktujte prosím správce.
login.oauth2RequestNotFound=Požadavek na autorizaci nebyl nalezen login.oauth2RequestNotFound=Požadavek na autorizaci nebyl nalezen
login.oauth2InvalidUserInfoResponse=Neplatná odpověď s informacemi o uživateli login.oauth2InvalidUserInfoResponse=Neplatná odpověď s informacemi o uživateli
login.oauth2invalidRequest=Neplatný požadavek login.oauth2invalidRequest=Neplatný požadavek

View File

@ -572,8 +572,8 @@ login.invalid=Ugyldigt brugernavn eller adgangskode.
login.locked=Din konto er blevet låst. login.locked=Din konto er blevet låst.
login.signinTitle=Log venligst ind login.signinTitle=Log venligst ind
login.ssoSignIn=Log ind via Single Sign-on login.ssoSignIn=Log ind via Single Sign-on
login.oauth2AutoCreateDisabled=OAUTH2 Auto-Opret Bruger Deaktiveret login.oAuth2AutoCreateDisabled=OAUTH2 Auto-Opret Bruger Deaktiveret
login.oauth2AdminBlockedUser=Registrering eller login af ikke-registrerede brugere er i øjeblikket blokeret. Kontakt venligst administratoren. login.oAuth2AdminBlockedUser=Registrering eller login af ikke-registrerede brugere er i øjeblikket blokeret. Kontakt venligst administratoren.
login.oauth2RequestNotFound=Autorisationsanmodning ikke fundet login.oauth2RequestNotFound=Autorisationsanmodning ikke fundet
login.oauth2InvalidUserInfoResponse=Ugyldigt Brugerinfo Svar login.oauth2InvalidUserInfoResponse=Ugyldigt Brugerinfo Svar
login.oauth2invalidRequest=Ugyldig Anmodning login.oauth2invalidRequest=Ugyldig Anmodning

View File

@ -572,8 +572,8 @@ login.invalid=Benutzername oder Passwort ungültig.
login.locked=Ihr Konto wurde gesperrt. login.locked=Ihr Konto wurde gesperrt.
login.signinTitle=Bitte melden Sie sich an. login.signinTitle=Bitte melden Sie sich an.
login.ssoSignIn=Anmeldung per Single Sign-On login.ssoSignIn=Anmeldung per Single Sign-On
login.oauth2AutoCreateDisabled=OAUTH2 Benutzer automatisch erstellen deaktiviert login.oAuth2AutoCreateDisabled=OAUTH2 Benutzer automatisch erstellen deaktiviert
login.oauth2AdminBlockedUser=Die Registrierung bzw. das anmelden von nicht registrierten Benutzern ist derzeit gesperrt. Bitte wenden Sie sich an den Administrator. login.oAuth2AdminBlockedUser=Die Registrierung bzw. das anmelden von nicht registrierten Benutzern ist derzeit gesperrt. Bitte wenden Sie sich an den Administrator.
login.oauth2RequestNotFound=Autorisierungsanfrage nicht gefunden login.oauth2RequestNotFound=Autorisierungsanfrage nicht gefunden
login.oauth2InvalidUserInfoResponse=Ungültige Benutzerinformationsantwort login.oauth2InvalidUserInfoResponse=Ungültige Benutzerinformationsantwort
login.oauth2invalidRequest=ungültige Anfrage login.oauth2invalidRequest=ungültige Anfrage

View File

@ -572,8 +572,8 @@ login.invalid=Μη έγκυρο όνομα χρήστη ή κωδικός.
login.locked=Ο λογαριασμός σας έχει κλειδωθεί. login.locked=Ο λογαριασμός σας έχει κλειδωθεί.
login.signinTitle=Παρακαλώ συνδεθείτε login.signinTitle=Παρακαλώ συνδεθείτε
login.ssoSignIn=Σύνδεση μέσω Single Sign-on login.ssoSignIn=Σύνδεση μέσω Single Sign-on
login.oauth2AutoCreateDisabled=Η αυτόματη δημιουργία χρήστη OAUTH2 είναι απενεργοποιημένη login.oAuth2AutoCreateDisabled=Η αυτόματη δημιουργία χρήστη OAUTH2 είναι απενεργοποιημένη
login.oauth2AdminBlockedUser=Η εγγραφή ή σύνδεση μη εγγεγραμμένων χρηστών είναι προς το παρόν αποκλεισμένη. Παρακαλώ επικοινωνήστε με τον διαχειριστή. login.oAuth2AdminBlockedUser=Η εγγραφή ή σύνδεση μη εγγεγραμμένων χρηστών είναι προς το παρόν αποκλεισμένη. Παρακαλώ επικοινωνήστε με τον διαχειριστή.
login.oauth2RequestNotFound=Το αίτημα εξουσιοδότησης δεν βρέθηκε login.oauth2RequestNotFound=Το αίτημα εξουσιοδότησης δεν βρέθηκε
login.oauth2InvalidUserInfoResponse=Μη έγκυρη απόκριση πληροφοριών χρήστη login.oauth2InvalidUserInfoResponse=Μη έγκυρη απόκριση πληροφοριών χρήστη
login.oauth2invalidRequest=Μη έγκυρο αίτημα login.oauth2invalidRequest=Μη έγκυρο αίτημα

View File

@ -572,8 +572,8 @@ login.invalid=Invalid username or password.
login.locked=Your account has been locked. login.locked=Your account has been locked.
login.signinTitle=Please sign in login.signinTitle=Please sign in
login.ssoSignIn=Login via Single Sign-on login.ssoSignIn=Login via Single Sign-on
login.oauth2AutoCreateDisabled=OAUTH2 Auto-Create User Disabled login.oAuth2AutoCreateDisabled=OAUTH2 Auto-Create User Disabled
login.oauth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator. login.oAuth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator.
login.oauth2RequestNotFound=Authorization request not found login.oauth2RequestNotFound=Authorization request not found
login.oauth2InvalidUserInfoResponse=Invalid User Info Response login.oauth2InvalidUserInfoResponse=Invalid User Info Response
login.oauth2invalidRequest=Invalid Request login.oauth2invalidRequest=Invalid Request

View File

@ -572,8 +572,8 @@ login.invalid=Invalid username or password.
login.locked=Your account has been locked. login.locked=Your account has been locked.
login.signinTitle=Please sign in login.signinTitle=Please sign in
login.ssoSignIn=Login via Single Sign-on login.ssoSignIn=Login via Single Sign-on
login.oauth2AutoCreateDisabled=OAUTH2 Auto-Create User Disabled login.oAuth2AutoCreateDisabled=OAUTH2 Auto-Create User Disabled
login.oauth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator. login.oAuth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator.
login.oauth2RequestNotFound=Authorization request not found login.oauth2RequestNotFound=Authorization request not found
login.oauth2InvalidUserInfoResponse=Invalid User Info Response login.oauth2InvalidUserInfoResponse=Invalid User Info Response
login.oauth2invalidRequest=Invalid Request login.oauth2invalidRequest=Invalid Request

View File

@ -572,8 +572,8 @@ login.invalid=Nombre de usuario o contraseña erróneos.
login.locked=Su cuenta se ha bloqueado. login.locked=Su cuenta se ha bloqueado.
login.signinTitle=Por favor, inicie sesión login.signinTitle=Por favor, inicie sesión
login.ssoSignIn=Iniciar sesión a través del inicio de sesión único login.ssoSignIn=Iniciar sesión a través del inicio de sesión único
login.oauth2AutoCreateDisabled=Usuario de creación automática de OAUTH2 DESACTIVADO login.oAuth2AutoCreateDisabled=Usuario de creación automática de OAUTH2 DESACTIVADO
login.oauth2AdminBlockedUser=El registro o inicio de sesión de usuarios no registrados está actualmente bloqueado. Por favor, contáctese con el administrador. login.oAuth2AdminBlockedUser=El registro o inicio de sesión de usuarios no registrados está actualmente bloqueado. Por favor, contáctese con el administrador.
login.oauth2RequestNotFound=Solicitud de autorización no encontrada login.oauth2RequestNotFound=Solicitud de autorización no encontrada
login.oauth2InvalidUserInfoResponse=Respuesta de información de usuario no válida login.oauth2InvalidUserInfoResponse=Respuesta de información de usuario no válida
login.oauth2invalidRequest=Solicitud no válida login.oauth2invalidRequest=Solicitud no válida

View File

@ -572,8 +572,8 @@ login.invalid=Okerreko erabiltzaile izena edo pasahitza.
login.locked=Zure kontua blokeatu egin da. login.locked=Zure kontua blokeatu egin da.
login.signinTitle=Mesedez, hasi saioa login.signinTitle=Mesedez, hasi saioa
login.ssoSignIn=Hasi saioa Saioa hasteko modu bakarraren bidez login.ssoSignIn=Hasi saioa Saioa hasteko modu bakarraren bidez
login.oauth2AutoCreateDisabled=OAUTH2 Sortu automatikoki erabiltzailea desgaituta dago login.oAuth2AutoCreateDisabled=OAUTH2 Sortu automatikoki erabiltzailea desgaituta dago
login.oauth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator. login.oAuth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator.
login.oauth2RequestNotFound=Authorization request not found login.oauth2RequestNotFound=Authorization request not found
login.oauth2InvalidUserInfoResponse=Invalid User Info Response login.oauth2InvalidUserInfoResponse=Invalid User Info Response
login.oauth2invalidRequest=Invalid Request login.oauth2invalidRequest=Invalid Request

View File

@ -572,8 +572,8 @@ login.invalid=نام کاربری یا رمز عبور اشتباه است.
login.locked=حساب شما قفل شده است. login.locked=حساب شما قفل شده است.
login.signinTitle=لطفاً وارد شوید login.signinTitle=لطفاً وارد شوید
login.ssoSignIn=ورود از طریق Single Sign-on login.ssoSignIn=ورود از طریق Single Sign-on
login.oauth2AutoCreateDisabled=ایجاد خودکار کاربر با OAUTH2 غیرفعال است login.oAuth2AutoCreateDisabled=ایجاد خودکار کاربر با OAUTH2 غیرفعال است
login.oauth2AdminBlockedUser=ثبت‌نام یا ورود کاربران ثبت‌نشده در حال حاضر مسدود است. لطفاً با مدیر تماس بگیرید. login.oAuth2AdminBlockedUser=ثبت‌نام یا ورود کاربران ثبت‌نشده در حال حاضر مسدود است. لطفاً با مدیر تماس بگیرید.
login.oauth2RequestNotFound=درخواست احراز هویت پیدا نشد login.oauth2RequestNotFound=درخواست احراز هویت پیدا نشد
login.oauth2InvalidUserInfoResponse=پاسخ اطلاعات کاربری نامعتبر است login.oauth2InvalidUserInfoResponse=پاسخ اطلاعات کاربری نامعتبر است
login.oauth2invalidRequest=درخواست نامعتبر login.oauth2invalidRequest=درخواست نامعتبر

View File

@ -572,8 +572,8 @@ login.invalid=Nom d'utilisateur ou mot de passe invalide.
login.locked=Votre compte a été verrouillé. login.locked=Votre compte a été verrouillé.
login.signinTitle=Veuillez vous connecter login.signinTitle=Veuillez vous connecter
login.ssoSignIn=Se connecter via l'authentification unique login.ssoSignIn=Se connecter via l'authentification unique
login.oauth2AutoCreateDisabled=OAUTH2 Création automatique d'utilisateur désactivée login.oAuth2AutoCreateDisabled=OAUTH2 Création automatique d'utilisateur désactivée
login.oauth2AdminBlockedUser=La création ou l'authentification d'utilisateurs non enregistrés est actuellement bloquée. Veuillez contacter l'administrateur. login.oAuth2AdminBlockedUser=La création ou l'authentification d'utilisateurs non enregistrés est actuellement bloquée. Veuillez contacter l'administrateur.
login.oauth2RequestNotFound=Demande d'autorisation introuvable login.oauth2RequestNotFound=Demande d'autorisation introuvable
login.oauth2InvalidUserInfoResponse=Réponse contenant les informations de l'utilisateur est invalide login.oauth2InvalidUserInfoResponse=Réponse contenant les informations de l'utilisateur est invalide
login.oauth2invalidRequest=Requête invalide login.oauth2invalidRequest=Requête invalide

View File

@ -572,8 +572,8 @@ login.invalid=अमान्य उपयोगकर्ता नाम या
login.locked=आपका खाता लॉक कर दिया गया है। login.locked=आपका खाता लॉक कर दिया गया है।
login.signinTitle=कृपया साइन इन करें login.signinTitle=कृपया साइन इन करें
login.ssoSignIn=सिंगल साइन-ऑन के माध्यम से लॉगिन करें login.ssoSignIn=सिंगल साइन-ऑन के माध्यम से लॉगिन करें
login.oauth2AutoCreateDisabled=OAUTH2 स्वतः उपयोगकर्ता निर्माण अक्षम है login.oAuth2AutoCreateDisabled=OAUTH2 स्वतः उपयोगकर्ता निर्माण अक्षम है
login.oauth2AdminBlockedUser=गैर-पंजीकृत उपयोगकर्ताओं का पंजीकरण या लॉगिन वर्तमान में अवरुद्ध है। कृपया व्यवस्थापक से संपर्क करें। login.oAuth2AdminBlockedUser=गैर-पंजीकृत उपयोगकर्ताओं का पंजीकरण या लॉगिन वर्तमान में अवरुद्ध है। कृपया व्यवस्थापक से संपर्क करें।
login.oauth2RequestNotFound=प्राधिकरण अनुरोध नहीं मिला login.oauth2RequestNotFound=प्राधिकरण अनुरोध नहीं मिला
login.oauth2InvalidUserInfoResponse=अमान्य उपयोगकर्ता जानकारी प्रतिक्रिया login.oauth2InvalidUserInfoResponse=अमान्य उपयोगकर्ता जानकारी प्रतिक्रिया
login.oauth2invalidRequest=अमान्य अनुरोध login.oauth2invalidRequest=अमान्य अनुरोध

View File

@ -572,8 +572,8 @@ login.invalid=Neispravno korisničko ime ili zaporka.
login.locked=Vaš račun je zaključan. login.locked=Vaš račun je zaključan.
login.signinTitle=Molimo vas da se prijavite login.signinTitle=Molimo vas da se prijavite
login.ssoSignIn=Prijavite se putem jedinstvene prijave login.ssoSignIn=Prijavite se putem jedinstvene prijave
login.oauth2AutoCreateDisabled=OAUTH2 automatsko kreiranje korisnika je onemogućeno login.oAuth2AutoCreateDisabled=OAUTH2 automatsko kreiranje korisnika je onemogućeno
login.oauth2AdminBlockedUser=Registracija ili prijava nekadreguiranih korisnika trenutno su blokirane. Molimo Vas da kontaktirate administratora. login.oAuth2AdminBlockedUser=Registracija ili prijava nekadreguiranih korisnika trenutno su blokirane. Molimo Vas da kontaktirate administratora.
login.oauth2RequestNotFound=Zahtjev za autorizaciju nije pronađen login.oauth2RequestNotFound=Zahtjev za autorizaciju nije pronađen
login.oauth2InvalidUserInfoResponse=Nevažeće informacije o korisniku login.oauth2InvalidUserInfoResponse=Nevažeće informacije o korisniku
login.oauth2invalidRequest=Neispravan zahtjev login.oauth2invalidRequest=Neispravan zahtjev

View File

@ -572,8 +572,8 @@ login.invalid=Érvénytelen felhasználónév vagy jelszó.
login.locked=A fiókja zárolva van. login.locked=A fiókja zárolva van.
login.signinTitle=Kérjük, jelentkezzen be login.signinTitle=Kérjük, jelentkezzen be
login.ssoSignIn=Bejelentkezés egyszeri bejelentkezéssel login.ssoSignIn=Bejelentkezés egyszeri bejelentkezéssel
login.oauth2AutoCreateDisabled=OAuth2 automatikus felhasználólétrehozás letiltva login.oAuth2AutoCreateDisabled=OAuth2 automatikus felhasználólétrehozás letiltva
login.oauth2AdminBlockedUser=A nem regisztrált felhasználók regisztrációja vagy bejelentkezése jelenleg le van tiltva. Kérjük, forduljon a rendszergazdához. login.oAuth2AdminBlockedUser=A nem regisztrált felhasználók regisztrációja vagy bejelentkezése jelenleg le van tiltva. Kérjük, forduljon a rendszergazdához.
login.oauth2RequestNotFound=A hitelesítési kérés nem található login.oauth2RequestNotFound=A hitelesítési kérés nem található
login.oauth2InvalidUserInfoResponse=Érvénytelen felhasználói információ válasz login.oauth2InvalidUserInfoResponse=Érvénytelen felhasználói információ válasz
login.oauth2invalidRequest=Érvénytelen kérés login.oauth2invalidRequest=Érvénytelen kérés

View File

@ -572,8 +572,8 @@ login.invalid=Nama pengguna atau kata sandi tidak valid.
login.locked=Akun Anda telah dikunci. login.locked=Akun Anda telah dikunci.
login.signinTitle=Silakan masuk login.signinTitle=Silakan masuk
login.ssoSignIn=Masuk melalui Single Sign - on login.ssoSignIn=Masuk melalui Single Sign - on
login.oauth2AutoCreateDisabled=OAUTH2 Buat Otomatis Pengguna Dinonaktifkan login.oAuth2AutoCreateDisabled=OAUTH2 Buat Otomatis Pengguna Dinonaktifkan
login.oauth2AdminBlockedUser=Registrasi atau login pengguna yang tidak terdaftar saat ini diblokir. Silakan hubungi administrator. login.oAuth2AdminBlockedUser=Registrasi atau login pengguna yang tidak terdaftar saat ini diblokir. Silakan hubungi administrator.
login.oauth2RequestNotFound=Permintaan otorisasi tidak ditemukan login.oauth2RequestNotFound=Permintaan otorisasi tidak ditemukan
login.oauth2InvalidUserInfoResponse=Respons Info Pengguna Tidak Valid login.oauth2InvalidUserInfoResponse=Respons Info Pengguna Tidak Valid
login.oauth2invalidRequest=Permintaan Tidak Valid login.oauth2invalidRequest=Permintaan Tidak Valid

View File

@ -572,8 +572,8 @@ login.invalid=Nome utente o password errati.
login.locked=Il tuo account è stato bloccato. login.locked=Il tuo account è stato bloccato.
login.signinTitle=Per favore accedi login.signinTitle=Per favore accedi
login.ssoSignIn=Accedi tramite Single Sign-on login.ssoSignIn=Accedi tramite Single Sign-on
login.oauth2AutoCreateDisabled=Creazione automatica utente OAUTH2 DISABILITATA login.oAuth2AutoCreateDisabled=Creazione automatica utente OAUTH2 DISABILITATA
login.oauth2AdminBlockedUser=La registrazione o l'accesso degli utenti non registrati è attualmente bloccata. Si prega di contattare l'amministratore. login.oAuth2AdminBlockedUser=La registrazione o l'accesso degli utenti non registrati è attualmente bloccata. Si prega di contattare l'amministratore.
login.oauth2RequestNotFound=Richiesta di autorizzazione non trovata login.oauth2RequestNotFound=Richiesta di autorizzazione non trovata
login.oauth2InvalidUserInfoResponse=Risposta relativa alle informazioni utente non valida login.oauth2InvalidUserInfoResponse=Risposta relativa alle informazioni utente non valida
login.oauth2invalidRequest=Richiesta non valida login.oauth2invalidRequest=Richiesta non valida

View File

@ -572,8 +572,8 @@ login.invalid=ユーザー名かパスワードが無効です。
login.locked=あなたのアカウントはロックされています。 login.locked=あなたのアカウントはロックされています。
login.signinTitle=サインインしてください login.signinTitle=サインインしてください
login.ssoSignIn=シングルサインオンでログイン login.ssoSignIn=シングルサインオンでログイン
login.oauth2AutoCreateDisabled=OAuth 2自動作成ユーザーが無効 login.oAuth2AutoCreateDisabled=OAuth 2自動作成ユーザーが無効
login.oauth2AdminBlockedUser=現在、未登録ユーザーの登録またはログインはブロックされています。管理者にお問い合わせください。 login.oAuth2AdminBlockedUser=現在、未登録ユーザーの登録またはログインはブロックされています。管理者にお問い合わせください。
login.oauth2RequestNotFound=認証リクエストが見つかりません login.oauth2RequestNotFound=認証リクエストが見つかりません
login.oauth2InvalidUserInfoResponse=無効なユーザー情報の応答 login.oauth2InvalidUserInfoResponse=無効なユーザー情報の応答
login.oauth2invalidRequest=無効なリクエスト login.oauth2invalidRequest=無効なリクエスト

View File

@ -572,8 +572,8 @@ login.invalid=사용자 이름 또는 비밀번호가 잘못되었습니다.
login.locked=계정이 잠겼습니다. login.locked=계정이 잠겼습니다.
login.signinTitle=로그인해 주세요 login.signinTitle=로그인해 주세요
login.ssoSignIn=단일 로그인으로 로그인 login.ssoSignIn=단일 로그인으로 로그인
login.oauth2AutoCreateDisabled=OAuth2 사용자 자동 생성이 비활성화되었습니다 login.oAuth2AutoCreateDisabled=OAuth2 사용자 자동 생성이 비활성화되었습니다
login.oauth2AdminBlockedUser=현재 미등록 사용자의 등록 또는 로그인이 차단되어 있습니다. 관리자에게 문의하세요. login.oAuth2AdminBlockedUser=현재 미등록 사용자의 등록 또는 로그인이 차단되어 있습니다. 관리자에게 문의하세요.
login.oauth2RequestNotFound=인증 요청을 찾을 수 없습니다 login.oauth2RequestNotFound=인증 요청을 찾을 수 없습니다
login.oauth2InvalidUserInfoResponse=잘못된 사용자 정보 응답 login.oauth2InvalidUserInfoResponse=잘못된 사용자 정보 응답
login.oauth2invalidRequest=잘못된 요청 login.oauth2invalidRequest=잘못된 요청

View File

@ -572,8 +572,8 @@ login.invalid=Ongeldige gebruikersnaam of wachtwoord.
login.locked=Je account is geblokkeerd. login.locked=Je account is geblokkeerd.
login.signinTitle=Gelieve in te loggen login.signinTitle=Gelieve in te loggen
login.ssoSignIn=Inloggen via Single Sign-on login.ssoSignIn=Inloggen via Single Sign-on
login.oauth2AutoCreateDisabled=OAUTH2 Automatisch aanmaken gebruiker uitgeschakeld login.oAuth2AutoCreateDisabled=OAUTH2 Automatisch aanmaken gebruiker uitgeschakeld
login.oauth2AdminBlockedUser=Registratie of inloggen van niet-registreerde gebruikers is helaas momenteel geblokkeerd. Neem contact op met de beheerder. login.oAuth2AdminBlockedUser=Registratie of inloggen van niet-registreerde gebruikers is helaas momenteel geblokkeerd. Neem contact op met de beheerder.
login.oauth2RequestNotFound=Autorisatieverzoek niet gevonden login.oauth2RequestNotFound=Autorisatieverzoek niet gevonden
login.oauth2InvalidUserInfoResponse=Ongeldige reactie op gebruikersinfo login.oauth2InvalidUserInfoResponse=Ongeldige reactie op gebruikersinfo
login.oauth2invalidRequest=Ongeldig verzoek login.oauth2invalidRequest=Ongeldig verzoek

View File

@ -572,8 +572,8 @@ login.invalid=Ugyldig brukernavn eller passord.
login.locked=Kontoen din har blitt låst. login.locked=Kontoen din har blitt låst.
login.signinTitle=Vennligst logg inn login.signinTitle=Vennligst logg inn
login.ssoSignIn=Logg inn via Enkel Pålogging login.ssoSignIn=Logg inn via Enkel Pålogging
login.oauth2AutoCreateDisabled=OAUTH2 Auto-Opretting av bruker deaktivert login.oAuth2AutoCreateDisabled=OAUTH2 Auto-Opretting av bruker deaktivert
login.oauth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator. login.oAuth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator.
login.oauth2RequestNotFound=Autentiseringsforespørsel ikke funnet login.oauth2RequestNotFound=Autentiseringsforespørsel ikke funnet
login.oauth2InvalidUserInfoResponse=Ugyldig brukerinforespons login.oauth2InvalidUserInfoResponse=Ugyldig brukerinforespons
login.oauth2invalidRequest=Ugyldig forespørsel login.oauth2invalidRequest=Ugyldig forespørsel

View File

@ -572,8 +572,8 @@ login.invalid=Nieprawidłowe dane logowania
login.locked=Konto jest zablokowane login.locked=Konto jest zablokowane
login.signinTitle=Zaloguj się login.signinTitle=Zaloguj się
login.ssoSignIn=Zaloguj się za pomocą logowania jednokrotnego login.ssoSignIn=Zaloguj się za pomocą logowania jednokrotnego
login.oauth2AutoCreateDisabled=Wyłączono automatyczne tworzenie użytkownika OAUTH2 login.oAuth2AutoCreateDisabled=Wyłączono automatyczne tworzenie użytkownika OAUTH2
login.oauth2AdminBlockedUser=Rejestracja lub logowanie niezarejestrowanych użytkowników jest obecnie zablokowane. Prosimy o kontakt z administratorem. login.oAuth2AdminBlockedUser=Rejestracja lub logowanie niezarejestrowanych użytkowników jest obecnie zablokowane. Prosimy o kontakt z administratorem.
login.oauth2RequestNotFound=Błąd logowania OAuth2 login.oauth2RequestNotFound=Błąd logowania OAuth2
login.oauth2InvalidUserInfoResponse=Niewłaściwe dane logowania login.oauth2InvalidUserInfoResponse=Niewłaściwe dane logowania
login.oauth2invalidRequest=Nieprawidłowe żądanie login.oauth2invalidRequest=Nieprawidłowe żądanie

View File

@ -572,8 +572,8 @@ login.invalid=Usuário ou senha inválidos.
login.locked=Sua conta foi bloqueada. login.locked=Sua conta foi bloqueada.
login.signinTitle=Por favor, inicie a sessão login.signinTitle=Por favor, inicie a sessão
login.ssoSignIn=Iniciar sessão através de login único (SSO) login.ssoSignIn=Iniciar sessão através de login único (SSO)
login.oauth2AutoCreateDisabled=Auto-Criar Usuário OAUTH2 Desativado login.oAuth2AutoCreateDisabled=Auto-Criar Usuário OAUTH2 Desativado
login.oauth2AdminBlockedUser=O registro ou login de usuários não registrados está atualmente bloqueado. Entre em contato com o administrador. login.oAuth2AdminBlockedUser=O registro ou login de usuários não registrados está atualmente bloqueado. Entre em contato com o administrador.
login.oauth2RequestNotFound=Solicitação de autorização não encontrada login.oauth2RequestNotFound=Solicitação de autorização não encontrada
login.oauth2InvalidUserInfoResponse=Resposta de informação de usuário inválida login.oauth2InvalidUserInfoResponse=Resposta de informação de usuário inválida
login.oauth2invalidRequest=Requisição Inválida login.oauth2invalidRequest=Requisição Inválida

View File

@ -572,8 +572,8 @@ login.invalid=Nome de utilizador ou palavra-passe inválidos.
login.locked=A sua conta foi bloqueada. login.locked=A sua conta foi bloqueada.
login.signinTitle=Por favor inicie sessão login.signinTitle=Por favor inicie sessão
login.ssoSignIn=Login via Single Sign-on login.ssoSignIn=Login via Single Sign-on
login.oauth2AutoCreateDisabled=Criação Automática de Utilizador OAUTH2 Desativada login.oAuth2AutoCreateDisabled=Criação Automática de Utilizador OAUTH2 Desativada
login.oauth2AdminBlockedUser=O registo ou login de utilizadores não registados está atualmente bloqueado. Por favor contacte o administrador. login.oAuth2AdminBlockedUser=O registo ou login de utilizadores não registados está atualmente bloqueado. Por favor contacte o administrador.
login.oauth2RequestNotFound=Pedido de autorização não encontrado login.oauth2RequestNotFound=Pedido de autorização não encontrado
login.oauth2InvalidUserInfoResponse=Resposta de Informação de Utilizador Inválida login.oauth2InvalidUserInfoResponse=Resposta de Informação de Utilizador Inválida
login.oauth2invalidRequest=Pedido Inválido login.oauth2invalidRequest=Pedido Inválido

View File

@ -572,8 +572,8 @@ login.invalid=Nume de utilizator sau parolă invalidă.
login.locked=Contul tău a fost blocat. login.locked=Contul tău a fost blocat.
login.signinTitle=Te rugăm să te autentifici login.signinTitle=Te rugăm să te autentifici
login.ssoSignIn=Conectare prin conectare unică login.ssoSignIn=Conectare prin conectare unică
login.oauth2AutoCreateDisabled=OAUTH2 Creare automată utilizator dezactivată login.oAuth2AutoCreateDisabled=OAUTH2 Creare automată utilizator dezactivată
login.oauth2AdminBlockedUser=Înregistrarea sau conectarea utilizatorilor neînregistrați este în prezent blocată. Te rugăm să contactezi administratorul. login.oAuth2AdminBlockedUser=Înregistrarea sau conectarea utilizatorilor neînregistrați este în prezent blocată. Te rugăm să contactezi administratorul.
login.oauth2RequestNotFound=Cererea de autorizare nu a fost găsită login.oauth2RequestNotFound=Cererea de autorizare nu a fost găsită
login.oauth2InvalidUserInfoResponse=Răspuns Invalid la Informațiile Utilizatorului login.oauth2InvalidUserInfoResponse=Răspuns Invalid la Informațiile Utilizatorului
login.oauth2invalidRequest=Cerere Invalidă login.oauth2invalidRequest=Cerere Invalidă

View File

@ -572,8 +572,8 @@ login.invalid=Неверное имя пользователя или парол
login.locked=Ваша учетная запись заблокирована. login.locked=Ваша учетная запись заблокирована.
login.signinTitle=Пожалуйста, войдите login.signinTitle=Пожалуйста, войдите
login.ssoSignIn=Вход через единый вход login.ssoSignIn=Вход через единый вход
login.oauth2AutoCreateDisabled=Автоматическое создание пользователей OAuth2 отключено login.oAuth2AutoCreateDisabled=Автоматическое создание пользователей OAuth2 отключено
login.oauth2AdminBlockedUser=Регистрация или вход незарегистрированных пользователей в настоящее время заблокированы. Обратитесь к администратору. login.oAuth2AdminBlockedUser=Регистрация или вход незарегистрированных пользователей в настоящее время заблокированы. Обратитесь к администратору.
login.oauth2RequestNotFound=Запрос авторизации не найден login.oauth2RequestNotFound=Запрос авторизации не найден
login.oauth2InvalidUserInfoResponse=Недействительный ответ с информацией о пользователе login.oauth2InvalidUserInfoResponse=Недействительный ответ с информацией о пользователе
login.oauth2invalidRequest=Недействительный запрос login.oauth2invalidRequest=Недействительный запрос

View File

@ -572,8 +572,8 @@ login.invalid=Neplatné používateľské meno alebo heslo.
login.locked=Váš účet bol uzamknutý. login.locked=Váš účet bol uzamknutý.
login.signinTitle=Prosím, prihláste sa login.signinTitle=Prosím, prihláste sa
login.ssoSignIn=Prihlásiť sa cez Single Sign-on login.ssoSignIn=Prihlásiť sa cez Single Sign-on
login.oauth2AutoCreateDisabled=Vytváranie používateľa cez OAUTH2 je zakázané login.oAuth2AutoCreateDisabled=Vytváranie používateľa cez OAUTH2 je zakázané
login.oauth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator. login.oAuth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator.
login.oauth2RequestNotFound=Authorization request not found login.oauth2RequestNotFound=Authorization request not found
login.oauth2InvalidUserInfoResponse=Invalid User Info Response login.oauth2InvalidUserInfoResponse=Invalid User Info Response
login.oauth2invalidRequest=Invalid Request login.oauth2invalidRequest=Invalid Request

View File

@ -572,8 +572,8 @@ login.invalid=Neveljavno uporabniško ime ali geslo.
login.locked=Vaš račun je bil zaklenjen. login.locked=Vaš račun je bil zaklenjen.
login.signinTitle=Prosim prijavite se login.signinTitle=Prosim prijavite se
login.ssoSignIn=Prijava prek enotne prijave login.ssoSignIn=Prijava prek enotne prijave
login.oauth2AutoCreateDisabled=OAUTH2 Samodejno ustvarjanje uporabnika onemogočeno login.oAuth2AutoCreateDisabled=OAUTH2 Samodejno ustvarjanje uporabnika onemogočeno
login.oauth2AdminBlockedUser=Registracija ali prijava neregistriranih uporabnikov je trenutno blokirana. Prosimo kontaktirajte skrbnika. login.oAuth2AdminBlockedUser=Registracija ali prijava neregistriranih uporabnikov je trenutno blokirana. Prosimo kontaktirajte skrbnika.
login.oauth2RequestNotFound=Zahteva za avtorizacijo ni bila najdena login.oauth2RequestNotFound=Zahteva za avtorizacijo ni bila najdena
login.oauth2InvalidUserInfoResponse=Neveljaven odgovor z informacijami o uporabniku login.oauth2InvalidUserInfoResponse=Neveljaven odgovor z informacijami o uporabniku
login.oauth2invalidRequest=Neveljavna zahteva login.oauth2invalidRequest=Neveljavna zahteva

View File

@ -572,8 +572,8 @@ login.invalid=Neispravno korisničko ime ili lozinka.
login.locked=Vaš nalog je zaključan. login.locked=Vaš nalog je zaključan.
login.signinTitle=Molimo vas da se prijavite login.signinTitle=Molimo vas da se prijavite
login.ssoSignIn=Prijavite se putem jedinstvene prijave login.ssoSignIn=Prijavite se putem jedinstvene prijave
login.oauth2AutoCreateDisabled=OAUTH2 automatsko kreiranje korisnika je onemogućeno login.oAuth2AutoCreateDisabled=OAUTH2 automatsko kreiranje korisnika je onemogućeno
login.oauth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator. login.oAuth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator.
login.oauth2RequestNotFound=Authorization request not found login.oauth2RequestNotFound=Authorization request not found
login.oauth2InvalidUserInfoResponse=Invalid User Info Response login.oauth2InvalidUserInfoResponse=Invalid User Info Response
login.oauth2invalidRequest=Invalid Request login.oauth2invalidRequest=Invalid Request

View File

@ -572,8 +572,8 @@ login.invalid=Ogiltigt användarnamn eller lösenord.
login.locked=Ditt konto har låsts. login.locked=Ditt konto har låsts.
login.signinTitle=Vänligen logga in login.signinTitle=Vänligen logga in
login.ssoSignIn=Logga in via enkel inloggning login.ssoSignIn=Logga in via enkel inloggning
login.oauth2AutoCreateDisabled=OAUTH2 Auto-skapa användare inaktiverad login.oAuth2AutoCreateDisabled=OAUTH2 Auto-skapa användare inaktiverad
login.oauth2AdminBlockedUser=Registrering eller inloggning av icke-registrerade användare är för närvarande blockerad. Kontakta administratören. login.oAuth2AdminBlockedUser=Registrering eller inloggning av icke-registrerade användare är för närvarande blockerad. Kontakta administratören.
login.oauth2RequestNotFound=Auktoriseringsbegäran hittades inte login.oauth2RequestNotFound=Auktoriseringsbegäran hittades inte
login.oauth2InvalidUserInfoResponse=Ogiltigt svar på användarinformation login.oauth2InvalidUserInfoResponse=Ogiltigt svar på användarinformation
login.oauth2invalidRequest=Ogiltig begäran login.oauth2invalidRequest=Ogiltig begäran

View File

@ -572,8 +572,8 @@ login.invalid=ชื่อผู้ใช้หรือรหัสผ่าน
login.locked=บัญชีของคุณถูกล็อค login.locked=บัญชีของคุณถูกล็อค
login.signinTitle=กรุณาลงชื่อเข้าใช้ login.signinTitle=กรุณาลงชื่อเข้าใช้
login.ssoSignIn=เข้าสู่ระบบด้วย Single Sign-on login.ssoSignIn=เข้าสู่ระบบด้วย Single Sign-on
login.oauth2AutoCreateDisabled=การสร้างผู้ใช้ OAuth2 อัตโนมัติถูกปิดใช้งาน login.oAuth2AutoCreateDisabled=การสร้างผู้ใช้ OAuth2 อัตโนมัติถูกปิดใช้งาน
login.oauth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator. login.oAuth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator.
login.oauth2RequestNotFound=ไม่พบคำขอการอนุญาต login.oauth2RequestNotFound=ไม่พบคำขอการอนุญาต
login.oauth2InvalidUserInfoResponse=การตอบกลับข้อมูลผู้ใช้ไม่ถูกต้อง login.oauth2InvalidUserInfoResponse=การตอบกลับข้อมูลผู้ใช้ไม่ถูกต้อง
login.oauth2invalidRequest=คำขอไม่ถูกต้อง login.oauth2invalidRequest=คำขอไม่ถูกต้อง

View File

@ -572,8 +572,8 @@ login.invalid=Geçersiz kullanıcı adı veya şifre.
login.locked=Hesabınız kilitlendi. login.locked=Hesabınız kilitlendi.
login.signinTitle=Lütfen giriş yapınız. login.signinTitle=Lütfen giriş yapınız.
login.ssoSignIn=Tek Oturum Açma ile Giriş Yap login.ssoSignIn=Tek Oturum Açma ile Giriş Yap
login.oauth2AutoCreateDisabled=OAUTH2 Otomatik Oluşturma Kullanıcı Devre Dışı Bırakıldı login.oAuth2AutoCreateDisabled=OAUTH2 Otomatik Oluşturma Kullanıcı Devre Dışı Bırakıldı
login.oauth2AdminBlockedUser=Kayıtlı olmayan kullanıcıların kayıt veya giriş yapması şu anda engellenmiştir. Lütfen yöneticiyle iletişime geçin. login.oAuth2AdminBlockedUser=Kayıtlı olmayan kullanıcıların kayıt veya giriş yapması şu anda engellenmiştir. Lütfen yöneticiyle iletişime geçin.
login.oauth2RequestNotFound=Yetkilendirme isteği bulunamadı login.oauth2RequestNotFound=Yetkilendirme isteği bulunamadı
login.oauth2InvalidUserInfoResponse=Geçersiz Kullanıcı Bilgisi Yanıtı login.oauth2InvalidUserInfoResponse=Geçersiz Kullanıcı Bilgisi Yanıtı
login.oauth2invalidRequest=Geçersiz İstek login.oauth2invalidRequest=Geçersiz İstek

View File

@ -572,8 +572,8 @@ login.invalid=Недійсне ім'я користувача або парол
login.locked=Ваш обліковий запис заблоковано. login.locked=Ваш обліковий запис заблоковано.
login.signinTitle=Будь ласка, увійдіть login.signinTitle=Будь ласка, увійдіть
login.ssoSignIn=Увійти через єдиний вхід login.ssoSignIn=Увійти через єдиний вхід
login.oauth2AutoCreateDisabled=Автоматичне створення користувача OAUTH2 ВИМКНЕНО login.oAuth2AutoCreateDisabled=Автоматичне створення користувача OAUTH2 ВИМКНЕНО
login.oauth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator. login.oAuth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator.
login.oauth2RequestNotFound=Запит на авторизація не знайдено login.oauth2RequestNotFound=Запит на авторизація не знайдено
login.oauth2InvalidUserInfoResponse=Недійсна відповідь з інформацією користувача login.oauth2InvalidUserInfoResponse=Недійсна відповідь з інформацією користувача
login.oauth2invalidRequest=Недійсний запит login.oauth2invalidRequest=Недійсний запит

View File

@ -572,8 +572,8 @@ login.invalid=Tên đăng nhập hoặc mật khẩu không hợp lệ.
login.locked=Tài khoản của bạn đã bị khóa. login.locked=Tài khoản của bạn đã bị khóa.
login.signinTitle=Vui lòng đăng nhập login.signinTitle=Vui lòng đăng nhập
login.ssoSignIn=Đăng nhập qua Single Sign-on login.ssoSignIn=Đăng nhập qua Single Sign-on
login.oauth2AutoCreateDisabled=Tự động tạo người dùng OAUTH2 bị vô hiệu hóa login.oAuth2AutoCreateDisabled=Tự động tạo người dùng OAUTH2 bị vô hiệu hóa
login.oauth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator. login.oAuth2AdminBlockedUser=Registration or logging in of non-registered users is currently blocked. Please contact the administrator.
login.oauth2RequestNotFound=Không tìm thấy yêu cầu ủy quyền login.oauth2RequestNotFound=Không tìm thấy yêu cầu ủy quyền
login.oauth2InvalidUserInfoResponse=Phản hồi thông tin người dùng không hợp lệ login.oauth2InvalidUserInfoResponse=Phản hồi thông tin người dùng không hợp lệ
login.oauth2invalidRequest=Yêu cầu không hợp lệ login.oauth2invalidRequest=Yêu cầu không hợp lệ

View File

@ -572,8 +572,8 @@ login.invalid=སྤྱོད་མིང་ངམ་གསང་ཚིག་ན
login.locked=ཁྱེད་ཀྱི་ཐོ་མཛོད་ཟྭ་རྒྱག་བརྒྱབ་ཟིན། login.locked=ཁྱེད་ཀྱི་ཐོ་མཛོད་ཟྭ་རྒྱག་བརྒྱབ་ཟིན།
login.signinTitle=ནང་འཛུལ་གནང་རོགས། login.signinTitle=ནང་འཛུལ་གནང་རོགས།
login.ssoSignIn=གཅིག་གྱུར་ནང་འཛུལ་བརྒྱུད་ནས་ནང་འཛུལ། login.ssoSignIn=གཅིག་གྱུར་ནང་འཛུལ་བརྒྱུད་ནས་ནང་འཛུལ།
login.oauth2AutoCreateDisabled=OAUTH2 རང་འགུལ་སྤྱོད་མཁན་གསར་བཟོ་བཀག་སྡོམ་བྱས་ཟིན། login.oAuth2AutoCreateDisabled=OAUTH2 རང་འགུལ་སྤྱོད་མཁན་གསར་བཟོ་བཀག་སྡོམ་བྱས་ཟིན།
login.oauth2AdminBlockedUser=ད་ལྟ་ཐོ་འགོད་མ་བྱས་པའི་སྤྱོད་མཁན་གྱི་ཐོ་འགོད་དང་ནང་འཛུལ་བཀག་སྡོམ་བྱས་ཡོད། དོ་དམ་པར་འབྲེལ་བ་གནང་རོགས། login.oAuth2AdminBlockedUser=ད་ལྟ་ཐོ་འགོད་མ་བྱས་པའི་སྤྱོད་མཁན་གྱི་ཐོ་འགོད་དང་ནང་འཛུལ་བཀག་སྡོམ་བྱས་ཡོད། དོ་དམ་པར་འབྲེལ་བ་གནང་རོགས།
login.oauth2RequestNotFound=དབང་སྤྲོད་རེ་ཞུ་རྙེད་མ་བྱུང་། login.oauth2RequestNotFound=དབང་སྤྲོད་རེ་ཞུ་རྙེད་མ་བྱུང་།
login.oauth2InvalidUserInfoResponse=སྤྱོད་མཁན་གྱི་གནས་ཚུལ་ལན་འདེབས་ནོར་འཁྲུལ། login.oauth2InvalidUserInfoResponse=སྤྱོད་མཁན་གྱི་གནས་ཚུལ་ལན་འདེབས་ནོར་འཁྲུལ།
login.oauth2invalidRequest=རེ་ཞུ་ནོར་འཁྲུལ། login.oauth2invalidRequest=རེ་ཞུ་ནོར་འཁྲུལ།

View File

@ -572,8 +572,8 @@ login.invalid=用户名或密码无效。
login.locked=您的账户已被锁定。 login.locked=您的账户已被锁定。
login.signinTitle=请登录 login.signinTitle=请登录
login.ssoSignIn=通过单点登录登录 login.ssoSignIn=通过单点登录登录
login.oauth2AutoCreateDisabled=OAuth2 自动创建用户已禁用 login.oAuth2AutoCreateDisabled=OAuth2 自动创建用户已禁用
login.oauth2AdminBlockedUser=目前已阻止未注册用户的注册或登录。请联系管理员。 login.oAuth2AdminBlockedUser=目前已阻止未注册用户的注册或登录。请联系管理员。
login.oauth2RequestNotFound=找不到验证请求 login.oauth2RequestNotFound=找不到验证请求
login.oauth2InvalidUserInfoResponse=无效的用户信息响应 login.oauth2InvalidUserInfoResponse=无效的用户信息响应
login.oauth2invalidRequest=无效请求 login.oauth2invalidRequest=无效请求

View File

@ -572,8 +572,8 @@ login.invalid=使用者名稱或密碼無效。
login.locked=您的帳號已被鎖定。 login.locked=您的帳號已被鎖定。
login.signinTitle=請登入 login.signinTitle=請登入
login.ssoSignIn=透過 SSO 單一登入 login.ssoSignIn=透過 SSO 單一登入
login.oauth2AutoCreateDisabled=OAuth 2.0 自動建立使用者功能已停用 login.oAuth2AutoCreateDisabled=OAuth 2.0 自動建立使用者功能已停用
login.oauth2AdminBlockedUser=目前不允許未註冊的使用者註冊或登入。請聯絡系統管理員。 login.oAuth2AdminBlockedUser=目前不允許未註冊的使用者註冊或登入。請聯絡系統管理員。
login.oauth2RequestNotFound=找不到驗證請求 login.oauth2RequestNotFound=找不到驗證請求
login.oauth2InvalidUserInfoResponse=使用者資訊回應無效 login.oauth2InvalidUserInfoResponse=使用者資訊回應無效
login.oauth2invalidRequest=請求無效 login.oauth2invalidRequest=請求無效

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 &&
@ -104,8 +104,8 @@
<br> <br>
<hr /> <hr />
</div> </div>
<div th:if="${erroroauth}" class="alert alert-danger text-center"> <div th:if="${errorOAuth}" class="alert alert-danger text-center">
<div th:if="${erroroauth}" th:text="#{${erroroauth}}">OAuth2: Error Message</div> <div th:if="${errorOAuth}" th:text="#{${errorOAuth}}">OAuth2: Error Message</div>
</div> </div>
<div th:if="${error}" class="alert alert-danger text-center"> <div th:if="${error}" class="alert alert-danger text-center">
@ -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>

View File

@ -0,0 +1,266 @@
package stirling.software.SPDF.config.security;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import stirling.software.SPDF.model.ApplicationProperties;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class CustomLogoutSuccessHandlerTest {
@Mock
private ApplicationProperties applicationProperties;
@InjectMocks
private CustomLogoutSuccessHandler customLogoutSuccessHandler;
@Test
void testSuccessfulLogout() throws IOException {
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
String logoutPath = "/login?logout=true";
when(response.isCommitted()).thenReturn(false);
when(request.getContextPath()).thenReturn("");
when(response.encodeRedirectURL(logoutPath)).thenReturn(logoutPath);
customLogoutSuccessHandler.onLogoutSuccess(request, response, null);
verify(response).sendRedirect(logoutPath);
}
@Test
void testSuccessfulLogoutViaOAuth2() throws IOException {
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
OAuth2AuthenticationToken oAuth2AuthenticationToken = mock(OAuth2AuthenticationToken.class);
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
when(response.isCommitted()).thenReturn(false);
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
when(request.getParameter("errorOAuth")).thenReturn(null);
when(request.getScheme()).thenReturn("http");
when(request.getServerName()).thenReturn("localhost");
when(request.getServerPort()).thenReturn(8080);
when(request.getContextPath()).thenReturn("");
when(applicationProperties.getSecurity()).thenReturn(security);
when(security.getOauth2()).thenReturn(oauth);
when(oAuth2AuthenticationToken.getAuthorizedClientRegistrationId()).thenReturn("test");
customLogoutSuccessHandler.onLogoutSuccess(request, response, oAuth2AuthenticationToken);
verify(response).sendRedirect("http://localhost:8080/login?logout=true");
}
@Test
void testUserIsDisabledRedirect() throws IOException {
String error = "userIsDisabled";
String url = "http://localhost:8080";
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
when(response.isCommitted()).thenReturn(false);
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
when(request.getParameter("errorOAuth")).thenReturn(null);
when(request.getParameter("oAuth2AutoCreateDisabled")).thenReturn(null);
when(request.getParameter("oAuth2AdminBlockedUser")).thenReturn(null);
when(request.getParameter(error)).thenReturn("true");
when(request.getScheme()).thenReturn("http");
when(request.getServerName()).thenReturn("localhost");
when(request.getServerPort()).thenReturn(8080);
when(request.getContextPath()).thenReturn("");
when(applicationProperties.getSecurity()).thenReturn(security);
when(security.getOauth2()).thenReturn(oauth);
when(authentication.getAuthorizedClientRegistrationId()).thenReturn("test");
customLogoutSuccessHandler.onLogoutSuccess(request, response, authentication);
verify(response).sendRedirect(url + "/login?errorOAuth=" + error);
}
@Test
void testUserAlreadyExistsWebRedirect() throws IOException {
String error = "oAuth2AuthenticationErrorWeb";
String errorPath = "userAlreadyExistsWeb";
String url = "http://localhost:8080";
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
when(response.isCommitted()).thenReturn(false);
when(request.getParameter(error)).thenReturn("true");
when(request.getScheme()).thenReturn("http");
when(request.getServerName()).thenReturn("localhost");
when(request.getServerPort()).thenReturn(8080);
when(request.getContextPath()).thenReturn("");
when(applicationProperties.getSecurity()).thenReturn(security);
when(security.getOauth2()).thenReturn(oauth);
when(authentication.getAuthorizedClientRegistrationId()).thenReturn("test");
customLogoutSuccessHandler.onLogoutSuccess(request, response, authentication);
verify(response).sendRedirect(url + "/login?errorOAuth=" + errorPath);
}
@Test
void testErrorOAuthRedirect() throws IOException {
String error = "testError";
String url = "http://localhost:8080";
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
when(response.isCommitted()).thenReturn(false);
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
when(request.getParameter("errorOAuth")).thenReturn("!!!" + error + "!!!");
when(request.getScheme()).thenReturn("http");
when(request.getServerName()).thenReturn("localhost");
when(request.getServerPort()).thenReturn(8080);
when(request.getContextPath()).thenReturn("");
when(applicationProperties.getSecurity()).thenReturn(security);
when(security.getOauth2()).thenReturn(oauth);
when(authentication.getAuthorizedClientRegistrationId()).thenReturn("test");
customLogoutSuccessHandler.onLogoutSuccess(request, response, authentication);
verify(response).sendRedirect(url + "/login?errorOAuth=" + error);
}
@Test
void testOAuth2AutoCreateDisabled() throws IOException {
String error = "oAuth2AutoCreateDisabled";
String url = "http://localhost:8080";
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
when(response.isCommitted()).thenReturn(false);
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
when(request.getParameter("errorOAuth")).thenReturn(null);
when(request.getParameter(error)).thenReturn("true");
when(request.getContextPath()).thenReturn(url);
when(request.getScheme()).thenReturn("http");
when(request.getServerName()).thenReturn("localhost");
when(request.getServerPort()).thenReturn(8080);
when(request.getContextPath()).thenReturn("");
when(applicationProperties.getSecurity()).thenReturn(security);
when(security.getOauth2()).thenReturn(oauth);
when(authentication.getAuthorizedClientRegistrationId()).thenReturn("test");
customLogoutSuccessHandler.onLogoutSuccess(request, response, authentication);
verify(response).sendRedirect(url + "/login?errorOAuth=" + error);
}
@Test
void testOAuth2Error() throws IOException {
String error = "test";
String url = "http://localhost:8080";
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
when(response.isCommitted()).thenReturn(false);
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
when(request.getParameter("errorOAuth")).thenReturn(null);
when(request.getParameter("oAuth2AutoCreateDisabled")).thenReturn(null);
when(request.getParameter("oAuth2AdminBlockedUser")).thenReturn(null);
when(request.getParameter("userIsDisabled")).thenReturn(null);
when(request.getParameter("error")).thenReturn("!@$!@£" + error + "£$%^*$");
when(request.getScheme()).thenReturn("http");
when(request.getServerName()).thenReturn("localhost");
when(request.getServerPort()).thenReturn(8080);
when(request.getContextPath()).thenReturn("");
when(applicationProperties.getSecurity()).thenReturn(security);
when(security.getOauth2()).thenReturn(oauth);
when(authentication.getAuthorizedClientRegistrationId()).thenReturn("test");
customLogoutSuccessHandler.onLogoutSuccess(request, response, authentication);
verify(response).sendRedirect(url + "/login?errorOAuth=" + error);
}
@Test
void testOAuth2BadCredentialsError() throws IOException {
String error = "badCredentials";
String url = "http://localhost:8080";
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
when(response.isCommitted()).thenReturn(false);
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
when(request.getParameter("errorOAuth")).thenReturn(null);
when(request.getParameter("oAuth2AutoCreateDisabled")).thenReturn(null);
when(request.getParameter("oAuth2AdminBlockedUser")).thenReturn(null);
when(request.getParameter("userIsDisabled")).thenReturn(null);
when(request.getParameter("error")).thenReturn(null);
when(request.getParameter(error)).thenReturn("true");
when(request.getScheme()).thenReturn("http");
when(request.getServerName()).thenReturn("localhost");
when(request.getServerPort()).thenReturn(8080);
when(request.getContextPath()).thenReturn("");
when(applicationProperties.getSecurity()).thenReturn(security);
when(security.getOauth2()).thenReturn(oauth);
when(authentication.getAuthorizedClientRegistrationId()).thenReturn("test");
customLogoutSuccessHandler.onLogoutSuccess(request, response, authentication);
verify(response).sendRedirect(url + "/login?errorOAuth=" + error);
}
@Test
void testOAuth2AdminBlockedUser() throws IOException {
String error = "oAuth2AdminBlockedUser";
String url = "http://localhost:8080";
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
OAuth2AuthenticationToken authentication = mock(OAuth2AuthenticationToken.class);
ApplicationProperties.Security security = mock(ApplicationProperties.Security.class);
ApplicationProperties.Security.OAUTH2 oauth = mock(ApplicationProperties.Security.OAUTH2.class);
when(response.isCommitted()).thenReturn(false);
when(request.getParameter("oAuth2AuthenticationErrorWeb")).thenReturn(null);
when(request.getParameter("errorOAuth")).thenReturn(null);
when(request.getParameter("oAuth2AutoCreateDisabled")).thenReturn(null);
when(request.getParameter(error)).thenReturn("true");
when(request.getScheme()).thenReturn("http");
when(request.getServerName()).thenReturn("localhost");
when(request.getServerPort()).thenReturn(8080);
when(request.getContextPath()).thenReturn("");
when(applicationProperties.getSecurity()).thenReturn(security);
when(security.getOauth2()).thenReturn(oauth);
when(authentication.getAuthorizedClientRegistrationId()).thenReturn("test");
customLogoutSuccessHandler.onLogoutSuccess(request, response, authentication);
verify(response).sendRedirect(url + "/login?errorOAuth=" + error);
}
}

View File

@ -0,0 +1,58 @@
package stirling.software.SPDF.utils.validation;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.junit.jupiter.MockitoExtension;
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;
import java.util.List;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class ValidatorTest {
@Test
void testSuccessfulValidation() {
var provider = mock(GitHubProvider.class);
when(provider.getClientId()).thenReturn("clientId");
when(provider.getClientSecret()).thenReturn("clientSecret");
when(provider.getScopes()).thenReturn(List.of("read:user"));
when(provider.getUseAsUsername()).thenReturn("email");
assertTrue(Validator.validateProvider(provider));
}
@ParameterizedTest
@MethodSource("providerParams")
void testUnsuccessfulValidation(Provider provider) {
assertFalse(Validator.validateProvider(provider));
}
public static Stream<Arguments> providerParams() {
Provider generic = null;
var google = new GoogleProvider(null, "clientSecret", List.of("scope"), "email");
var github = new GitHubProvider("clientId", "", List.of("scope"), "login");
var keycloak = new KeycloakProvider("issuer", "clientId", "clientSecret", List.of("scope"), "email");
keycloak.setUseAsUsername(null);
return Stream.of(
Arguments.of(generic),
Arguments.of(google),
Arguments.of(github),
Arguments.of(keycloak)
);
}
}