@aws/nx-plugin 0.1.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/LICENSE-THIRD-PARTY +114 -244
  2. package/generators.json +1 -7
  3. package/package.json +1 -1
  4. package/src/cloudscape-website/app/README.md +84 -48
  5. package/src/cloudscape-website/app/__snapshots__/generator.spec.ts.snap +157 -218
  6. package/src/cloudscape-website/app/files/app/README.md.template +44 -0
  7. package/src/cloudscape-website/app/files/app/src/layouts/App/index.tsx.template +40 -43
  8. package/src/cloudscape-website/app/files/app/src/layouts/App/navitems.ts.template +3 -3
  9. package/src/cloudscape-website/app/files/app/src/layouts/Routes/index.tsx.template +4 -6
  10. package/src/cloudscape-website/app/files/app/src/main.tsx.template +7 -10
  11. package/src/cloudscape-website/app/files/app/src/pages/Home/index.tsx.template +0 -2
  12. package/src/cloudscape-website/app/files/common/constructs/src/app/static-websites/__websiteNameKebabCase__.ts.template +13 -0
  13. package/src/cloudscape-website/app/files/common/constructs/src/{__websiteNameKebabCase__ → core}/static-website.ts.template +74 -144
  14. package/src/cloudscape-website/app/generator.js +74 -64
  15. package/src/cloudscape-website/app/generator.js.map +1 -1
  16. package/src/cloudscape-website/app/schema.d.ts +3 -4
  17. package/src/cloudscape-website/app/schema.json +1 -24
  18. package/src/cloudscape-website/cognito-auth/README.md +53 -32
  19. package/src/cloudscape-website/cognito-auth/__snapshots__/generator.spec.ts.snap +161 -125
  20. package/src/cloudscape-website/cognito-auth/files/app/components/CognitoAuth/index.tsx.template +53 -39
  21. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/core/user-identity.ts.template +168 -0
  22. package/src/cloudscape-website/cognito-auth/generator.js +129 -46
  23. package/src/cloudscape-website/cognito-auth/generator.js.map +1 -1
  24. package/src/cloudscape-website/cognito-auth/schema.d.ts +1 -0
  25. package/src/cloudscape-website/cognito-auth/schema.json +7 -1
  26. package/src/cloudscape-website/runtime-config/__snapshots__/generator.spec.ts.snap +15 -17
  27. package/src/cloudscape-website/runtime-config/files/app/components/RuntimeConfig/index.tsx.template +7 -10
  28. package/src/cloudscape-website/runtime-config/files/app/hooks/useRuntimeConfig.tsx.template +13 -0
  29. package/src/cloudscape-website/runtime-config/generator.js +3 -1
  30. package/src/cloudscape-website/runtime-config/generator.js.map +1 -1
  31. package/src/infra/app/README.md +71 -46
  32. package/src/infra/app/__snapshots__/generator.spec.ts.snap +114 -252
  33. package/src/infra/app/files/app/README.md.template +76 -0
  34. package/src/infra/app/files/app/src/main.ts.template +18 -0
  35. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/aws-prototyping.guard +1282 -0
  36. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/cfn-nag.guard +6839 -0
  37. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/hipaa-security.guard +2807 -0
  38. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/nist-csf.guard +2585 -0
  39. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/pci-dss-3-2-1.guard +2236 -0
  40. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/wa-reliability-pillar.guard +885 -0
  41. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/wa-security-pillar.guard +2205 -0
  42. package/src/infra/app/files/common/constructs/src/core/cfn-guard.ts.template +63 -0
  43. package/src/infra/app/generator.js +17 -3
  44. package/src/infra/app/generator.js.map +1 -1
  45. package/src/infra/app/schema.d.ts +10 -1
  46. package/src/infra/app/schema.json +16 -8
  47. package/src/trpc/backend/README.md +102 -80
  48. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +37 -17
  49. package/src/trpc/backend/files/backend/README.md.template +33 -0
  50. package/src/trpc/backend/files/common/constructs/src/app/trpc-apis/__apiNameKebabCase__.ts.template +18 -0
  51. package/src/trpc/backend/files/common/constructs/src/{__apiNameKebabCase__/index.ts.template → core/trpc-api.ts.template} +12 -16
  52. package/src/trpc/backend/files/schema/README.md.template +33 -0
  53. package/src/trpc/backend/generator.js +29 -43
  54. package/src/trpc/backend/generator.js.map +1 -1
  55. package/src/trpc/backend/schema.d.ts +3 -1
  56. package/src/trpc/backend/schema.json +8 -13
  57. package/src/trpc/react/README.md +46 -66
  58. package/src/trpc/react/__snapshots__/generator.spec.ts.snap +104 -65
  59. package/src/trpc/react/files/src/components/TrpcClients/IsolatedTrpcProvider.tsx.template +75 -0
  60. package/src/trpc/react/files/src/components/TrpcClients/TrpcApis.tsx.template +1 -0
  61. package/src/trpc/react/files/src/components/TrpcClients/TrpcClientProviders.tsx.template +10 -0
  62. package/src/trpc/react/files/src/components/TrpcClients/index.tsx.template +5 -0
  63. package/src/trpc/react/files/src/hooks/useSigV4.tsx.template +38 -0
  64. package/src/trpc/react/files/src/hooks/use__apiNameClassName__.tsx.template +3 -0
  65. package/src/trpc/react/generator.js +123 -24
  66. package/src/trpc/react/generator.js.map +1 -1
  67. package/src/trpc/react/schema.json +2 -2
  68. package/src/ts/cjs-to-esm/generator.js.map +1 -1
  69. package/src/ts/lib/eslint.d.ts +1 -1
  70. package/src/ts/lib/eslint.js +59 -11
  71. package/src/ts/lib/eslint.js.map +1 -1
  72. package/src/ts/lib/files/README.md.template +33 -0
  73. package/src/ts/lib/generator.js +11 -4
  74. package/src/ts/lib/generator.js.map +1 -1
  75. package/src/ts/lib/schema.d.ts +1 -3
  76. package/src/ts/lib/schema.json +2 -15
  77. package/src/ts/lib/ts-project-utils.js.map +1 -1
  78. package/src/ts/lib/vitest.js +14 -0
  79. package/src/ts/lib/vitest.js.map +1 -1
  80. package/src/utils/ast.d.ts +13 -0
  81. package/src/utils/ast.js +102 -0
  82. package/src/utils/ast.js.map +1 -0
  83. package/src/utils/files/common/constructs/src/app/index.ts.template +0 -0
  84. package/src/utils/files/common/constructs/src/{runtime-config → core}/runtime-config.ts.template +3 -5
  85. package/src/utils/files/common/constructs/src/index.ts.template +2 -1
  86. package/src/utils/files/common/readme/README.md.template +33 -0
  87. package/src/utils/files/common/types/src/runtime-config.ts.template +1 -13
  88. package/src/utils/format.js.map +1 -1
  89. package/src/utils/names.d.ts +2 -0
  90. package/src/utils/names.js +27 -0
  91. package/src/utils/names.js.map +1 -0
  92. package/src/utils/npm-scope.js.map +1 -1
  93. package/src/utils/paths.js.map +1 -1
  94. package/src/utils/shared-constructs.js +37 -4
  95. package/src/utils/shared-constructs.js.map +1 -1
  96. package/src/utils/versions.d.ts +15 -9
  97. package/src/utils/versions.js +14 -8
  98. package/src/utils/versions.js.map +1 -1
  99. package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/cloudfront-web-acl.ts.template +0 -317
  100. package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/index.ts.template +0 -4
  101. package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/webacl_event_handler/index.ts.template +0 -301
  102. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/index.ts.template +0 -4
  103. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/user-identity.ts.template +0 -66
  104. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/userpool-with-mfa.ts.template +0 -70
  105. package/src/gitlab/generator.d.ts +0 -8
  106. package/src/gitlab/generator.js +0 -16
  107. package/src/gitlab/generator.js.map +0 -1
  108. package/src/gitlab/schema.d.ts +0 -9
  109. package/src/gitlab/schema.json +0 -52
  110. package/src/infra/app/files/src/main.ts.template +0 -37
  111. package/src/trpc/react/files/src/components/TRPCClientProvider/index.tsx.template +0 -34
  112. package/src/trpc/react/files/src/hooks/useTrpc.tsx.template +0 -5
  113. /package/src/infra/app/files/{cdk.json → app/cdk.json} +0 -0
  114. /package/src/infra/app/files/{src → app/src}/stacks/application-stack.ts.template +0 -0
  115. /package/src/utils/files/common/constructs/src/{runtime-config → core}/index.ts.template +0 -0
@@ -1,12 +1,10 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`cognito-auth generator > should generate files > cognito-auth-component 1`] = `
4
- "/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
5
- SPDX-License-Identifier: Apache-2.0 */
6
- import { CognitoAuth as NorthstarCognitoAuth } from '@aws-northstar/ui';
7
- import React, { useContext } from 'react';
8
- import Config from '../../config';
9
- import { RuntimeConfigContext } from '../RuntimeConfig';
4
+ "import React, { PropsWithChildren, useEffect } from 'react';
5
+ import { AuthProvider, AuthProviderProps, useAuth } from 'react-oidc-context';
6
+ import { Alert, Spinner } from '@cloudscape-design/components';
7
+ import { useRuntimeConfig } from '../../hooks/useRuntimeConfig';
10
8
 
11
9
  /**
12
10
  * Sets up the Cognito auth.
@@ -14,105 +12,119 @@ import { RuntimeConfigContext } from '../RuntimeConfig';
14
12
  * This assumes a runtime-config.json file is present at '/'. In order for Auth to be set up automatically,
15
13
  * the runtime-config.json must have the cognitoProps set.
16
14
  */
17
- const CognitoAuth: React.FC<any> = ({ children }) => {
18
- const runtimeConfig = useContext(RuntimeConfigContext);
19
-
20
- return runtimeConfig?.cognitoProps ? (
21
- <NorthstarCognitoAuth
22
- header={Config.applicationName}
23
- userPoolId={runtimeConfig.cognitoProps.userPoolId}
24
- clientId={runtimeConfig.cognitoProps.userPoolWebClientId}
25
- region={runtimeConfig.cognitoProps.region}
26
- identityPoolId={runtimeConfig.cognitoProps.identityPoolId}
27
- allowSignup={true}
28
- signUpAttributes={[
29
- {
30
- displayName: 'Email',
31
- name: 'email',
32
- required: true,
33
- },
34
- {
35
- displayName: 'Given name',
36
- name: 'given_name',
37
- required: true,
38
- },
39
- {
40
- displayName: 'Last name',
41
- name: 'family_name',
42
- required: true,
43
- },
44
- ]}
45
- >
46
- {children}
47
- </NorthstarCognitoAuth>
48
- ) : (
49
- <></>
15
+ const CognitoAuth: React.FC<PropsWithChildren> = ({ children }) => {
16
+ const { cognitoProps } = useRuntimeConfig();
17
+
18
+ if (!cognitoProps) {
19
+ return (
20
+ <Alert type="error" header="Runtime config configuration error">
21
+ The cognitoProps have not been configured in the runtime-config.json.
22
+ </Alert>
23
+ );
24
+ }
25
+
26
+ const cognitoAuthConfig: AuthProviderProps = {
27
+ authority: \`https://cognito-idp.\${cognitoProps.region}.amazonaws.com/\${cognitoProps.userPoolId}\`,
28
+ client_id: cognitoProps.userPoolWebClientId,
29
+ redirect_uri: window.location.origin,
30
+ response_type: 'code',
31
+ scope: 'email openid profile',
32
+ };
33
+
34
+ return (
35
+ <AuthProvider {...cognitoAuthConfig}>
36
+ <CognitoAuthInternal>{children}</CognitoAuthInternal>
37
+ </AuthProvider>
50
38
  );
51
39
  };
52
40
 
41
+ const CognitoAuthInternal: React.FC<PropsWithChildren> = ({ children }) => {
42
+ const auth = useAuth();
43
+
44
+ useEffect(() => {
45
+ if (!auth.isAuthenticated && !auth.isLoading) {
46
+ auth.signinRedirect();
47
+ }
48
+ }, [auth]);
49
+
50
+ if (auth.isAuthenticated) {
51
+ return children;
52
+ } else if (auth.error) {
53
+ return (
54
+ <Alert type="error" header="Configuration error">
55
+ Error contacting Cognito. Please check your runtime-config.json is
56
+ configured with the correct endpoints.
57
+ </Alert>
58
+ );
59
+ } else {
60
+ return <Spinner />;
61
+ }
62
+ };
63
+
53
64
  export default CognitoAuth;
54
65
  "
55
66
  `;
