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 identity provider with support for Facebook & Amazon #8134

Merged
merged 14 commits into from
Jun 3, 2020
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 @@ -3,4 +3,5 @@ export * from './cognito.generated';
export * from './user-pool';
export * from './user-pool-attr';
export * from './user-pool-client';
export * from './user-pool-domain';
export * from './user-pool-domain';
export * from './user-pool-idp';
220 changes: 220 additions & 0 deletions packages/@aws-cdk/aws-cognito/lib/user-pool-idp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
import { Construct, IResource, Resource } from '@aws-cdk/core';
import { CfnUserPoolIdentityProvider } from './cognito.generated';
import { IUserPool } from './user-pool';

/**
* Represents a UserPoolIdentityProvider
*/
export interface IUserPoolIdentityProvider extends IResource {
/**
* The primary identifier of this identity provider
* @attribute
*/
readonly providerName: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

This could be typed UserPoolClientIdentityProvider.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not so confident that they are one and the same. They are the same at the moment, for the providers I've chosen to implement.

Ex: the list here does not match up with here.

It's not clear yet if this is a documentation gap, or something more.

Leaving this as is for now.

}

/**
* Properties to initialize UserPoolFacebookIdentityProvider
*/
export interface UserPoolFacebookIdentityProviderProps {
/**
* The user pool to which this construct provides identities.
*/
readonly userPool: IUserPool;

/**
* The client id recognized by Facebook APIs.
*/
readonly clientId: string;
/**
* The client secret to be accompanied with clientUd for Facebook to authenticate the client.
* @see https://developers.facebook.com/docs/facebook-login/security#appsecret
*/
readonly clientSecret: string;
/**
* The list of facebook permissions to obtain for getting access to the Facebook profile.
* @see https://developers.facebook.com/docs/facebook-login/permissions
* @default [ public_profile ]
*/
readonly scopes?: string[];
/**
* The Facebook API version to use
* @default - to the oldest version supported by Facebook
*/
readonly apiVersion?: string;
}

/**
* Represents a identity provider that integrates with 'Facebook Login'
* @resource AWS::Cognito::UserPoolIdentityProvider
*/
export class UserPoolFacebookIdentityProvider extends Resource implements IUserPoolIdentityProvider {
public readonly providerName: string;

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

const scopes = props.scopes ?? [ 'public_profile' ];

const resource = new CfnUserPoolIdentityProvider(this, 'Resource', {
userPoolId: props.userPool.userPoolId,
providerName: 'Facebook', // must be 'Facebook' when the type is 'Facebook'
providerType: 'Facebook',
providerDetails: {
client_id: props.clientId,
client_secret: props.clientSecret,
authorize_scopes: scopes.join(','),
api_version: props.apiVersion,
},
});

this.providerName = super.getResourceNameAttribute(resource.ref);
}
}

/**
* Properties to initialize UserPoolAmazonIdentityProvider
*/
export interface UserPoolAmazonIdentityProviderProps {
/**
* The user pool to which this construct provides identities.
*/
readonly userPool: IUserPool;

/**
* The client id recognized by 'Login with Amazon' APIs.
* @see https://developer.amazon.com/docs/login-with-amazon/security-profile.html#client-identifier
*/
readonly clientId: string;
/**
* The client secret to be accompanied with clientId for 'Login with Amazon' APIs to authenticate the client.
* @see https://developer.amazon.com/docs/login-with-amazon/security-profile.html#client-identifier
*/
readonly clientSecret: string;
/**
* The types of user profile data to obtain for the Amazon profile.
* @see https://developer.amazon.com/docs/login-with-amazon/customer-profile.html
* @default [ profile ]
*/
readonly scopes?: string[];
}

/**
* Represents a identity provider that integrates with 'Login with Amazon'
* @resource AWS::Cognito::UserPoolIdentityProvider
*/
export class UserPoolAmazonIdentityProvider extends Resource implements IUserPoolIdentityProvider {
public readonly providerName: string;

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

const scopes = props.scopes ?? [ 'profile' ];

const resource = new CfnUserPoolIdentityProvider(this, 'Resource', {
userPoolId: props.userPool.userPoolId,
providerName: 'LoginWithAmazon', // must be 'LoginWithAmazon' when the type is 'LoginWithAmazon'
providerType: 'LoginWithAmazon',
providerDetails: {
client_id: props.clientId,
client_secret: props.clientSecret,
authorize_scopes: scopes.join(' '),
},
});

this.providerName = super.getResourceNameAttribute(resource.ref);
}
}

/**
* Properties to initialize UserPoolAppleIdentityProvider
*/
export interface UserPoolAppleIdentityProviderProps {
/**
* The user pool to which this construct provides identities.
*/
readonly userPool: IUserPool;

/**
* The Services id received when the 'Sign in with Apple' client was created.
*/
readonly servicesId: string;
/**
* The team id received when the 'Sign in with Apple' client was created.
*/
readonly teamId: string;
/**
* The key id received when the 'Sign in with Apple' client was created.
*/
readonly keyId: string;
/**
* The private key received when the 'Sign in with Apple' client was created.
*/
readonly privateKey: string;
/**
* The types of user profile data to obtain for the Amazon profile.
* @see https://developer.amazon.com/docs/login-with-amazon/customer-profile.html
* @default [ public_profile, email ]
*/
readonly scopes?: string[];
}

