You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by ma...@apache.org on 2026/06/15 12:19:32 UTC
(syncope) branch 4_1_X updated (9c4d8609fd -> aa96a05a94)
This is an automated email from the ASF dual-hosted git repository.
massx1 pushed a change to branch 4_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git
from 9c4d8609fd Fixing Neo4j
new 7f71ad7857 Avoid authentication error detail disclosure
new 537c607d4e Make authentication error detail disclosure configurable
new 076bb6dc70 [SYNCOPE-1973] Align FIT expectations with generic authentication errors
new aa96a05a94 [SYNCOPE-1973] Document authentication error detail properties
The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../core/spring/security/SecurityProperties.java | 31 ++++++++
.../SyncopeBasicAuthenticationEntryPoint.java | 15 +++-
.../core/spring/security/WebSecurityContext.java | 5 +-
.../SyncopeBasicAuthenticationEntryPointTest.java | 90 +++++++++++++++++++++-
core/starter/src/main/resources/core.properties | 3 +
.../syncope/fit/core/AuthenticationITCase.java | 22 ++++++
.../org/apache/syncope/fit/core/JWTITCase.java | 3 +-
.../syncope/fit/core/MultitenancyITCase.java | 4 +-
src/main/asciidoc/reference-guide/usage/core.adoc | 33 ++++++++
9 files changed, 198 insertions(+), 8 deletions(-)
(syncope) 04/04: [SYNCOPE-1973] Document authentication error detail properties
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
massx1 pushed a commit to branch 4_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git
commit aa96a05a9472dbcc630551e629c4903b069c7b25
Author: Massimiliano Perrone <ma...@tirasa.net>
AuthorDate: Mon Jun 15 13:12:59 2026 +0200
[SYNCOPE-1973] Document authentication error detail properties
---
src/main/asciidoc/reference-guide/usage/core.adoc | 33 +++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/src/main/asciidoc/reference-guide/usage/core.adoc b/src/main/asciidoc/reference-guide/usage/core.adoc
index 9ef8acd8e8..50b0dd0c68 100644
--- a/src/main/asciidoc/reference-guide/usage/core.adoc
+++ b/src/main/asciidoc/reference-guide/usage/core.adoc
@@ -107,6 +107,39 @@ https://docs.spring.io/spring-security/reference/6.5/servlet/authentication/anon
<<entitlements,entitlements>>, handed over to users via <<roles,roles>>.
****
+[[authentication-error-details]]
+===== Authentication Error Details
+Since 4.1.2 version, by default, authentication failures return a generic error message in the `X-Syncope-Error-Info` response header.
+
+This avoids exposing details that could help distinguish between different authentication failure causes, such as an unknown user, invalid credentials, disabled account, invalid domain or invalid token.
+
+The behavior can be configured with the following properties:
+[cols="1,1,3",options="header"]
+|===
+|Property
+|Default
+|Description
+|`security.authenticationError.exposeDetails`
+|`false`
+|When `false`, authentication failures expose the configured generic message. When `true`, the original authentication exception message is exposed. Setting this to `true` restores the previous, more detailed behavior.
+|`security.authenticationError.genericMessage`
+|`Authentication failed`
+|Message returned for authentication failures when `security.authenticationError.exposeDetails` is `false`. If left empty, Syncope
+ falls back to `Authentication failed`.
+|===
+Example:
+[source,properties]
+----
+security.authenticationError.exposeDetails=false
+security.authenticationError.genericMessage=Authentication failed
+----
+
+For compatibility with previous behavior, administrators can enable detailed messages:
+[source,properties]
+----
+security.authenticationError.exposeDetails=true
+----
+
===== Authentication Throttling
This functionality can throttle repeated failed username / password authentication attempts, to reduce the effectiveness of automated guessing attacks.
(syncope) 02/04: Make authentication error detail disclosure configurable
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
massx1 pushed a commit to branch 4_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git
commit 537c607d4e88726d7fe338e6ab3408238ca4d568
Author: Massimiliano Perrone <ma...@tirasa.net>
AuthorDate: Thu Jun 4 06:34:15 2026 +0200
Make authentication error detail disclosure configurable
---
.../core/spring/security/SecurityProperties.java | 31 ++++++++++++++++
.../SyncopeBasicAuthenticationEntryPoint.java | 15 ++++++--
.../core/spring/security/WebSecurityContext.java | 5 +--
.../SyncopeBasicAuthenticationEntryPointTest.java | 41 +++++++++++++++++++---
core/starter/src/main/resources/core.properties | 3 ++
.../syncope/fit/core/AuthenticationITCase.java | 22 ++++++++++++
.../org/apache/syncope/fit/core/JWTITCase.java | 3 +-
.../syncope/fit/core/MultitenancyITCase.java | 3 +-
8 files changed, 112 insertions(+), 11 deletions(-)
diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/security/SecurityProperties.java b/core/spring/src/main/java/org/apache/syncope/core/spring/security/SecurityProperties.java
index fce444315f..296d870ebc 100644
--- a/core/spring/src/main/java/org/apache/syncope/core/spring/security/SecurityProperties.java
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/security/SecurityProperties.java
@@ -68,6 +68,31 @@ public class SecurityProperties {
}
}
+ public static class AuthenticationErrorProperties {
+
+ public static final String DEFAULT_GENERIC_MESSAGE = "Authentication failed";
+
+ private boolean exposeDetails = false;
+
+ private String genericMessage = DEFAULT_GENERIC_MESSAGE;
+
+ public boolean isExposeDetails() {
+ return exposeDetails;
+ }
+
+ public void setExposeDetails(final boolean exposeDetails) {
+ this.exposeDetails = exposeDetails;
+ }
+
+ public String getGenericMessage() {
+ return genericMessage;
+ }
+
+ public void setGenericMessage(final String genericMessage) {
+ this.genericMessage = genericMessage;
+ }
+ }
+
public static class DigesterProperties {
private int saltIterations = 1;
@@ -149,6 +174,8 @@ public class SecurityProperties {
private final AuthenticationThrottleProperties authenticationThrottle = new AuthenticationThrottleProperties();
+ private final AuthenticationErrorProperties authenticationError = new AuthenticationErrorProperties();
+
private final DigesterProperties digester = new DigesterProperties();
public String getAdminUser() {
@@ -243,6 +270,10 @@ public class SecurityProperties {
return authenticationThrottle;
}
+ public AuthenticationErrorProperties getAuthenticationError() {
+ return authenticationError;
+ }
+
public DigesterProperties getDigester() {
return digester;
}
diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPoint.java b/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPoint.java
index 1f03bf4479..9693780dbd 100644
--- a/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPoint.java
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPoint.java
@@ -21,6 +21,7 @@ package org.apache.syncope.core.spring.security;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
+import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.rest.api.RESTHeaders;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@@ -32,13 +33,23 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationEn
*/
public class SyncopeBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
- public static final String AUTHENTICATION_FAILED = "Authentication failed";
+ private final SecurityProperties securityProperties;
+
+ public SyncopeBasicAuthenticationEntryPoint(final SecurityProperties securityProperties) {
+ this.securityProperties = securityProperties;
+ }
@Override
public void commence(final HttpServletRequest request, final HttpServletResponse response,
final AuthenticationException authException) throws IOException {
- response.addHeader(RESTHeaders.ERROR_INFO, AUTHENTICATION_FAILED);
+ response.addHeader(
+ RESTHeaders.ERROR_INFO,
+ securityProperties.getAuthenticationError().isExposeDetails()
+ ? authException.getMessage()
+ : StringUtils.defaultIfBlank(
+ securityProperties.getAuthenticationError().getGenericMessage(),
+ SecurityProperties.AuthenticationErrorProperties.DEFAULT_GENERIC_MESSAGE));
if (authException instanceof RateLimitAuthenticationException rateLimit) {
response.addHeader(HttpHeaders.RETRY_AFTER, Long.toString(rateLimit.getRetryAfterSeconds()));
response.sendError(HttpStatus.TOO_MANY_REQUESTS.value(), authException.getMessage());
diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/security/WebSecurityContext.java b/core/spring/src/main/java/org/apache/syncope/core/spring/security/WebSecurityContext.java
index bb948d0961..c99fd6cc83 100644
--- a/core/spring/src/main/java/org/apache/syncope/core/spring/security/WebSecurityContext.java
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/security/WebSecurityContext.java
@@ -84,7 +84,8 @@ public class WebSecurityContext {
final UsernamePasswordAuthenticationProvider usernamePasswordAuthenticationProvider,
final AccessDeniedHandler accessDeniedHandler,
final AuthDataAccessor dataAccessor,
- final DefaultCredentialChecker defaultCredentialChecker) throws Exception {
+ final DefaultCredentialChecker defaultCredentialChecker,
+ final SecurityProperties securityProperties) throws Exception {
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManagerBuilder.class).
parentAuthenticationManager(null).
@@ -96,7 +97,7 @@ public class WebSecurityContext {
new SyncopeAuthenticationDetailsSource();
SyncopeBasicAuthenticationEntryPoint basicAuthenticationEntryPoint =
- new SyncopeBasicAuthenticationEntryPoint();
+ new SyncopeBasicAuthenticationEntryPoint(securityProperties);
basicAuthenticationEntryPoint.setRealmName("Apache Syncope authentication");
http.httpBasic(customizer -> customizer.
authenticationEntryPoint(basicAuthenticationEntryPoint).
diff --git a/core/spring/src/test/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPointTest.java b/core/spring/src/test/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPointTest.java
index 86ce543ecb..191b6b0028 100644
--- a/core/spring/src/test/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPointTest.java
+++ b/core/spring/src/test/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPointTest.java
@@ -35,9 +35,12 @@ class SyncopeBasicAuthenticationEntryPointTest {
private SyncopeBasicAuthenticationEntryPoint entryPoint;
+ private SecurityProperties securityProperties;
+
@BeforeEach
public void setUp() throws Exception {
- entryPoint = new SyncopeBasicAuthenticationEntryPoint();
+ securityProperties = new SecurityProperties();
+ entryPoint = new SyncopeBasicAuthenticationEntryPoint(securityProperties);
entryPoint.setRealmName("Apache Syncope authentication");
entryPoint.afterPropertiesSet();
}
@@ -53,7 +56,7 @@ class SyncopeBasicAuthenticationEntryPointTest {
assertEquals(HttpStatus.TOO_MANY_REQUESTS.value(), response.getStatus());
assertEquals("30", response.getHeader(HttpHeaders.RETRY_AFTER));
- assertEquals(SyncopeBasicAuthenticationEntryPoint.AUTHENTICATION_FAILED,
+ assertEquals(SecurityProperties.AuthenticationErrorProperties.DEFAULT_GENERIC_MESSAGE,
response.getHeader(RESTHeaders.ERROR_INFO));
}
@@ -67,7 +70,7 @@ class SyncopeBasicAuthenticationEntryPointTest {
new BadCredentialsException("rossini: invalid password provided"));
assertEquals(HttpStatus.UNAUTHORIZED.value(), response.getStatus());
- assertEquals(SyncopeBasicAuthenticationEntryPoint.AUTHENTICATION_FAILED,
+ assertEquals(SecurityProperties.AuthenticationErrorProperties.DEFAULT_GENERIC_MESSAGE,
response.getHeader(RESTHeaders.ERROR_INFO));
}
@@ -81,7 +84,7 @@ class SyncopeBasicAuthenticationEntryPointTest {
new UsernameNotFoundException("not-a-user"));
assertEquals(HttpStatus.UNAUTHORIZED.value(), response.getStatus());
- assertEquals(SyncopeBasicAuthenticationEntryPoint.AUTHENTICATION_FAILED,
+ assertEquals(SecurityProperties.AuthenticationErrorProperties.DEFAULT_GENERIC_MESSAGE,
response.getHeader(RESTHeaders.ERROR_INFO));
}
@@ -95,7 +98,35 @@ class SyncopeBasicAuthenticationEntryPointTest {
new DisabledException("User rossini is suspended"));
assertEquals(HttpStatus.UNAUTHORIZED.value(), response.getStatus());
- assertEquals(SyncopeBasicAuthenticationEntryPoint.AUTHENTICATION_FAILED,
+ assertEquals(SecurityProperties.AuthenticationErrorProperties.DEFAULT_GENERIC_MESSAGE,
response.getHeader(RESTHeaders.ERROR_INFO));
}
+
+ @Test
+ public void genericErrorInfoCanBeConfigured() throws Exception {
+ securityProperties.getAuthenticationError().setGenericMessage("Login failed");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+
+ entryPoint.commence(
+ new MockHttpServletRequest(),
+ response,
+ new BadCredentialsException("rossini: invalid password provided"));
+
+ assertEquals(HttpStatus.UNAUTHORIZED.value(), response.getStatus());
+ assertEquals("Login failed", response.getHeader(RESTHeaders.ERROR_INFO));
+ }
+
+ @Test
+ public void detailsCanBeExposedWhenConfigured() throws Exception {
+ securityProperties.getAuthenticationError().setExposeDetails(true);
+ MockHttpServletResponse response = new MockHttpServletResponse();
+
+ entryPoint.commence(
+ new MockHttpServletRequest(),
+ response,
+ new BadCredentialsException("rossini: invalid password provided"));
+
+ assertEquals(HttpStatus.UNAUTHORIZED.value(), response.getStatus());
+ assertEquals("rossini: invalid password provided", response.getHeader(RESTHeaders.ERROR_INFO));
+ }
}
diff --git a/core/starter/src/main/resources/core.properties b/core/starter/src/main/resources/core.properties
index 54a5bef4cf..05d6cc30ed 100644
--- a/core/starter/src/main/resources/core.properties
+++ b/core/starter/src/main/resources/core.properties
@@ -107,6 +107,9 @@ security.authenticationThrottle.maxAttempts=5
security.authenticationThrottle.windowSeconds=60
security.authenticationThrottle.lockSeconds=60
+security.authenticationError.exposeDetails=false
+security.authenticationError.genericMessage=Authentication failed
+
# default for LDAP / RFC2307 SSHA
security.digester.saltIterations=1
security.digester.saltSizeBytes=8
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
index 90f0bff11a..8b5bf35676 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
@@ -71,6 +71,7 @@ import org.apache.syncope.common.rest.api.beans.UserRequestQuery;
import org.apache.syncope.common.rest.api.service.AnyObjectService;
import org.apache.syncope.common.rest.api.service.SchemaService;
import org.apache.syncope.common.rest.api.service.UserService;
+import org.apache.syncope.core.spring.security.SecurityProperties;
import org.apache.syncope.fit.AbstractITCase;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -330,6 +331,27 @@ public class AuthenticationITCase extends AbstractITCase {
assertEquals(0, userService4.read(userKey).getFailedLogins());
}
+ @Test
+ public void authenticationFailureErrorInfoIsGeneric() {
+ NotAuthorizedException e = assertThrows(
+ NotAuthorizedException.class,
+ () -> CLIENT_FACTORY.create(getUUIDString(), "anypassword").self());
+ assertEquals(SecurityProperties.AuthenticationErrorProperties.DEFAULT_GENERIC_MESSAGE,
+ e.getResponse().getHeaderString(RESTHeaders.ERROR_INFO));
+
+ UserCR userCR = UserITCase.getUniqueSample("genericAuthError@syncope.apache.org");
+ userCR.getRoles().add("User manager");
+
+ UserTO userTO = createUser(userCR).getEntity();
+ assertNotNull(userTO);
+
+ e = assertThrows(
+ NotAuthorizedException.class,
+ () -> CLIENT_FACTORY.create(userTO.getUsername(), "wrongpwd"));
+ assertEquals(SecurityProperties.AuthenticationErrorProperties.DEFAULT_GENERIC_MESSAGE,
+ e.getResponse().getHeaderString(RESTHeaders.ERROR_INFO));
+ }
+
@Test
public void checkUserSuspension() {
UserCR userCR = UserITCase.getUniqueSample("checkSuspension@syncope.apache.org");
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/JWTITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/JWTITCase.java
index c1f626b9b9..b77027f636 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/JWTITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/JWTITCase.java
@@ -54,6 +54,7 @@ import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.rest.api.RESTHeaders;
import org.apache.syncope.common.rest.api.service.AccessTokenService;
import org.apache.syncope.common.rest.api.service.UserSelfService;
+import org.apache.syncope.core.spring.security.SecurityProperties;
import org.apache.syncope.core.spring.security.jws.AccessTokenJWSSigner;
import org.apache.syncope.core.spring.security.jws.AccessTokenJWSVerifier;
import org.apache.syncope.fit.AbstractITCase;
@@ -142,7 +143,7 @@ public class JWTITCase extends AbstractITCase {
jwtUserSelfService.read();
fail("Failure expected on a modified token");
} catch (NotAuthorizedException e) {
- assertEquals("Invalid signature found in JWT", e.getMessage());
+ assertEquals(SecurityProperties.AuthenticationErrorProperties.DEFAULT_GENERIC_MESSAGE, e.getMessage());
}
}
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
index 6f596a1f3f..d65e40846a 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
@@ -66,6 +66,7 @@ import org.apache.syncope.common.rest.api.service.SchemaService;
import org.apache.syncope.common.rest.api.service.TaskService;
import org.apache.syncope.common.rest.api.service.UserSelfService;
import org.apache.syncope.common.rest.api.service.UserService;
+import org.apache.syncope.core.spring.security.SecurityProperties;
import org.apache.syncope.fit.AbstractITCase;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.junit.jupiter.api.BeforeEach;
@@ -243,7 +244,7 @@ public class MultitenancyITCase extends AbstractITCase {
create(UserITCase.getUniqueSample("syncope1377@syncope.apache.org"));
fail("This should not happen");
} catch (NotAuthorizedException e) {
- assertTrue(e.getMessage().contains("Could not find domain NotExisting"));
+ assertEquals(SecurityProperties.AuthenticationErrorProperties.DEFAULT_GENERIC_MESSAGE, e.getMessage());
}
}
}
(syncope) 01/04: Avoid authentication error detail disclosure
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
massx1 pushed a commit to branch 4_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git
commit 7f71ad78570b984b0808b64c4ce0a4830e4fbc67
Author: Massimiliano Perrone <ma...@tirasa.net>
AuthorDate: Thu Jun 4 06:07:23 2026 +0200
Avoid authentication error detail disclosure
---
.../SyncopeBasicAuthenticationEntryPoint.java | 4 +-
.../SyncopeBasicAuthenticationEntryPointTest.java | 59 +++++++++++++++++++++-
2 files changed, 60 insertions(+), 3 deletions(-)
diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPoint.java b/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPoint.java
index 24efdce799..1f03bf4479 100644
--- a/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPoint.java
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPoint.java
@@ -32,11 +32,13 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationEn
*/
public class SyncopeBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
+ public static final String AUTHENTICATION_FAILED = "Authentication failed";
+
@Override
public void commence(final HttpServletRequest request, final HttpServletResponse response,
final AuthenticationException authException) throws IOException {
- response.addHeader(RESTHeaders.ERROR_INFO, authException.getMessage());
+ response.addHeader(RESTHeaders.ERROR_INFO, AUTHENTICATION_FAILED);
if (authException instanceof RateLimitAuthenticationException rateLimit) {
response.addHeader(HttpHeaders.RETRY_AFTER, Long.toString(rateLimit.getRetryAfterSeconds()));
response.sendError(HttpStatus.TOO_MANY_REQUESTS.value(), authException.getMessage());
diff --git a/core/spring/src/test/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPointTest.java b/core/spring/src/test/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPointTest.java
index 7f34017eb8..86ce543ecb 100644
--- a/core/spring/src/test/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPointTest.java
+++ b/core/spring/src/test/java/org/apache/syncope/core/spring/security/SyncopeBasicAuthenticationEntryPointTest.java
@@ -21,17 +21,29 @@ package org.apache.syncope.core.spring.security;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.DisabledException;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
class SyncopeBasicAuthenticationEntryPointTest {
+ private SyncopeBasicAuthenticationEntryPoint entryPoint;
+
+ @BeforeEach
+ public void setUp() throws Exception {
+ entryPoint = new SyncopeBasicAuthenticationEntryPoint();
+ entryPoint.setRealmName("Apache Syncope authentication");
+ entryPoint.afterPropertiesSet();
+ }
+
@Test
void rateLimitAuthenticationExceptionReturnsTooManyRequests() throws Exception {
- SyncopeBasicAuthenticationEntryPoint entryPoint = new SyncopeBasicAuthenticationEntryPoint();
MockHttpServletResponse response = new MockHttpServletResponse();
entryPoint.commence(
@@ -41,6 +53,49 @@ class SyncopeBasicAuthenticationEntryPointTest {
assertEquals(HttpStatus.TOO_MANY_REQUESTS.value(), response.getStatus());
assertEquals("30", response.getHeader(HttpHeaders.RETRY_AFTER));
- assertEquals("Too many authentication failures", response.getHeader(RESTHeaders.ERROR_INFO));
+ assertEquals(SyncopeBasicAuthenticationEntryPoint.AUTHENTICATION_FAILED,
+ response.getHeader(RESTHeaders.ERROR_INFO));
+ }
+
+ @Test
+ public void badCredentialsExposeGenericErrorInfo() throws Exception {
+ MockHttpServletResponse response = new MockHttpServletResponse();
+
+ entryPoint.commence(
+ new MockHttpServletRequest(),
+ response,
+ new BadCredentialsException("rossini: invalid password provided"));
+
+ assertEquals(HttpStatus.UNAUTHORIZED.value(), response.getStatus());
+ assertEquals(SyncopeBasicAuthenticationEntryPoint.AUTHENTICATION_FAILED,
+ response.getHeader(RESTHeaders.ERROR_INFO));
+ }
+
+ @Test
+ public void missingUserExposeGenericErrorInfo() throws Exception {
+ MockHttpServletResponse response = new MockHttpServletResponse();
+
+ entryPoint.commence(
+ new MockHttpServletRequest(),
+ response,
+ new UsernameNotFoundException("not-a-user"));
+
+ assertEquals(HttpStatus.UNAUTHORIZED.value(), response.getStatus());
+ assertEquals(SyncopeBasicAuthenticationEntryPoint.AUTHENTICATION_FAILED,
+ response.getHeader(RESTHeaders.ERROR_INFO));
+ }
+
+ @Test
+ public void disabledUserExposeGenericErrorInfo() throws Exception {
+ MockHttpServletResponse response = new MockHttpServletResponse();
+
+ entryPoint.commence(
+ new MockHttpServletRequest(),
+ response,
+ new DisabledException("User rossini is suspended"));
+
+ assertEquals(HttpStatus.UNAUTHORIZED.value(), response.getStatus());
+ assertEquals(SyncopeBasicAuthenticationEntryPoint.AUTHENTICATION_FAILED,
+ response.getHeader(RESTHeaders.ERROR_INFO));
}
}
(syncope) 03/04: [SYNCOPE-1973] Align FIT expectations with generic authentication errors
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
massx1 pushed a commit to branch 4_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git
commit 076bb6dc70290ed1cea64b2478dbd055e29b136b
Author: Massimiliano Perrone <ma...@tirasa.net>
AuthorDate: Mon Jun 15 13:12:01 2026 +0200
[SYNCOPE-1973] Align FIT expectations with generic authentication errors
---
.../src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
index d65e40846a..ba2a4f4cc1 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
@@ -21,7 +21,6 @@ package org.apache.syncope.fit.core;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeTrue;