Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't set field-level authorization in amplify gen2 #2786

Closed
binarycombinatrix opened this issue Aug 18, 2024 · 7 comments
Closed

Can't set field-level authorization in amplify gen2 #2786

binarycombinatrix opened this issue Aug 18, 2024 · 7 comments
Labels
Gen 2 pending-community-response Issue is pending a response from the author or community. pending-response question Further information is requested transferred

Comments

@binarycombinatrix
Copy link

binarycombinatrix commented Aug 18, 2024

Environment information

System:
  OS: Windows 10 10.0.19045
  CPU: (8) x64 Intel(R) Core(TM) i5-8300H CPU @ 2.30GHz
  Memory: 1.06 GB / 7.86 GB
Binaries:
  Node: 20.16.0 - C:\Program Files\nodejs\node.EXE   
  Yarn: 1.22.10 - ~\AppData\Roaming\npm\yarn.CMD     
  npm: 10.8.1 - C:\Program Files\nodejs\npm.CMD      
  pnpm: undefined - undefined
NPM Packages:
  @aws-amplify/backend: 1.0.4
  @aws-amplify/backend-cli: 1.1.1
  aws-amplify: 6.5.0
  aws-cdk: 2.149.0
  aws-cdk-lib: 2.149.0
  typescript: 5.5.3
AWS environment variables:
  AWS_NODEJS_CONNECTION_REUSE_ENABLED = 1
  AWS_SDK_LOAD_CONFIG = 1
  AWS_STS_REGIONAL_ENDPOINTS = regional
No CDK environment variables

Description

Even after specifying field level authorization for all required fields, it says required fields missing field-level authorization rules: below is the schema file
amplify/data/resource.ts

import { type ClientSchema, a, defineData } from "@aws-amplify/backend";

const schema = a.schema({
  Comment: a.customType({
    content: a
      .string()
      .required()
      .authorization((allow) => [
        allow.publicApiKey().to(["read"]),
        allow.authenticated(),
      ]),
    username: a
      .string()
      .required()
      .authorization((allow) => [
        allow.publicApiKey().to(["read"]),
        allow.authenticated(),
      ]),
    dp: a
      .string()
      .required()
      .authorization((allow) => [
        allow.publicApiKey().to(["read"]),
        allow.authenticated(),
      ]),
    dn: a
      .string()
      .required()
      .authorization((allow) => [
        allow.publicApiKey().to(["read"]),
        allow.authenticated(),
      ]),
  }),
  Video: a
    .model({
      partitionKey: a
        .string()
        .required()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.owner(),
        ]),
      sortKey: a
        .string()
        .required()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.owner(),
        ]), ////video title or username   + uuidv1
      type: a
        .string()
        .required()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.owner(),
        ]), ///specify type to avoid confusion
      category: a.string(), /// category which is partition key for video entry
      debate: a.json().array(), ///debate of the video
      description: a.string(), ///channel or video description
      url: a.string(), ///video url
      thumbnail: a.string(), ///video thumbnail
      dp: a.string(), ///user dp can store in both cases,
      comment: a
        .ref("Comment")
        .array()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.authenticated(),
        ]), ///only in case of video
      dn: a.string(), //display name
      username: a.string(),
    })
    .identifier(["partitionKey", "sortKey"])
    .authorization((allow) => [
      // allow.publicApiKey(),
      allow.publicApiKey().to(["read"]),
      // Allow signed-in user to create, read, update,
      // and delete their __OWN__ posts.
      allow.owner(),
    ]),
});

export type Schema = ClientSchema<typeof schema>;

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: "apiKey",
    // API Key is used for a.allow.public() rules
    apiKeyAuthorizationMode: {
      expiresInDays: 30,
    },
  },
});

The error from the terminal is as below:

Failed to instantiate data construct

Caused By: When using field-level authorization rules you need to add rules to all of the model's required fields with at least read permissions. Found model "Video" with required fields ["partitionKey","sortKey","type"] missing field-level authorization rules.\n\nFor more information visit https://docs.amplify.aws/ction-rules
@ykethan
Copy link
Member

ykethan commented Aug 19, 2024

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

@ykethan ykethan transferred this issue from aws-amplify/amplify-backend Aug 19, 2024
@AnilMaktala AnilMaktala added the question Further information is requested label Aug 21, 2024
@AnilMaktala
Copy link
Member

Hey @binarycombinatrix, When using field-level authorization, you must grant at least read permissions to the remaining fields. I've noticed that the category, debate, description, url, thumbnail, dp, dn, and username fields in the Video model are missing permissions. Please modify the fields as shown below and let me know if this resolves your issue.

Video: a
    .model({
      partitionKey: a
        .string()
        .required()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.owner(),
        ]),
      sortKey: a
        .string()
        .required()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.owner(),
        ]), ////video title or username   + uuidv1
      type: a
        .string()
        .required()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.owner(),
        ]), ///specify type to avoid confusion
      category: a
        .string()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]),
      debate: a
        .json()
        .array()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]), ///debate of the video
      description: a
        .string()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]), ///channel or video description
      url: a
        .string()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]), ///video url
      thumbnail: a
        .string()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]), ///video thumbnail
      dp: a
        .string()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]), ///user dp can store in both cases,
      comment: a
        .ref("Comment")
        .array()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.authenticated(),
        ]), ///only in case of video
      dn: a
        .string()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]), //display name
      username: a
        .string()
        .authorization((allow) => [allow.publicApiKey().to(["read"])]),
    })
    .identifier(["partitionKey", "sortKey"])
    .authorization((allow) => [
      // allow.publicApiKey(),
      allow.publicApiKey().to(["read"]),
      // Allow signed-in user to create, read, update,
      // and delete their __OWN__ posts.
      allow.owner(),
    ]),

@binarycombinatrix
Copy link
Author

Hi @AnilMaktala did you try running your version? Those other fields are not required fields and so do not require field level auth, as the model level authorization applies to them and I added publicApi read to it already.

The error too says the issue is with required fields.

@dpilch
Copy link
Member

dpilch commented Sep 30, 2024

I believe there is a bug with the error message. The error message is present when including allow.authenticated() on the comment field.

comment: a
  .ref("Comment")
  .authorization((allow) => [
    allow.authenticated(),
  ]),

I'm not sure why this is causing this error, but you may want to change this anyway. This auth configuration allows any user to modify the comments associated with a video (even videos they do not own). That means any authenticated user could remove comments from a video.

I assume you set this auth so that any user could leave a comment on a given video. A more secure way to implement this would be to create a custom mutation (such as createCommentOnVideo). This would allow authenticated users to add comments to a video, but not remove them.

https://docs.amplify.aws/react/build-a-backend/data/custom-business-logic/

@dpilch dpilch added the bug Something isn't working label Sep 30, 2024
@AnilMaktala AnilMaktala removed the question Further information is requested label Oct 1, 2024
@AnilMaktala AnilMaktala added question Further information is requested and removed bug Something isn't working labels Oct 30, 2024
@AnilMaktala
Copy link
Member

Hey @binarycombinatrix, After further investigation, we found that the comment model has publicApiKey and authenticated auth settings. To resolve the issue, you need to grant access to authenticated users for the required fields as well. Below is the updated schema. Please try it out and let me know the results.

import {
  type ClientSchema,
  a,
  defineData,
  defineFunction,
} from "@aws-amplify/backend";

//const echoHandler = defineFunction({ entry: "./echo-handler/handler.ts" });

const schema = a.schema({
  Comment: a.customType({
    content: a
      .string()
      .required()
      .authorization((allow) => [
        allow.publicApiKey().to(["read"]),
        allow.authenticated(),
      ]),
    username: a
      .string()
      .required()
      .authorization((allow) => [
        allow.publicApiKey().to(["read"]),
        allow.authenticated(),
      ]),
    dp: a
      .string()
      .required()
      .authorization((allow) => [
        allow.publicApiKey().to(["read"]),
        allow.authenticated(),
      ]),
    dn: a
      .string()
      .required()
      .authorization((allow) => [
        allow.publicApiKey().to(["read"]),
        allow.authenticated(),
      ]),
  }),
  Video: a
    .model({
      partitionKey: a
        .string()
        .required()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.owner(),
          allow.authenticated(),
        ]),
      sortKey: a
        .string()
        .required()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.owner(),
          allow.authenticated(),
        ]), ////video title or username   + uuidv1
      type: a
        .string()
        .required()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.owner(),
          allow.authenticated(),
        ]), ///specify type to avoid confusion
      category: a.string(), /// category which is partition key for video entry
      debate: a.json().array(), ///debate of the video
      description: a.string(), ///channel or video description
      url: a.string(), ///video url
      thumbnail: a.string(), ///video thumbnail
      dp: a.string(), ///user dp can store in both cases,
      comment: a
        .ref("Comment")
        .array()
        .authorization((allow) => [
          allow.publicApiKey().to(["read"]),
          allow.authenticated(),
        ]), ///only in case of video
      dn: a.string(), //display name
      username: a.string(),
    })
    .identifier(["partitionKey", "sortKey"])
    .authorization((allow) => [
      // allow.publicApiKey(),
      allow.publicApiKey().to(["read"]),
      // Allow signed-in user to create, read, update,
      // and delete their __OWN__ posts.
      allow.owner(),
    ]),
});

export type Schema = ClientSchema<typeof schema>;

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: "apiKey",
    // API Key is used for a.allow.public() rules
    apiKeyAuthorizationMode: {
      expiresInDays: 30,
    },
  },
});

@AnilMaktala AnilMaktala added pending-response pending-community-response Issue is pending a response from the author or community. labels Oct 31, 2024
@AnilMaktala
Copy link
Member

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.

Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Gen 2 pending-community-response Issue is pending a response from the author or community. pending-response question Further information is requested transferred
Projects
None yet
Development

No branches or pull requests

4 participants