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
89 stars 77 forks source link

Unable to deploy subscription auth resolvers after upgrading amplify cli #1492

Closed rezab777 closed 6 months ago

rezab777 commented 1 year ago

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.0

What operating system are you using?

Windows

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

No

Describe the bug

I had been using amplify cli version 10.5.1 until I upgraded to the latest version i.e. amplify cli version 12.0.0 in order to use the --minify flag ( the flag did not work as expected in version 10.5.1) .

We are overriding all the auth resolvers as we're using Lambda authorization.

I have noticed that there has been additional logic added to the auth resolvers in the newest version (12.0.0) , namely to search (related to the @searchable directive) and subscription (graphql) auth resolvers .

So I went ahead and updated the search and subscriptions resolvers so they include the latest updates .

Here is what the issue is:

I was able to push the auth resolvers related to search e.g. Query.searchMeasurements.auth.1.req.vtl . But the updated auth resolvers related to graphql subscriptions cause the push to fail with the error message

The following resources failed to deploy:
Resource Name: ▀▀▀redacted▀▀▀ (AWS::CloudFormation::Stack)
Event Type: update
Reason: Circular dependency between resources: [SearchableStack, ▀▀▀redacted▀▀▀]
URL: https://console.aws.amazon.com/cloudformation/home?region=▀▀▀redacted▀▀▀#/stacks/arn%3Aaws%3Acloudformation%3A▀▀▀redacted▀▀▀

Resource is not in the state stackUpdateComplete
Name: ▀▀▀redacted▀▀▀ (AWS::CloudFormation::Stack), Event Type: update, Reason: Circular dependency between resources: [▀▀▀redacted▀▀▀], ▀▀▀redacted▀▀▀

Expected behavior

After updating the custom auth resolvers, changes should deploy.

Reproduction steps

  1. Override graphql subscription resolvers generated by version 10.5.1 by placing it in the resolvers folder. e.g. Subscription.onCreateCustomer.auth.1.req.vtl
  2. Try to push with amplify version 12.0.0

Project Identifier

Project Identifier: 888164d0a62c44d3956d89db2613c7ec

Session Identifier: 0e8bf909-bc9d-4c5e-a038-cac108108654

Log output

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

Additional information

No response

Before submitting, please confirm:

AnilMaktala commented 1 year ago

Hey @rezab777, Thank you for reporting this issue. Please try the instructions provided below and inform us if they successfully resolve the issue you are facing,

  1. Update the CLI to the latest version (12.0.3).
  2. Add the property "DisableResolverDeduping": true to the ./amplify/backend//transform.conf.json file.
  3. Execute the command amplify api gql-compile.
  4. Finally, run amplify push. This should successfully push the changes.
image
rezab777 commented 1 year ago

Thank you @AnilMaktala . The solution you suggested fixed the issue with pushing the resolvers to the cloud .

I am still seeing an error when starting a subscription though. Here's the error:

