aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.43k stars 2.12k forks source link

GraphQL query fails when using AWS Lambda as a secondary authorization mode #8712

Closed makrasnov100 closed 3 years ago

makrasnov100 commented 3 years ago

Before opening, please confirm:

JavaScript Framework

React

Amplify APIs

Authentication, GraphQL API

Amplify Categories

auth, api

Environment information

``` # Put output below this line System: OS: Windows 10 10.0.19043 CPU: (8) x64 Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz Memory: 34.42 GB / 63.94 GB Binaries: Node: 12.21.0 - C:\Program Files\nodejs\node.EXE npm: 7.19.0 - C:\Work\rivial-information-security-center\node_modules\.bin\npm.CMD Browsers: Chrome: 91.0.4472.124 Edge: Spartan (44.19041.1023.0), Chromium (92.0.902.62) Internet Explorer: 11.0.19041.1 npmPackages: @aws-amplify/analytics: ^5.0.8 => 5.0.8 @aws-amplify/api: ^4.0.8 => 4.0.8 @aws-amplify/auth: ^4.2.0 => 4.2.0 @aws-amplify/core: ^4.2.2 => 4.2.2 @aws-amplify/interactions: ^4.0.8 => 4.0.8 @aws-amplify/storage: ^4.3.3 => 4.3.3 @aws-amplify/ui: ^2.0.3 => 2.0.3 @aws-amplify/ui-react: ^1.2.8 => 1.2.8 @aws-amplify/xr: ^3.0.8 => 3.0.8 @babel/cli: ^7.13.10 => 7.13.10 @babel/core: ^7.11.6 => 7.11.6 (7.14.6, 7.12.3) @babel/preset-env: ^7.11.5 => 7.11.5 (7.14.7, 7.12.1) @coreui/coreui: ^2.1.16 => 2.1.16 @coreui/coreui-plugin-chartjs-custom-tooltips: ^1.3.1 => 1.3.1 @coreui/icons: 0.3.0 => 0.3.0 @coreui/react: ^2.5.4 => 2.5.7 @date-io/date-fns: ^1.3.13 => 1.3.13 @material-ui/core: ^4.11.3 => 4.11.3 @material-ui/icons: ^4.11.2 => 4.11.2 @material-ui/lab: ^4.0.0-alpha.57 => 4.0.0-alpha.57 @material-ui/pickers: ^3.3.10 => 3.3.10 @nivo/bar: ^0.71.0 => 0.71.0 @nivo/core: ^0.71.0 => 0.71.0 @nivo/line: ^0.71.0 => 0.71.0 @nivo/pie: ^0.71.0 => 0.71.0 @nivo/radar: ^0.71.0 => 0.71.0 @progress/kendo-drawing: ^1.6.0 => 1.6.0 @progress/kendo-react-pdf: ^3.11.0 => 3.11.0 @rivial-security/appsync-utils: ^1.2.0 => 1.8.0 @rivial-security/generategraphql: ^1.1.0 => 1.1.0 @rivial-security/metric-utils: ^1.0.2 => 1.0.2 @rivial-security/risk-calc-utils: ^1.6.1 => 1.6.1 @syncfusion/ej2-base: ^18.2.44 => 18.2.44 (18.1.57, 18.1.53, 18.4.44, 18.3.52, 18.3.48, 18.4.30, 19.2.44, 18.4.31, 18.4.34, 19.1.64, 18.2.47, 18.2.59) @syncfusion/ej2-charts: ^18.1.55 => 18.1.55 (18.3.52, 18.1.48) @syncfusion/ej2-dropdowns: ^18.2.45 => 18.2.45 (18.3.52, 18.3.48, 19.2.44, 18.4.49, 18.2.59, 18.2.44) @syncfusion/ej2-react-base: ^18.4.32 => 18.4.32 (19.1.69, 18.1.54, 18.4.41, 18.3.52, 19.2.44, 18.4.46, 18.4.30, 18.1.52, 18.2.44) @syncfusion/ej2-react-buttons: ^18.4.33 => 18.4.33 @syncfusion/ej2-react-calendars: ^19.1.66 => 19.1.66 @syncfusion/ej2-react-charts: ^18.1.48 => 18.1.48 @syncfusion/ej2-react-circulargauge: ^18.4.39 => 18.4.39 @syncfusion/ej2-react-documenteditor: ^18.3.52 => 18.3.52 @syncfusion/ej2-react-dropdowns: ^19.2.44 => 19.2.44 @syncfusion/ej2-react-grids: ^18.4.49 => 18.4.49 @syncfusion/ej2-react-inputs: ^18.3.53 => 18.3.53 @syncfusion/ej2-react-layouts: ^18.4.30 => 18.4.30 @syncfusion/ej2-react-navigations: ^18.1.52 => 18.1.52 @syncfusion/ej2-react-progressbar: ^18.1.52 => 18.1.52 @syncfusion/ej2-react-querybuilder: ^19.2.44 => 19.2.44 @syncfusion/ej2-react-richtexteditor: ^18.2.48 => 18.2.48 @syncfusion/ej2-react-schedule: ^18.2.44 => 18.2.44 @syncfusion/ej2-react-splitbuttons: ^18.1.43 => 18.1.43 @syncfusion/ej2-react-spreadsheet: ^18.2.46 => 18.2.46 @syncfusion/ej2-spreadsheet: ^18.3.47 => 18.3.47 (18.2.46) @testing-library/jest-dom: ^5.5.0 => 5.5.0 @testing-library/react: ^10.0.2 => 10.0.2 @testing-library/react-hooks: ^3.2.1 => 3.2.1 @testing-library/user-event: ^10.0.1 => 10.0.1 @tinymce/tinymce-react: ^3.6.0 => 3.6.0 @types/reactstrap: ^8.5.2 => 8.5.2 amazon-chime-sdk-js: ^1.16.0 => 1.16.0 apollo-boost: ^0.4.9 => 0.4.9 assert: 1.0.0 aws-amplify-react: ^5.0.8 => 5.0.8 aws-appsync: ^1.8.1 => 1.8.1 (4.0.2) aws-appsync-react: ^1.2.9 => 1.2.9 aws-sdk: ^2.617.0 => 2.642.0 (2.518.0, 2.472.0) bin: undefined (1.0.0) bootstrap: ^4.4.1 => 4.4.1 chart.js: ^2.9.4 => 2.9.4 classnames: ^2.2.6 => 2.2.6 core-js: ^2.6.11 => 2.6.11 (3.6.4, 1.2.7, 2.5.7, 3.15.1) cron-parser: ^3.3.0 => 3.5.0 cronstrue: ^1.113.0 => 1.113.0 crypto-js: ^4.0.0 => 4.0.0 (4.1.1) cypress: ^6.3.0 => 6.3.0 cypress-localstorage-commands: ^1.2.2 => 1.4.0 cypress-wait-until: ^1.7.1 => 1.7.1 date-fns: ^2.22.1 => 2.22.1 (1.30.1) dist: undefined (1.0.0) dom-to-image: ^2.6.0 => 2.6.0 enzyme: ^3.11.0 => 3.11.0 enzyme-adapter-react-16: ^1.15.2 => 1.15.2 expect.js: 0.3.1 faker: ^4.1.0 => 4.1.0 file-saver: ^2.0.2 => 2.0.2 flag-icon-css: ^3.4.6 => 3.4.6 font-awesome: ^4.7.0 => 4.7.0 fs-extra: ^9.1.0 => 9.1.0 (7.0.1, 8.1.0) graphiql: ^1.0.6 => 1.0.6 graphql-tag: ^2.10.0 => 2.10.3 (2.11.0) html-react-parser: ^1.2.7 => 1.2.7 imagediff: 1.0.8 jest-extended: ^0.11.5 => 0.11.5 jexcel: ^3.9.1 => 3.9.1 json-logic-js: ^2.0.0 => 2.0.0 jstat: ^1.9.2 => 1.9.2 jszip: ^3.5.0 => 3.5.0 (2.5.0) localforage: ^1.7.3 => 1.7.3 lodash: ^4.17.21 => 4.17.21 material-ui-cron: 0.0.4 => 0.0.4 mem: ^5.1.1 => 5.1.1 moment: ^2.24.0 => 2.24.0 (2.29.1) nivo: ^0.31.0 => 0.31.0 node-sass: ^6.0.1 => 6.0.1 npm: ^7.19.0 => 7.19.0 prop-types: ^15.6.2 => 15.7.2 qrcode.react: ^1.0.0 => 1.0.0 (0.8.0) react: ^16.12.0 => 16.13.1 react-apollo: ^2.3.3 => 2.5.8 react-app-polyfill: ^0.1.3 => 0.1.3 (2.0.0) react-awesome-lightbox: ^1.7.3 => 1.7.3 react-beautiful-dnd: ^13.1.0 => 13.1.0 react-big-calendar: ^0.24.4 => 0.24.4 react-card-flip: ^1.1.0 => 1.1.0 react-chartjs-2: ^2.9.0 => 2.9.0 react-color: ^2.18.0 => 2.18.0 react-contextmenu: ^2.13.0 => 2.13.0 react-csv-reader: ^3.1.1 => 3.1.1 react-datepicker: ^2.12.1 => 2.14.0 react-dom: ^16.12.0 => 16.13.1 react-draggable: ^4.2.0 => 4.2.0 (3.3.2) react-google-recaptcha: ^2.0.1 => 2.0.1 react-grid-layout: ^0.16.6 => 0.16.6 react-loadable: ^5.5.0 => 5.5.0 react-perfect-scrollbar: ^1.5.8 => 1.5.8 react-router-config: ^4.4.0-beta.6 => 4.4.0-beta.8 react-router-dom: ^5.1.2 => 5.1.2 react-scripts: ^4.0.3 => 4.0.3 react-sticky: ^6.0.3 => 6.0.3 react-swipeable-views: ^0.14.0 => 0.14.0 react-test-renderer: ^16.12.0 => 16.13.1 react-testing-library: ^5.4.4 => 5.9.0 reactstrap: ^8.4.1 => 8.4.1 semantic-ui-react: ^0.84.0 => 0.84.0 simple-line-icons: ^2.4.1 => 2.4.1 styled-components: ^5.2.0 => 5.2.0 styled-components/macro: undefined () styled-components/native: undefined () styled-components/primitives: undefined () terser: ^3.14.1 => 3.14.1 (4.8.0, 5.7.1) typescript: ^4.0.3 => 4.0.3 (3.9.7) uuid: ^3.4.0 => 3.4.0 (8.3.2, 3.3.2) video.js: ^7.13.3 => 7.13.3 npmGlobalPackages: npm: 6.14.11 ```

