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

feat(cognito): user pool domain #7224

Merged
merged 14 commits into from
Apr 22, 2020
20 changes: 20 additions & 0 deletions packages/@aws-cdk/aws-cognito/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw
- [Lambda Triggers](#lambda-triggers)
- [Import](#importing-user-pools)
- [App Clients](#app-clients)
- [Domains](#domains)

## User Pools

Expand Down Expand Up @@ -399,3 +400,22 @@ pool.addClient('app-client', {
}
});
```

### Domains

After setting up an [app client](#app-clients), the address for the user pool's sign-up and sign-in webpages can be
configured using domains. There are two ways to set up a domain - either the Amazon Cognito hosted domain can be chosen
with an available domain prefix, or a custom domain name can be chosen. The custom domain must be one that is already
owned, and whose certificate is registered in AWS Certificate Manager.

The following code sets up a user pool domain in Amazon Cognito hosted domain with the prefix 'my-awesome-app' -

```ts
const pool = new UserPool(this, 'Pool');
pool.addDomain('domain', {
cognitoDomainPrefix: 'my-awesome-app',
});
```

The `UserPoolDomain` construct exposes a `cloudFrontDomainName` attribute that returns the CloudFront domain name. This
nija-at marked this conversation as resolved.
Show resolved Hide resolved
can then be used to wire it up with a CloudFront distribution or to a Route53 target.
3 changes: 2 additions & 1 deletion packages/@aws-cdk/aws-cognito/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export * from './cognito.generated';

export * from './user-pool';
export * from './user-pool-attr';
export * from './user-pool-client';
export * from './user-pool-client';
export * from './user-pool-domain';
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export class OAuthScope {
}

/**
* Properties for the UserPoolClient construct
* Options to create a UserPoolClient
*/
export interface UserPoolClientOptions {
/**
Expand Down
109 changes: 109 additions & 0 deletions packages/@aws-cdk/aws-cognito/lib/user-pool-domain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { ICertificate } from '@aws-cdk/aws-certificatemanager';
import { Construct, IResource, Resource } from '@aws-cdk/core';
import { AwsCustomResource, AwsCustomResourcePolicy, AwsSdkCall, PhysicalResourceId } from '@aws-cdk/custom-resources';
import { CfnUserPoolDomain } from './cognito.generated';
import { IUserPool } from './user-pool';

/**
* Represents a user pool domain.
*/
export interface IUserPoolDomain extends IResource {
/**
* The domain that was specified to be created.
* If a customDomain was selected, this holds the full domain name that was specified.
* If the `cognitoDomainPrefix` was used, it contains the prefix to the Cognito hosted domain.
* @attribute
*/
readonly domainName: string;
}

/**
* Options to create a UserPoolDomain
*/
export interface UserPoolDomainOptions {
/**
* The domain name that you would like to associate with this User Pool.
* If this is specified, the `certificate` property must also be specified.
* @see https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-add-custom-domain.html
* Both `userPoolDomainName` and `cognitoDomainPrefix` cannot be specified.
* @default - none
*/
readonly userPoolDomainName?: string;

/**
* The prefix to the Cognito hosted domain name that will be associated with the user pool.
* The final domain name will be '[customPrefixDomain].auth.[region].amazoncognito.com'.
nija-at marked this conversation as resolved.
Show resolved Hide resolved
* @see https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-assign-domain-prefix.html
* Both `userPoolDomainName` and `cognitoDomainPrefix` cannot be specified.
* @default - CDK will generate a unique prefix, unless `userPoolDomainName` is specified.
*/
readonly cognitoDomainPrefix?: string;

/**
* The certificate to associate with this domain when `userPoolDomainName` property is used.
* @default - none
*/
readonly certificate?: ICertificate;
}

/**
* Props for UserPoolDomain construct
*/
export interface UserPoolDomainProps extends UserPoolDomainOptions {
/**
* The user pool to which this domain should be associated.
*/
readonly userPool: IUserPool;
}

/**
* Define a user pool domain
*/
export class UserPoolDomain extends Resource implements IUserPoolDomain {
public readonly domainName: string;

constructor(scope: Construct, id: string, props: UserPoolDomainProps) {
super(scope, id);

if ((props.cognitoDomainPrefix && props.userPoolDomainName) || (!props.cognitoDomainPrefix && !props.userPoolDomainName)) {
nija-at marked this conversation as resolved.
Show resolved Hide resolved
throw new Error('One, and only one, of cognitoDomainPrefix and userPoolDomainName must be specified');
}
if (props.userPoolDomainName && !props.certificate) {
nija-at marked this conversation as resolved.
Show resolved Hide resolved
throw new Error('A certificate must be specified when creating your own domain');
}

const domain = props.userPoolDomainName ?? props.cognitoDomainPrefix!;
nija-at marked this conversation as resolved.
Show resolved Hide resolved
const resource = new CfnUserPoolDomain(this, 'Resource', {
userPoolId: props.userPool.userPoolId,
domain,
customDomainConfig: props.certificate ? { certificateArn: props.certificate.certificateArn } : undefined,
});

this.domainName = resource.ref;
}

/**
* The domain name of the CloudFront distribution associated with the user pool domain.
*/
public get cloudFrontDomainName(): string {
nija-at marked this conversation as resolved.
Show resolved Hide resolved
const sdkCall: AwsSdkCall = {
service: 'CognitoIdentityServiceProvider',
action: 'describeUserPoolDomain',
parameters: {
Domain: this.domainName,
},
physicalResourceId: PhysicalResourceId.of(this.domainName),
};
const customResource = new AwsCustomResource(this, 'CloudFrontDomainName', {
resourceType: 'Custom::UserPoolCloudFrontDomainName',
onCreate: sdkCall,
onUpdate: sdkCall,
policy: AwsCustomResourcePolicy.fromSdkCalls({
// DescribeUserPoolDomain only supports access level '*'
// https://docs.aws.amazon.com/IAM/latest/UserGuide/list_amazoncognitouserpools.html#amazoncognitouserpools-actions-as-permissions
resources: [ '*' ],
}),
});
return customResource.getResponseField('DomainDescription.CloudFrontDistribution');
}
}
16 changes: 16 additions & 0 deletions packages/@aws-cdk/aws-cognito/lib/user-pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Construct, Duration, IResource, Lazy, Resource, Stack } from '@aws-cdk/
import { CfnUserPool } from './cognito.generated';
import { ICustomAttribute, RequiredAttributes } from './user-pool-attr';
import { IUserPoolClient, UserPoolClient, UserPoolClientOptions } from './user-pool-client';
import { UserPoolDomain, UserPoolDomainOptions } from './user-pool-domain';

/**
* The different ways in which users of this pool can sign up or sign in.
Expand Down Expand Up @@ -658,13 +659,28 @@ export class UserPool extends Resource implements IUserPool {
(this.triggers as any)[operation.operationName] = fn.functionArn;
}

/**
* Add a new app client to this user pool.
* @see https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-client-apps.html
*/
public addClient(id: string, options?: UserPoolClientOptions): IUserPoolClient {
return new UserPoolClient(this, id, {
userPool: this,
...options
});
}

/**
* Associate a domain to this user pool.
* @see https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-assign-domain.html
*/
public addDomain(id: string, options?: UserPoolDomainOptions): UserPoolDomain {
return new UserPoolDomain(this, id, {
userPool: this,
...options
});
}

private addLambdaPermission(fn: lambda.IFunction, name: string): void {
const capitalize = name.charAt(0).toUpperCase() + name.slice(1);
fn.addPermission(`${capitalize}Cognito`, {
Expand Down
4 changes: 4 additions & 0 deletions packages/@aws-cdk/aws-cognito/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,20 @@
"pkglint": "0.0.0"
},
"dependencies": {
"@aws-cdk/aws-certificatemanager": "0.0.0",
"@aws-cdk/aws-iam": "0.0.0",
"@aws-cdk/aws-lambda": "0.0.0",
"@aws-cdk/core": "0.0.0",
"@aws-cdk/custom-resources": "0.0.0",
"constructs": "^2.0.0"
},
"homepage": "https://github.com/aws/aws-cdk",
"peerDependencies": {
"@aws-cdk/aws-certificatemanager": "0.0.0",
"@aws-cdk/aws-iam": "0.0.0",
"@aws-cdk/aws-lambda": "0.0.0",
"@aws-cdk/core": "0.0.0",
"@aws-cdk/custom-resources": "0.0.0",
"constructs": "^2.0.0"
},
"jest": {},
Expand Down
Loading