56
67
 
57
68
  exports[`cognito-auth generator > should generate files > identity-index 1`] = `
58
- "/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
59
- SPDX-License-Identifier: Apache-2.0 */
60
- export * from './user-identity.js';
61
- export * from './userpool-with-mfa.js';
62
- "
69
+ "export * from "./user-identity.js";
70
+ export * from './runtime-config.js';"
63
71
  `;
64
72
 
65
73
  exports[`cognito-auth generator > should generate files > user-identity 1`] = `
66
- "/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
67
- SPDX-License-Identifier: Apache-2.0 */
68
- import {
74
+ "import {
69
75
  IdentityPool,
70
76
  UserPoolAuthenticationProvider,
71
77
  } from '@aws-cdk/aws-cognito-identitypool-alpha';
72
- import { CfnOutput, Stack } from 'aws-cdk-lib';
73
- import { UserPool, UserPoolClient } from 'aws-cdk-lib/aws-cognito';
78
+ import { CfnOutput, Duration, Lazy, Stack } from 'aws-cdk-lib';
79
+ import {
80
+ AccountRecovery,
81
+ CfnManagedLoginBranding,
82
+ CfnUserPoolDomain,
83
+ FeaturePlan,
84
+ Mfa,
85
+ OAuthScope,
86
+ UserPool,
87
+ UserPoolClient,
88
+ } from 'aws-cdk-lib/aws-cognito';
74
89
  import { Construct } from 'constructs';
75
- import { UserPoolWithMfa } from './userpool-with-mfa.js';
76
- import { RuntimeConfig } from '../runtime-config/index.js';
90
+ import { RuntimeConfig } from './runtime-config.js';
91
+ import { Distribution } from 'aws-cdk-lib/aws-cloudfront';
77
92
 
78
93
  const WEB_CLIENT_ID = 'WebClient';
79
-
80
94
  /**
81
95
  * Creates a UserPool and Identity Pool with sane defaults configured intended for usage from a web client.
82
96
  */
83
97
  export class UserIdentity extends Construct {
98
+ public readonly region: string;
84
99
  public readonly identityPool: IdentityPool;
85
100
  public readonly userPool: UserPool;
86
101
  public readonly userPoolClient: UserPoolClient;
102
+ public readonly userPoolDomain: CfnUserPoolDomain;
87
103
 
88
104
  constructor(scope: Construct, id: string) {
89
105
  super(scope, id);
90
106
 
91
- // Unless explicitly stated, created a default Cognito User Pool and Web Client.
92
- this.userPool = new UserPoolWithMfa(this, 'UserPool');
93
-
94
- this.identityPool = new IdentityPool(this, 'IdentityPool');
95
-
96
- const existingClient = this.userPool.node.children.find(
97
- (e) => e.node.id === WEB_CLIENT_ID && e instanceof UserPoolClient
98
- ) as UserPoolClient | undefined;
99
-
100
- this.userPoolClient =
101
- existingClient ??
102
- this.userPool.addClient(WEB_CLIENT_ID, {
103
- authFlows: {
104
- userPassword: true,
105
- userSrp: true,
106
- },
107
- });
108
-
109
- this.identityPool.addUserPoolAuthentication(
110
- new UserPoolAuthenticationProvider({
111
- userPool: this.userPool,
112
- userPoolClient: this.userPoolClient,
113
- })
107
+ this.region = Stack.of(this).region;
108
+ this.userPool = this.createUserPool();
109
+ this.userPoolDomain = this.createUserPoolDomain(this.userPool);
110
+ this.userPoolClient = this.createUserPoolClient(this.userPool);
111
+ this.identityPool = this.createIdentityPool(
112
+ this.userPool,
113
+ this.userPoolClient
114
+ );
115
+ this.createManagedLoginBranding(
116
+ this.userPool,
117
+ this.userPoolClient,
118
+ this.userPoolDomain
114
119
  );
115
120
 
121
+ RuntimeConfig.ensure(this).config.cognitoProps = {
122
+ region: Stack.of(this).region,
123
+ identityPoolId: this.identityPool.identityPoolId,
124
+ userPoolId: this.userPool.userPoolId,
125
+ userPoolWebClientId: this.userPoolClient.userPoolClientId,
126
+ };
127
+
116
128
  new CfnOutput(this, \`\${id}-UserPoolId\`, {
117
129
  value: this.userPool.userPoolId,
118
130
  });
@@ -120,37 +132,10 @@ export class UserIdentity extends Construct {
120
132
  new CfnOutput(this, \`\${id}-IdentityPoolId\`, {
121
133
  value: this.identityPool.identityPoolId,
122
134
  });
123
-
124
- RuntimeConfig.ensure(this).config.cognitoProps = {
125
- region: Stack.of(this).region,
126
- identityPoolId: this.identityPool.identityPoolId,
127
- userPoolId: this.userPool?.userPoolId,
128
- userPoolWebClientId: this.userPoolClient?.userPoolClientId,
129
- };
130
135
  }
131
- }
132
- "
133
- `;
134
136
 
