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