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

fix(graphql-auth-transformer): protection for connection types #5655

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1670,7 +1670,7 @@ operations will be generated by the CLI.`,
// member is accessible.
const directives = this.getDirectivesForRules(rules, false);
if (directives.length > 0) {
this.addDirectivesToField(ctx, inputDef.name.value, field.name.value, directives);
this.addDirectivesToOperation(ctx, inputDef.name.value, field.name.value, directives);
}

if (isListType(field.type)) {
Expand Down
95 changes: 93 additions & 2 deletions packages/graphql-auth-transformer/src/__tests__/MultiAuth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { GraphQLTransform } from 'graphql-transformer-core';
import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer';
import { ModelConnectionTransformer } from 'graphql-connection-transformer';
import { ModelAuthTransformer, AppSyncAuthConfiguration, AppSyncAuthMode } from '../ModelAuthTransformer';
import { KeyTransformer } from '../../../graphql-key-transformer/src/KeyTransformer';

const noAuthModeDefaultConfig: AppSyncAuthConfiguration = {
defaultAuthentication: {
Expand Down Expand Up @@ -158,7 +159,12 @@ const getSchemaWithRecursiveNonModelField = (authDirective: string) => {

const getTransformer = (authConfig: AppSyncAuthConfiguration) =>
new GraphQLTransform({
transformers: [new DynamoDBModelTransformer(), new ModelConnectionTransformer(), new ModelAuthTransformer({ authConfig })],
transformers: [
new DynamoDBModelTransformer(),
new KeyTransformer(),
new ModelConnectionTransformer(),
new ModelAuthTransformer({ authConfig }),
],
});

const getObjectType = (doc: DocumentNode, type: string): ObjectTypeDefinitionNode | undefined => {
Expand All @@ -172,7 +178,7 @@ const expectNone = fieldOrType => {
};

const expectOne = (fieldOrType, directiveName) => {
expect(fieldOrType.directives.length === 1);
expect(fieldOrType.directives.length).toBe(1);
expect(fieldOrType.directives.find(d => d.name.value === directiveName)).toBeDefined();
};

Expand Down Expand Up @@ -673,6 +679,91 @@ describe('Type directive transformation tests', () => {
// const modelPostConnectionType = getObjectType(schemaDoc, 'ModelPostConnection');
// expect (expectOne(modelPostConnectionType, '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`, () => {
const schema = `
type User @model
@auth(rules: [
{ allow: private, provider: iam, operations: [read] }
{ allow: groups, groups: ["Group"], operations: [read, update, delete] },
]) {
id: ID!
posts: [Post!] @connection(keyName:"byUser", fields: ["id"])
}

type Post @model(
queries: null)
@auth(rules: [
{ allow: private, provider: iam, operations: [read] },
{ allow: groups, groups: ["Group"], operations: [read, update, delete] }
])
@key(name: "byUser", fields: ["postUserId"])
{
id: ID!
postUserId: ID!
message: String
}
`;

const transformer = getTransformer(withAuthModes(iamDefaultConfig, ['AMAZON_COGNITO_USER_POOLS']));
const out = transformer.transform(schema);
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] @connection(keyName: "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 }])
@key(name: "byPost", fields: ["postID", "editorID"])
@key(name: "byEditor", fields: ["editorID", "postID"]) {
id: ID!
postID: ID!
editorID: ID!
post: Post! @connection(fields: ["postID"])
editor: User! @connection(fields: ["editorID"])
}

type User @model @auth(rules: [{ allow: owner }]) {
id: ID!
username: String!
posts: [PostEditor] @connection(keyName: "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();
expectOne(modelPostEditorConnectionType, 'aws_cognito_user_pools');
});
});

describe(`Policy slicing tests`, () => {
Expand Down