[
https://issues.apache.org/jira/browse/FINERACT-2956?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18127745#comment-18127745
]
Mandib Chaulagain commented on FINERACT-2956:
---------------------------------------------
While fixing this, I found a second gap in the same check.
When the reuse check is on, a user can "change" their password to the one they
are already using, and it is accepted because the history table only stores old
passwords. The current password is added to it only after it has been replaced,
so it is never checked against. The code does have a separate "has the password
changed?" check ({{JsonCommand.isChangeInPasswordParameterNamed}}). It has the
same bug as this ticket, though: it hashes the new password and compares the
hashes with {{equals()}}. bcrypt salts every hash, so it always reports a
change, even when the password is the same.
The fix is present in the pr too.
> 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
> Priority: Major
> 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)