135
- exports[`cognito-auth generator > should generate files > userpool-with-mfa 1`] = `
136
- "/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
137
- SPDX-License-Identifier: Apache-2.0 */
138
- import { PDKNag } from '@aws/pdk/pdk-nag';
139
- import { Duration, Stack } from 'aws-cdk-lib';
140
- import {
141
- AccountRecovery,
142
- AdvancedSecurityMode,
143
- Mfa,
144
- UserPool,
145
- } from 'aws-cdk-lib/aws-cognito';
146
- import { Construct } from 'constructs';
147
-
148
- /**
149
- * Configures a UserPool with MFA across SMS/TOTP using sane defaults.
150
- */
151
- export class UserPoolWithMfa extends UserPool {
152
- constructor(scope: Construct, id: string) {
153
- super(scope, id, {
137
+ private createUserPool = () =>
138
+ new UserPool(this, 'UserPool', {
154
139
  deletionProtection: true,
155
140
  passwordPolicy: {
156
141
  minLength: 8,
@@ -161,9 +146,9 @@ export class UserPoolWithMfa extends UserPool {
161
146
  tempPasswordValidity: Duration.days(3),
162
147
  },
163
148
  mfa: Mfa.REQUIRED,
149
+ featurePlan: FeaturePlan.ESSENTIALS,
164
150
  mfaSecondFactor: { sms: true, otp: true },
165
151
  signInCaseSensitive: false,
166
- advancedSecurityMode: AdvancedSecurityMode.ENFORCED,
167
152
  signInAliases: { username: true, email: true },
168
153
  accountRecovery: AccountRecovery.EMAIL_ONLY,
169
154
  selfSignUpEnabled: true,
@@ -183,25 +168,76 @@ export class UserPoolWithMfa extends UserPool {
183
168
  },
184
169
  });
185
170
 
186
- const stack = Stack.of(this);
187
-
188
- ['AwsSolutions-IAM5', 'AwsPrototyping-IAMNoWildcardPermissions'].forEach(
189
- (RuleId) => {
190
- PDKNag.addResourceSuppressionsByPathNoThrow(
191
- stack,
192
- \`\${PDKNag.getStackPrefix(stack)}\${id}/UserPool/smsRole/Resource\`,
193
- [
194
- {
195
- id: RuleId,
196
- reason:
197
- 'MFA requires sending a text to a users phone number which cannot be known at deployment time.',
198
- appliesTo: ['Resource::*'],
199
- },
200
- ]
201
- );
202
- }
171
+ private createUserPoolDomain = (userPool: UserPool) =>
172
+ new CfnUserPoolDomain(this, 'UserPoolDomain', {
173
+ domain: \`test-\${Stack.of(this).account}\`,
174
+ userPoolId: userPool.userPoolId,
175
+ managedLoginVersion: 2,
176
+ });
177
+
178
+ private createUserPoolClient = (userPool: UserPool) => {
179
+ const lazilyComputedCallbackUrls = Lazy.list({
180
+ produce: () =>
181
+ [
182
+ 'http://localhost:4200',
183
+ \`https://\${Stack.of(this).region}.console.aws.amazon.com\`,
184
+ ].concat(
185
+ this.findCloudFrontDistributions().map(
186
+ (d) => \`https://\${d.domainName}\`
187
+ )
188
+ ),
189
+ });
190
+
191
+ return userPool.addClient(WEB_CLIENT_ID, {
192
+ authFlows: {
193
+ userPassword: true,
194
+ userSrp: true,
195
+ user: true,
196
+ },
197
+ oAuth: {
198
+ flows: {
199
+ authorizationCodeGrant: true,
200
+ },
201
+ scopes: [OAuthScope.EMAIL, OAuthScope.OPENID, OAuthScope.PROFILE],
202
+ callbackUrls: lazilyComputedCallbackUrls,
203
+ logoutUrls: lazilyComputedCallbackUrls,
204
+ },
205
+ preventUserExistenceErrors: true,
206
+ });
207
+ };
208
+
209
+ private createIdentityPool = (
210
+ userPool: UserPool,
211
+ userPoolClient: UserPoolClient
212
+ ) => {
213
+ const identityPool = new IdentityPool(this, 'IdentityPool');
214
+
215
+ identityPool.addUserPoolAuthentication(
216
+ new UserPoolAuthenticationProvider({
217
+ userPool,
218
+ userPoolClient,
219
+ })
203
220
  );
204
- }
221
+
222
+ return identityPool;
223
+ };
224
+
225
+ private createManagedLoginBranding = (
226
+ userPool: UserPool,
227
+ userPoolClient: UserPoolClient,
228
+ userPoolDomain: CfnUserPoolDomain
229
+ ) => {
230
+ new CfnManagedLoginBranding(this, 'ManagedLoginBranding', {
231
+ userPoolId: userPool.userPoolId,
232
+ clientId: userPoolClient.userPoolClientId,
233
+ useCognitoProvidedValues: true,
234
+ }).node.addDependency(userPoolClient, userPool, userPoolDomain);
235
+ };
236
+
237
+ private findCloudFrontDistributions = (): Distribution[] =>
238
+ Stack.of(this)
239
+ .node.findAll()
240
+ .filter((child) => child instanceof Distribution);
205
241
  }
206
242
  "
207
243
  `;
