Amplify-cli: Not Authorized to access field on nested type (without model) using IAM

Created on 22 Dec 2019  路  10Comments  路  Source: aws-amplify/amplify-cli

Describe the bug
When you have a model, that contains nested data from other types, the Authorization rules in the resolvers seem to get wonky in terms of who is authorized to view what.

Data is accessible via the default cognito access, when using Group or Private however IAM functions in Lambda get all the field values replaced by nulls on the request and recieve an error when trying to post.

To Reproduce
Steps to reproduce the behavior:

  1. Create a schema which has @auth directives including IAM and nested types
  2. Create a lambda function to query and/or mutate the model
  3. Fill up some data via a cognito user.
  4. Data within the nested element returns null values.

-- or --

type Product @model
  @auth(rules: [
    { allow: private, provider:userPools, operations: [read]},
    { allow: groups, groups: ["Admin"], operations: [create, update, read, delete]}
    { allow: private, provider: iam, operations: [create, update, read, delete] }
  ])
 {
  id: ID!
  availableSlots: [AvailableSlots]
 }

type AvailableSlots {
  date: AWSDate
  times: [AvailableHours]
}

type Mutation {
  bookSlot(date: AWSDateTime): String @function(name: "bookViewing-${env}")
}

Expected behavior
I expect the nested types to inherit the same permissions as the other fields since I did not set different permissions on these fields.

@auth graphql-transformer question

Most helpful comment

@jonmifsud Could you please try this workaround, while I'm working on auth rule propagation for scenarios like this:

  • Place @aws_iam directive on your UserTags type
  • Create a policy for the IAM user/group you've to make sure it can access the UserTags type under the AppSync API.

This should solve your problem. Please get back to me with the results.

All 10 comments

I seem to have run into a similar problem, but mine is even more extreme. The below example might help solve the root of the problem.

type User @model (subscriptions: { level: off })
@key(fields: ["id"])
@auth (rules: [
{allow: public, provider: iam, operations: [read]},
{allow: private, provider: userPools, operations: [read, create, update, delete]},
{allow: private, provider: iam, operations: [create, read, update, delete]}])
{
id: ID!
userTags: [UserTags]
}

type UserTags {
id: String
name: String
}

With the above schema the cognito user can successfully access the userTags attribute for the user, but for iam role (lambda function in this case) they get the following error: GraphQL error: Not Authorized to access id on type UserTags. GraphQL error: Not Authorized to access name on type UserTags. Note that this issue occurs when UserTags is not a @model

Amplify CLI Version
4.8.0

@attilah / @kaustavghosh06 - let me know if there's any way at all I could help in getting a fix for this. We're possibly blocked from going live with this issue as it's likely going to impact us at multiple points as the solution we are working on does require quite a bit of lambda processing.

I can also confirm @grigull's statement that users via cognito always have access to the full/complete information. The issue seems to be exclusively on the IAM access component when mixing it with @auth directives.

@jonmifsud Could you please try this workaround, while I'm working on auth rule propagation for scenarios like this:

  • Place @aws_iam directive on your UserTags type
  • Create a policy for the IAM user/group you've to make sure it can access the UserTags type under the AppSync API.

This should solve your problem. Please get back to me with the results.

Hit this issue and setting @aws_api_key at the end of my subtype definition worked!

Had me stumped for a little bit, would be nice for it to pass it through if it no auth directive policies to apply from the sub type but you are otherwise allowed access at the parent model type level.

I think some docs that better demonstrate public data access on an amplify project you setup with cognito auth baked in. Anyhow, generally loving the amplify tools, I get to dip into it every couple of months and I love where it's going!

The patch above does not fully solve this problem. It only propagates permissions 1-level, not arbitrary levels deep.
For those folks affected the workaround is to annotate with the permissions you want to cascade down,

@aws_api_key to鈥擜 field uses API_KEY for authorization.
@aws_iam鈥擜 field uses AWS_IAM for authorization.
@aws_oidc鈥擜 field uses OPENID_CONNECT for authorization.
@aws_cognito_user_pools鈥擜 field uses AMAZON_COGNITO_USER_POOLS for authorization.

So far I haven't seen any downsides, so I recommend annotating every type without a model with all of the auth mechanisms you use for your API (until of course the patch is extended to do arbitrary nesting/cascading).

I'd have saved a few afternoons' worth of effort, when I tried to use a type in a new nested context only to scratch my head and remember about this bug.

@jonmifsud Could you please try this workaround, while I'm working on auth rule propagation for scenarios like this:

  • Place @aws_iam directive on your UserTags type
  • Create a policy for the IAM user/group you've to make sure it can access the UserTags type under the AppSync API.

This should solve your problem. Please get back to me with the results.

THANKS!!!!!!!!!!!!!!!

Hi @attilah! Thanks for temp fix. Did you have the chance to advance on the auth rule propagation?

+1. Just ran into this with api key auth.

Having the same issue with this schema:

type Registration
  @model
  @key(name: "registrationByDate", fields: ["date"])
  @auth(
    rules: [
      {
        allow: owner
        ownerField: "owner"
        operations: [create, update, delete, read]
      }
    ]
  ) {
  id: ID!
  horeca: Horeca! @connection
  members: [Member]! @connection
  date: String!
  time: String!
  owner: String!
}

type Horeca
  @model
  @key(fields: ["id", "name"])
  @key(name: "horecaByName", fields: ["name", "place"])
  @key(name: "horecaByPlace", fields: ["place", "name"])
  @auth(
    rules: [
      {
        allow: owner
        ownerField: "owner"
        operations: [create, delete, update, read]
      }
    ]
  ) {
  id: ID!
  name: String!
  place: String!
  qr: String
  owner: String!
  registrations: [Registration] @connection
}

type Family
  @model
  @key(name: "byfamilyName", fields: ["familyName"])
  @auth(
    rules: [
      {
        allow: owner
        ownerField: "owner"
        operations: [create, delete, update, read]
      }
    ]
  ) {
  id: ID!
  familyName: String!
  address: String!
  phone: String!
  members: [Member]! @connection
  owner: String!
}

type Member
  @model
  @key(name: "byName", fields: ["name"])
  @auth(
    rules: [
      {
        allow: owner
        ownerField: "owner"
        operations: [create, delete, update, read]
      }
    ]
  ) {
  id: ID!
  family: Family! @connection
  name: String!
  owner: String!
  registrations: [Registration] @connection
}

with this query

mutation createhoreca {
  createHoreca(input:{
    name: "bar 1"
    place:"nijmegen"
    owner:"[email protected]"
  }) {
    id place owner
  } 
}

I receive this error:

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

using @aws-amplify/[email protected]

Sorry, I missed this spot: { allow: private}

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ffxsam picture ffxsam  路  3Comments

adriatikgashi picture adriatikgashi  路  3Comments

jkeys-ecg-nmsu picture jkeys-ecg-nmsu  路  3Comments

jexh picture jexh  路  3Comments

ReidWeb picture ReidWeb  路  3Comments