aws-amplify / amplify-category-api

The AWS Amplify CLI is a toolchain for simplifying serverless web and mobile development. This plugin provides functionality for the API category, allowing for the creation and management of GraphQL and REST based backends for your amplify project.
https://docs.amplify.aws/
Apache License 2.0
88 stars 76 forks source link

api gql-compile produces wrong auth VTL for Mutation #2454

Open nilyin opened 5 months ago

nilyin commented 5 months ago

How did you install the Amplify CLI?

npm

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

v21.7.1

Amplify CLI Version

12.10.3

What operating system are you using?

Mac, Win10

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

No

Describe the bug

after amplify api gql-compile the vtl file for deleteComponent mutation has no code to process "User Pool Authorization", which results to authorization error in graphql Mutation deleteComponet. My generated Mutation.deleteComponent.auth.1.res.vtl file content (bad file):

## [Start] Authorization Steps. 
$util.qr($ctx.stash.put("hasAuth", true))
#set( $isAuthorized = false )
#if( $util.authType() == "API Key Authorization" )
$util.unauthorized()
#end
#if( $util.authType() == "IAM Authorization" )
  #foreach( $adminRole in $ctx.stash.adminRoles )
    #if( $ctx.identity.userArn.contains($adminRole) && $ctx.identity.userArn != $ctx.stash.authRole && $ctx.identity.userArn != $ctx.stash.unauthRole )
      #return($util.toJson({}))
    #end
  #end
$util.unauthorized()
#end
#if( $util.authType() == "User Pool Authorization" )

#end
#if( !$isAuthorized )
$util.unauthorized()
#end
$util.toJson({"version":"2018-05-29","payload":{}})
## [End] Authorization Steps.

when i've tried to use new machine and installed all codebase and deps i initially received correct (good) file content for "User Pool Authorization":

## [Start] Authorization Steps. 
$util.qr($ctx.stash.put("hasAuth", true))
#set( $isAuthorized = false )
#if( $util.authType() == "API Key Authorization" )
$util.unauthorized()
#end
#if( $util.authType() == "User Pool Authorization" )
  #if( !$isAuthorized )
    #set( $ownerEntity0 = $util.defaultIfNull($ctx.result.userCreated, null) )
    #set( $ownerClaim0 = $util.defaultIfNull($ctx.identity.claims.get("sub"), null) )
    #if( !$util.isNull($ownerClaim0) )

      #set( $ownerClaimsList0 = [] )
      #if( $ownerEntity0 == $ownerClaim0 || $ownerClaimsList0.contains($ownerEntity0) )
        #set( $isAuthorized = true )
      #end
    #end
  #end
  #if( !$isAuthorized )
    #set( $ownerEntity1 = $util.defaultIfNull($ctx.result.owners, null) )
    #set( $ownerClaim1 = $util.defaultIfNull($ctx.identity.claims.get("sub"), null) )
    #if( !$util.isNull($ownerClaim1) )

      #set( $ownerClaimsList1 = [] )
      #foreach( $allowedOwner in $ownerEntity1 )
        #if( $allowedOwner == $ownerClaim1 || $ownerClaimsList1.contains($allowedOwner) )
          #set( $isAuthorized = true )
        #end
      #end
    #end
  #end
#end
#if( !$isAuthorized )
$util.unauthorized()
#end
$util.toJson({"version":"2018-05-29","payload":{}})
## [End] Authorization Steps.