@@ -228,6 +264,6 @@ export function App() {
228
264
  `;
229
265
 
230
266
  exports[`cognito-auth generator > should update shared constructs index.ts > common/constructs-index 1`] = `
231
- "export * from './identity/index.js';
232
- export * from './runtime-config/index.js';"
267
+ "export * from "./user-identity.js";
268
+ export * from './runtime-config.js';"
233
269
  `;
@@ -1,9 +1,7 @@
1
- /*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
2
- SPDX-License-Identifier: Apache-2.0 */
3
- import { CognitoAuth as NorthstarCognitoAuth } from '@aws-northstar/ui';
4
- import React, { useContext } from 'react';
5
- import Config from '../../config';
6
- import { RuntimeConfigContext } from '../RuntimeConfig';
1
+ import React, { PropsWithChildren, useEffect } from 'react';
2
+ import { AuthProvider, AuthProviderProps, useAuth } from 'react-oidc-context';
3
+ import { Alert, Spinner } from '@cloudscape-design/components';
4
+ import { useRuntimeConfig } from '../../hooks/useRuntimeConfig';
7
5
 
8
6
  /**
9
7
  * Sets up the Cognito auth.
@@ -11,40 +9,56 @@ import { RuntimeConfigContext } from '../RuntimeConfig';
11
9
  * This assumes a runtime-config.json file is present at '/'. In order for Auth to be set up automatically,
12
10
  * the runtime-config.json must have the cognitoProps set.
13
11
  */
14
- const CognitoAuth: React.FC<any> = ({ children }) => {
15
- const runtimeConfig = useContext(RuntimeConfigContext);
16
-
17
- return runtimeConfig?.cognitoProps ? (
18
- <NorthstarCognitoAuth
19
- header={Config.applicationName}
20
- userPoolId={runtimeConfig.cognitoProps.userPoolId}
21
- clientId={runtimeConfig.cognitoProps.userPoolWebClientId}
22
- region={runtimeConfig.cognitoProps.region}
23
- identityPoolId={runtimeConfig.cognitoProps.identityPoolId}
24
- <%if (allowSignup) {%>allowSignup={true}<% } %>
25
- signUpAttributes={[
26
- {
27
- displayName: 'Email',
28
- name: 'email',
29
- required: true,
30
- },
31
- {
32
- displayName: 'Given name',
33
- name: 'given_name',
34
- required: true,
35
- },
36
- {
37
- displayName: 'Last name',
38
- name: 'family_name',
39
- required: true,
40
- },
41
- ]}
42
- >
43
- {children}
44
- </NorthstarCognitoAuth>
45
- ) : (
46
- <></>
12
+ const CognitoAuth: React.FC<PropsWithChildren> = ({ children }) => {
13
+ const { cognitoProps } = useRuntimeConfig();
14
+
15
+ if (!cognitoProps) {
16
+ return (
17
+ <Alert
18
+ type="error"
19
+ header="Runtime config configuration error"
20
+ >
21
+ The cognitoProps have not been configured in the runtime-config.json.
22
+ </Alert>
23
+ );
24
+ }
25
+
26
+ const cognitoAuthConfig: AuthProviderProps = {
27
+ authority: `https://cognito-idp.${cognitoProps.region}.amazonaws.com/${cognitoProps.userPoolId}`,
28
+ client_id: cognitoProps.userPoolWebClientId,
29
+ redirect_uri: window.location.origin,
30
+ response_type: 'code',
31
+ scope: 'email openid profile',
32
+ };
33
+
34
+ return (
35
+ <AuthProvider {...cognitoAuthConfig}>
36
+ <CognitoAuthInternal>{children}</CognitoAuthInternal>
37
+ </AuthProvider>
47
38
  );
