Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/aws-cdk-lib/aws-cognito/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -480,13 +480,13 @@ new cognito.UserPool(this, 'myuserpool', {

### Threat Protection

This feature is only available if your Feature Plan is set to PLUS.

Threat Protection can be set to configure enforcement levels and automatic responses for users in password-based and custom-challenge authentication flows.
For configuration, there are 2 options for standard authentication and custom authentication.
These are represented with properties `standardThreatProtectionMode` and `customThreatProtectionMode`.
See the [documentation on Threat Protection](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-threat-protection.html)

**Note**: Threat Protection requires the PLUS feature plan for new user pools. CDK allows you to configure threat protection settings at synthesis time, and CloudFormation will validate feature plan requirements at deployment time. Existing user pools that are grandfathered on LITE plans with threat protection enabled will continue to work.


### Emails

Expand Down
17 changes: 3 additions & 14 deletions packages/aws-cdk-lib/aws-cognito/lib/user-pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1210,25 +1210,14 @@ export class UserPool extends UserPoolBase {
});
this.emailConfiguration = emailConfiguration;

if (
props.featurePlan !== FeaturePlan.PLUS &&
(props.advancedSecurityMode && (props.advancedSecurityMode !== AdvancedSecurityMode.OFF))
) {
throw new ValidationError('you cannot enable Advanced Security when feature plan is not Plus.', this);
}
// Note: We do not validate feature plan requirements for threat protection at CDK synthesis time.
// CloudFormation will validate these requirements at deployment time, which allows existing user pools
// that are grandfathered on LITE plan with threat protection to continue working.

const advancedSecurityAdditionalFlows = undefinedIfNoKeys({
customAuthMode: props.customThreatProtectionMode,
});

if (
(props.featurePlan !== FeaturePlan.PLUS) &&
(props.standardThreatProtectionMode && (props.standardThreatProtectionMode !== StandardThreatProtectionMode.NO_ENFORCEMENT) ||
advancedSecurityAdditionalFlows)
) {
throw new ValidationError('you cannot enable Threat Protection when feature plan is not Plus.', this);
}

if (
props.advancedSecurityMode &&
(props.standardThreatProtectionMode || advancedSecurityAdditionalFlows)
Expand Down
49 changes: 37 additions & 12 deletions packages/aws-cdk-lib/aws-cognito/test/user-pool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2457,49 +2457,74 @@ test('advanced security defaults when no option provided', () => {
Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', {});
});

// Note: We no longer validate feature plan requirements at CDK synthesis time.
// CloudFormation validates these requirements at deployment time, which allows existing user pools
// that are grandfathered on LITE plan with threat protection to continue working.

test.each([
[FeaturePlan.ESSENTIALS, AdvancedSecurityMode.AUDIT],
[FeaturePlan.ESSENTIALS, AdvancedSecurityMode.ENFORCED],
[FeaturePlan.LITE, AdvancedSecurityMode.AUDIT],
[FeaturePlan.LITE, AdvancedSecurityMode.ENFORCED],
])('throws when feature plan is %s and advanced security mode is %s', (featurePlan, advancedSecurityMode) => {
])('generates CloudFormation template when feature plan is %s and advanced security mode is %s', (featurePlan, advancedSecurityMode) => {
// GIVEN
const stack = new Stack();

// WHEN
expect(() => {
new UserPool(stack, 'Pool', { featurePlan, advancedSecurityMode });
}).toThrow('you cannot enable Advanced Security when feature plan is not Plus.');
new UserPool(stack, 'Pool', { featurePlan, advancedSecurityMode });

// THEN - CloudFormation template should be generated successfully
Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', {
UserPoolAddOns: {
AdvancedSecurityMode: advancedSecurityMode === AdvancedSecurityMode.AUDIT ? 'AUDIT' : 'ENFORCED',
},
UserPoolTier: featurePlan,
});
});

test.each([
[FeaturePlan.ESSENTIALS, StandardThreatProtectionMode.AUDIT_ONLY],
[FeaturePlan.ESSENTIALS, StandardThreatProtectionMode.FULL_FUNCTION],
[FeaturePlan.LITE, StandardThreatProtectionMode.AUDIT_ONLY],
[FeaturePlan.LITE, StandardThreatProtectionMode.FULL_FUNCTION],
])('throws when feature plan is %s and standard threat protection mode is %s', (featurePlan, standardThreatProtectionMode) => {
])('generates CloudFormation template when feature plan is %s and standard threat protection mode is %s', (featurePlan, standardThreatProtectionMode) => {
// GIVEN
const stack = new Stack();

// WHEN
expect(() => {
new UserPool(stack, 'Pool', { featurePlan, standardThreatProtectionMode });
}).toThrow('you cannot enable Threat Protection when feature plan is not Plus.');
new UserPool(stack, 'Pool', { featurePlan, standardThreatProtectionMode });

// THEN - CloudFormation template should be generated successfully
Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', {
UserPoolAddOns: {
AdvancedSecurityMode: standardThreatProtectionMode === StandardThreatProtectionMode.AUDIT_ONLY ? 'AUDIT' : 'ENFORCED',
},
UserPoolTier: featurePlan,
});
});

test.each([
[FeaturePlan.ESSENTIALS, CustomThreatProtectionMode.AUDIT_ONLY],
[FeaturePlan.ESSENTIALS, CustomThreatProtectionMode.FULL_FUNCTION],
[FeaturePlan.LITE, CustomThreatProtectionMode.AUDIT_ONLY],
[FeaturePlan.LITE, CustomThreatProtectionMode.FULL_FUNCTION],
])('throws when feature plan is %s and custom threat protection mode is %s', (featurePlan, customThreatProtectionMode) => {
])('generates CloudFormation template when feature plan is %s and custom threat protection mode is %s', (featurePlan, customThreatProtectionMode) => {
// GIVEN
const stack = new Stack();

// WHEN
expect(() => {
new UserPool(stack, 'Pool', { featurePlan, customThreatProtectionMode });
}).toThrow('you cannot enable Threat Protection when feature plan is not Plus.');
new UserPool(stack, 'Pool', { featurePlan, customThreatProtectionMode });

// THEN - CloudFormation template should be generated successfully
Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', {
UserPoolAddOns: {
AdvancedSecurityAdditionalFlows: {
CustomAuthMode: customThreatProtectionMode === CustomThreatProtectionMode.AUDIT_ONLY ? 'AUDIT' : 'ENFORCED',
},
AdvancedSecurityMode: 'OFF',
},
UserPoolTier: featurePlan,
});
});

test('throws when deprecated property AdvancedSecurityMode and StandardThreatProtectionMode are specified at the same time.', () => {
Expand Down
Loading