diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool-attr.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool-attr.ts index bd3a2146eb433..13a2db6a1d7f2 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool-attr.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-attr.ts @@ -1,113 +1,3 @@ -/** - * The set of standard attributes that can be marked as required. - * - * @deprecated use {@link StandardAttributes} - * @see https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#cognito-user-pools-standard-attributes - */ -export interface RequiredAttributes { - /** - * Whether the user's postal address is a required attribute. - * @default - Attribute is not required - */ - readonly address?: boolean; - - /** - * Whether the user's birthday, represented as an ISO 8601:2004 format, is a required attribute. - * @default - Attribute is not required - */ - readonly birthdate?: boolean; - - /** - * Whether theb user's e-mail address, represented as an RFC 5322 [RFC5322] addr-spec, is a required attribute. - * @default - Attribute is not required - */ - readonly email?: boolean; - - /** - * Whether the surname or last name of the user is a required attribute. - * @default - Attribute is not required - */ - readonly familyName?: boolean; - - /** - * Whether the user's gender is a required attribute. - * @default - Attribute is not required - */ - readonly gender?: boolean; - - /** - * Whether the user's first name or give name is a required attribute. - * @default - Attribute is not required - */ - readonly givenName?: boolean; - - /** - * Whether the user's locale, represented as a BCP47 [RFC5646] language tag, is a required attribute. - * @default - Attribute is not required - */ - readonly locale?: boolean; - - /** - * Whether the user's middle name is a required attribute. - * @default - Attribute is not required - */ - readonly middleName?: boolean; - - /** - * Whether user's full name in displayable form, including all name parts, titles and suffixes, is a required attibute. - * @default - Attribute is not required - */ - readonly fullname?: boolean; - - /** - * Whether the user's nickname or casual name is a required attribute. - * @default - Attribute is not required - */ - readonly nickname?: boolean; - - /** - * Whether the user's telephone number is a required attribute. - * @default - Attribute is not required - */ - readonly phoneNumber?: boolean; - - /** - * Whether the URL to the user's profile picture is a required attribute. - * @default - Attribute is not required - */ - readonly profilePicture?: boolean; - - /** - * Whether the user's preffered username, different from the immutable user name, is a required attribute. - * @default - Attribute is not required - */ - readonly preferredUsername?: boolean; - - /** - * Whether the URL to the user's profile page is a required attribute. - * @default - Attribute is not required - */ - readonly profilePage?: boolean; - - /** - * Whether the user's time zone is a required attribute. - * @default - Attribute is not required - */ - readonly timezone?: boolean; - - /** - * Whether the time, the user's information was last updated, is a required attribute. - * @default - Attribute is not required - */ - readonly lastUpdateTime?: boolean; - - /** - * Whether the URL to the user's web page or blog is a required attribute. - * @default - Attribute is not required - */ - readonly website?: boolean; -} - /** * The set of standard attributes that can be marked as required or mutable. * @@ -115,104 +5,104 @@ export interface RequiredAttributes { */ export interface StandardAttributes { /** - * Whether the user's postal address is a required attribute. - * @default - Attribute is not required + * The user's postal address is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly address?: StandardAttribute; /** - * Whether the user's birthday, represented as an ISO 8601:2004 format, is a required attribute. - * @default - Attribute is not required + * The user's birthday, represented as an ISO 8601:2004 format, is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly birthdate?: StandardAttribute; /** - * Whether theb user's e-mail address, represented as an RFC 5322 [RFC5322] addr-spec, is a required attribute. - * @default - Attribute is not required + * Theb user's e-mail address, represented as an RFC 5322 [RFC5322] addr-spec, is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly email?: StandardAttribute; /** - * Whether the surname or last name of the user is a required attribute. - * @default - Attribute is not required + * The surname or last name of the user is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly familyName?: StandardAttribute; /** - * Whether the user's gender is a required attribute. - * @default - Attribute is not required + * The user's gender is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly gender?: StandardAttribute; /** - * Whether the user's first name or give name is a required attribute. - * @default - Attribute is not required + * The user's first name or give name is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly givenName?: StandardAttribute; /** - * Whether the user's locale, represented as a BCP47 [RFC5646] language tag, is a required attribute. - * @default - Attribute is not required + * The user's locale, represented as a BCP47 [RFC5646] language tag, is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly locale?: StandardAttribute; /** - * Whether the user's middle name is a required attribute. - * @default - Attribute is not required + * The user's middle name is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly middleName?: StandardAttribute; /** * Whether user's full name in displayable form, including all name parts, titles and suffixes, is a required attibute. - * @default - Attribute is not required + * @default - see the defaults under `StandardAttribute` */ readonly fullname?: StandardAttribute; /** - * Whether the user's nickname or casual name is a required attribute. - * @default - Attribute is not required + * The user's nickname or casual name is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly nickname?: StandardAttribute; /** - * Whether the user's telephone number is a required attribute. - * @default - Attribute is not required + * The user's telephone number is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly phoneNumber?: StandardAttribute; /** - * Whether the URL to the user's profile picture is a required attribute. - * @default - Attribute is not required + * The URL to the user's profile picture is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly profilePicture?: StandardAttribute; /** - * Whether the user's preffered username, different from the immutable user name, is a required attribute. - * @default - Attribute is not required + * The user's preffered username, different from the immutable user name, is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly preferredUsername?: StandardAttribute; /** - * Whether the URL to the user's profile page is a required attribute. - * @default - Attribute is not required + * The URL to the user's profile page is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly profilePage?: StandardAttribute; /** - * Whether the user's time zone is a required attribute. - * @default - Attribute is not required + * The user's time zone is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly timezone?: StandardAttribute; /** - * Whether the time, the user's information was last updated, is a required attribute. - * @default - Attribute is not required + * The time, the user's information was last updated, is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly lastUpdateTime?: StandardAttribute; /** - * Whether the URL to the user's web page or blog is a required attribute. - * @default - Attribute is not required + * The URL to the user's web page or blog is a required attribute. + * @default - see the defaults under `StandardAttribute` */ readonly website?: StandardAttribute; } @@ -229,7 +119,7 @@ export interface StandardAttribute { * Amazon Cognito updates mapped attributes when users sign in to your application through an identity provider. * If an attribute is immutable, Amazon Cognito throws an error when it attempts to update the attribute. * - * @default false + * @default true */ readonly mutable?: boolean; /** diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts index 4efdc5f02765d..da27030976904 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool.ts @@ -2,7 +2,7 @@ import { IRole, PolicyDocument, PolicyStatement, Role, ServicePrincipal } from ' import * as lambda from '@aws-cdk/aws-lambda'; import { Construct, Duration, IResource, Lazy, Resource, Stack } from '@aws-cdk/core'; import { CfnUserPool } from './cognito.generated'; -import { ICustomAttribute, RequiredAttributes, StandardAttributes } from './user-pool-attr'; +import { ICustomAttribute, StandardAttribute, StandardAttributes } from './user-pool-attr'; import { IUserPoolClient, UserPoolClient, UserPoolClientOptions } from './user-pool-client'; import { UserPoolDomain, UserPoolDomainOptions } from './user-pool-domain'; @@ -452,15 +452,6 @@ export interface UserPoolProps { */ readonly autoVerify?: AutoVerifiedAttrs; - /** - * The set of attributes that are required for every user in the user pool. - * Read more on attributes here - https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html - * - * @deprecated use {@link standardAttributes} - * @default - No required attributes. - */ - readonly requiredAttributes?: RequiredAttributes; - /** * The set of attributes that are required for every user in the user pool. * Read more on attributes here - https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html @@ -758,24 +749,24 @@ export class UserPool extends Resource implements IUserPool { if (signIn.username) { aliasAttrs = []; - if (signIn.email) { aliasAttrs.push(StandardAttribute.EMAIL); } - if (signIn.phone) { aliasAttrs.push(StandardAttribute.PHONE_NUMBER); } - if (signIn.preferredUsername) { aliasAttrs.push(StandardAttribute.PREFERRED_USERNAME); } + if (signIn.email) { aliasAttrs.push(StandardAttributeNames.EMAIL); } + if (signIn.phone) { aliasAttrs.push(StandardAttributeNames.PHONE_NUMBER); } + if (signIn.preferredUsername) { aliasAttrs.push(StandardAttributeNames.PREFERRED_USERNAME); } if (aliasAttrs.length === 0) { aliasAttrs = undefined; } } else { usernameAttrs = []; - if (signIn.email) { usernameAttrs.push(StandardAttribute.EMAIL); } - if (signIn.phone) { usernameAttrs.push(StandardAttribute.PHONE_NUMBER); } + if (signIn.email) { usernameAttrs.push(StandardAttributeNames.EMAIL); } + if (signIn.phone) { usernameAttrs.push(StandardAttributeNames.PHONE_NUMBER); } } if (props.autoVerify) { autoVerifyAttrs = []; - if (props.autoVerify.email) { autoVerifyAttrs.push(StandardAttribute.EMAIL); } - if (props.autoVerify.phone) { autoVerifyAttrs.push(StandardAttribute.PHONE_NUMBER); } + if (props.autoVerify.email) { autoVerifyAttrs.push(StandardAttributeNames.EMAIL); } + if (props.autoVerify.phone) { autoVerifyAttrs.push(StandardAttributeNames.PHONE_NUMBER); } } else if (signIn.email || signIn.phone) { autoVerifyAttrs = []; - if (signIn.email) { autoVerifyAttrs.push(StandardAttribute.EMAIL); } - if (signIn.phone) { autoVerifyAttrs.push(StandardAttribute.PHONE_NUMBER); } + if (signIn.email) { autoVerifyAttrs.push(StandardAttributeNames.EMAIL); } + if (signIn.phone) { autoVerifyAttrs.push(StandardAttributeNames.PHONE_NUMBER); } } return { usernameAttrs, aliasAttrs, autoVerifyAttrs }; @@ -860,37 +851,15 @@ export class UserPool extends Resource implements IUserPool { const schema: CfnUserPool.SchemaAttributeProperty[] = []; if (props.standardAttributes) { - const standardAttributes = props.standardAttributes; - const stdAttributes = Object.keys(standardAttributes) - .filter( - attrName => - !!standardAttributes[attrName as keyof StandardAttributes], - ).filter( - attrName => - standardAttributes[attrName as keyof StandardAttributes]!.required || - standardAttributes[attrName as keyof StandardAttributes]!.mutable, - ) - .map(attrName => ({ - name: StandardAttributeMap[attrName as keyof StandardAttributes], - ...(standardAttributes[attrName as keyof StandardAttributes] || {}), + const stdAttributes = (Object.entries(props.standardAttributes) as Array<[keyof StandardAttributes, StandardAttribute]>) + .filter(([, attr]) => !!attr) + .map(([attrName, attr]) => ({ + name: StandardAttributeMap[attrName], + mutable: attr.mutable ?? true, + required: attr.required ?? false, })); schema.push(...stdAttributes); - } else if (props.requiredAttributes) { - const requiredAttributes = props.requiredAttributes; - const requiredAttrs = Object.keys(requiredAttributes) - .filter( - attrName => - !!requiredAttributes[attrName as keyof StandardAttributes], - ) - .map( - attrName => ({ - name: StandardAttributeMap[attrName as keyof StandardAttributes], - required: true, - }), - ); - - schema.push(...requiredAttrs); } if (props.customAttributes) { @@ -934,7 +903,7 @@ export class UserPool extends Resource implements IUserPool { } } -const enum StandardAttribute { +const enum StandardAttributeNames { ADDRESS = 'address', BIRTHDATE = 'birthdate', EMAIL = 'email', @@ -954,27 +923,24 @@ const enum StandardAttribute { WEBSITE = 'website', } -const StandardAttributeMap: Record< -keyof StandardAttributes, -StandardAttribute -> = { - address: StandardAttribute.ADDRESS, - birthdate: StandardAttribute.BIRTHDATE, - email: StandardAttribute.EMAIL, - familyName: StandardAttribute.FAMILY_NAME, - gender: StandardAttribute.GENDER, - givenName: StandardAttribute.GIVEN_NAME, - locale: StandardAttribute.LOCALE, - middleName: StandardAttribute.MIDDLE_NAME, - fullname: StandardAttribute.NAME, - nickname: StandardAttribute.NICKNAME, - phoneNumber: StandardAttribute.PHONE_NUMBER, - profilePicture: StandardAttribute.PICTURE_URL, - preferredUsername: StandardAttribute.PREFERRED_USERNAME, - profilePage: StandardAttribute.PROFILE_URL, - timezone: StandardAttribute.TIMEZONE, - lastUpdateTime: StandardAttribute.LAST_UPDATE_TIME, - website: StandardAttribute.WEBSITE, +const StandardAttributeMap: Record = { + address: StandardAttributeNames.ADDRESS, + birthdate: StandardAttributeNames.BIRTHDATE, + email: StandardAttributeNames.EMAIL, + familyName: StandardAttributeNames.FAMILY_NAME, + gender: StandardAttributeNames.GENDER, + givenName: StandardAttributeNames.GIVEN_NAME, + locale: StandardAttributeNames.LOCALE, + middleName: StandardAttributeNames.MIDDLE_NAME, + fullname: StandardAttributeNames.NAME, + nickname: StandardAttributeNames.NICKNAME, + phoneNumber: StandardAttributeNames.PHONE_NUMBER, + profilePicture: StandardAttributeNames.PICTURE_URL, + preferredUsername: StandardAttributeNames.PREFERRED_USERNAME, + profilePage: StandardAttributeNames.PROFILE_URL, + timezone: StandardAttributeNames.TIMEZONE, + lastUpdateTime: StandardAttributeNames.LAST_UPDATE_TIME, + website: StandardAttributeNames.WEBSITE, }; function undefinedIfNoKeys(struct: object): object | undefined { diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json index bd91fc58f681a..7625b4a9a80d7 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.expected.json @@ -781,11 +781,13 @@ "Schema": [ { "Name": "name", - "Required": true + "Required": true, + "Mutable": true }, { "Name": "email", - "Required": true + "Required": true, + "Mutable": true }, { "AttributeDataType": "String", diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts index a55aa2697cf5f..1f4f7fe8193c5 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-explicit-props.ts @@ -29,6 +29,7 @@ const userpool = new UserPool(stack, 'myuserpool', { standardAttributes: { fullname: { required: true, + mutable: true, }, email: { required: true, diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts index 44862efc992aa..bd675d1930fd2 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts @@ -484,7 +484,7 @@ describe('User Pool', () => { }); }); - test('required attributes', () => { + test('standard attributes default to mutable', () => { // GIVEN const stack = new Stack(); @@ -506,10 +506,12 @@ describe('User Pool', () => { { Name: 'name', Required: true, + Mutable: true, }, { Name: 'zoneinfo', Required: true, + Mutable: true, }, ], }); @@ -521,6 +523,7 @@ describe('User Pool', () => { // WHEN new UserPool(stack, 'Pool', { + userPoolName: 'Pool', standardAttributes: { fullname: { required: true, @@ -533,8 +536,21 @@ describe('User Pool', () => { }, }); + new UserPool(stack, 'Pool1', { + userPoolName: 'Pool1', + standardAttributes: { + fullname: { + mutable: false, + }, + timezone: { + mutable: false, + }, + }, + }); + // THEN expect(stack).toHaveResourceLike('AWS::Cognito::UserPool', { + UserPoolName: 'Pool', Schema: [ { Mutable: true, @@ -548,34 +564,21 @@ describe('User Pool', () => { }, ], }); - }); - - test('schema is absent when standard attributes are specified but not required and not mutable', () => { - // GIVEN - const stack = new Stack(); - - // WHEN - new UserPool(stack, 'Pool1', { - userPoolName: 'Pool1', - }); - new UserPool(stack, 'Pool2', { - userPoolName: 'Pool2', - standardAttributes: { - familyName: { - required: false, - mutable: false, - }, - }, - }); - // THEN expect(stack).toHaveResourceLike('AWS::Cognito::UserPool', { UserPoolName: 'Pool1', - Schema: ABSENT, - }); - expect(stack).toHaveResourceLike('AWS::Cognito::UserPool', { - UserPoolName: 'Pool2', - Schema: ABSENT, + Schema: [ + { + Name: 'name', + Required: false, + Mutable: false, + }, + { + Name: 'zoneinfo', + Required: false, + Mutable: false, + }, + ], }); });