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 <[email protected]>
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));
     }
 }

Reply via email to