Describe the bug

Seeing the recent announcement about a lambda authorization mode in AppSync. And the recently merged PR , we wanted to try this solution for executing custom role permission logic.

However, using the lambda authorization method I get the following response when trying to execute any query.

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

If this feature is not yet supported I guess this bug report should become a feature request.

Expected behavior

I receive a response with all of the requested object data. Like so:

{"data":{"getEvidence":{"id":"f544cdfe-3dc0-40fa-8494-6f286cd1109b","ownerGroup":"a0f073c1-81a0-494d-969b-43c1dc7194ea","frequency":"0 9 1 * *","status":"expired","enabled":true}}}

Reproduction steps

  1. Add the lambda authorization lambda through the amplify CLI amplify function add
  2. Grant it auth and API category resource access (most likely unneeded?)
  3. Update lambda's index.js file to the following
    
    /* Amplify Params - DO NOT EDIT
    API_RISC_GRAPHQLAPIENDPOINTOUTPUT
    API_RISC_GRAPHQLAPIIDOUTPUT
    ENV
    REGION
    Amplify Params - DO NOT EDIT */

var util = require('util');

exports.handler = async (event) => { console.log("Running Role Checker Lambda..") console.log("Printing Event: ") console.log(util.inspect(event))

const response = { "isAuthorized": true, //for now allow all requests } return response; };

4. Run `amplify push`
5. Add the `@aws_lambda` directive to the schema object that will be queried with lambda authorization
```graphql
type Evidence
@key(name: "evidencesByOwnerGroup", fields: ["ownerGroup"], queryField: "evidencesByOwnerGroup")
@model
@aws_lambda
@auth(rules: [
  { allow: groups, groupsField: "ownerGroup" },
  { allow: groups, groups: ["Admin"] },
  { allow: private, provider: iam }
])
{
  id: ID!
  name: String!
  ownerGroup: String!
  frequency: String # cron expression
  status: EvidenceStatus
  enabled: Boolean
}
  1. run amplify push again
  2. In the aws-exports.js file note that the default authorization mode is AMAZON_COGNITO_USER_POOLS
    {
    ...
    "aws_appsync_graphqlEndpoint": "https://[secret].appsync-api.us-west-2.amazonaws.com/graphql",
    "aws_appsync_region": "us-west-2",
    "aws_appsync_authenticationType": "AMAZON_COGNITO_USER_POOLS",
    ...
    };
  3. Create a test function that calls the API with lambda authorization

    const getItem = async ()  => {
    const getEvidence = /* GraphQL */ `
      query GetEvidence($id: ID!) {
        getEvidence(id: $id) {
          id
          ownerGroup
          frequency
          status
          enabled
        }
      }
    `;
    
    try {
      await API.graphql({
        query: getEvidence,
        variables: {
          id: "f544cdfe-3dc0-40fa-8494-6f286cd1109b"
        },
        authMode: "AWS_LAMBDA",
        authToken: "test"
      }).then((data) => {
        console.log({data});
        setResult(JSON.stringify(data));
      });
    
    } catch (error) {
      console.log(error);
      setResult(JSON.stringify(error));
    }
    }
  4. Add lambda authorization mode through appsync settings Tab in AWS AppSync Console (save all changes) image
  5. Observe the function getting called but the unauthorized response still being returned for the query

Code Snippet

All snippets in reproduction steps

Log output

``` No errors just a 200 response that says unauthorized. ```

aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

iartemiev commented 3 years ago

Hey @makrasnov100, thanks for providing a detailed explanation of the issue you're experiencing.

The Amplify CLI does not yet support the @aws_lambda directive, so it's not going to transpile the model you have in step 5 in the way you're expecting. You will need to add that annotation manually to the schema in the AppSync console. Make sure to add it to the model itself, as well as all queries, mutations, and subscription queries for that model, e.g., getEvidence, listEvidences, createEvidence, onCreateEvidence etc. There should also be a type ModelEvidenceConnection in there - make sure to add the directive to that too.

The team is working on adding CLI support, so this is just a temporary stopgap measure until then.

makrasnov100 commented 3 years ago

Thanks for your response and the temporary workaround. Looking forward to this feature being supported by the CLI!

github-actions[bot] commented 2 years ago

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.