Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GraphQL - Roles defined without read action returns error #1464

Closed
1 task done
severussundar opened this issue May 1, 2023 · 5 comments · Fixed by #1874 or #1893
Closed
1 task done

GraphQL - Roles defined without read action returns error #1464

severussundar opened this issue May 1, 2023 · 5 comments · Fixed by #1874 or #1893
Assignees
Labels
bug Something isn't working graphql
Milestone

Comments

@severussundar
Copy link
Contributor

severussundar commented May 1, 2023

When a role is defined without read action, mutations performed in the context of that role, returns an error response. However, at the database level, the mutation(update,insert, etc. action) succeeds.

Repro steps:

  1. In the config file available in the main branch, remove the read action for the Anonymous role
  2. Execute the following mutation request in the context of Anonymous role
mutation {
     updatebook(id: 1, item: {title: "Harry Potter and the Goblet of Fire"}){
          id
          title
     }
}

Mutation - Read role not defined bug

Config file:

{
  "$schema": "https://github.com/Azure/data-api-builder/releases/download/vmajor.minor.patch/dab.draft.schema.json",
  "data-source": {
    "database-type": "mssql",
    "connection-string": "...",
    "options": {
      "set-session-context": false
    }
  },
  "runtime": {
    "rest": {
      "enabled": true,
      "path": "/api"
    },
    "graphql": {
      "enabled": true,
      "path": "/graphql",
      "allow-introspection": true
    },
    "host": {
      "cors": {
        "origins": [],
        "allow-credentials": false
      },
      "authentication": {
        "provider": "StaticWebApps"
      },
      "mode": "development"
    }
  },
  "entities": {
    "Book": {
      "source": {
        "object": "books",
        "type": "table"
      },
      "graphql": {
        "enabled": true,
        "type": {
          "singular": "book",
          "plural": "books"
        }
      },
      "rest": {
        "enabled": true
      },
      "permissions": [
        {
          "role": "anonymous",
          "actions": [
            {
              "action": "create"
            },
            {
              "action": "update"
            },
            {
              "action": "delete"
            }
          ]
        },
        {
          "role": "authenticated",
          "actions": [
            {
              "action": "create"
            },
            {
              "action": "read"
            },
            {
              "action": "update"
            },
            {
              "action": "delete"
            }
          ]
        }
      ]
    }
  }
}

The mutation was executed in the context of Anonymous role.

In these requests,
a) The database operation goes through when the corresponding permission is setup (create action for a create mutation, update action for update mutation, etc.)
b) The lack of read action causes the authz error to be thrown.

Note We observe this behavior only in SQL DB types. With cosmos, even when read permission is not setup, valid response (response with values for fields requested in the selection set) is returned.

Tasks

  1. bug cosmos graphql hacktoberfest
    neeraj-sharma2592 sajeetharan
@severussundar severussundar added this to the May2023 milestone May 1, 2023
@severussundar severussundar self-assigned this May 1, 2023
@Aniruddh25 Aniruddh25 modified the milestones: 0.8, 0.9 Jul 6, 2023
@severussundar
Copy link
Contributor Author

In this case, the database operation succeeds (the update/insert/delete goes through without any issues), but we return error since the read action is not defined for the role. This is ambiguous as it is natural to conclude that the update/insert/delete did not go through since error is being returned.

Note: We don't see this behavior with Cosmos. Even if read action is not defined for the role, valid response (response with values for the fields specified in the selection set) is returned.

To make the behavior more consistent, we could do one of the following things.
a) Check if read action is defined for the role and if not defined, the update/insert/delete operation at the database layer need not be executed (The AuthZ error can be thrown before executing the update/insert/delete database query). So, this will force users to setup read action in addition to the create/update/delete for that role, thereby preventing this inconsistent behavior. Or a slight varation of this could be to allow when the mutation when only __typename is present in the selection set. When any of the entity fields are present, then the mutation request can be errored out.

b) The AuthZ checks before executing the select statement as part of the mutation can be relaxed to validate if the corresponding mutation action (Ex: update action for an update mutation, delete action for delete mutation and create action for a create mutation) is setup and not require the read action to be setup.
At the moment, the AuthZ checks for REST requests work this way.
For ex: for a given role, if only create, update and delete actions are setup, the PATCH request works fine and returns a response with updated/created item details.
c) The error message can be more explicit to state that the database operation did succeed, just that the lack of read action leads to authz error response.

