Piotr Wargulak created FINERACT-2953:
----------------------------------------
Summary: Datatable entry update/delete with a second id acts on
another entity's row
Key: FINERACT-2953
URL: https://issues.apache.org/jira/browse/FINERACT-2953
Project: Apache Fineract
Issue Type: Bug
Reporter: Piotr Wargulak
{{PUT}} and {{{}DELETE /datatables/\{datatable}/\{apptableId}/{datatableId{}}}}
(also through {{{}/batches{}}}, and {{{}DELETE
/survey/\{surveyName}/\{clientId}/{fulfilledId{}}}}, which reaches the same
delete) check that {{apptableId}} exists and is within the user's office scope,
but choose the row they write or delete by {{{}datatableId{}}}. Three cases
follow:
# *One-to-one datatable, PUT with a second id.*
{{DatatableUtil#retrieveDataTableGenericResultSet}} ignores {{datatableId}} on
a one-to-one table, so the existing row is read for {{{}apptableId{}}}; the
UPDATE is then keyed on {{datatableId ?? apptableId}}
({{{}DatatableWriteServiceImpl#updateDatatableEntry{}}}). The row of the entity
whose id is {{datatableId}} is updated.
# *One-to-one datatable, DELETE with a second id.* The statement is {{{}DELETE
... WHERE "id" = ?{}}}, a column a one-to-one table does not have, so the
caller gets HTTP 403 {{error.msg.data.integrity.issue}} carrying the raw
database message ({{{}ERROR: column "id" does not exist{}}}).
# *One-to-many datatable, DELETE with a second id.* The statement is {{DELETE
... WHERE id = ?}} with no condition on {{{}apptableId{}}}, so an entry
belonging to another entity is deleted. (PUT is not affected: its read uses
both ids and answers 404.)
In cases 1 and 3, the office scope check and any state check made on
{{apptableId}} do not apply to the entity whose row actually changes.
A related edge: {{isMultirowDatatable}} only looks for a column named
{{{}id{}}}. A table registered through {{POST /datatables/register/...}} whose
primary key is the foreign key, and which also has a plain {{id}} column, reads
as one-to-many, and its PUT keys the UPDATE on {{datatableId}} as in case 1.
{*}Steps to reproduce{*}: two clients X and B, a one-to-one datatable
{{dt_one}} and a one-to-many {{dt_many}} on {{{}m_client{}}}, one entry each.
||Request||Result||
|{{PUT /datatables/dt_one/X/B}} {{{{}"note":"via-X"{}}}}|200; *B's* row is now
{{{}via-X{}}}, X's unchanged|
|{{DELETE /datatables/dt_one/X/B}}|403, message {{ERROR: column "id" does not
exist}}|
|{{DELETE /datatables/dt_many/X/<id of B's entry>}}|200; *B's* entry deleted|
|{{POST /batches}} with {{PUT v1/datatables/dt_one/X/B}}|inner 200; B's row
written|
|{{DELETE /survey/dt_many/X/<id of B's entry>}}|200; *B's* entry deleted|
*Expected*
* A one-to-one datatable refuses an entry id on PUT and DELETE (403, like the
existing {{error.msg.attempting.multiple.update}} for a one-to-many PUT without
one).
* A one-to-many DELETE by entry id deletes only an entry of
{{{}apptableId{}}}; when no such entry exists, 404
{{{}error.msg.datatable.data.not.found{}}}, as the PUT already answers.
* A PUT updates the row it has just read for {{apptableId}} (keyed on that
row's primary key).
--
This message was sent by Atlassian Jira
(v8.20.10#820010)