Mandib Chaulagain created FINERACT-2961:
-------------------------------------------
Summary: Submitting the current password is always treated as a
password change
Key: FINERACT-2961
URL: https://issues.apache.org/jira/browse/FINERACT-2961
Project: Apache Fineract
Issue Type: Bug
Components: Security, User Management
Affects Versions: 1.15.0
Environment: develop @ d4ef406954
Reporter: Mandib Chaulagain
Assignee: Mandib Chaulagain
Fix For: 1.16.0
Attachments: image-2026-10-16-19-44-54-613.png,
image-2026-10-16-19-45-27-140.png, image-2026-10-16-19-47-52-513.png,
image-2026-10-16-19-50-04-971.png, image-2026-10-16-19-50-23-067.png,
image-2026-10-16-19-54-04-455.png, image-2026-10-16-19-56-22-322.png
If you set a user's password to the one they already have, Fineract treats it
as a real change. It saves a new hash, adds a row to the password history,
updates the password's last-updated date and returns {{"password": true}} in
the response. This only happens when the password reuse check is off, which is
the default. When the check is on, the fix in FINERACT-2956 rejects the current
password before it gets this far.
The problem is in {{JsonCommand.isChangeInPasswordParameterNamed}}, which
checks whether the submitted password is different from the stored one. It
hashes the submitted password and compares that hash with the stored one using
{{equals()}}. Fineract uses bcrypt, which adds a new random salt every time it
hashes, so the two hashes are never equal and the method always returns true.
It's the same root cause as FINERACT-2956, just in a different method, and PR
#6670 doesn't touch it.
Steps to reproduce, with the reuse check
({{password-reuse-check-history-count}}) turned off:
1. Create a user with password A on {{POST /v1/users}}:
!image-2026-10-16-19-44-54-613.png!
I got user id 5 back:
!image-2026-10-16-19-45-27-140.png!
2. Set the user's last-updated date to a date in the past, so it's easy to see
if it changes, and check what's stored:
{code:sql}
UPDATE m_appuser SET last_time_password_updated = DATE '2020-01-01' WHERE id =
5;
SELECT password, last_time_password_updated FROM m_appuser WHERE id = 5;
SELECT id, removal_date FROM m_appuser_previous_password WHERE user_id = 5;
{code}
!image-2026-10-16-19-47-52-513.png!
3. Send the same password A again on {{POST /v1/users/5/pwd}}:
!image-2026-10-16-19-50-04-971.png!
Response:
!image-2026-10-16-19-50-23-067.png!
4. Run the two SELECTs from step 2 again:
!image-2026-10-16-19-56-22-322.png!
!image-2026-10-16-19-54-04-455.png!
I did steps 2 to 4 twice, and each time one more row was added to the history.
The request returns 200 with {{"password": true}} under {{changes}}. In the
database, the hash is different, {{last_time_password_updated}} has moved from
2020-01-01 to today, and there's a new history row with the same password in it.
Since the password didn't actually change, I'd expect none of this to happen:
no password change in the response, and the stored hash, the history and
{{last_time_password_updated}} left as they were.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)