Skip to content

Preventing update/insert of read-only fields in a table by user#1596

Merged
ayush3797 merged 64 commits intomainfrom
dev/agarwalayush/PreventingUpdateForReadOnlyColumns
Sep 13, 2023
Merged

Preventing update/insert of read-only fields in a table by user#1596
ayush3797 merged 64 commits intomainfrom
dev/agarwalayush/PreventingUpdateForReadOnlyColumns

Conversation

@ayush3797
Copy link
Copy Markdown
Contributor

@ayush3797 ayush3797 commented Jul 20, 2023

Why make this change?

There are certain type of columns in databases which cannot be provided a value (not even null value) for by the user. Eg. in MsSql tables, we cannot provide values for columns that are computed base on other columns in the table or have a datatype of timestamp/rowversion. Similarly for PgSql,/MySql we cannot provide a value for generated columns. This PR prevents DAB from allowing user to attempt an update/insert of such columns. The way DAB will do this is by collecting metadata about columns during the startup phase and populate the IsReadOnly property of the ColumnDefinition of each column in the table. More details about the specifics can be found on the linked issues for MsSql(#1453), PgSql(#1584), MySql(#1583).

NOTE: The columns which are autogenerated are also considered as read-only columns irrespective of the database flavor (MsSql/PgSql/MySql).

What is this change?

  • Added a new boolean property IsReadOnly to ColumnDefinition class which if true, will indicate that the column is read-only, i.e. it cannot be provided a value for (via INSERT/UPDATE).
  • Added a new method GetQueryToGetReadOnlyColumns() to IQueryBuilder.cs class which will have its overridden implementation in Pg/My/MsSql. This method will return the query that will fetch the metadata about the whether a column is read-only.
  • Added validations to RequestValidator.cs class which will ensure that no read-only column is present the request body either for update (via Upsert/UpsertIncremental/Update/UpdateIncremental) or insert operations.
  • Added similar validations to SqlInsertQueryStructure.cs/SqlUpdateQueryStructure.cs- classes as the request validation stage is not a part of the codeflow for GQL requests.
  • Via GQL, value for a read-only field cannot be provided. This will be enabled by adding the AutoGeneratedDirectiveType when a column is read-only. Previous this directive was only added for autogenerated fields (which is a subset of read-only fields).

Implemented Behaviors:

  1. When a read-only field is included in the request body for mutation: This is a bad request as we cannot provide values for read-only fields. We will throw an exception no matter what operation is being executed (PUT/PATCH/POST via REST). For create/update via GQL, we would see a warning in the BCP UI for read-only fields as well that the field is not valid for mutation (just like we see currently for autogen fields).
  2. When a read-only field is excluded from the request body for mutation: This is a valid scenario. In this case (for PUT/PATCH operations via REST), we won't NULL out the field's value but let the responsibility on the database to deal with it. For other operations, we really don't need to do anything as the field is not present in the request body.

How was this tested?

  • Integration Tests

@ayush3797 ayush3797 self-assigned this Jul 20, 2023
@ayush3797 ayush3797 added bug Something isn't working pgsql an issue thats specific to pgsql mssql an issue thats specific to mssql labels Jul 20, 2023
@ayush3797 ayush3797 added this to the 0.9 milestone Jul 20, 2023
@ayush3797 ayush3797 changed the title Preventing update/insert of read-only fields by user Preventing update/insert of read-only fields in a table by user Jul 20, 2023
Comment thread src/Core/Resolvers/MySqlQueryBuilder.cs Outdated
Comment thread src/Core/Resolvers/MySqlQueryBuilder.cs
Comment thread src/Service.Tests/SqlTests/RestApiTests/Put/PutApiTestBase.cs
Comment thread src/Service.Tests/SqlTests/RestApiTests/Patch/PatchApiTestBase.cs
Comment thread src/Service.Tests/SqlTests/RestApiTests/Patch/PatchApiTestBase.cs Outdated
Comment thread src/Service.Tests/SqlTests/RestApiTests/Patch/MsSqlPatchApiTests.cs
Comment thread src/Service.Tests/SqlTests/RestApiTests/Insert/InsertApiTestBase.cs Outdated
Copy link
Copy Markdown
Contributor

@seantleonard seantleonard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarification on how tests validate behavior -> would be good to be explicit in comments across tests.

Question about how post mutation select uses TableDefinition.AllColumns() which may result in not honoring read permissions or may not honor GraphQL selection set fields / REST request querystring $select fields.

@Aniruddh25
Copy link
Copy Markdown
Collaborator

Clarification on how tests validate behavior -> would be good to be explicit in comments across tests.

Question about how post mutation select uses TableDefinition.AllColumns() which may result in not honoring read permissions or may not honor GraphQL selection set fields / REST request querystring $select fields.

I think Shyam's PR should handle that separately.

Copy link
Copy Markdown
Collaborator

@Aniruddh25 Aniruddh25 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, few nits. Thanks!

Comment thread src/Service.Tests/DatabaseSchema-MsSql.sql Outdated
Comment thread src/Service.Tests/DatabaseSchema-MsSql.sql Outdated
Comment thread src/Service.Tests/dab-config.MsSql.json
Comment thread src/Service.Tests/SqlTests/RestApiTests/Put/PutApiTestBase.cs
Comment thread src/Service.Tests/SqlTests/RestApiTests/Put/MsSqlPutApiTests.cs Outdated
Comment thread src/Service.Tests/SqlTests/RestApiTests/Put/MsSqlPutApiTests.cs
Comment thread src/Service.Tests/SqlTests/RestApiTests/Patch/PatchApiTestBase.cs
Comment thread src/Service.Tests/SqlTests/RestApiTests/Patch/MsSqlPatchApiTests.cs Outdated
Comment thread src/Service.Tests/SqlTests/RestApiTests/Patch/MsSqlPatchApiTests.cs
Comment thread src/Service.Tests/SqlTests/RestApiTests/Patch/MsSqlPatchApiTests.cs Outdated
Comment thread src/Service.Tests/SqlTests/RestApiTests/Insert/MsSqlInsertApiTests.cs Outdated
Copy link
Copy Markdown
Contributor

@seantleonard seantleonard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circled back to a few areas where the validation query for a test doesn't look to actually validate what you are checking for. Some tests were updated to accommodate, but there are still some leftovers to address.

…e computed columns are not nulled out when excluded from a patch update request.
Copy link
Copy Markdown
Contributor

@seantleonard seantleonard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for addressing comments and implementing this feature! I added one last commit to address a comment that is consistent with the other changes you were making for the sake of time.

@ayush3797 ayush3797 enabled auto-merge (squash) September 13, 2023 06:24
@ayush3797 ayush3797 merged commit d9f2a1a into main Sep 13, 2023
@ayush3797 ayush3797 deleted the dev/agarwalayush/PreventingUpdateForReadOnlyColumns branch September 13, 2023 06:37
ayush3797 added a commit that referenced this pull request Sep 18, 2023
## Why make this change?
Add support for allowing extraneous fields in request body as per:
#1606.

## What is this change?
DAB will expose another CLI option in the `init` command
`rest.request-body-strict`, which when set to true/false, would set the
property `runtime.rest.request-body-strict` as `true`/`false` in the
generated runtime config file. What this essentially means is that, as
part of the REST mutations (POST/PUT/PATCH), there can be extraneous
fields present in the request body and they will be ignored. Default
behavior of DAB will continue to be the same as what it is today, i.e.
any extraneous fields in the request body would return an error. So to
say, the default value of `runtime.rest.request-body-strict` is `true`.

## Additional change
Refactored `RequestValidator.cs` class to be a singleton dependent on
`ISqlMetaDataProvider` and `RuntimeConfigProvider` services. Better
presents its dependency on the two services and simplifies the code.

## What are the different extraneous fields?
1. Fields in request body that do not map to any backing column in the
table/view. They will be ignored.
2. Fields that are repeated - present as PK in the request URL for
PUT/PATCH requests and also present in the request body. The ones in the
request body will be ignored.
3. Read-only fields. The support for this will be added in a subsequent
PR: #1596.
-> Read-only field are: **Computed** (or Generated) / **AutoGenerated**
fields in MsSql/MySql/PgSql
 -> **timestamp** fields in MsSql

## Questions:

**1. What about authorization of extraneous fields?**
When operating in flexible mode, the user is _not_ authorized for
extraneous fields NOT defined on table because those fields are ignored.
For all other cases, authorization goes as usual.

## How was this tested?

- [x] Integration Tests - Added tests to validate that extraneous fields
are allowed in the request body for all the 3 relational DBs in the
`{*}RestBodyNonStrictModeTests.cs` classes inheriting from the base
class `RestBodyNonStrictModeTests.cs`. (* = MsSql,MySql,PostgreSql)
- [x] Unit Tests - Added unit test to validate the functionality of the
newly added --`rest.request-body-strict` feature in the init command.

---------

Co-authored-by: Aniruddh Munde <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working mssql pgsql mysql an issue that applies to all relational databases, same as labeling with `mssql` `mysql` and `pgsql`

Projects

Status: Done

3 participants