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(cognito): user pool - link style email verification fails to deploy #6938

Merged
merged 3 commits into from
Mar 24, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 51 additions & 20 deletions packages/@aws-cdk/aws-cognito/lib/user-pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ export interface UserVerificationConfig {
* The email body template for the verification email sent to the user upon sign up.
* See https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-message-templates.html to
* learn more about message templates.
* @default 'Hello {username}, Your verification code is {####}'
*
* @default - 'Hello {username}, Your verification code is {####}' if VerificationEmailStyle.CODE is chosen,
* 'Hello {username}, Verify your account by clicking on {##Verify Email##}' if VerificationEmailStyle.LINK is chosen.
*/
readonly emailBody?: string;

Expand All @@ -159,7 +161,9 @@ export interface UserVerificationConfig {
* The message template for the verification SMS sent to the user upon sign up.
* See https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-message-templates.html to
* learn more about message templates.
* @default 'The verification code to your new account is {####}'
*
* @default - 'The verification code to your new account is {####}' if VerificationEmailStyle.CODE is chosen,
* not configured if VerificationEmailStyle.LINK is chosen
*/
readonly smsMessage?: string;
}
Expand Down Expand Up @@ -486,24 +490,15 @@ export class UserPool extends Resource implements IUserPool {
}
}

const emailVerificationSubject = props.userVerification?.emailSubject ?? 'Verify your new account';
const emailVerificationMessage = props.userVerification?.emailBody ?? 'Hello {username}, Your verification code is {####}';
const smsVerificationMessage = props.userVerification?.smsMessage ?? 'The verification code to your new account is {####}';

const defaultEmailOption = props.userVerification?.emailStyle ?? VerificationEmailStyle.CODE;
const verificationMessageTemplate: CfnUserPool.VerificationMessageTemplateProperty =
(defaultEmailOption === VerificationEmailStyle.CODE) ? {
defaultEmailOption,
emailMessage: emailVerificationMessage,
emailSubject: emailVerificationSubject,
smsMessage: smsVerificationMessage,
} : {
defaultEmailOption,
emailMessageByLink: emailVerificationMessage,
emailSubjectByLink: emailVerificationSubject,
smsMessage: smsVerificationMessage
};

const verificationMessageTemplate = this.verificationMessageConfiguration(props);
let emailVerificationMessage;
let emailVerificationSubject;
let smsVerificationMessage;
if (verificationMessageTemplate.defaultEmailOption === VerificationEmailStyle.CODE) {
emailVerificationMessage = verificationMessageTemplate.emailMessage;
emailVerificationSubject = verificationMessageTemplate.emailSubject;
smsVerificationMessage = verificationMessageTemplate.smsMessage;
}
const inviteMessageTemplate: CfnUserPool.InviteMessageTemplateProperty = {
emailMessage: props.userInvitation?.emailBody,
emailSubject: props.userInvitation?.emailSubject,
Expand Down Expand Up @@ -664,6 +659,42 @@ export class UserPool extends Resource implements IUserPool {
});
}

private verificationMessageConfiguration(props: UserPoolProps): CfnUserPool.VerificationMessageTemplateProperty {
const emailStyle = props.userVerification?.emailStyle ?? VerificationEmailStyle.CODE;
const emailSubject = props.userVerification?.emailSubject ?? 'Verify your new account';

if (emailStyle === VerificationEmailStyle.CODE) {
const emailMessage = props.userVerification?.emailBody ?? 'Hello {username}, Your verification code is {####}';
const smsMessage = props.userVerification?.smsMessage ?? 'The verification code to your new account is {####}';
if (emailMessage.indexOf('{####}') < 0) {
throw new Error(`Verification email body must contain the template string '{####}'`);
}
if (smsMessage.indexOf('{####}') < 0) {
throw new Error(`SMS message must contain the template string '{####}'`);
}
return {
defaultEmailOption: VerificationEmailStyle.CODE,
emailMessage,
emailSubject,
smsMessage,
};
} else {
if (props.userVerification?.smsMessage !== undefined) {
throw new Error('SMS message cannot be configured when emailStyle is configured to CODE');
}
const emailMessage = props.userVerification?.emailBody ?? 'Hello {username}, Verify your account by clicking on {##Verify Email##}';
if (emailMessage.indexOf('{##Verify Email##}') < 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't like this placeholder very much. Do we have control over it, or is this what Cognito decided upon?

In any case shouldn't these all be in constants somewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cognito's placeholders - https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-message-templates.html
And the {##Verify Email##} is an undocumented one.

In any case shouldn't these all be in constants somewhere?

Yep, will change

throw new Error(`Verification email body must contain the template string '{##Verify Email##}'`);
}
return {
defaultEmailOption: VerificationEmailStyle.LINK,
emailMessageByLink: emailMessage,
emailSubjectByLink: emailSubject,
smsMessage: props.userVerification?.smsMessage,
};
}
}

private signInConfiguration(props: UserPoolProps) {
let aliasAttrs: string[] | undefined;
let usernameAttrs: string[] | undefined;
Expand Down
67 changes: 63 additions & 4 deletions packages/@aws-cdk/aws-cognito/test/user-pool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,22 +96,81 @@ describe('User Pool', () => {
// WHEN
new UserPool(stack, 'Pool', {
userVerification: {
emailStyle: VerificationEmailStyle.LINK
emailStyle: VerificationEmailStyle.LINK,
}
});

// THEN
expect(stack).toHaveResourceLike('AWS::Cognito::UserPool', {
EmailVerificationMessage: 'Hello {username}, Your verification code is {####}',
EmailVerificationSubject: 'Verify your new account',
EmailVerificationMessage: ABSENT,
EmailVerificationSubject: ABSENT,
SmsVerificationMessage: ABSENT,
VerificationMessageTemplate: {
DefaultEmailOption: 'CONFIRM_WITH_LINK',
EmailMessageByLink: 'Hello {username}, Your verification code is {####}',
EmailMessageByLink: 'Hello {username}, Verify your account by clicking on {##Verify Email##}',
EmailSubjectByLink: 'Verify your new account',
SmsMessage: ABSENT,
}
});
}),

test('sms message cannot be specified if link-style email verification is configured', () => {
const stack = new Stack();

expect(() => new UserPool(stack, 'Pool', {
userVerification: {
emailStyle: VerificationEmailStyle.LINK,
smsMessage: 'sms message'
}
})).toThrow(/SMS message cannot be configured/);
});

test('email and sms verification messages are validated', () => {
const stack = new Stack();

expect(() => new UserPool(stack, 'Pool1', {
userVerification: {
emailStyle: VerificationEmailStyle.CODE,
emailBody: 'invalid email body',
}
})).toThrow(/Verification email body/);

expect(() => new UserPool(stack, 'Pool2', {
userVerification: {
emailStyle: VerificationEmailStyle.CODE,
emailBody: 'valid email body {####}',
}
})).not.toThrow();

expect(() => new UserPool(stack, 'Pool3', {
userVerification: {
emailStyle: VerificationEmailStyle.CODE,
smsMessage: 'invalid sms message',
}
})).toThrow(/SMS message/);

expect(() => new UserPool(stack, 'Pool4', {
userVerification: {
emailStyle: VerificationEmailStyle.CODE,
smsMessage: 'invalid sms message {####}',
}
})).not.toThrow();

expect(() => new UserPool(stack, 'Pool5', {
userVerification: {
emailStyle: VerificationEmailStyle.LINK,
emailBody: 'invalid email body {####}',
}
})).toThrow(/Verification email body/);

expect(() => new UserPool(stack, 'Pool6', {
userVerification: {
emailStyle: VerificationEmailStyle.LINK,
emailBody: 'invalid email body {##Verify Email##}',
}
})).not.toThrow();
});

test('user invitation messages are configured correctly', () => {
// GIVEN
const stack = new Stack();
Expand Down