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


The following commit(s) were added to refs/heads/4_1_X by this push:
     new e1c234e84b [SYNCOPE-1974] Avoid password reset user enumeration (#1416)
e1c234e84b is described below

commit e1c234e84b60f149c4e1942aae60f85ac3c135d6
Author: Massimiliano Perrone <[email protected]>
AuthorDate: Wed Jun 17 10:52:10 2026 +0200

    [SYNCOPE-1974] Avoid password reset user enumeration (#1416)
---
 .../enduser/pages/SelfPasswordReset.properties     |  4 +--
 .../pages/SelfPasswordReset_fr_CA.properties       |  4 +--
 .../enduser/pages/SelfPasswordReset_it.properties  |  4 +--
 .../enduser/pages/SelfPasswordReset_ja.properties  |  4 +--
 .../pages/SelfPasswordReset_pt_BR.properties       |  4 +--
 .../enduser/pages/SelfPasswordReset_ru.properties  |  4 +--
 .../apache/syncope/core/logic/UserSelfLogic.java   |  2 +-
 .../core/spring/security/SecurityProperties.java   | 10 ++++++
 core/starter/src/main/resources/core.properties    |  2 ++
 .../apache/syncope/fit/core/UserSelfITCase.java    | 40 +++++++++++-----------
 10 files changed, 45 insertions(+), 33 deletions(-)

diff --git 
a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset.properties
 
b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset.properties
index 3c4818ec56..affd3baa6f 100644
--- 
a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset.properties
+++ 
b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset.properties
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 password-reset=Password reset
-self.pwd.reset.success=Your password has been reset successfully!
-self.pwd.reset.success.msg=An email has been sent to your address.
+self.pwd.reset.success=Password reset process started
+self.pwd.reset.success.msg=If an account matching the provided information 
exists, password reset instructions will be sent to the associated email 
address in a few seconds.
 self.pwd.reset.error=Error during password reset!
 self.pwd.reset.error.msg=Try again or contact an administrator.
diff --git 
a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_fr_CA.properties
 
b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_fr_CA.properties
index 3c4818ec56..affd3baa6f 100644
--- 
a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_fr_CA.properties
+++ 
b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_fr_CA.properties
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 password-reset=Password reset
-self.pwd.reset.success=Your password has been reset successfully!
-self.pwd.reset.success.msg=An email has been sent to your address.
+self.pwd.reset.success=Password reset process started
+self.pwd.reset.success.msg=If an account matching the provided information 
exists, password reset instructions will be sent to the associated email 
address in a few seconds.
 self.pwd.reset.error=Error during password reset!
 self.pwd.reset.error.msg=Try again or contact an administrator.
diff --git 
a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_it.properties
 
b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_it.properties
index c8a9683197..52e91c1fbc 100644
--- 
a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_it.properties
+++ 
b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_it.properties
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 password-reset=Reset della password
-self.pwd.reset.success=La password \u00e8 stata resettata con successo
-self.pwd.reset.success.msg=Una email \u00e8 stata inviata all'indirizzo 
configurato
+self.pwd.reset.success=Processo di reset password avviato
+self.pwd.reset.success.msg=Se esiste un account corrispondente alle 
informazioni fornite, le istruzioni per il reset della password verranno 
inviate all'indirizzo email associato entro pochi secondi.
 self.pwd.reset.error=Error during password reset!
 self.pwd.reset.error.msg=Try again or contact an administrator.
diff --git 
a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_ja.properties
 
b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_ja.properties
index 791121e5d1..d294a2ab02 100644
--- 
a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_ja.properties
+++ 
b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_ja.properties
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 password-reset=\u30d1\u30b9\u30ef\u30fc\u30c9\u306e\u30ea\u30bb\u30c3\u30c8
-self.pwd.reset.success=\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u30ea\u30bb\u30c3\u30c8\u3057\u307e\u3057\u305f
-self.pwd.reset.success.msg=An email has been sent to your address.
+self.pwd.reset.success=Password reset process started
+self.pwd.reset.success.msg=If an account matching the provided information 
exists, password reset instructions will be sent to the associated email 
address in a few seconds.
 self.pwd.reset.error=Error during password reset!
 self.pwd.reset.error.msg=Try again or contact an administrator.
diff --git 
a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_pt_BR.properties
 
b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_pt_BR.properties
index 7195575402..af504335ba 100644
--- 
a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_pt_BR.properties
+++ 
b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_pt_BR.properties
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 password-reset=Resetar a senha
-self.pwd.reset.success=Senha redefinida com sucesso
-self.pwd.reset.success.msg=An email has been sent to your address.
+self.pwd.reset.success=Password reset process started
+self.pwd.reset.success.msg=If an account matching the provided information 
exists, password reset instructions will be sent to the associated email 
address in a few seconds.
 self.pwd.reset.error=Error during password reset!
 self.pwd.reset.error.msg=Try again or contact an administrator.
diff --git 
a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_ru.properties
 
b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_ru.properties
index 2bc9d14a11..dc00337122 100644
--- 
a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_ru.properties
+++ 
b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/SelfPasswordReset_ru.properties
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
password-reset=\u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435
 \u043f\u0430\u0440\u043e\u043b\u044f
-self.pwd.reset.success=\u041f\u0430\u0440\u043e\u043b\u044c 
\u0443\u0441\u043f\u0435\u0448\u043d\u043e 
\u0441\u0431\u0440\u043e\u0448\u0435\u043d
-self.pwd.reset.success.msg=An email has been sent to your address.
+self.pwd.reset.success=Password reset process started
+self.pwd.reset.success.msg=If an account matching the provided information 
exists, password reset instructions will be sent to the associated email 
address in a few seconds.
 self.pwd.reset.error=Error during password reset!
 self.pwd.reset.error.msg=Try again or contact an administrator.
diff --git 
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/UserSelfLogic.java
 
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/UserSelfLogic.java
index 8e6ef9db5f..8a95f9e4a3 100644
--- 
a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/UserSelfLogic.java
+++ 
b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/UserSelfLogic.java
@@ -316,7 +316,7 @@ public class UserSelfLogic extends AbstractUserLogic {
         }
 
         User user = userDAO.findByToken(token).
-                orElseThrow(() -> new NotFoundException("User with token " + 
token));
+                orElseThrow(() -> new NotFoundException("User"));
 
         provisioningManager.confirmPasswordReset(
                 user.getKey(), token, password, 
AuthContextUtils.getUsername(), REST_CONTEXT);
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 2470d84051..f444717a3e 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
@@ -174,6 +174,8 @@ public class SecurityProperties {
 
     private final ThrottleProperties authenticationThrottle = new 
ThrottleProperties();
 
+    private boolean passwordResetHideDetails = true;
+
     private final ThrottleProperties passwordResetThrottle = new 
ThrottleProperties();
 
     private final AuthenticationErrorProperties authenticationError = new 
AuthenticationErrorProperties();
@@ -272,6 +274,14 @@ public class SecurityProperties {
         return authenticationThrottle;
     }
 
+    public boolean isPasswordResetHideDetails() {
+        return passwordResetHideDetails;
+    }
+
+    public void setPasswordResetHideDetails(final boolean 
passwordResetHideDetails) {
+        this.passwordResetHideDetails = passwordResetHideDetails;
+    }
+
     public ThrottleProperties getPasswordResetThrottle() {
         return passwordResetThrottle;
     }
diff --git a/core/starter/src/main/resources/core.properties 
b/core/starter/src/main/resources/core.properties
index d32437a65e..e9dfe4650b 100644
--- a/core/starter/src/main/resources/core.properties
+++ b/core/starter/src/main/resources/core.properties
@@ -107,6 +107,8 @@ security.authenticationThrottle.maxAttempts=5
 security.authenticationThrottle.windowSeconds=60
 security.authenticationThrottle.lockSeconds=60
 
+security.passwordResetHideDetails=true
+
 security.passwordResetThrottle.enabled=true
 security.passwordResetThrottle.maxAttempts=5
 security.passwordResetThrottle.windowSeconds=300
diff --git 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
index 552817e07f..ee4981bfa2 100644
--- 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
+++ 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
@@ -351,12 +351,12 @@ public class UserSelfITCase extends AbstractITCase {
         assertNotNull(read);
 
         // 3. request password reset (as anonymous) providing the expected 
security answer
-        try {
-            
ANONYMOUS_CLIENT.getService(UserSelfService.class).requestPasswordReset(user.getUsername(),
 "WRONG");
-            fail("This should not happen");
-        } catch (SyncopeClientException e) {
-            assertEquals(ClientExceptionType.InvalidSecurityAnswer, 
e.getType());
-        }
+        SyncopeClientException e = assertThrows(
+                SyncopeClientException.class,
+                () -> ANONYMOUS_CLIENT.getService(UserSelfService.class).
+                        requestPasswordReset(user.getUsername(), "WRONG"));
+        assertEquals(ClientExceptionType.InvalidSecurityAnswer, e.getType());
+
         
ANONYMOUS_CLIENT.getService(UserSelfService.class).requestPasswordReset(user.getUsername(),
 "Rossi");
 
         if (IS_EXT_SEARCH_ENABLED) {
@@ -378,13 +378,13 @@ public class UserSelfITCase extends AbstractITCase {
                 StringUtils::isNotBlank);
 
         // 5. confirm password reset
-        try {
-            
ANONYMOUS_CLIENT.getService(UserSelfService.class).confirmPasswordReset("WRONG 
TOKEN", "newPassword");
-            fail("This should not happen");
-        } catch (SyncopeClientException e) {
-            assertEquals(ClientExceptionType.NotFound, e.getType());
-            assertTrue(e.getMessage().contains("WRONG TOKEN"));
-        }
+        e = assertThrows(
+                SyncopeClientException.class,
+                () -> ANONYMOUS_CLIENT.getService(UserSelfService.class).
+                        confirmPasswordReset("WRONG TOKEN", "newPassword"));
+        assertEquals(ClientExceptionType.NotFound, e.getType());
+        assertFalse(e.getMessage().contains("WRONG TOKEN"));
+
         
ANONYMOUS_CLIENT.getService(UserSelfService.class).confirmPasswordReset(token, 
"newPassword123");
 
         if (!IS_NEO4J_PERSISTENCE) {
@@ -451,13 +451,13 @@ public class UserSelfITCase extends AbstractITCase {
         assertNotNull(token);
 
         // 5. confirm password reset
-        try {
-            
ANONYMOUS_CLIENT.getService(UserSelfService.class).confirmPasswordReset("WRONG 
TOKEN", "newPassword");
-            fail("This should not happen");
-        } catch (SyncopeClientException e) {
-            assertEquals(ClientExceptionType.NotFound, e.getType());
-            assertTrue(e.getMessage().contains("WRONG TOKEN"));
-        }
+        SyncopeClientException e = assertThrows(
+                SyncopeClientException.class,
+                () -> ANONYMOUS_CLIENT.getService(UserSelfService.class).
+                        confirmPasswordReset("WRONG TOKEN", "newPassword"));
+        assertEquals(ClientExceptionType.NotFound, e.getType());
+        assertFalse(e.getMessage().contains("WRONG TOKEN"));
+
         
ANONYMOUS_CLIENT.getService(UserSelfService.class).confirmPasswordReset(token, 
"newPassword123");
 
         // 6. verify that password was reset and token removed

Reply via email to