/**
* Represents a identity provider that integrates with 'Login with Amazon'
* @resource AWS::Cognito::UserPoolIdentityProvider
*/
export class UserPoolAppleIdentityProvider extends Resource implements IUserPoolIdentityProvider {
public readonly providerName: string;

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

const scopes = props.scopes ?? [ 'public_profile', 'email' ];

const resource = new CfnUserPoolIdentityProvider(this, 'Resource', {
userPoolId: props.userPool.userPoolId,
providerName: 'SignInWithApple', // must be 'SignInWithApple' when the type is 'SignInWithApple'
providerType: 'SignInWithApple',
providerDetails: {
client_id: props.servicesId,
team_id: props.teamId,
key_id: props.keyId,
private_key: props.privateKey,
authorize_scopes: scopes.join(' '),
},
});

this.providerName = super.getResourceNameAttribute(resource.ref);
}
}

/**
* Options to integrate with the various social identity providers.
*/
export class UserPoolIdentityProvider {
/**
* Federate with 'Facebook Login'
* @see https://developers.facebook.com/docs/facebook-login/
*/
public static facebook(scope: Construct, id: string, options: UserPoolFacebookIdentityProviderProps) {
return new UserPoolFacebookIdentityProvider(scope, id, options);
}

/**
* Federate with 'Login with Amazon'
* @see https://developer.amazon.com/apps-and-games/login-with-amazon
*/
public static amazon(scope: Construct, id: string, options: UserPoolAmazonIdentityProviderProps) {
return new UserPoolAmazonIdentityProvider(scope, id, options);
}

/**
* Federate with 'Sign in with Apple'
* @see https://developer.apple.com/sign-in-with-apple/
*/
public static apple(scope: Construct, id: string, options: UserPoolAppleIdentityProviderProps) {
return new UserPoolAppleIdentityProvider(scope, id, options);
}

private constructor() {}
}
5 changes: 4 additions & 1 deletion packages/@aws-cdk/aws-cognito/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@
"exclude": [
"attribute-tag:@aws-cdk/aws-cognito.UserPoolClient.userPoolClientName",
"resource-attribute:@aws-cdk/aws-cognito.UserPoolClient.userPoolClientClientSecret",
"props-physical-name:@aws-cdk/aws-cognito.UserPoolDomainProps"
"props-physical-name:@aws-cdk/aws-cognito.UserPoolDomainProps",
"props-physical-name:@aws-cdk/aws-cognito.UserPoolFacebookIdentityProviderProps",
"props-physical-name:@aws-cdk/aws-cognito.UserPoolAmazonIdentityProviderProps",
"props-physical-name:@aws-cdk/aws-cognito.UserPoolAppleIdentityProviderProps"
]
},
"stability": "experimental",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{
"Resources": {
"poolsmsRole04048F13": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "integuserpoolidppoolAE0BD80C"
}
},
"Effect": "Allow",
"Principal": {
"Service": "cognito-idp.amazonaws.com"
}
}
],
"Version": "2012-10-17"
},
"Policies": [
{
"PolicyDocument": {
"Statement": [
{
"Action": "sns:Publish",
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"PolicyName": "sns-publish"
}
]
}
},
"pool056F3F7E": {
"Type": "AWS::Cognito::UserPool",
"Properties": {
"AdminCreateUserConfig": {
"AllowAdminCreateUserOnly": true
},
"EmailVerificationMessage": "The verification code to your new account is {####}",
"EmailVerificationSubject": "Verify your new account",
"SmsConfiguration": {
"ExternalId": "integuserpoolidppoolAE0BD80C",
"SnsCallerArn": {
"Fn::GetAtt": [
"poolsmsRole04048F13",
"Arn"
]
}
},
"SmsVerificationMessage": "The verification code to your new account is {####}",
"VerificationMessageTemplate": {
"DefaultEmailOption": "CONFIRM_WITH_CODE",
"EmailMessage": "The verification code to your new account is {####}",
"EmailSubject": "Verify your new account",
"SmsMessage": "The verification code to your new account is {####}"
}
}
},
"amazon2D32744A": {
"Type": "AWS::Cognito::UserPoolIdentityProvider",
"Properties": {
"ProviderName": "LoginWithAmazon",
"ProviderType": "LoginWithAmazon",
"UserPoolId": {
"Ref": "pool056F3F7E"
},
"ProviderDetails": {
"client_id": "amzn-client-id",
"client_secret": "amzn-client-secret",
"authorize_scopes": "profile"
}
}
},
"facebook4309A463": {
"Type": "AWS::Cognito::UserPoolIdentityProvider",
"Properties": {
"ProviderName": "Facebook",
"ProviderType": "Facebook",
"UserPoolId": {
"Ref": "pool056F3F7E"
},
"ProviderDetails": {
"client_id": "amzn-client-id",
"client_secret": "amzn-client-secret",
"authorize_scopes": "public_profile"
}
}
}
}
}
19 changes: 19 additions & 0 deletions packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { App, Stack } from '@aws-cdk/core';
import { UserPool, UserPoolIdentityProvider } from '../lib';

const app = new App();
const stack = new Stack(app, 'integ-user-pool-idp');

const userpool = new UserPool(stack, 'pool');

UserPoolIdentityProvider.amazon(stack, 'amazon', {
clientId: 'amzn-client-id',
clientSecret: 'amzn-client-secret',
userPool: userpool,
});

UserPoolIdentityProvider.facebook(stack, 'facebook', {
clientId: 'amzn-client-id',
clientSecret: 'amzn-client-secret',
userPool: userpool,
});
Loading