@yorek @JerryNixon @Aniruddh25 @seantleonard @sajeetharan Please kindly share your thoughts

@seantleonard
Copy link
Contributor

We'll need to see if HotChocolate supports grouping the update/read-result to be protected by the runtime config defined permissions for the update operation, out of the box.

Since the selection set is a read operation, HotChocolate would enforce the authorization rules we set on the Object Type definition in the GraphQL schema for read operations.

@Aniruddh25 Aniruddh25 added the bug Something isn't working label Jul 10, 2023
@JerryNixon
Copy link
Contributor

Desired behavior

If READ is not supported, rewrite the select to primary keys only.

@Aniruddh25
Copy link
Contributor

@JerryNixon, shouldnt the select be allowed to all the fields that are allowed for the mutation: e.g. title and id in this case, not just the primary key?

@aaronpowell
Copy link
Contributor

From a GraphQL standpoint, the behaviour of SQL backends is correct while Cosmos is incorrect, based on the auth config provided the anonymous user is allows to write but it can't read data back out, and a mutation is a two-part process, mutate the database then read the database.

In a custom GraphQL server where you aren't doing one-to-one data mapping a mutation doesn't have to represent a data construct in our backend, it's indicating a concept that you're performing. Using a trivia game example, you could have a mutation createGame which doesn't take any parameters but it uses that information to go and create a record in the database with some initial game state, and then there's a selection set you can pick fields from whatever data structure that is deemed right at that point. This will be implemented as "modify database" and then "query database", and if you don't have read permissions you'd get the above outlined error.

So is it more of an education piece, people aren't aware that they are really performing two database operations CREATE (or UPDATE or DELETE) followed by a SELECT? And if I am denied permissions for SELECT then it'd make sense I get an error, unless I try to just get back __typename (since that doesn't hit the database).

@severussundar severussundar modified the milestones: 0.9rc, 0.10rc Aug 30, 2023
seantleonard pushed a commit that referenced this issue Dec 1, 2023
…sions - SQL database types (#1874)

## Why make this change?

- Closes #1464 
- At the moment, when a mutation operation is executed using a role
which does not have read permissions (and Anonymous does not have read
permissions), the mutation operation succeeds at the database layer but
a generic AuthZ error message is returned. This could lead to the user
concluding that the database operation did not go through because of the
error response.
- This PR adds changes to return a helpful error message to the users -
`The mutation operation {operation name} was successful but the current
user is unauthorized to view the response due to lack of read
permissions`
## What is this change?

- The objective of this change is to return a helpful error message that
lets users know a) what has happened as a result of executing this
mutation request b) the reason as why this error message is returned
- Presence of read permission is evaluated for the current role (with
which the request was executed) as well as Anonymous role (because, for
graphQL, read permissions is inherited from Anonymous role by other
roles). If read permission is inapplicable, then a custom error message
is returned.
 

## How was this tested?
- [x] Integration Testing
- [x] Manual Testing

The request is executed in the context of Anonymous role. Anonymous role
does not have read permissions configured but has the other three -
create, update and delete configured.

**Response:**

![image](https://github.com/Azure/data-api-builder/assets/11196553/fe31bb33-fbe3-472d-8961-4e2b7afaf76f)

**Create operation executed successfully**

![image](https://github.com/Azure/data-api-builder/assets/11196553/bca54e12-9742-4c96-8743-fb93c35def12)


## Error Messages

**Current Format (for mutation without read permission)**

![image](https://github.com/Azure/data-api-builder/assets/11196553/62de9657-b07b-499e-8680-7f37312bc387)


**New Format introduced by this change (for mutation without read
permission)**

![image](https://github.com/Azure/data-api-builder/assets/11196553/93960121-e6f3-4912-a326-aaeb5d78ceb3)

The operation name such as `createbook`/`createPublisher` is included in
the error message to help identify the operation which resulted in error
when there are multiple mutations in the same request

![image](https://github.com/Azure/data-api-builder/assets/11196553/bdfab0fe-dce0-4601-bbc6-be2729cf6335)
neeraj-sharma2592 added a commit that referenced this issue Dec 22, 2023
…he Mutation result. (#1893)

## Why make this change?
Resolves #1464 for CosmosDB.

## What is this change?
Verifying the read access of anonymous users prior to transmitting the
Mutation result

## How was this tested?

- [X] Integration Tests
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment