Skip to content

Commit

Permalink
fix: add @manytomany join table auth (#8460)
Browse files Browse the repository at this point in the history
* fix: add @manytomany join table auth

This commit adds auth to the many to many join table.

* fix: break dependency cycle

This commit moves several tests from the @auth v2 package to the
relational v2 package to break a dependency cycle.

* fix: address lgtm bot comment

Co-authored-by: Colin Ihrig <colihrig@amazon.com>
  • Loading branch information
cjihrig and cjihrig-aws committed Oct 15, 2021
1 parent 1868054 commit 424bbda
Show file tree
Hide file tree
Showing 11 changed files with 835 additions and 151 deletions.
1 change: 0 additions & 1 deletion packages/amplify-graphql-auth-transformer/package.json
Expand Up @@ -42,7 +42,6 @@
},
"devDependencies": {
"@aws-amplify/graphql-index-transformer": "0.4.0",
"@aws-amplify/graphql-relational-transformer": "0.3.1",
"@aws-amplify/graphql-searchable-transformer": "0.6.3",
"@types/fs-extra": "^8.0.1",
"@aws-cdk/assert": "~1.124.0",
Expand Down
@@ -1,6 +1,5 @@
import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer';
import { ModelTransformer } from '@aws-amplify/graphql-model-transformer';
import { HasManyTransformer } from '@aws-amplify/graphql-relational-transformer';
import { GraphQLTransform } from '@aws-amplify/graphql-transformer-core';
import { ResourceConstants } from 'graphql-transformer-common';
import { AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces';
Expand Down Expand Up @@ -28,7 +27,6 @@ test('subscriptions are only generated if the respective mutation operation exis
authConfig,
transformers: [
new ModelTransformer(),
new HasManyTransformer(),
new AuthTransformer({
authConfig,
addAwsIamAuthInOutputSchema: false,
Expand All @@ -48,43 +46,6 @@ test('subscriptions are only generated if the respective mutation operation exis
expect(out.pipelineFunctions['Mutation.deleteSalary.res.vtl']).toContain('$util.qr($ctx.result.put("__operation", "Mutation"))');
});

test('per-field auth on relational field', () => {
const validSchema = `
type Post @model @auth(rules: [ { allow: groups, groups: ["admin"] }, { allow: groups, groups: ["viewer"], operations: [read] } ]){
id: ID!
title: String!
comments: [Comment] @hasMany @auth(rules: [ { allow: groups, groups: ["admin"] } ])
}
type Comment @model {
id: ID!
content: String
}`;
const authConfig: AppSyncAuthConfiguration = {
defaultAuthentication: {
authenticationType: 'AMAZON_COGNITO_USER_POOLS',
},
additionalAuthenticationProviders: [{ authenticationType: 'AWS_IAM' }],
};
const transformer = new GraphQLTransform({
authConfig,
transformers: [
new ModelTransformer(),
new HasManyTransformer(),
new AuthTransformer({
authConfig,
addAwsIamAuthInOutputSchema: false,
}),
],
});
const out = transformer.transform(validSchema);
expect(out).toBeDefined();

expect(out.pipelineFunctions['Post.comments.auth.1.req.vtl']).toContain(
'#set( $staticGroupRoles = [{"claim":"cognito:groups","entity":"admin"}] )',
);
});

test('per-field @auth without @model', () => {
const validSchema = `
type Query {
Expand Down
@@ -1,7 +1,5 @@
import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer';
import { ModelTransformer } from '@aws-amplify/graphql-model-transformer';
import { IndexTransformer } from '@aws-amplify/graphql-index-transformer';
import { HasManyTransformer, HasOneTransformer, BelongsToTransformer } from '@aws-amplify/graphql-relational-transformer';
import { GraphQLTransform } from '@aws-amplify/graphql-transformer-core';
import { AppSyncAuthConfiguration, AppSyncAuthConfigurationOIDCEntry, AppSyncAuthMode } from '@aws-amplify/graphql-transformer-interfaces';
import { DocumentNode, ObjectTypeDefinitionNode, Kind, FieldDefinitionNode, parse, InputValueDefinitionNode } from 'graphql';
Expand Down Expand Up @@ -170,10 +168,6 @@ const getTransformer = (authConfig: AppSyncAuthConfiguration) =>
authConfig,
transformers: [
new ModelTransformer(),
new IndexTransformer(),
new HasManyTransformer(),
new HasOneTransformer(),
new BelongsToTransformer(),
new AuthTransformer({
authConfig,
addAwsIamAuthInOutputSchema: false,
Expand Down Expand Up @@ -604,80 +598,4 @@ describe('schema generation directive tests', () => {
expect(expectedDireciveNameCount).toEqual(addressType.directives.length);
}
});

test(`ModelXConnection type is getting the directives added, when a field has @hasMany but one fo the types has no queries defined`, () => {
const validSchema = `
type User @model
@auth(rules: [
{ allow: private, provider: iam, operations: [read] }
{ allow: groups, groups: ["group"], operations: [read, update, delete] },
]) {
id: ID!
posts: [Post!] @hasMany(indexName: "byUser", fields: ["id"])
}
type Post @model(queries: null)
@auth(rules: [
{ allow: private, provider: iam, operations: [read] },
{ allow: groups, groups: ["group"], operations: [read, update, delete] }
]) {
id: ID!
postUserId: ID! @index(name: "byUser")
message: String
}`;
const transformer = getTransformer(withAuthModes(iamDefaultConfig, ['AMAZON_COGNITO_USER_POOLS']));
const out = transformer.transform(validSchema);
const schemaDoc = parse(out.schema);
const queryType = getObjectType(schemaDoc, 'Query');
const mutationType = getObjectType(schemaDoc, 'Mutation');

expectTwo(getField(queryType, 'getUser'), ['aws_iam', 'aws_cognito_user_pools']);
expectTwo(getField(queryType, 'listUsers'), ['aws_iam', 'aws_cognito_user_pools']);

expectNone(getField(mutationType, 'createUser'));
expectOne(getField(mutationType, 'updateUser'), 'aws_cognito_user_pools');
expectOne(getField(mutationType, 'deleteUser'), 'aws_cognito_user_pools');

const userType = getObjectType(schemaDoc, 'User');
expectTwo(userType, ['aws_iam', 'aws_cognito_user_pools']);
expectNone(getField(userType, 'posts'));

const modelPostConnectionType = getObjectType(schemaDoc, 'ModelPostConnection');
expect(modelPostConnectionType).toBeDefined();
expectTwo(modelPostConnectionType, ['aws_iam', 'aws_cognito_user_pools']);
});

test(`ModelXConnection type is getting the directives added, when a field has @connection but one of the types has no queries defined. Many to Many`, () => {
const schema = `
type Post @model @auth(rules: [{ allow: owner }]) {
id: ID!
title: String!
editors: [PostEditor] @hasMany(indexName: "byPost", fields: ["id"])
}
# Create a join model and disable queries as you don't need them
# and can query through Post.editors and User.posts
type PostEditor
@model(queries: null)
@auth(rules: [{ allow: owner }]) {
id: ID!
postID: ID! @index(name: "byPost", sortKeyFields: ["editorID"])
editorID: ID! @index(name: "byEditor", sortKeyFields: ["postID"])
post: Post! @belongsTo(fields: ["postID"])
editor: User! @belongsTo(fields: ["editorID"])
}
type User @model @auth(rules: [{ allow: owner }]) {
id: ID!
username: String!
posts: [PostEditor] @hasMany(indexName: "byEditor", fields: ["id"])
}`;

const transformer = getTransformer(withAuthModes(apiKeyDefaultConfig, ['AMAZON_COGNITO_USER_POOLS']));
const out = transformer.transform(schema);
const schemaDoc = parse(out.schema);

const modelPostEditorConnectionType = getObjectType(schemaDoc, 'ModelPostEditorConnection');
expect(modelPostEditorConnectionType).toBeDefined();
// since we have resolver level auth to deny providers the default is added here to ensure the access is granted if the default type is not applied on the parent
// therefore we just need to make sure that the access is at least granted on the schema level
expect(modelPostEditorConnectionType.directives.some(dir => dir.name.value === 'aws_cognito_user_pools')).toBe(true);
});
});
Expand Up @@ -27,6 +27,7 @@
"test": "jest"
},
"dependencies": {
"@aws-amplify/graphql-auth-transformer": "0.1.0",
"@aws-amplify/graphql-index-transformer": "0.4.0",
"@aws-amplify/graphql-model-transformer": "0.6.4",
"@aws-amplify/graphql-transformer-core": "0.9.2",
Expand Down

0 comments on commit 424bbda

Please sign in to comment.