Skip to content

Commit

Permalink
fix: #8997 - auth trigger detached after push (#9312)
Browse files Browse the repository at this point in the history
  • Loading branch information
Attila Hajdrik committed Dec 19, 2021
1 parent ef93353 commit d5b4e8f
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 16 deletions.
18 changes: 10 additions & 8 deletions packages/amplify-category-auth/resources/lambda-function.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const response = require('cfn-response');
const aws = require('aws-sdk');

exports.handler = async function (event, context) {
const physicalResourceId = `${event.LogicalResourceId}-${event.ResourceProperties.userpoolId}`;

try {
const userPoolId = event.ResourceProperties.userpoolId;
const lambdaConfig = event.ResourceProperties.lambdaConfig;
Expand Down Expand Up @@ -41,31 +43,31 @@ exports.handler = async function (event, context) {
}

lambdaConfig.forEach(lambda => (config[`${lambda.triggerType}`] = lambda.lambdaFunctionArn));
if (event.RequestType == 'Delete') {
if (event.RequestType === 'Delete') {
try {
updateUserPoolConfig.LambdaConfig = {};
const result = await cognitoClient.updateUserPool(updateUserPoolConfig).promise();
console.log('delete response data ' + JSON.stringify(result));
await response.send(event, context, response.SUCCESS, {});
await response.send(event, context, response.SUCCESS, {}, physicalResourceId);
} catch (err) {
console.log(err.stack);
await response.send(event, context, response.FAILED, { err });
await response.send(event, context, response.FAILED, { err }, physicalResourceId);
}
}
if (event.RequestType == 'Update' || event.RequestType == 'Create') {
if (event.RequestType === 'Update' || event.RequestType === 'Create') {
updateUserPoolConfig.LambdaConfig = config;
console.log(updateUserPoolConfig);
console.log(`${event.RequestType}: ${updateUserPoolConfig}`);
try {
const result = await cognitoClient.updateUserPool(updateUserPoolConfig).promise();
console.log('createOrUpdate response data ' + JSON.stringify(result));
await response.send(event, context, response.SUCCESS, { result });
await response.send(event, context, response.SUCCESS, {}, physicalResourceId);
} catch (err) {
console.log(err.stack);
await response.send(event, context, response.FAILED, { err });
await response.send(event, context, response.FAILED, { err }, physicalResourceId);
}
}
} catch (err) {
console.log(err.stack);
await response.send(event, context, response.FAILED, { err });
await response.send(event, context, response.FAILED, { err }, physicalResourceId);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { prepareApp } from '@aws-cdk/core/lib/private/prepare-app';
import { AuthTriggerConnection, CognitoStackOptions } from '../service-walkthrough-types/cognito-user-input-types';
import { CustomResource } from '@aws-cdk/core';
import { authTriggerAssetFilePath } from '../constants';
import { v4 as uuid } from 'uuid';

type CustomResourceAuthStackProps = Readonly<{
description: string;
Expand Down Expand Up @@ -48,7 +49,7 @@ export class CustomResourceAuthStack extends cdk.Stack {
config.lambdaFunctionArn = fnArn.valueAsString;
});

createCustomResource(this, props.authTriggerConnections, userpoolId, userpoolArn);
createCustomResource(this, props.authTriggerConnections, userpoolId);
}

toCloudFormation() {
Expand Down Expand Up @@ -84,12 +85,7 @@ async function createCustomResourceforAuthTrigger(authTriggerConnections: AuthTr
return cfn;
}

function createCustomResource(
stack: cdk.Stack,
authTriggerConnections: AuthTriggerConnection[],
userpoolId: cdk.CfnParameter,
userpoolArn: cdk.CfnParameter,
) {
function createCustomResource(stack: cdk.Stack, authTriggerConnections: AuthTriggerConnection[], userpoolId: cdk.CfnParameter) {
const triggerCode = fs.readFileSync(authTriggerAssetFilePath, 'utf-8');
const authTriggerFn = new lambda.Function(stack, 'authTriggerFn', {
runtime: lambda.Runtime.NODEJS_12_X,
Expand All @@ -107,10 +103,12 @@ function createCustomResource(
}),
);
}

// The custom resource that uses the provider to supply value
// Passing in a nonce parameter to ensure that the custom resource is triggered on every deployment
new CustomResource(stack, 'CustomAuthTriggerResource', {
serviceToken: authTriggerFn.functionArn,
properties: { userpoolId: userpoolId.valueAsString, lambdaConfig: authTriggerConnections },
properties: { userpoolId: userpoolId.valueAsString, lambdaConfig: authTriggerConnections, nonce: uuid() },
resourceType: 'Custom::CustomAuthTriggerResourceOutputs',
});
}
Expand Down
109 changes: 109 additions & 0 deletions packages/amplify-e2e-tests/src/__tests__/auth_9.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import {
addAuthWithRecaptchaTrigger,
amplifyPushAuth,
createNewProjectDir,
deleteProject,
deleteProjectDir,
getCLIPath,
getProjectMeta,
getUserPool,
initJSProjectWithProfile,
nspawn as spawn,
} from 'amplify-e2e-core';
import { CognitoIdentityServiceProvider } from 'aws-sdk';

const defaultsSettings = {
name: 'authTest',
};

describe('amplify auth with trigger', () => {
let projRoot: string;

beforeEach(async () => {
projRoot = await createNewProjectDir('auth');
});

afterEach(async () => {
await deleteProject(projRoot);
deleteProjectDir(projRoot);
});

it('add auth with trigger, push, update auth, push, verify trigger attachment', async () => {
await initJSProjectWithProfile(projRoot, defaultsSettings);
await addAuthWithRecaptchaTrigger(projRoot, {});
await amplifyPushAuth(projRoot);

const meta = getProjectMeta(projRoot);
const userPoolId = Object.keys(meta.auth).map(key => meta.auth[key])[0].output.UserPoolId;
let userPool = (await getUserPool(
userPoolId,
meta.providers.awscloudformation.Region,
)) as CognitoIdentityServiceProvider.DescribeUserPoolResponse;

expect(userPool.UserPool).toBeDefined();
expect(userPool.UserPool.LambdaConfig).toBeDefined();
expect(userPool.UserPool.LambdaConfig.CreateAuthChallenge).toBeDefined();
expect(userPool.UserPool.LambdaConfig.DefineAuthChallenge).toBeDefined();
expect(userPool.UserPool.LambdaConfig.VerifyAuthChallengeResponse).toBeDefined();

await updateAuthChangeToUserPoolOnlyAndSetCodeMessages(projRoot, {});

await amplifyPushAuth(projRoot);

userPool = (await getUserPool(
userPoolId,
meta.providers.awscloudformation.Region,
)) as CognitoIdentityServiceProvider.DescribeUserPoolResponse;

expect(userPool.UserPool).toBeDefined();
expect(userPool.UserPool.EmailVerificationSubject).toBe('New code');
expect(userPool.UserPool.EmailVerificationMessage).toBe('New code is {####}');
expect(userPool.UserPool.LambdaConfig).toBeDefined();
expect(userPool.UserPool.LambdaConfig.CreateAuthChallenge).toBeDefined();
expect(userPool.UserPool.LambdaConfig.DefineAuthChallenge).toBeDefined();
expect(userPool.UserPool.LambdaConfig.VerifyAuthChallengeResponse).toBeDefined();
});

const updateAuthChangeToUserPoolOnlyAndSetCodeMessages = async (cwd: string, settings: any): Promise<void> => {
return new Promise((resolve, reject) => {
const chain = spawn(getCLIPath(), ['update', 'auth'], { cwd, stripColors: true });

chain
.wait('What do you want to do')
.sendKeyDown()
.sendCarriageReturn()
.wait('Select the authentication/authorization services that you want to use')
.sendKeyDown()
.sendCarriageReturn()
.wait('Do you want to add User Pool Groups')
.sendKeyDown()
.sendCarriageReturn() // No
.wait('Do you want to add an admin queries API')
.sendKeyDown()
.sendCarriageReturn() // No
.wait('Multifactor authentication (MFA) user login options')
.sendCarriageReturn() // Select Off
.wait('Email based user registration/forgot password')
.sendCarriageReturn() // Enabled
.wait('Specify an email verification subject')
.sendLine('New code') // New code
.wait('Specify an email verification message')
.sendLine('New code is {####}') // New code is {####}
.wait('Do you want to override the default password policy')
.sendConfirmNo()
.wait("Specify the app's refresh token expiration period")
.sendCarriageReturn() // 30
.wait('Do you want to specify the user attributes this app can read and write')
.sendConfirmNo()
.wait('Do you want to enable any of the following capabilities')
.sendCarriageReturn() // Preserve recaptcha trigger
.wait('Do you want to use an OAuth flow')
.sendKeyDown()
.sendCarriageReturn() // No
.wait('Do you want to configure Lambda Triggers for Cognito')
.sendConfirmNo()
.sendEof()
.run((err: Error) => (err ? reject(err) : resolve()));
});
};
});

0 comments on commit d5b4e8f

Please sign in to comment.