when I have initialized my backend env and did amplify pull my good vtl file above was rewritten to bad one from the cloud backend. But when weird things happened: my following amplify api gql-compile commands stopped generating the correct file (only bad file above was genereted every time). BTW my deleting of build/resolvers/* files didn't help at all.

What could happen? Why vtl engine stopped working correctly if my original schema.graphql file wasn't changed?

Expected behavior

correct (good) vtl / reolver file is to be generated

Reproduction steps

  1. amplify pull from my backend
  2. run amplify api gql-compile

Project Identifier

0682ade323272668435183796fe4bc9e

Log output

``` # Put your logs below this line ```

Additional information

No response

Before submitting, please confirm:

ykethan commented 5 months ago

Hey,👋 thanks for raising this! I'm going to transfer this over to our API repository for better assistance 🙂

AaronZyLee commented 5 months ago

I notice you have IAM Authorization in the bad code which is missing in the correct code. Do you have any admin roles defined in the file custom-roles.json which is mentioned here? I also cannot find it in the uploaded project folder, which could be related to the difference of the resolvers.

nilyin commented 5 months ago

Hi, I don't know why correct vtl code has missing IAM Authorization section, as my schema.graphql contains: { allow: public, operations: [read], provider: iam } in @auth for Component model. I can provide Component model definition or whole schema file, if needed. I have no admin roles defined as well as custom-roles.json file in my project. I am using multi auth: Cognito UserPool for authorized users and IAM for Unauthorized ones.

biller-aivy commented 5 months ago

I maybe had some similar problems. Try to reorder the rules array, than it should be work. If yes, maybe there is a bug than.

nilyin commented 5 months ago

I tried to reorder @auth rules but it hasn't solved the problem. My current rules set is given below:

type Component @model @auth (
        rules: [
          { allow: public, operations: [read], provider: iam },
          { allow: public, operations: [read] },
          { allow: owner, ownerField: "userCreated", identityClaim: "sub"},
          { allow: owner, ownerField: "owners", identityClaim: "sub"},
          { allow: owner, ownerField: "organizationID", identityClaim: "website", operations: [create, read] },
          { allow: private, operations: [read] }
      ]
  )

I have also just upgraded amplify-cli to 12.11.1 but had no change.

biller-aivy commented 5 months ago

@nilyin an other tip, don't use sub as the claim. When you ever have to restore your users to a new instance of cognito Pool, the sub will be not the same because this is unique in the whole cognito service. Username is the "for me" better solution and in my setup, the same value like sub.

Second info: I had to play around some pushes, I couldn't create items with a create rule. After I played with the rules, at some point it just works. (Maybe this was an other problem like cache or something)

nilyin commented 5 months ago

@biller-aivy thanks for your advice on token's username as a claim. BTW, I was thinking on using sub value for id field of my User model, but stick with generating different id (to be independent from potentially numerous IDPs). My User's owner field keeps actual 'sub' value. Do you use the same approach? if not, why?

About current issue: in my case only resolver for deleteComponent Mutation is broken. My experiments show that it happened after amplify pull command. As this pulling shouldn't touch / change my local amplify/backend/api/{myprojectname}/schema.graphql file the problem IMHO is not with schema file but in some other file / setting that has been modified by pulling from cloud backend. I was trying to look through all the changes made, but haven't detected anything suspicious. Still waiting for a help from Amplify team.

biller-aivy commented 5 months ago

@biller-aivy thanks for your advice on token's username as a claim. BTW, I was thinking on using sub value for id field of my User model, but stick with generating different id (to be independent from potentially numerous IDPs). My User's owner field keeps actual 'sub' value. Do you use the same approach? if not, why?

About current issue: in my case only resolver for deleteComponent Mutation is broken. My experiments show that it happened after amplify pull command. As this pulling shouldn't touch / change my local amplify/backend/api/{myprojectname}/schema.graphql file the problem IMHO is not with schema file but in some other file / setting that has been modified by pulling from cloud backend. I was trying to look through all the changes made, but haven't detected anything suspicious. Still waiting for a help from Amplify team.

{
        allow: owner
        identityClaim: "username" #  explicit use of username
      }

with this, you can use username as clam in the Schema. In my Case, sub and username is the same value. The Problem is, when you create a new UserPool, than the sub is different from username and different from current sub.

Or did I misunderstand your question?

nilyin commented 4 months ago

@biller-aivy I was asking about id field for your user record. Is it different from sub value generated by Cognito and is sub value only kept in owner attribute?

nilyin commented 4 months ago

to Amplify team: is there any way (such as command line option) to turn on debug or verbose mode for amplify api gql-compile command?

biller-aivy commented 4 months ago

@biller-aivy I was asking about id field for your user record. Is it different from sub value generated by Cognito and is sub value only kept in owner attribute?

At the moment it is the same id like the sub/username but it is not necessary for my logic. I replaced all sub to username in my code. And the user I call by owner with an secondary index. The risk is to high if we need a recovery system with a new userpool.

nilyin commented 4 months ago

@AnilMaktala hi, did you find any clue to my problem with corrupted deleteComponent Mutation's VTL generation? Or at least pls. give me an idea how can i debug amplify api gql-compile command by myself.

phani-srikar commented 3 months ago

Hi @nilyin, can you check if you have a file override for that resolver defined under api/<apiName>/resolvers directory? This is not under the build directory.

nilyin commented 3 months ago

Hi @phani-srikar : my api/<apiName>/resolvers folder has no overrides. Pls. let me know if you need any other information.

AnilMaktala commented 1 month ago

Hey @nilyin, Can you please try adding below sample model in your local machine and run amplify gql-compile and provide us the generated resolvers?

type Component @model @auth (
        rules: [
          { allow: public, operations: [read], provider: iam },
          { allow: public, operations: [read] },
          { allow: owner, ownerField: "userCreated", identityClaim: "sub"},
          { allow: owner, ownerField: "owners", identityClaim: "sub"},
          { allow: owner, ownerField: "organizationID", identityClaim: "website", operations: [create, read] },
          { allow: private, operations: [read] }
      ]
  )
nilyin commented 1 month ago

hi @AnilMaktala , thank you for getting back to me. So, what I've done: 1) i have replaced schema.graphql file in my existing project with file, which only has your sample empty model 2) I have cleaned all current resolvers in <myproject>/build/resolvers folder 3) i've run command amplify api gql-compile

after that I have got this output in terminal:

` ⚠️ WARNING: Schema is using an @auth directive with deprecated provider 'iam'. Replace 'iam' provider with 'identityPool' provider. 🛑 Removing a model from the GraphQL schema will also remove the underlying DynamoDB table. This update will remove table(s) [ArchitectureTable, ComponentSubscriptionTable, OrganizationTable, OsTable, RoleTable, TeamTable, UserTable] ALL EXISTING DATA IN THESE TABLES WILL BE LOST! If this is intended, rerun the command with '--allow-destructive-graphql-schema-updates'.

The generated resolvers and schema.graphql are attached: build_folder_resolvers.zip

nilyin commented 1 month ago

Hi @AnilMaktala are there any news? It looks like single model (Component) schema.graphql generates not empty User Pool Authorization section.

What should I do next?

Is it possible that things mentioned in this amplify api gql-compile command message affect the deleteComponent resolver generation:

Be careful when using @auth directives on a field in a root type. @auth directives on field definitions use the source object to perform authorization logic and the source will be an empty object for fields on root types. Static group authorization should perform as expected. ✅ GraphQL schema compiled successfully.

AnilMaktala commented 1 week ago

Hi @nilyin, The issue you are facing appears to be specific to your particular scenario. Would you be available for a call where we can screen share, allowing me to better understand and assist you with resolving the problem?

nilyin commented 1 week ago

Anil, hi. Yes, I'll be available for a call Mon -Thursday upcoming week. Please send me a link for a meeting at your convenience.

Thank you, N.

пт, 6 сент. 2024 в 23:00 Anil @.***> написал(-а):

Hi @nilyin, The issue you are facing appears to be specific to your particular scenario. Would you be available for a call where we can screen share, allowing me to better understand and assist you with resolving the problem?

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>

nilyin commented 1 day ago

@AnilMaktala hi, can you please offer possible time-slots for today or dates at the end of next week? You may send it to directly to my email.