You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@fineract.apache.org by "Aman-Mittal (via GitHub)" <gi...@apache.org> on 2026/10/03 17:04:28 UTC
[I] Four permission gates name a code that cannot authorise what the control does [fineract-backoffice-ui]
Aman-Mittal opened a new issue, #696:
URL: https://github.com/apache/fineract-backoffice-ui/issues/696
Separate from #691, which is about a dispatch route declaring one code for many commands. These are individual gates naming the wrong code, or a code that does not exist at all.
Each was measured against a running Fineract with an **empty body**, which separates authorisation from validation without writing anything: the platform authorises before it validates, so `403 error.msg.not.authorized` means the code is wrong and `400 validation.msg...` means it is right and only the body was bad.
## 1. The savings cash-withdrawal button asks for the application-withdrawal code
`savings-account-view.component.ts`:
```html
<ion-button data-testid="savings-withdraw-action"
appRequiresPermission="WITHDRAW_SAVINGSACCOUNT"
(click)="onTransaction('withdrawal')">
```
Both codes exist, one letter apart, and they are strictly non-interchangeable:
| Operation | `WITHDRAWAL_SAVINGSACCOUNT` | `WITHDRAW_SAVINGSACCOUNT` |
| --- | --- | --- |
| cash withdrawal (`transactions?command=withdrawal`) | **400 authorised** | 403 refused |
| application withdrawal (`?command=withdrawnByApplicant`) | 403 refused | **400 authorised** |
`WITHDRAW_SAVINGSACCOUNT` withdraws the *application* — which is what the Withdrawn-by-applicant button immediately above it correctly uses. This one withdraws *cash*.
So a teller holding `WITHDRAWAL_SAVINGSACCOUNT` is shown a disabled Withdraw button they are entitled to use, and a holder of the application code is offered an enabled one the platform refuses.
This is the one a static check cannot find, because both codes are real.
## 2. `UNDOWITHDRAW_CLIENT` does not exist
`client-view.component.ts` gates the client undo-withdrawal action on it. The real code is `UNDOWITHDRAWAL_CLIENT` — the same missing "AL" as above:
```
POST /clients/{id}?command=undoWithdrawal
UNDOWITHDRAWAL_CLIENT → 400 authorised
WITHDRAW_CLIENT → 403 refused
```
## 3. `UPDATE_LOAN_AVAILABLE_DISBURSEMENT_AMOUNT` does not exist, and nothing can replace it
`loan-view.component.ts` gates the revise-available-disbursement-amount action on it. There is no such code — and no narrower one, either. Found by bisecting the whole catalogue:
- a role granted **all 721 grantable codes** is still refused `PUT /loans/{id}/available-disbursement-amount` with 403;
- the superuser gets 400 on the identical request.
So the endpoint is genuinely superuser-only. `ALL_FUNCTIONS` is the honest declaration, and it makes the refusal hint name something an administrator can act on.
Arguably the platform should define a grantable code for an operation it exposes; that belongs in the [ASF Jira project](https://issues.apache.org/jira/projects/FINERACT) rather than here, and is noted only because it is why this one cannot be fixed by naming a better code.
## 4. Office transactions — and #665's proposed fix would not have worked
Recorded here because measuring it changed the answer. #665 recommended requiring `READ_OFFICETRANSACTION` **and** `READ_OFFICE`. In fact the transaction code does nothing for these endpoints at all:
```
READ_OFFICE alone → GET /officetransactions 200, /officetransactions/template 200
READ_OFFICETRANSACTION alone → 403, 403
READ_CLIENT alone (control) → 403, 403
```
An AND would still refuse a `READ_OFFICE` holder the platform serves.
## Why 2 and 3 are the worst of these
`DOCS/RBAC.md` already says it:
> **Do not invent codes.** A gate on a code that does not exist can never be satisfied by any role, which is worse than no gate.
A control gated on a nonexistent code is disabled *forever*, for every account except a superuser's, and looks exactly like a control the viewer is not entitled to. Nobody reports it, because the UI is behaving as though the answer were "no".
## Fix
#695, along with a check so the class cannot return.
`scripts/check-permission-codes.mjs` compares every code named in an action gate, structural gate, route, nav entry, data table or command map against a committed snapshot of the catalogue — 311 codes today — and runs in CI with no Fineract started. Its header states plainly what it **cannot** catch, which is defect 1: a code that exists but is wrong for the operation. That needs a run against a real platform, which `e2e/savings-flows-non-admin-roles.spec.ts` now provides, asserting the withdrawal code from both sides.
How 2 and 3 were found is worth noting: not by using the app, but by diffing the source against a live `GET /v1/permissions`. Neither would have surfaced from a bug report.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@fineract.apache.org.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [I] Four permission gates name a code that cannot authorise what the control does [fineract-backoffice-ui]
Posted by "Aman-Mittal (via GitHub)" <gi...@apache.org>.
Aman-Mittal closed issue #696: Four permission gates name a code that cannot authorise what the control does
URL: https://github.com/apache/fineract-backoffice-ui/issues/696
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@fineract.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org