amplify-category-api icon indicating copy to clipboard operation
amplify-category-api copied to clipboard

Groups authorization groupsField create protection not working with multiple rules

Open parvusville opened this issue 2 years ago • 3 comments

How did you install the Amplify CLI?

No response

If applicable, what version of Node.js are you using?

No response

Amplify CLI Version

12.0.1

What operating system are you using?

Pop Os

Did you make any manual changes to the cloud resources managed by Amplify? Please describe the changes made.

no

Describe the bug

So I'm not sure if this is intentional or not. If I have only { allow: groups, groupsField: "group" } on my @model, as expected I can only create items with the group I am member of. Same goes if my model only has {allow: groups, groupsField: "orgBusinessId", groupClaim: "orgBusinessAdmin"}, I can only create items if the groupClaim matches groupsField.

But if I have them both, there seems to be trouble. Lets say I am logged in with a user that is in a Cognito group "group-a". With the example model below, I am able to create a Vehicle with group: "group-a", orgBusinessId: "literally anything" . And same goes the other way too, if I have a groupClaim "businessAdmin: business-a", I can create a Vehicle with that businessId and any group I want. Is this how it should be? I am on Transformer v1.

  @model
  @auth(
    rules: [
      { allow: private, provider: iam }
      { allow: groups, groupsField: "group" }
      { allow: groups, groupsField: "organizationId", groupClaim: "orgAdmin" }
      {
        allow: groups
        groupsField: "orgBusinessId"
        groupClaim: "orgBusinessAdmin"
      }
      { allow: public, operations: [read] }
    ]
  ) {
  id: ID!
  group: String
  organizationId: ID
  orgBusinessId: ID
}

I see that with this field level @auth rule I can prevent the group value of an existing record being changed, even with the correct orgBusinessAdmin groupClaim. I can still create record with any group though.

  group: String
    @auth(
      rules: [
        { allow: groups, groupsField: "group" }
        { allow: private, operations: [read] }
        { allow: public, operations: [read] }
      ]
    )

Expected behavior

I expect not to be able to create a Model with group that I am not part of, when that given groupsField is set with @auth rule.

Reproduction steps

  1. Use the provided example schema
  2. Create an user with group "group-a"
  3. See how you are able to create a Vehicle with group: "group-a" and an arbitrary orgBusinessId.

Project Identifier

3c5cae686b22c72a9c59640b51e0f075

Log output

# Put your logs below this line


Additional information

No response

Before submitting, please confirm:

  • [X] I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.
  • [X] I have removed any sensitive information from my code snippets and submission.

parvusville avatar May 27 '23 13:05 parvusville

Another thing I observed with the example model (let's say its Vehicle) from the original post is that I can update a Vehicle that belongs into my group, to have any group:

I am logged in with a Cognito user that has a custom claim orgAdmin: '29c96e92-a1f0-417a-a957-a5f2a8fbae1c', and does not belong to any group.

Trying to create a Vehicle with organizationId I don't belong to returns Unauthorized, as expected

 mutation MyMutation {
  createVehicle(input: {name: "New Vehicle", organizationId: "doesnotexist"}) {
    id
  }
}

{
  "data": {
    "createVehicle": null
  },
  "errors": [
    {
      "path": [
        "createVehicle"
      ],
      "data": null,
      "errorType": "Unauthorized",
      "errorInfo": null,
      "locations": [
        {
          "line": 2,
          "column": 3,
          "sourceName": null
        }
      ],
      "message": "Not Authorized to access createVehicle on type Vehicle"
    }
  ]
}

Now when I create a Vehicle with appropriate organizationId, I can update it whatever organizationId I want?

mutation MyMutation {
  createVehicle(input: {name: "New Vehicle", organizationId: "29c96e92-a1f0-417a-a957-a5f2a8fbae1c"}) {
    id
  }
}
{
  "data": {
    "createVehicle": {
      "id": "59cec61c-dd51-4bd4-a688-2037d7ceef2c"
    }
  }
}

mutation MyMutation {
  updateVehicle(input: {id: "59cec61c-dd51-4bd4-a688-2037d7ceef2c", organizationId: "doesnotexist"}) {
    id
    group
    organizationId
  }
}

{
  "data": {
    "updateVehicle": {
      "id": "59cec61c-dd51-4bd4-a688-2037d7ceef2c",
      "group": null,
      "organizationId": "doesnotexist"
    }
  }
}

And now when I try to update the same Vehicle, I cant as expected. However I do not get Unauthorized, but DynamoDB:ConditionalCheckFailedException

mutation MyMutation {
  updateVehicle(input: {id: "59cec61c-dd51-4bd4-a688-2037d7ceef2c"}) {
    id
    group
    organizationId
  }
}
{
  "data": {
    "updateVehicle": null
  },
  "errors": [
    {
      "path": [
        "updateVehicle"
      ],
      "data": null,
      "errorType": "DynamoDB:ConditionalCheckFailedException",
      "errorInfo": null,
      "locations": [
        {
          "line": 2,
          "column": 3,
          "sourceName": null
        }
      ],
      "message": "The conditional request failed (Service: DynamoDb, Status Code: 400, Request ID: ET2SSKHLHPAT88MRRLL277A9IBVV4KQNSO5AEMVJF66Q9ASUAAJG)"
    }
  ]
}

I verified that the same behaviour exist, if I am logged with a user that belongs to group and has no custom claims. I can update a Vehicle that belongs into my group, to be into any other group. Which surely should not happen?

parvusville avatar Jun 30 '23 08:06 parvusville

Hi @parvusville, the behavior you're seeing is expected. The @auth rules on a model are treated as a set of OR conditions, so if the state of the user identity matches any of the allowed Auth states, they will be allowed to do that operation. If you want to be more restrictive about which fields get updated based on specific Auth rule, you need to define them on field level.

phani-srikar avatar Aug 21 '23 23:08 phani-srikar

Hello @phani-srikar , thanks for the information. As mentioned in my post though, having a field level rule did not prevent me from setting any value to that field on creation, even if the rule is not met. So that does not really work

parvusville avatar Aug 22 '23 05:08 parvusville