This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch 4_0_X
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/4_0_X by this push:
     new ad823fe393 [SYNCOPE-1937] fixes password history length management 
(#1256)
ad823fe393 is described below

commit ad823fe393774c2bf99da17b88ddbcca883f744f
Author: Andrea Patricelli <[email protected]>
AuthorDate: Sat Dec 6 07:20:56 2025 +0100

    [SYNCOPE-1937] fixes password history length management (#1256)
---
 .../core/persistence/jpa/entity/user/JPAUser.java  |  3 +-
 .../core/persistence/jpa/inner/UserTest.java       | 43 ++++++++++++++++++++++
 .../persistence/neo4j/entity/user/Neo4jUser.java   |  3 +-
 .../core/persistence/neo4j/inner/UserTest.java     | 43 ++++++++++++++++++++++
 4 files changed, 88 insertions(+), 4 deletions(-)

diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
index 177cb1920f..d6cd8419b4 100644
--- 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
@@ -334,8 +334,7 @@ public class JPAUser
     @Override
     public void removeOldestEntriesFromPasswordHistory(final int n) {
         List<String> ph = getPasswordHistory();
-        ph.subList(n, ph.size());
-        passwordHistory = POJOHelper.serialize(ph);
+        passwordHistory = POJOHelper.serialize(ph.subList(Math.min(n, 
ph.size()), ph.size()));
     }
 
     @Override
diff --git 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java
 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java
index 85e43d1382..a67b68d36c 100644
--- 
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java
+++ 
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.core.persistence.jpa.inner;
 
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -25,8 +26,13 @@ import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
 import java.time.OffsetDateTime;
 import java.util.List;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
 import org.apache.syncope.core.persistence.api.EncryptorManager;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
@@ -253,4 +259,41 @@ public class UserTest extends AbstractTest {
         assertTrue(encryptorManager.getInstance().
                 verify(securityAnswer, CipherAlgorithm.SSHA256, 
actual.getSecurityAnswer()));
     }
+
+    @Test
+    public void issueSYNCOPE1937()
+            throws NoSuchPaddingException, IllegalBlockSizeException, 
NoSuchAlgorithmException, BadPaddingException,
+            InvalidKeyException {
+        User user = entityFactory.newEntity(User.class);
+        user.setUsername("username");
+        user.setRealm(realmDAO.getRoot());
+        user.setCreator("admin");
+        user.setCreationDate(OffsetDateTime.now());
+
+        user.setCipherAlgorithm(CipherAlgorithm.SHA1);
+        user.setPassword("password123");
+
+        User actual = userDAO.save(user);
+
+        assertEquals(0, user.getPasswordHistory().size());
+
+        // add some other password to history
+        
user.addToPasswordHistory(encryptorManager.getInstance().encode("Password123!", 
CipherAlgorithm.SHA1));
+        
user.addToPasswordHistory(encryptorManager.getInstance().encode("Password124!", 
CipherAlgorithm.SHA1));
+        
user.addToPasswordHistory(encryptorManager.getInstance().encode("Password125!", 
CipherAlgorithm.SHA1));
+        
user.addToPasswordHistory(encryptorManager.getInstance().encode("Password126!", 
CipherAlgorithm.SHA1));
+        
user.addToPasswordHistory(encryptorManager.getInstance().encode("Password127!", 
CipherAlgorithm.SHA1));
+
+        assertEquals(5, user.getPasswordHistory().size());
+
+        // keep only the last three passwords into history
+        user.removeOldestEntriesFromPasswordHistory(2);
+
+        assertEquals(3, user.getPasswordHistory().size());
+
+        // try with an exceeding number
+        assertDoesNotThrow(() -> 
user.removeOldestEntriesFromPasswordHistory(user.getPasswordHistory().size() + 
5));
+
+        assertNotNull(actual);
+    }
 }
diff --git 
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/user/Neo4jUser.java
 
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/user/Neo4jUser.java
index e12319ba37..3b8dc2536c 100644
--- 
a/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/user/Neo4jUser.java
+++ 
b/core/persistence-neo4j/src/main/java/org/apache/syncope/core/persistence/neo4j/entity/user/Neo4jUser.java
@@ -291,8 +291,7 @@ public class Neo4jUser
     @Override
     public void removeOldestEntriesFromPasswordHistory(final int n) {
         List<String> ph = getPasswordHistory();
-        ph.subList(n, ph.size());
-        passwordHistory = POJOHelper.serialize(ph);
+        passwordHistory = POJOHelper.serialize(ph.subList(Math.min(n, 
ph.size()), ph.size()));
     }
 
     @Override
diff --git 
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/inner/UserTest.java
 
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/inner/UserTest.java
index caf605158a..9a1ed7549c 100644
--- 
a/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/inner/UserTest.java
+++ 
b/core/persistence-neo4j/src/test/java/org/apache/syncope/core/persistence/neo4j/inner/UserTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.core.persistence.neo4j.inner;
 
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -25,8 +26,13 @@ import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
 import java.time.OffsetDateTime;
 import java.util.List;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
 import org.apache.syncope.core.persistence.api.EncryptorManager;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
@@ -253,4 +259,41 @@ public class UserTest extends AbstractTest {
         assertTrue(encryptorManager.getInstance().
                 verify(securityAnswer, CipherAlgorithm.SSHA256, 
actual.getSecurityAnswer()));
     }
+
+    @Test
+    public void issueSYNCOPE1937()
+            throws NoSuchPaddingException, IllegalBlockSizeException, 
NoSuchAlgorithmException, BadPaddingException,
+            InvalidKeyException {
+        User user = entityFactory.newEntity(User.class);
+        user.setUsername("username");
+        user.setRealm(realmDAO.getRoot());
+        user.setCreator("admin");
+        user.setCreationDate(OffsetDateTime.now());
+
+        user.setCipherAlgorithm(CipherAlgorithm.SHA1);
+        user.setPassword("password123");
+
+        User actual = userDAO.save(user);
+
+        assertEquals(0, user.getPasswordHistory().size());
+
+        // add some other password to history
+        
user.addToPasswordHistory(encryptorManager.getInstance().encode("Password123!", 
CipherAlgorithm.SHA1));
+        
user.addToPasswordHistory(encryptorManager.getInstance().encode("Password124!", 
CipherAlgorithm.SHA1));
+        
user.addToPasswordHistory(encryptorManager.getInstance().encode("Password125!", 
CipherAlgorithm.SHA1));
+        
user.addToPasswordHistory(encryptorManager.getInstance().encode("Password126!", 
CipherAlgorithm.SHA1));
+        
user.addToPasswordHistory(encryptorManager.getInstance().encode("Password127!", 
CipherAlgorithm.SHA1));
+
+        assertEquals(5, user.getPasswordHistory().size());
+
+        // keep only the last three passwords into history
+        user.removeOldestEntriesFromPasswordHistory(2);
+
+        assertEquals(3, user.getPasswordHistory().size());
+
+        // try with an exceeding number
+        assertDoesNotThrow(() -> 
user.removeOldestEntriesFromPasswordHistory(user.getPasswordHistory().size() + 
5));
+
+        assertNotNull(actual);
+    }
 }

Reply via email to