Skip to content

Commit 81c630d

Browse files
Josue Ruizkaustavghosh06
authored andcommitted
Adding Auth on Subscriptions (#2068)
* feat(graphql-auth-transformer): protecting subscriptions adding protection on subscriptions BREAKING CHANGE: If an owner is used in the auth directive it will either be a requirement if it's the only rule or an optional input if used with other rules re #1766 #1043 * feat(graphql-auth-transformer): pr changes added changes based on review BREAKING CHANGE: If an owner is included in the auth directive it will either be a requirement if it's the only rule or an optional input if used with other rules re #1766 #1043 * feat(graphql-auth-transformer): protect mutations protecting mutations as the same response is used in subscriptions - protected fields should still be accessible through query operations BREAKING CHANGE: the subscription operations will require an argument if owner is the only auth rule re #1766 #1043 * feat(graphql-dynamodb-transformer): auth check adding a check on auth in model re #1766 #1043 * feat(graphql-transformer-core): added getfieldarguments added function to get field arguments from type re #1766 #1043 * Added changes to check for prev version of auth * add checks for prev version of auth and added warning when adding a @model w/o @auth * Changes to check if parent type has @model * Updated ModelSubscriptionMap with status enum * Updated Auth snapshots * Updated Tests to account for new changes in auth * Added learn more links * Added identifyClaim * changed status to level to match storage naming convention * added version number in transformer config * updated e2e tests based on auth changes * Added change to read from cloud backend dir * changes to modelsubscriptionmap * Change to ModelSubsriptionMap * Updated yarn.lock * feat: pr review changes add changes based pr comments and added a per field auth e2e test BREAKING CHANGE: Subscriptions will require an argument if an owner is only rule set - If owner & group rules are owner will be an optional arg re pr #2068 * Added comment change * refactor: additional pr review changes Edited version check, for subscriptions added check for nonnull field auth, updated ddb transformer to account for public flag re pr #2068 * refactor(graphql-auth-transformer): changed subscription resolver changed the subscription resolver response template re pr #2068 * feat: subscription feedback changes per field auth now protects mutations where it sets the operation label in mutation operations re pr #2068 * chore(yarn.lock): update yarn.lock * refactor(graphql-auth-transformer): per field auth error message edit re pr #2068 * Updating based on new PR comments re pr #2068 * Change transformerConfig Ver * DynamoDB Transformer check for public * Added info on subscription levels in ddb transformer * Changed typo here * feat(graphql-auth-transformer): subscription resolver logic change changed resolver logic to also get created when subscription level is PUBLIC also added snapshot tests * feat(graphql-auth-transformer): change add owner logic changes based on pr review changing add owner logic which looks at list of rules and change of remove command on package.json re pr #2068 * updated yarn lock * feat(graphql-auth-transformer): subscriptions obj logic change changed logic to subscriptions object and added rimraf as devdependency re pr #2068 * moved add owner argument logic in else flow for adding logic * Added padding to prompts
1 parent 440d68b commit 81c630d

File tree

27 files changed

+1055
-184
lines changed

27 files changed

+1055
-184
lines changed

packages/amplify-cli/src/commands/push.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ module.exports = {
55
context.amplify.constructExeInfo(context);
66
await context.amplify.pushResources(context);
77
} catch (e) {
8-
context.print.error(`An error occured during the push operation: ${e.message}`);
8+
if (e.name !== 'InvalidDirectiveError') {
9+
context.print.error(`An error occured during the push operation: ${e.message}`);
10+
}
911
process.exit(1);
1012
}
1113
},

packages/amplify-provider-awscloudformation/lib/transform-graphql-schema.js

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ const KeyTransformer = require('graphql-key-transformer').default;
1313
const providerName = require('./constants').ProviderName;
1414
const TransformPackage = require('graphql-transformer-core');
1515

16-
const { collectDirectiveNames } = TransformPackage;
16+
const {
17+
collectDirectivesByTypeNames,
18+
readTransformerConfiguration,
19+
writeTransformerConfiguration,
20+
} = TransformPackage;
1721

1822
const category = 'api';
1923
const parametersFileName = 'parameters.json';
@@ -22,11 +26,61 @@ const schemaDirName = 'schema';
2226

2327
function failOnInvalidAuthType(usedDirectives, opts) {
2428
if (usedDirectives.includes('auth') && !opts.isUserPoolEnabled) {
25-
throw new Error(`You are trying to use the @auth directive without enabling Amazon Cognito user pools for your API.
26-
Run \`amplify update api\` and choose "Amazon Cognito User Pool" as the authorization type for the API.`);
29+
throw new Error(`You are trying to
30+
use the @auth directive without enabling Amazon Cognito user pools for your API.
31+
Run \`amplify update api\` and choose
32+
"Amazon Cognito User Pool" as the authorization type for the API.`);
2733
}
2834
}
2935

36+
function warnOnAuth(context, map) {
37+
const unAuthModelTypes = Object.keys(map).filter(type => (!map[type].includes('auth') && map[type].includes('model')));
38+
if (unAuthModelTypes.length) {
39+
context.print.warning('\nThe following types do not have \'@auth\' enabled. Consider using @auth with @model');
40+
context.print.warning(unAuthModelTypes.map(type => `\t - ${type}`).join('\n'));
41+
context.print.info('Learn more about @auth here: https://aws-amplify.github.io/docs/cli-toolchain/graphql#auth \n');
42+
}
43+
}
44+
45+
/**
46+
* @TODO Include a map of versions to keep track
47+
*/
48+
async function transformerVersionCheck(
49+
context, resourceDir, cloudBackendDirectory,
50+
updatedResources, usedDirectives,
51+
) {
52+
const versionChangeMessage = 'The default behaviour for @auth has changed in the latest version of Amplify\nRead here for details: https://aws-amplify.github.io/docs/cli-toolchain/graphql#authorizing-subscriptions';
53+
let transformerConfig;
54+
// this is where we check if there is a prev version of the transformer being used
55+
// by using the transformer.conf.json file
56+
try {
57+
transformerConfig = await readTransformerConfiguration(cloudBackendDirectory);
58+
} catch (err) {
59+
// check local resource if the question has been answered before
60+
transformerConfig = await readTransformerConfiguration(resourceDir);
61+
}
62+
const resources = updatedResources.filter(resource => resource.service === 'AppSync');
63+
if (!transformerConfig.Version && usedDirectives.includes('auth')
64+
&& resources.length > 0) {
65+
if (context.exeInfo &&
66+
context.exeInfo.inputParams && context.exeInfo.inputParams.yes) {
67+
context.print.warning(`\n${versionChangeMessage}\n`);
68+
} else {
69+
const response = await inquirer.prompt({
70+
name: 'transformerConfig',
71+
type: 'confirm',
72+
message: `\n${versionChangeMessage} \n Do you wish to continue?`,
73+
default: false,
74+
});
75+
if (!response.transformerConfig) {
76+
process.exit(0);
77+
}
78+
}
79+
}
80+
transformerConfig.Version = 4.0;
81+
await writeTransformerConfiguration(resourceDir, transformerConfig);
82+
}
83+
3084
function apiProjectIsFromOldVersion(pathToProject, resourcesToBeCreated) {
3185
const resources = resourcesToBeCreated.filter(resource => resource.service === 'AppSync');
3286
if (!pathToProject || resources.length > 0) {
@@ -202,11 +256,23 @@ async function transformGraphQLSchema(context, options) {
202256
const project = await TransformPackage.readProjectConfiguration(resourceDir);
203257

204258
// Check for common errors
205-
const usedDirectives = collectDirectiveNames(project.schema);
259+
const directiveMap = collectDirectivesByTypeNames(project.schema);
206260
failOnInvalidAuthType(
207-
usedDirectives,
261+
directiveMap.directives,
208262
{ isUserPoolEnabled: Boolean(parameters.AuthCognitoUserPoolId) },
209263
);
264+
warnOnAuth(
265+
context,
266+
directiveMap.types,
267+
);
268+
269+
await transformerVersionCheck(
270+
context,
271+
resourceDir,
272+
previouslyDeployedBackendDir,
273+
resourcesToBeUpdated,
274+
directiveMap.directives,
275+
);
210276

211277
const authMode = parameters.AuthCognitoUserPoolId ? 'AMAZON_COGNITO_USER_POOLS' : 'API_KEY';
212278
const transformerList = [
@@ -222,7 +288,7 @@ async function transformGraphQLSchema(context, options) {
222288
new ModelAuthTransformer({ authMode }),
223289
];
224290

225-
if (usedDirectives.includes('searchable')) {
291+
if (directiveMap.directives.includes('searchable')) {
226292
transformerList.push(new SearchableModelTransformer());
227293
}
228294

packages/amplify-util-mock/src/api/api.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ export class APITest {
114114
}
115115

116116
private async reload(context, filePath, action) {
117+
const apiDir = await this.getAPIBackendDirectory(context)
118+
const inputSchemaPath = path.join(apiDir, 'schema');
117119
try {
118120
let shouldReload;
119121
if (this.resolverOverrideManager.isTemplateFile(filePath)) {
@@ -139,7 +141,7 @@ export class APITest {
139141
mappingTemplates,
140142
});
141143
}
142-
} else {
144+
} else if(filePath.includes(inputSchemaPath)) {
143145
context.print.info('GraphQL Schema change detected. Reloading...');
144146
const config = await this.runTransformer(context);
145147
await this.appSyncSimulator.reload(config);

packages/graphql-auth-transformer/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"test": "jest",
88
"test-ci": "jest --ci -i",
99
"build": "tsc",
10-
"clean": "rm -rf ./lib"
10+
"clean": "rimraf ./lib",
11+
"watch": "tsc -w"
1112
},
1213
"keywords": [
1314
"graphql",
@@ -30,6 +31,7 @@
3031
"cloudform-types": "^3.7.0",
3132
"graphql-dynamodb-transformer": "3.12.0",
3233
"jest": "^23.1.0",
34+
"rimraf": "^3.0.0",
3335
"ts-jest": "^22.4.6",
3436
"tslint": "^5.18.0",
3537
"typescript": "^3.5.3"

packages/graphql-auth-transformer/src/AuthRule.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ export interface AuthRule {
55
allow: 'owner' | 'groups';
66
ownerField?: string;
77
identityField?: string;
8+
identityClaim?: string;
89
groupsField?: string;
10+
groupClaim?: string;
911
groups?: string[];
10-
operations?: ModelOperation[]
11-
queries?: ModelQuery[]
12-
mutations?: ModelMutation[]
12+
operations?: ModelOperation[];
13+
queries?: ModelQuery[];
14+
mutations?: ModelMutation[];
1315
}

0 commit comments

Comments
 (0)