48
39
  };
49
40
 
41
+ const CognitoAuthInternal: React.FC<PropsWithChildren> = ({ children }) => {
42
+ const auth = useAuth();
43
+
44
+ useEffect(() => {
45
+ if (!auth.isAuthenticated && !auth.isLoading) {
46
+ auth.signinRedirect();
47
+ }
48
+ }, [auth])
49
+
50
+ if (auth.isAuthenticated) {
51
+ return children;
52
+ } else if (auth.error) {
53
+ return (
54
+ <Alert type="error" header="Configuration error">
55
+ Error contacting Cognito. Please check your runtime-config.json is
56
+ configured with the correct endpoints.
57
+ </Alert>
58
+ );
59
+ } else {
60
+ return <Spinner />;
61
+ }
62
+ };
63
+
50
64
  export default CognitoAuth;
@@ -0,0 +1,168 @@
1
+ import {
2
+ IdentityPool,
3
+ UserPoolAuthenticationProvider,
4
+ } from '@aws-cdk/aws-cognito-identitypool-alpha';
5
+ import { CfnOutput, Duration, Lazy, Stack } from 'aws-cdk-lib';
6
+ import {
7
+ AccountRecovery,
8
+ CfnManagedLoginBranding,
9
+ CfnUserPoolDomain,
10
+ FeaturePlan,
11
+ Mfa,
12
+ OAuthScope,
13
+ UserPool,
14
+ UserPoolClient,
15
+ } from 'aws-cdk-lib/aws-cognito';
16
+ import { Construct } from 'constructs';
17
+ import { RuntimeConfig } from './runtime-config.js';
18
+ import { Distribution } from 'aws-cdk-lib/aws-cloudfront';
19
+
20
+ const WEB_CLIENT_ID = 'WebClient';
21
+ /**
22
+ * Creates a UserPool and Identity Pool with sane defaults configured intended for usage from a web client.
23
+ */
24
+ export class UserIdentity extends Construct {
25
+ public readonly region: string;
26
+ public readonly identityPool: IdentityPool;
27
+ public readonly userPool: UserPool;
28
+ public readonly userPoolClient: UserPoolClient;
29
+ public readonly userPoolDomain: CfnUserPoolDomain;
30
+
31
+ constructor(scope: Construct, id: string) {
32
+ super(scope, id);
33
+
34
+ this.region = Stack.of(this).region;
35
+ this.userPool = this.createUserPool();
36
+ this.userPoolDomain = this.createUserPoolDomain(this.userPool);
37
+ this.userPoolClient = this.createUserPoolClient(this.userPool);
38
+ this.identityPool = this.createIdentityPool(
39
+ this.userPool,
40
+ this.userPoolClient
41
+ );
42
+ this.createManagedLoginBranding(
43
+ this.userPool,
44
+ this.userPoolClient,
45
+ this.userPoolDomain
46
+ );
47
+
48
+ RuntimeConfig.ensure(this).config.cognitoProps = {
49
+ region: Stack.of(this).region,
50
+ identityPoolId: this.identityPool.identityPoolId,
51
+ userPoolId: this.userPool.userPoolId,
52
+ userPoolWebClientId: this.userPoolClient.userPoolClientId,
53
+ };
54
+
55
+ new CfnOutput(this, `${id}-UserPoolId`, {
56
+ value: this.userPool.userPoolId,
57
+ });
58
+
59
+ new CfnOutput(this, `${id}-IdentityPoolId`, {
60
+ value: this.identityPool.identityPoolId,
61
+ });
62
+ }
63
+
64
+ private createUserPool = () =>
65
+ new UserPool(this, 'UserPool', {
66
+ deletionProtection: true,
67
+ passwordPolicy: {
68
+ minLength: 8,
69
+ requireLowercase: true,
70
+ requireUppercase: true,
71
+ requireDigits: true,
72
+ requireSymbols: true,
73
+ tempPasswordValidity: Duration.days(3),
74
+ },
75
+ mfa: Mfa.REQUIRED,
76
+ featurePlan: FeaturePlan.ESSENTIALS,
77
+ mfaSecondFactor: { sms: true, otp: true },
78
+ signInCaseSensitive: false,
79
+ signInAliases: { username: true, email: true },
80
+ accountRecovery: AccountRecovery.EMAIL_ONLY,
81
+ selfSignUpEnabled: <%= allowSignup %>,
82
+ standardAttributes: {
83
+ phoneNumber: { required: false },
84
+ email: { required: true },
85
+ givenName: { required: true },
86
+ familyName: { required: true },
87
+ },
88
+ autoVerify: {
89
+ email: true,
90
+ phone: true,
91
+ },
92
+ keepOriginal: {
93
+ email: true,
94
+ phone: true,
95
+ },
96
+ });
97
+
98
+ private createUserPoolDomain = (userPool: UserPool) =>
99
+ new CfnUserPoolDomain(this, 'UserPoolDomain', {
100
+ domain: `<%= cognitoDomain %>-${Stack.of(this).account}`,
101
+ userPoolId: userPool.userPoolId,
102
+ managedLoginVersion: 2,
103
+ });
104
+
105
+ private createUserPoolClient = (userPool: UserPool) => {
106
+ const lazilyComputedCallbackUrls = Lazy.list({
107
+ produce: () =>
108
+ [
109
+ 'http://localhost:4200',
110
+ `https://${Stack.of(this).region}.console.aws.amazon.com`,
111
+ ].concat(
112
+ this.findCloudFrontDistributions().map(
113
+ (d) => `https://${d.domainName}`
114
+ )
115
+ ),
116
+ });
117
+
118
+ return userPool.addClient(WEB_CLIENT_ID, {
119
+ authFlows: {
120
+ userPassword: true,
121
+ userSrp: true,
122
+ user: true,
123
+ },
124
+ oAuth: {
125
+ flows: {
126
+ authorizationCodeGrant: true,
127
+ },
128
+ scopes: [OAuthScope.EMAIL, OAuthScope.OPENID, OAuthScope.PROFILE],
129
+ callbackUrls: lazilyComputedCallbackUrls,
130
+ logoutUrls: lazilyComputedCallbackUrls,
131
+ },
132
+ preventUserExistenceErrors: true,
133
+ });
134
+ };
135
+
136
+ private createIdentityPool = (
137
+ userPool: UserPool,
138
+ userPoolClient: UserPoolClient
139
+ ) => {
140
+ const identityPool = new IdentityPool(this, 'IdentityPool');
141
+
142
+ identityPool.addUserPoolAuthentication(
143
+ new UserPoolAuthenticationProvider({
144
+ userPool,
145
+ userPoolClient,
146
+ })
147
+ );
148
+
149
+ return identityPool;
150
+ };
151
+
152
+ private createManagedLoginBranding = (
153
+ userPool: UserPool,
154
+ userPoolClient: UserPoolClient,
155
+ userPoolDomain: CfnUserPoolDomain
156
+ ) => {
157
+ new CfnManagedLoginBranding(this, 'ManagedLoginBranding', {
158
+ userPoolId: userPool.userPoolId,
159
+ clientId: userPoolClient.userPoolClientId,
160
+ useCognitoProvidedValues: true,
161
+ }).node.addDependency(userPoolClient, userPool, userPoolDomain);
162
+ };
163
+
164
+ private findCloudFrontDistributions = (): Distribution[] =>
165
+ Stack.of(this)
166
+ .node.findAll()
167
+ .filter((child) => child instanceof Distribution);
168
+ }