Mandib Chaulagain created FINERACT-2956:
-------------------------------------------

             Summary: Password reuse check never rejects a previously used 
password
                 Key: FINERACT-2956
                 URL: https://issues.apache.org/jira/browse/FINERACT-2956
             Project: Apache Fineract
          Issue Type: Bug
          Components: Security, User Management
    Affects Versions: 1.15.0
         Environment: develop @ d4ef406954 (bug also present on current develop 
999e7a704d), PostgreSQL 18.3, JDK 25, default tenant, no other configuration 
changes.
            Reporter: Mandib Chaulagain
            Assignee: Mandib Chaulagain
             Fix For: 1.16.0
         Attachments: image-2026-10-15-21-56-06-601.png, 
image-2026-10-15-21-56-20-210.png, image-2026-10-15-21-56-30-851.png, 
image-2026-10-15-21-57-03-681.png, image-2026-10-15-21-57-15-817.png, 
image-2026-10-15-21-57-33-625.png, image-2026-10-15-21-57-50-357.png, 
image-2026-10-15-21-57-59-635.png, image-2026-10-15-21-58-31-389.png, 
image-2026-10-15-21-59-10-033.png

Fineract has a setting, {{{}password-reuse-check-history-count{}}}, that is 
supposed to stop users from setting a password they have used before (added in 
FINERACT-2005). When the setting is turned on, it does not work. Fineract 
accepts an old password, and it also accepts the same password the user already 
has.

Here are the steps to reproduce:

# Turn on the check. On {{PUT /v1/configurations/name/\{configName\}}} with 
configName {{password-reuse-check-history-count}}, send this body ({{"value": 
3}} means the last 3 passwords can't be reused):
 !image-2026-10-15-21-56-06-601.png! 
Here's the response body:
 !image-2026-10-15-21-56-20-210.png! 
A GET on the same setting confirms it is enabled with value 3:
 !image-2026-10-15-21-56-30-851.png! 
# Create a test user. On {{POST /v1/users}}, I used the following request body 
(this is the first time the password is set, call it password A):
 !image-2026-10-15-21-57-03-681.png! 
And got this response (user id 4):
 !image-2026-10-15-21-57-15-817.png! 
# Change to a new password, B, on {{POST /v1/users/4/pwd}} (second time a 
password is given):
 !image-2026-10-15-21-57-33-625.png! 
The response was 200, which is correct.
# Reuse the old password A again (third time a password is given):
 !image-2026-10-15-21-57-50-357.png! 
*Actual:* 200, the password is changed.
 !image-2026-10-15-21-57-59-635.png! 
*Expected:* 400 {{error.msg.password.already.used}}, because A is one of the 
last 3 passwords.
# Resend the body from step 4, so A is set while A is already the current 
password (fourth time a password is given):
 !image-2026-10-15-21-58-31-389.png! 
*Actual:* 200 again.
*Expected:* 400 {{error.msg.password.already.used}}.


In 
{{AppUserWritePlatformServiceJpaRepositoryImpl.getCurrentPasswordToSaveAsPreview()}},
 the new password is hashed and compared with each old hash using 
{{String.equals}}. Fineract hashes passwords with bcrypt, which adds a random 
salt every time, so the same password never produces the same hash string. The 
comparison can never be true.

The database shows this. For user 4, the history holds testingasdhjS202@ (set 
at creation), asdklj@Wfasdsdf989 and testingasdhjS202@, and the current 
password is testingasdhjS202@. Three of the four hashes are the same password, 
and still all of them are different strings:
!image-2026-10-15-21-59-10-033.png!

There is a second problem. The current password is never checked, because it is 
only saved to the history table ({{m_appuser_previous_password}}) after it has 
been replaced.

The existing unit test does not catch this because it uses a fake encoder that 
always returns "encoded".



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to