Skip to content

Commit 9363400

Browse files
authored
Merge branch 'master' into njlynch/remove-snk
2 parents 58a0d0b + 6be5a92 commit 9363400

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+4119
-806
lines changed

packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,8 @@ export class UsagePlan extends Resource {
179179
* @param apiKey
180180
*/
181181
public addApiKey(apiKey: IApiKey): void {
182-
const prefix = 'UsagePlanKeyResource';
183-
184182
// Postfixing apikey id only from the 2nd child, to keep physicalIds of UsagePlanKey for existing CDK apps unmodifed.
185-
const id = this.node.tryFindChild(prefix) ? `${prefix}:${Names.nodeUniqueId(apiKey.node)}` : prefix;
183+
const id = `UsagePlanKeyResource:${Names.nodeUniqueId(apiKey.node)}`;
186184

187185
new CfnUsagePlanKey(this, id, {
188186
keyId: apiKey.keyId,

packages/@aws-cdk/aws-apigateway/test/integ.restapi.expected.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@
602602
"UsagePlanName": "Basic"
603603
}
604604
},
605-
"myapiUsagePlanUsagePlanKeyResource050D133F": {
605+
"myapiUsagePlanUsagePlanKeyResourcetestapigatewayrestapimyapiApiKeyC43601CB600D112D": {
606606
"Type": "AWS::ApiGateway::UsagePlanKey",
607607
"Properties": {
608608
"KeyId": {

packages/@aws-cdk/aws-apigateway/test/integ.usage-plan.multikey.expected.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"myusageplan4B391740": {
44
"Type": "AWS::ApiGateway::UsagePlan"
55
},
6-
"myusageplanUsagePlanKeyResource095B4EA9": {
6+
"myusageplanUsagePlanKeyResourcetestapigatewayusageplanmultikeymyapikey1DDABC389A2809A73": {
77
"Type": "AWS::ApiGateway::UsagePlanKey",
88
"Properties": {
99
"KeyId": {

packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,4 +205,32 @@ describe('usage plan', () => {
205205
},
206206
}, ResourcePart.Properties);
207207
});
208+
209+
test('UsagePlanKeys have unique logical ids', () => {
210+
// GIVEN
211+
const app = new cdk.App();
212+
const stack = new cdk.Stack(app, 'my-stack');
213+
const usagePlan = new apigateway.UsagePlan(stack, 'my-usage-plan');
214+
const apiKey1 = new apigateway.ApiKey(stack, 'my-api-key-1', {
215+
apiKeyName: 'my-api-key-1',
216+
});
217+
const apiKey2 = new apigateway.ApiKey(stack, 'my-api-key-2', {
218+
apiKeyName: 'my-api-key-2',
219+
});
220+
221+
// WHEN
222+
usagePlan.addApiKey(apiKey1);
223+
usagePlan.addApiKey(apiKey2);
224+
225+
// THEN
226+
const template = app.synth().getStackByName(stack.stackName).template;
227+
const logicalIds = Object.entries(template.Resources)
228+
.filter(([_, v]) => (v as any).Type === 'AWS::ApiGateway::UsagePlanKey')
229+
.map(([k, _]) => k);
230+
231+
expect(logicalIds).toEqual([
232+
'myusageplanUsagePlanKeyResourcemystackmyapikey1EE9AA1B359121274',
233+
'myusageplanUsagePlanKeyResourcemystackmyapikey2B4E8EB1456DC88E9',
234+
]);
235+
});
208236
});

packages/@aws-cdk/aws-autoscaling/lib/volume.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,25 @@ export enum EbsDeviceVolumeType {
178178
STANDARD = 'standard',
179179

180180
/**
181-
* Provisioned IOPS SSD
181+
* Provisioned IOPS SSD - IO1
182182
*/
183183
IO1 = 'io1',
184184

185185
/**
186-
* General Purpose SSD
186+
* Provisioned IOPS SSD - IO2
187+
*/
188+
IO2 = 'io2',
189+
190+
/**
191+
* General Purpose SSD - GP2
187192
*/
188193
GP2 = 'gp2',
189194

195+
/**
196+
* General Purpose SSD - GP3
197+
*/
198+
GP3 = 'gp3',
199+
190200
/**
191201
* Throughput Optimized HDD
192202
*/

packages/@aws-cdk/aws-codepipeline-actions/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ CodePipeline can use a BitBucket Git repository as a source:
137137
**Note**: you have to manually connect CodePipeline through the AWS Console with your BitBucket account.
138138
This is a one-time operation for a given AWS account in a given region.
139139
The simplest way to do that is to either start creating a new CodePipeline,
140-
or edit na existing one, while being logged in to BitBucket.
140+
or edit an existing one, while being logged in to BitBucket.
141141
Choose BitBucket as the source,
142142
and grant CodePipeline permissions to your BitBucket account.
143143
Copy & paste the Connection ARN that you get in the console,

packages/@aws-cdk/aws-cognito/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,30 @@ pool.addClient('app-client', {
572572
});
573573
```
574574

575+
Clients can (and should) be allowed to read and write relevant user attributes only. Usually every client can be allowed to read the `given_name`
576+
attribute but not every client should be allowed to set the `email_verified` attribute.
577+
The same criteria applies for both standard and custom attributes, more info is available at
578+
[Attribute Permissions and Scopes](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-attribute-permissions-and-scopes).
579+
The default behaviour is to allow read and write permissions on all attributes. The following code shows how this can be configured for a client.
580+
581+
```ts
582+
const pool = new cognito.UserPool(this, 'Pool');
583+
584+
const clientWriteAttributes = (new ClientAttributes())
585+
.withStandardAttributes({name: true, email: true})
586+
.withCustomAttributes(['favouritePizza']);
587+
588+
const clientReadAttributes = clientWriteAttributes
589+
.withStandardAttributes({emailVerified: true})
590+
.withCustomAttributes(['pointsEarned']);
591+
592+
pool.addClient('app-client', {
593+
// ...
594+
readAttributes: clientReadAttributes,
595+
writeAttributes: clientWriteAttributes,
596+
});
597+
```
598+
575599
### Resource Servers
576600

577601
A resource server is a server for access-protected resources. It handles authenticated requests from an app that has an

packages/@aws-cdk/aws-cognito/lib/private/attr-names.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ export const StandardAttributeNames = {
1616
timezone: 'zoneinfo',
1717
lastUpdateTime: 'updated_at',
1818
website: 'website',
19+
emailVerified: 'email_verified',
20+
phoneNumberVerified: 'phone_number_verified',
1921
};

packages/@aws-cdk/aws-cognito/lib/user-pool-attr.ts

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Token } from '@aws-cdk/core';
2+
import { StandardAttributeNames } from './private/attr-names';
23

34
/**
45
* The set of standard attributes that can be marked as required or mutable.
@@ -107,6 +108,18 @@ export interface StandardAttributes {
107108
* @default - see the defaults under `StandardAttribute`
108109
*/
109110
readonly website?: StandardAttribute;
111+
112+
/**
113+
* Whether the email address has been verified.
114+
* @default - see the defaults under `StandardAttribute`
115+
*/
116+
readonly emailVerified?: StandardAttribute;
117+
118+
/**
119+
* Whether the phone number has been verified.
120+
* @default - see the defaults under `StandardAttribute`
121+
*/
122+
readonly phoneNumberVerified?: StandardAttribute;
110123
}
111124

112125
/**
@@ -341,3 +354,190 @@ export class DateTimeAttribute implements ICustomAttribute {
341354
};
342355
}
343356
}
357+
358+
/**
359+
* This interface contains all standard attributes recognized by Cognito
360+
* from https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html
361+
* including `email_verified` and `phone_number_verified`
362+
*/
363+
export interface StandardAttributesMask {
364+
/**
365+
* The user's postal address.
366+
* @default false
367+
*/
368+
readonly address?: boolean;
369+
370+
/**
371+
* The user's birthday, represented as an ISO 8601:2004 format.
372+
* @default false
373+
*/
374+
readonly birthdate?: boolean;
375+
376+
/**
377+
* The user's e-mail address, represented as an RFC 5322 [RFC5322] addr-spec.
378+
* @default false
379+
*/
380+
readonly email?: boolean;
381+
382+
/**
383+
* The surname or last name of the user.
384+
* @default false
385+
*/
386+
readonly familyName?: boolean;
387+
388+
/**
389+
* The user's gender.
390+
* @default false
391+
*/
392+
readonly gender?: boolean;
393+
394+
/**
395+
* The user's first name or give name.
396+
* @default false
397+
*/
398+
readonly givenName?: boolean;
399+
400+
/**
401+
* The user's locale, represented as a BCP47 [RFC5646] language tag.
402+
* @default false
403+
*/
404+
readonly locale?: boolean;
405+
406+
/**
407+
* The user's middle name.
408+
* @default false
409+
*/
410+
readonly middleName?: boolean;
411+
412+
/**
413+
* The user's full name in displayable form, including all name parts, titles and suffixes.
414+
* @default false
415+
*/
416+
readonly fullname?: boolean;
417+
418+
/**
419+
* The user's nickname or casual name.
420+
* @default false
421+
*/
422+
readonly nickname?: boolean;
423+
424+
/**
425+
* The user's telephone number.
426+
* @default false
427+
*/
428+
readonly phoneNumber?: boolean;
429+
430+
/**
431+
* The URL to the user's profile picture.
432+
* @default false
433+
*/
434+
readonly profilePicture?: boolean;
435+
436+
/**
437+
* The user's preffered username, different from the immutable user name.
438+
* @default false
439+
*/
440+
readonly preferredUsername?: boolean;
441+
442+
/**
443+
* The URL to the user's profile page.
444+
* @default false
445+
*/
446+
readonly profilePage?: boolean;
447+
448+
/**
449+
* The user's time zone.
450+
* @default false
451+
*/
452+
readonly timezone?: boolean;
453+
454+
/**
455+
* The time, the user's information was last updated.
456+
* @default false
457+
*/
458+
readonly lastUpdateTime?: boolean;
459+
460+
/**
461+
* The URL to the user's web page or blog.
462+
* @default false
463+
*/
464+
readonly website?: boolean;
465+
466+
/**
467+
* Whether the email address has been verified.
468+
* @default false
469+
*/
470+
readonly emailVerified?: boolean;
471+
472+
/**
473+
* Whether the phone number has been verified.
474+
* @default false
475+
*/
476+
readonly phoneNumberVerified?: boolean;
477+
}
478+
479+
480+
/**
481+
* A set of attributes, useful to set Read and Write attributes
482+
*/
483+
export class ClientAttributes {
484+
485+
/**
486+
* The set of attributes
487+
*/
488+
private attributesSet: Set<string>;
489+
490+
/**
491+
* Creates a ClientAttributes with the specified attributes
492+
*
493+
* @default - a ClientAttributes object without any attributes
494+
*/
495+
constructor() {
496+
this.attributesSet = new Set<string>();
497+
}
498+
499+
/**
500+
* Creates a custom ClientAttributes with the specified attributes
501+
* @param attributes a list of standard attributes to add to the set
502+
*/
503+
public withStandardAttributes(attributes: StandardAttributesMask): ClientAttributes {
504+
let attributesSet = new Set(this.attributesSet);
505+
// iterate through key-values in the `StandardAttributeNames` constant
506+
// to get the value for all attributes
507+
for (const attributeKey in StandardAttributeNames) {
508+
if ((attributes as any)[attributeKey] === true) {
509+
const attributeName = (StandardAttributeNames as any)[attributeKey];
510+
attributesSet.add(attributeName);
511+
}
512+
}
513+
let aux = new ClientAttributes();
514+
aux.attributesSet = attributesSet;
515+
return aux;
516+
}
517+
518+
/**
519+
* Creates a custom ClientAttributes with the specified attributes
520+
* @param attributes a list of custom attributes to add to the set
521+
*/
522+
public withCustomAttributes(...attributes: string[]): ClientAttributes {
523+
let attributesSet: Set<string> = new Set(this.attributesSet);
524+
for (let attribute of attributes) {
525+
// custom attributes MUST begin with `custom:`, so add the string if not present
526+
if (!attribute.startsWith('custom:')) {
527+
attribute = 'custom:' + attribute;
528+
}
529+
attributesSet.add(attribute);
530+
}
531+
let aux = new ClientAttributes();
532+
aux.attributesSet = attributesSet;
533+
return aux;
534+
}
535+
536+
/**
537+
* The list of attributes represented by this ClientAttributes
538+
*/
539+
public attributes(): string[] {
540+
// sorting is unnecessary but it simplify testing
541+
return Array.from(this.attributesSet).sort();
542+
}
543+
}

packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { IResource, Resource, Duration } from '@aws-cdk/core';
22
import { Construct } from 'constructs';
33
import { CfnUserPoolClient } from './cognito.generated';
44
import { IUserPool } from './user-pool';
5+
import { ClientAttributes } from './user-pool-attr';
56
import { IUserPoolResourceServer, ResourceServerScope } from './user-pool-resource-server';
67

78
/**
@@ -272,6 +273,20 @@ export interface UserPoolClientOptions {
272273
* @default Duration.minutes(60)
273274
*/
274275
readonly accessTokenValidity?: Duration;
276+
277+
/**
278+
* The set of attributes this client will be able to read.
279+
* @see https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-attribute-permissions-and-scopes
280+
* @default - all standard and custom attributes
281+
*/
282+
readonly readAttributes?: ClientAttributes;
283+
284+
/**
285+
* The set of attributes this client will be able to write.
286+
* @see https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-attribute-permissions-and-scopes
287+
* @default - all standard and custom attributes
288+
*/
289+
readonly writeAttributes?: ClientAttributes;
275290
}
276291

277292
/**
@@ -358,6 +373,8 @@ export class UserPoolClient extends Resource implements IUserPoolClient {
358373
allowedOAuthFlowsUserPoolClient: !props.disableOAuth,
359374
preventUserExistenceErrors: this.configurePreventUserExistenceErrors(props.preventUserExistenceErrors),
360375
supportedIdentityProviders: this.configureIdentityProviders(props),
376+
readAttributes: props.readAttributes?.attributes(),
377+
writeAttributes: props.writeAttributes?.attributes(),
361378
});
362379
this.configureTokenValidity(resource, props);
363380

0 commit comments

Comments
 (0)