Error: {
    "errors": [
        {
            "message": "Connection failed: AuthorizerFailureException"
        }
    ]
}
    at Object.error (https://a.b.cdn.console.awsstatic.com/a/v1/UUEPSESYMZITODOR7COQDRMIBJCTVRNH7OA3IVA3TZXO2F6Y5FZQ/main.js:2:4940409)
    at b (https://a.b.cdn.console.awsstatic.com/a/v1/UUEPSESYMZITODOR7COQDRMIBJCTVRNH7OA3IVA3TZXO2F6Y5FZQ/main.js:2:4369146)
    at A (https://a.b.cdn.console.awsstatic.com/a/v1/UUEPSESYMZITODOR7COQDRMIBJCTVRNH7OA3IVA3TZXO2F6Y5FZQ/main.js:2:4369603)
    at e.value (https://a.b.cdn.console.awsstatic.com/a/v1/UUEPSESYMZITODOR7COQDRMIBJCTVRNH7OA3IVA3TZXO2F6Y5FZQ/main.js:2:4370220)
    at Gh.<anonymous> (https://a.b.cdn.console.awsstatic.com/a/v1/UUEPSESYMZITODOR7COQDRMIBJCTVRNH7OA3IVA3TZXO2F6Y5FZQ/main.js:2:4928467)
    at Generator.throw (<anonymous>)
    at s (https://a.b.cdn.console.awsstatic.com/a/v1/UUEPSESYMZITODOR7COQDRMIBJCTVRNH7OA3IVA3TZXO2F6Y5FZQ/main.js:2:4925355)

If this is not helpful, please let me know if I can provide more info .

Thanks

AnilMaktala commented 1 year ago

Hey @rezab777, Sorry for the delay. Would it be possible for you to share the Subscription.onCreateCustomer.auth.1.req.vtl file with us?

rezab777 commented 1 year ago

Hi @AnilMaktala Sure please find below;

## [Start] Authorization Steps. **
$util.qr($ctx.stash.put("hasAuth", true))
#set( $isAuthorized = false )

## BEGIN LAMBDA AUTHORIZATION 
#if( $util.authType() == "Lambda Authorization" )
  #if( !$isAuthorized )
    #set( $staticGroupRoles = [{"claim":"cognito:groups","entity":"Admin"}] )
    #foreach( $groupRole in $staticGroupRoles )
      #set( $groupsInToken = $util.defaultIfNull($ctx.identity.resolverContext.get($groupRole.claim).split(","), []) )
      #if( $groupsInToken.contains($groupRole.entity) )
        #set( $isAuthorized = true )
        #break
      #end
    #end
  #end
  #set( $hasValidOwnerArgument = false )
  #set( $authRuntimeFilter = [] )
  #set( $authOwnerRuntimeFilter = [] )
  #set( $authGroupRuntimeFilter = [] )
  #set( $ownerClaim0 = $util.defaultIfNull($ctx.identity.resolverContext.owner, null) )
  #set( $currentClaim1 = $util.defaultIfNull($ctx.identity.resolverContext.username, $util.defaultIfNull($ctx.identity.resolverContext.get("cognito:username"), null)) )
  #if( !$util.isNull($ownerClaim0) && !$util.isNull($currentClaim1) )
    #set( $ownerClaim0 = "$ownerClaim0::$currentClaim1" )
    #set( $ownerClaimsList0 = [] )
    $util.qr($ownerClaimsList0.add($util.defaultIfNull($ctx.identity.resolverContext.owner, null)))
    $util.qr($ownerClaimsList0.add($util.defaultIfNull($ctx.identity.resolverContext.username, $util.defaultIfNull($ctx.identity.resolverContext.get("cognito:username"), null))))
    $util.qr($authOwnerRuntimeFilter.add({ "owner": { "eq": $currentClaim1 } }))
    #set( $ownerEntity0 = $util.defaultIfNull($ctx.args.owner, null) )
    #if( !$isAuthorized && !$util.isNullOrEmpty($ownerEntity0) )
      #if( $ownerEntity0 == $ownerClaim0 || $ownerClaimsList0.contains($ownerEntity0) )
        #set( $isAuthorized = true )
        #set( $hasValidOwnerArgument = true )
      #else
        $util.unauthorized()
      #end
    #end
  #end
  ## Apply dynamic roles auth if not previously authorized by static groups and owner argument **
  #if( $authOwnerRuntimeFilter.size() > 0 )
    $util.qr($authRuntimeFilter.addAll($authOwnerRuntimeFilter))
  #end
  #if( $authGroupRuntimeFilter.size() > 0 )
    $util.qr($authRuntimeFilter.addAll($authGroupRuntimeFilter))
  #end
  #set( $filterArgsSize = 0 )
  #if( !$util.isNullOrEmpty($ctx.args.filter) )
    #set( $filterArgsSize = $ctx.args.filter.size() )
  #end
  #set( $isOwnerAuthAuthorizedAndNoOtherFilters = $hasValidOwnerArgument && $authRuntimeFilter.size() == 1 && $filterArgsSize == 0 )
  #set( $isOwnerOrDynamicAuthAuthorizedWithFilters = (!$isAuthorized || $hasValidOwnerArgument) && $authRuntimeFilter.size() > 0 )
  #if( !$isOwnerAuthAuthorizedAndNoOtherFilters && $isOwnerOrDynamicAuthAuthorizedWithFilters )
    #if( $util.isNullOrEmpty($ctx.args.filter) )
      #set( $ctx.args.filter = { "or": $authRuntimeFilter } )
    #else
      #set( $ctx.args.filter = { "and": [ { "or": $authRuntimeFilter }, $ctx.args.filter ]} )
    #end
    #set( $isAuthorized = true )
  #end
#end
## END LAMBDA AUTHORIZATION

#if( $util.authType() == "IAM Authorization" )
  #set( $adminRoles = ["example-role-1", "example-role-2"] )
  #foreach( $adminRole in $adminRoles )
    #if( $ctx.identity.userArn.contains($adminRole) && $ctx.identity.userArn != $ctx.stash.authRole && $ctx.identity.userArn != $ctx.stash.unauthRole )
      #return($util.toJson({}))
    #end
  #end
  #if( !$isAuthorized )
    #if( $ctx.identity.userArn == $ctx.stash.unauthRole )
      #set( $isAuthorized = true )
    #end
  #end
#end
#if( $util.authType() == "User Pool Authorization" )
  #if( !$isAuthorized )
    #set( $staticGroupRoles = [{"claim":"cognito:groups","entity":"Admin"}] )
    #foreach( $groupRole in $staticGroupRoles )
      #set( $groupsInToken = $util.defaultIfNull($ctx.identity.claims.get($groupRole.claim), []) )
      #if( $groupsInToken.contains($groupRole.entity) )
        #set( $isAuthorized = true )
        #break
      #end
    #end
  #end
  #set( $hasValidOwnerArgument = false )
  #set( $authRuntimeFilter = [] )
  #set( $authOwnerRuntimeFilter = [] )
  #set( $authGroupRuntimeFilter = [] )
  #set( $ownerClaim0 = $util.defaultIfNull($ctx.identity.claims.get("sub"), null) )
  #set( $currentClaim1 = $util.defaultIfNull($ctx.identity.claims.get("username"), $util.defaultIfNull($ctx.identity.claims.get("cognito:username"), null)) )
  #if( !$util.isNull($ownerClaim0) && !$util.isNull($currentClaim1) )
    #set( $ownerClaim0 = "$ownerClaim0::$currentClaim1" )
    #set( $ownerClaimsList0 = [] )
    $util.qr($ownerClaimsList0.add($util.defaultIfNull($ctx.identity.claims.get("sub"), null)))
    $util.qr($ownerClaimsList0.add($util.defaultIfNull($ctx.identity.claims.get("username"), $util.defaultIfNull($ctx.identity.claims.get("cognito:username"), null))))
    $util.qr($authOwnerRuntimeFilter.add({ "owner": { "eq": $currentClaim1 } }))
    #set( $ownerEntity0 = $util.defaultIfNull($ctx.args.owner, null) )
    #if( !$isAuthorized && !$util.isNullOrEmpty($ownerEntity0) )
      #if( $ownerEntity0 == $ownerClaim0 || $ownerClaimsList0.contains($ownerEntity0) )
        #set( $isAuthorized = true )
        #set( $hasValidOwnerArgument = true )
      #else
        $util.unauthorized()
      #end
    #end
  #end
  ## Apply dynamic roles auth if not previously authorized by static groups and owner argument **
  #if( $authOwnerRuntimeFilter.size() > 0 )
    $util.qr($authRuntimeFilter.addAll($authOwnerRuntimeFilter))
  #end
  #if( $authGroupRuntimeFilter.size() > 0 )
    $util.qr($authRuntimeFilter.addAll($authGroupRuntimeFilter))
  #end
  #set( $filterArgsSize = 0 )
  #if( !$util.isNullOrEmpty($ctx.args.filter) )
    #set( $filterArgsSize = $ctx.args.filter.size() )
  #end
  #set( $isOwnerAuthAuthorizedAndNoOtherFilters = $hasValidOwnerArgument && $authRuntimeFilter.size() == 1 && $filterArgsSize == 0 )
  #set( $isOwnerOrDynamicAuthAuthorizedWithFilters = (!$isAuthorized || $hasValidOwnerArgument) && $authRuntimeFilter.size() > 0 )
  #if( !$isOwnerAuthAuthorizedAndNoOtherFilters && $isOwnerOrDynamicAuthAuthorizedWithFilters )
    #if( $util.isNullOrEmpty($ctx.args.filter) )
      #set( $ctx.args.filter = { "or": $authRuntimeFilter } )
    #else
      #set( $ctx.args.filter = { "and": [ { "or": $authRuntimeFilter }, $ctx.args.filter ]} )
    #end
    #set( $isAuthorized = true )
  #end
#end
#if( !$isAuthorized )
$util.unauthorized()
#end
$util.toJson({"version":"2018-05-29","payload":{}})
## [End] Authorization Steps. **
AnilMaktala commented 1 year ago

Hi @rezab777, Thank you for sharing the VTL. Could you please clarify the type of authentication the logged-in user is using to initiate the subscription? Specifically, we would like to know if the user belongs to the admin Cognito user group or if they are the owner of the create mutation.

rezab777 commented 1 year ago

Hi @AnilMaktala

Apologies for the confusion and lack of adequate testing on our end.

To clarify :

Please let me know if I can provide further information.

Thanks

AnilMaktala commented 1 year ago

Hey @rezab777, Thank you for providing clarification. It appears that the previous project identifier has expired. Could you please run below command and send us the report and share us the project identifier again. amplify diagnose --send-report
please refer here

rezab777 commented 1 year ago

@AnilMaktala Sure here Project Identifier: 888164d0a62c44d3956d89db2613c7ec

AnilMaktala commented 1 year ago

Hey @rezab777,Thank you for sharing the diagnose report. Upon reviewing the customer model, it appears that only the admin group is configured in the schema. Are you considering the client group as a dynamic group in this context?

rezab777 commented 1 year ago

@AnilMaktala Hi and sorry for the late response. To answer the question, no we are not considering the client group as a dynamic group.

AnilMaktala commented 6 months ago

Hey @rezab777, Sorry for delay. Are you still experiencing this issue?

AnilMaktala commented 6 months ago

Hey 👋 , This issue is being closed due to inactivity. If you are still experiencing the same problem and need further assistance, please feel free to leave a comment. This will enable us to reopen the issue and provide you with the necessary support.

github-actions[bot] commented 6 months ago

This issue is now closed. Comments on closed issues are hard for our team to see. If you need more assistance, please open a new issue that references this one.