Skip to content

Commit 4baea78

Browse files
authored
feat(cognito): use secretsmanager secrets for clientSecretValue (#22885)
…nd validating if at least one is informed ---- ### All Submissions: * [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Unconventional Dependencies: * [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies) ### New Features * [ ] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [ ] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)? *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 10b6b96 commit 4baea78

File tree

10 files changed

+173
-36
lines changed

10 files changed

+173
-36
lines changed

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

+15
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,21 @@ const provider = new cognito.UserPoolIdentityProviderAmazon(this, 'Amazon', {
573573
});
574574
```
575575

576+
Using Google identity provider is possible to use clientSecretValue with SecretValue from secrets manager.
577+
578+
```ts
579+
const userpool = new cognito.UserPool(this, 'Pool');
580+
const secret = secretsManager.Secret.fromSecretAttributes(this, "CognitoClientSecret", {
581+
secretCompleteArn: "arn:aws:secretsmanager:xxx:xxx:secret:xxx-xxx"
582+
}).secretValue
583+
584+
const provider = new cognito.UserPoolIdentityProviderGoogle(this, 'Google', {
585+
clientId: 'amzn-client-id',
586+
clientSecretValue: secret,
587+
userPool: userpool,
588+
});
589+
```
590+
576591
Attribute mapping allows mapping attributes provided by the third-party identity providers to [standard and custom
577592
attributes](#Attributes) of the user pool. Learn more about [Specifying Identity Provider Attribute Mappings for Your
578593
User Pool](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-specifying-attribute-mapping.html).

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

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { SecretValue } from '@aws-cdk/core';
12
import { Construct } from 'constructs';
23
import { CfnUserPoolIdentityProvider } from '../cognito.generated';
34
import { UserPoolIdentityProviderProps } from './base';
@@ -15,8 +16,16 @@ export interface UserPoolIdentityProviderGoogleProps extends UserPoolIdentityPro
1516
/**
1617
* The client secret to be accompanied with clientId for Google APIs to authenticate the client.
1718
* @see https://developers.google.com/identity/sign-in/web/sign-in
19+
* @default none
20+
* @deprecated use clientSecretValue instead
1821
*/
19-
readonly clientSecret: string;
22+
readonly clientSecret?: string;
23+
/**
24+
* The client secret to be accompanied with clientId for Google APIs to authenticate the client as SecretValue
25+
* @see https://developers.google.com/identity/sign-in/web/sign-in
26+
* @default none
27+
*/
28+
readonly clientSecretValue?: SecretValue;
2029
/**
2130
* The list of google permissions to obtain for getting access to the google profile
2231
* @see https://developers.google.com/identity/sign-in/web/sign-in
@@ -37,13 +46,19 @@ export class UserPoolIdentityProviderGoogle extends UserPoolIdentityProviderBase
3746

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

49+
//at least one of the properties must be configured
50+
if ((!props.clientSecret && !props.clientSecretValue) ||
51+
(props.clientSecret && props.clientSecretValue)) {
52+
throw new Error('Exactly one of "clientSecret" or "clientSecretValue" must be configured.');
53+
}
54+
4055
const resource = new CfnUserPoolIdentityProvider(this, 'Resource', {
4156
userPoolId: props.userPool.userPoolId,
4257
providerName: 'Google', // must be 'Google' when the type is 'Google'
4358
providerType: 'Google',
4459
providerDetails: {
4560
client_id: props.clientId,
46-
client_secret: props.clientSecret,
61+
client_secret: props.clientSecretValue ? props.clientSecretValue.unsafeUnwrap() : props.clientSecret,
4762
authorize_scopes: scopes.join(' '),
4863
},
4964
attributeMapping: super.configureAttributeMapping(),
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"version":"20.0.0"}
1+
{"version":"21.0.0"}

packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.js.snapshot/integ-user-pool-idp-google.assets.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
{
2-
"version": "20.0.0",
2+
"version": "21.0.0",
33
"files": {
4-
"79536373e9b12c019b3f973b117c3673ee38c74b1d6ec98e640e039bc242cac9": {
4+
"3f71d591e59a499e629b4e779bfb0ca43a99273439cdca3810400c323ae66100": {
55
"source": {
66
"path": "integ-user-pool-idp-google.template.json",
77
"packaging": "file"
88
},
99
"destinations": {
1010
"current_account-current_region": {
1111
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
12-
"objectKey": "79536373e9b12c019b3f973b117c3673ee38c74b1d6ec98e640e039bc242cac9.json",
12+
"objectKey": "3f71d591e59a499e629b4e779bfb0ca43a99273439cdca3810400c323ae66100.json",
1313
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
1414
}
1515
}

packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.js.snapshot/integ-user-pool-idp-google.template.json

+24-1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,18 @@
6969
}
7070
}
7171
},
72+
"GoogleClientSecretValueD28C3034": {
73+
"Type": "AWS::SecretsManager::Secret",
74+
"Properties": {
75+
"GenerateSecretString": {
76+
"ExcludePunctuation": true,
77+
"PasswordLength": 20
78+
},
79+
"Name": "GoogleClientSecretValueName"
80+
},
81+
"UpdateReplacePolicy": "Delete",
82+
"DeletionPolicy": "Delete"
83+
},
7284
"googleDB2C5242": {
7385
"Type": "AWS::Cognito::UserPoolIdentityProvider",
7486
"Properties": {
@@ -86,7 +98,18 @@
8698
},
8799
"ProviderDetails": {
88100
"client_id": "google-client-id",
89-
"client_secret": "google-client-secret",
101+
"client_secret": {
102+
"Fn::Join": [
103+
"",
104+
[
105+
"{{resolve:secretsmanager:",
106+
{
107+
"Ref": "GoogleClientSecretValueD28C3034"
108+
},
109+
":SecretString:::}}"
110+
]
111+
]
112+
},
90113
"authorize_scopes": "profile"
91114
}
92115
}

packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.js.snapshot/integ.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "20.0.0",
2+
"version": "21.0.0",
33
"testCases": {
44
"integ.user-pool-idp.google": {
55
"stacks": [

packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.js.snapshot/manifest.json

+14-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
{
2-
"version": "20.0.0",
2+
"version": "21.0.0",
33
"artifacts": {
4-
"Tree": {
5-
"type": "cdk:tree",
6-
"properties": {
7-
"file": "tree.json"
8-
}
9-
},
104
"integ-user-pool-idp-google.assets": {
115
"type": "cdk:asset-manifest",
126
"properties": {
@@ -23,7 +17,7 @@
2317
"validateOnSynth": false,
2418
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
2519
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
26-
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/79536373e9b12c019b3f973b117c3673ee38c74b1d6ec98e640e039bc242cac9.json",
20+
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/3f71d591e59a499e629b4e779bfb0ca43a99273439cdca3810400c323ae66100.json",
2721
"requiresBootstrapStackVersion": 6,
2822
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
2923
"additionalDependencies": [
@@ -57,6 +51,12 @@
5751
"data": "pooldomain430FA744"
5852
}
5953
],
54+
"/integ-user-pool-idp-google/GoogleClientSecretValue/Resource": [
55+
{
56+
"type": "aws:cdk:logicalId",
57+
"data": "GoogleClientSecretValueD28C3034"
58+
}
59+
],
6060
"/integ-user-pool-idp-google/google/Resource": [
6161
{
6262
"type": "aws:cdk:logicalId",
@@ -83,6 +83,12 @@
8383
]
8484
},
8585
"displayName": "integ-user-pool-idp-google"
86+
},
87+
"Tree": {
88+
"type": "cdk:tree",
89+
"properties": {
90+
"file": "tree.json"
91+
}
8692
}
8793
}
8894
}

packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.js.snapshot/tree.json

+77-14
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,6 @@
44
"id": "App",
55
"path": "",
66
"children": {
7-
"Tree": {
8-
"id": "Tree",
9-
"path": "Tree",
10-
"constructInfo": {
11-
"fqn": "constructs.Construct",
12-
"version": "10.1.85"
13-
}
14-
},
157
"integ-user-pool-idp-google": {
168
"id": "integ-user-pool-idp-google",
179
"path": "integ-user-pool-idp-google",
@@ -137,6 +129,42 @@
137129
"version": "0.0.0"
138130
}
139131
},
132+
"GoogleClientSecretValue": {
133+
"id": "GoogleClientSecretValue",
134+
"path": "integ-user-pool-idp-google/GoogleClientSecretValue",
135+
"children": {
136+
"Resource": {
137+
"id": "Resource",
138+
"path": "integ-user-pool-idp-google/GoogleClientSecretValue/Resource",
139+
"attributes": {
140+
"aws:cdk:cloudformation:type": "AWS::SecretsManager::Secret",
141+
"aws:cdk:cloudformation:props": {
142+
"generateSecretString": {
143+
"excludePunctuation": true,
144+
"passwordLength": 20
145+
},
146+
"name": "GoogleClientSecretValueName"
147+
}
148+
},
149+
"constructInfo": {
150+
"fqn": "@aws-cdk/aws-secretsmanager.CfnSecret",
151+
"version": "0.0.0"
152+
}
153+
}
154+
},
155+
"constructInfo": {
156+
"fqn": "@aws-cdk/aws-secretsmanager.Secret",
157+
"version": "0.0.0"
158+
}
159+
},
160+
"GoogleClientSecretValue2": {
161+
"id": "GoogleClientSecretValue2",
162+
"path": "integ-user-pool-idp-google/GoogleClientSecretValue2",
163+
"constructInfo": {
164+
"fqn": "@aws-cdk/core.Resource",
165+
"version": "0.0.0"
166+
}
167+
},
140168
"google": {
141169
"id": "google",
142170
"path": "integ-user-pool-idp-google/google",
@@ -161,7 +189,18 @@
161189
},
162190
"providerDetails": {
163191
"client_id": "google-client-id",
164-
"client_secret": "google-client-secret",
192+
"client_secret": {
193+
"Fn::Join": [
194+
"",
195+
[
196+
"{{resolve:secretsmanager:",
197+
{
198+
"Ref": "GoogleClientSecretValueD28C3034"
199+
},
200+
":SecretString:::}}"
201+
]
202+
]
203+
},
165204
"authorize_scopes": "profile"
166205
}
167206
}
@@ -181,20 +220,44 @@
181220
"id": "SignInLink",
182221
"path": "integ-user-pool-idp-google/SignInLink",
183222
"constructInfo": {
184-
"fqn": "constructs.Construct",
185-
"version": "10.1.85"
223+
"fqn": "@aws-cdk/core.CfnOutput",
224+
"version": "0.0.0"
225+
}
226+
},
227+
"BootstrapVersion": {
228+
"id": "BootstrapVersion",
229+
"path": "integ-user-pool-idp-google/BootstrapVersion",
230+
"constructInfo": {
231+
"fqn": "@aws-cdk/core.CfnParameter",
232+
"version": "0.0.0"
233+
}
234+
},
235+
"CheckBootstrapVersion": {
236+
"id": "CheckBootstrapVersion",
237+
"path": "integ-user-pool-idp-google/CheckBootstrapVersion",
238+
"constructInfo": {
239+
"fqn": "@aws-cdk/core.CfnRule",
240+
"version": "0.0.0"
186241
}
187242
}
188243
},
244+
"constructInfo": {
245+
"fqn": "@aws-cdk/core.Stack",
246+
"version": "0.0.0"
247+
}
248+
},
249+
"Tree": {
250+
"id": "Tree",
251+
"path": "Tree",
189252
"constructInfo": {
190253
"fqn": "constructs.Construct",
191-
"version": "10.1.85"
254+
"version": "10.1.161"
192255
}
193256
}
194257
},
195258
"constructInfo": {
196-
"fqn": "constructs.Construct",
197-
"version": "10.1.85"
259+
"fqn": "@aws-cdk/core.App",
260+
"version": "0.0.0"
198261
}
199262
}
200263
}

packages/@aws-cdk/aws-cognito/test/integ.user-pool-idp.google.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,37 @@
1+
import { Secret } from '@aws-cdk/aws-secretsmanager';
12
import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core';
23
import { ProviderAttribute, UserPool, UserPoolIdentityProviderGoogle } from '../lib';
34

5+
46
/*
57
* Stack verification steps
68
* * Visit the URL provided by stack output 'SignInLink' in a browser, and verify the 'Google' sign in link shows up.
79
* * If you plug in valid 'Google' credentials, the federated log in should work.
810
*/
11+
912
const app = new App();
1013
const stack = new Stack(app, 'integ-user-pool-idp-google');
1114

1215
const userpool = new UserPool(stack, 'pool', {
1316
removalPolicy: RemovalPolicy.DESTROY,
1417
});
1518

19+
const secret = new Secret(stack, 'GoogleClientSecretValue', {
20+
secretName: 'GoogleClientSecretValueName',
21+
generateSecretString: {
22+
excludePunctuation: true,
23+
passwordLength: 20,
24+
},
25+
});
26+
27+
const clientSecret = Secret.fromSecretAttributes(stack, 'GoogleClientSecretValue2', {
28+
secretCompleteArn: secret.secretArn,
29+
}).secretValue;
30+
1631
new UserPoolIdentityProviderGoogle(stack, 'google', {
1732
userPool: userpool,
1833
clientId: 'google-client-id',
19-
clientSecret: 'google-client-secret',
34+
clientSecretValue: clientSecret,
2035
attributeMapping: {
2136
givenName: ProviderAttribute.GOOGLE_GIVEN_NAME,
2237
familyName: ProviderAttribute.GOOGLE_FAMILY_NAME,

packages/@aws-cdk/aws-cognito/test/user-pool-idps/google.test.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Template } from '@aws-cdk/assertions';
2-
import { Stack } from '@aws-cdk/core';
2+
import { SecretValue, Stack } from '@aws-cdk/core';
33
import { ProviderAttribute, UserPool, UserPoolIdentityProviderGoogle } from '../../lib';
44

55
describe('UserPoolIdentityProvider', () => {
@@ -13,7 +13,7 @@ describe('UserPoolIdentityProvider', () => {
1313
new UserPoolIdentityProviderGoogle(stack, 'userpoolidp', {
1414
userPool: pool,
1515
clientId: 'google-client-id',
16-
clientSecret: 'google-client-secret',
16+
clientSecretValue: SecretValue.unsafePlainText('google-client-secret'),
1717
});
1818

1919
Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolIdentityProvider', {
@@ -36,7 +36,7 @@ describe('UserPoolIdentityProvider', () => {
3636
new UserPoolIdentityProviderGoogle(stack, 'userpoolidp', {
3737
userPool: pool,
3838
clientId: 'google-client-id',
39-
clientSecret: 'google-client-secret',
39+
clientSecretValue: SecretValue.unsafePlainText('google-client-secret'),
4040
scopes: ['scope1', 'scope2'],
4141
});
4242

@@ -60,7 +60,7 @@ describe('UserPoolIdentityProvider', () => {
6060
const provider = new UserPoolIdentityProviderGoogle(stack, 'userpoolidp', {
6161
userPool: pool,
6262
clientId: 'google-client-id',
63-
clientSecret: 'google-client-secret',
63+
clientSecretValue: SecretValue.unsafePlainText('google-client-secret'),
6464
});
6565

6666
// THEN
@@ -76,7 +76,7 @@ describe('UserPoolIdentityProvider', () => {
7676
new UserPoolIdentityProviderGoogle(stack, 'userpoolidp', {
7777
userPool: pool,
7878
clientId: 'google-client-id',
79-
clientSecret: 'google-client-secret',
79+
clientSecretValue: SecretValue.unsafePlainText('google-client-secret'),
8080
attributeMapping: {
8181
givenName: ProviderAttribute.GOOGLE_NAME,
8282
address: ProviderAttribute.other('google-address'),

0 commit comments

Comments
 (0)