@ttoss/cloud-auth 0.6.4 → 0.7.1
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.
- package/.turbo/turbo-build.log +6 -6
- package/.turbo/turbo-test.log +18 -16
- package/CHANGELOG.md +12 -0
- package/coverage/clover.xml +185 -67
- package/coverage/coverage-final.json +1 -1
- package/coverage/lcov-report/config.ts.html +1 -1
- package/coverage/lcov-report/index.html +15 -15
- package/coverage/lcov-report/index.ts.html +1 -1
- package/coverage/lcov-report/template.ts.html +440 -86
- package/coverage/lcov.info +190 -69
- package/dist/esm/index.js +124 -13
- package/dist/index.d.ts +17 -20
- package/dist/index.js +124 -13
- package/package.json +5 -5
- package/src/template.ts +155 -37
- package/tests/unit/template.test.ts +85 -65
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttoss/cloud-auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"module": "./dist/esm/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -9,16 +9,16 @@
|
|
|
9
9
|
},
|
|
10
10
|
"typings": "./dist/index.d.ts",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@ttoss/cloudformation": "^0.
|
|
12
|
+
"@ttoss/cloudformation": "^0.6.1"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
|
-
"@ttoss/config": "^1.28.
|
|
15
|
+
"@ttoss/config": "^1.28.3",
|
|
16
16
|
"@types/jest": "^29.4.0",
|
|
17
|
-
"jest": "^29.
|
|
17
|
+
"jest": "^29.5.0",
|
|
18
18
|
"typescript": "^4.9.5"
|
|
19
19
|
},
|
|
20
20
|
"publishConfig": {
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
|
-
"gitHead": "
|
|
23
|
+
"gitHead": "56e8cfde36a962deaa5514453618280699824b4f"
|
|
24
24
|
}
|
package/src/template.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CloudFormationTemplate } from '@ttoss/cloudformation';
|
|
2
1
|
import { PASSWORD_MINIMUM_LENGTH } from './config';
|
|
2
|
+
import type { CloudFormationTemplate, Policy } from '@ttoss/cloudformation';
|
|
3
3
|
|
|
4
4
|
const CognitoUserPoolLogicalId = 'CognitoUserPool';
|
|
5
5
|
|
|
@@ -7,41 +7,46 @@ const CognitoUserPoolClientLogicalId = 'CognitoUserPoolClient';
|
|
|
7
7
|
|
|
8
8
|
const CognitoIdentityPoolLogicalId = 'CognitoIdentityPool';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
const IdentityPoolAuthenticatedIAMRoleLogicalId =
|
|
11
|
+
'IdentityPoolAuthenticatedIAMRole';
|
|
12
|
+
|
|
13
|
+
const IdentityPoolUnauthenticatedIAMRoleLogicalId =
|
|
14
|
+
'IdentityPoolUnauthenticatedIAMRole';
|
|
15
|
+
|
|
16
|
+
export const DenyStatement = {
|
|
17
|
+
Effect: 'Deny' as const,
|
|
18
|
+
Action: ['*'],
|
|
19
|
+
Resource: ['*'],
|
|
20
|
+
};
|
|
15
21
|
|
|
16
22
|
export const createAuthTemplate = ({
|
|
17
23
|
autoVerifiedAttributes = ['email'],
|
|
18
|
-
identityPool
|
|
19
|
-
roles,
|
|
24
|
+
identityPool,
|
|
20
25
|
schema,
|
|
21
26
|
usernameAttributes = ['email'],
|
|
22
27
|
}: {
|
|
23
28
|
autoVerifiedAttributes?: Array<'email' | 'phone_number'> | null | false;
|
|
24
|
-
identityPool?:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
identityPool?: {
|
|
30
|
+
enabled?: boolean;
|
|
31
|
+
authenticatedPolicies?: Policy[];
|
|
32
|
+
unauthenticatedPolicies?: Policy[];
|
|
28
33
|
};
|
|
29
34
|
/**
|
|
30
35
|
* https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpool-schemaattribute.html
|
|
31
36
|
*/
|
|
32
37
|
schema?: {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
attributeDataType?: 'Boolean' | 'DateTime' | 'Number' | 'String';
|
|
39
|
+
developerOnlyAttribute?: boolean;
|
|
40
|
+
mutable?: boolean;
|
|
41
|
+
name?: string;
|
|
42
|
+
numberAttributeConstraints?: {
|
|
43
|
+
maxValue?: string;
|
|
44
|
+
minValue?: string;
|
|
40
45
|
};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
required?: boolean;
|
|
47
|
+
stringAttributeConstraints?: {
|
|
48
|
+
maxLength: string;
|
|
49
|
+
minLength: string;
|
|
45
50
|
};
|
|
46
51
|
}[];
|
|
47
52
|
usernameAttributes?: Array<'email' | 'phone_number'> | null;
|
|
@@ -56,6 +61,7 @@ export const createAuthTemplate = ({
|
|
|
56
61
|
Resources: {
|
|
57
62
|
[CognitoUserPoolLogicalId]: {
|
|
58
63
|
Type: 'AWS::Cognito::UserPool',
|
|
64
|
+
DeletionPolicy: 'Retain',
|
|
59
65
|
Properties: {
|
|
60
66
|
AutoVerifiedAttributes,
|
|
61
67
|
Policies: {
|
|
@@ -68,7 +74,6 @@ export const createAuthTemplate = ({
|
|
|
68
74
|
TemporaryPasswordValidityDays: 30,
|
|
69
75
|
},
|
|
70
76
|
},
|
|
71
|
-
Schema: schema,
|
|
72
77
|
UsernameAttributes: usernameAttributes,
|
|
73
78
|
UsernameConfiguration: {
|
|
74
79
|
CaseSensitive: false,
|
|
@@ -126,7 +131,41 @@ export const createAuthTemplate = ({
|
|
|
126
131
|
},
|
|
127
132
|
};
|
|
128
133
|
|
|
129
|
-
if (
|
|
134
|
+
if (schema) {
|
|
135
|
+
const Schema = schema.map((attribute) => {
|
|
136
|
+
let NumberAttributeConstraints = undefined;
|
|
137
|
+
|
|
138
|
+
if (attribute.numberAttributeConstraints) {
|
|
139
|
+
NumberAttributeConstraints = {
|
|
140
|
+
MaxValue: attribute.numberAttributeConstraints?.maxValue,
|
|
141
|
+
MinValue: attribute.numberAttributeConstraints?.minValue,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let StringAttributeConstraints = undefined;
|
|
146
|
+
|
|
147
|
+
if (attribute.stringAttributeConstraints) {
|
|
148
|
+
StringAttributeConstraints = {
|
|
149
|
+
MaxLength: attribute.stringAttributeConstraints?.maxLength,
|
|
150
|
+
MinLength: attribute.stringAttributeConstraints?.minLength,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
AttributeDataType: attribute.attributeDataType,
|
|
156
|
+
DeveloperOnlyAttribute: attribute.developerOnlyAttribute,
|
|
157
|
+
Mutable: attribute.mutable,
|
|
158
|
+
Name: attribute.name,
|
|
159
|
+
NumberAttributeConstraints,
|
|
160
|
+
Required: attribute.required,
|
|
161
|
+
StringAttributeConstraints,
|
|
162
|
+
};
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
template.Resources[CognitoUserPoolLogicalId].Properties.Schema = Schema;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (identityPool?.enabled) {
|
|
130
169
|
/**
|
|
131
170
|
* https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-identitypool.html
|
|
132
171
|
*/
|
|
@@ -147,20 +186,99 @@ export const createAuthTemplate = ({
|
|
|
147
186
|
},
|
|
148
187
|
};
|
|
149
188
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
189
|
+
template.Resources[IdentityPoolAuthenticatedIAMRoleLogicalId] = {
|
|
190
|
+
Type: 'AWS::IAM::Role',
|
|
191
|
+
Properties: {
|
|
192
|
+
AssumeRolePolicyDocument: {
|
|
193
|
+
Version: '2012-10-17' as const,
|
|
194
|
+
Statement: [
|
|
195
|
+
{
|
|
196
|
+
Effect: 'Allow' as const,
|
|
197
|
+
Principal: {
|
|
198
|
+
Federated: 'cognito-identity.amazonaws.com',
|
|
199
|
+
},
|
|
200
|
+
Action: ['sts:AssumeRoleWithWebIdentity', 'sts:TagSession'],
|
|
201
|
+
Condition: {
|
|
202
|
+
StringEquals: {
|
|
203
|
+
'cognito-identity.amazonaws.com:aud': {
|
|
204
|
+
Ref: CognitoIdentityPoolLogicalId,
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
'ForAnyValue:StringLike': {
|
|
208
|
+
'cognito-identity.amazonaws.com:amr': 'authenticated',
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
},
|
|
214
|
+
Policies: identityPool.authenticatedPolicies || [
|
|
215
|
+
{
|
|
216
|
+
PolicyName: 'IdentityPoolAuthenticatedIAMRolePolicyName',
|
|
217
|
+
PolicyDocument: {
|
|
218
|
+
Version: '2012-10-17' as const,
|
|
219
|
+
Statement: [DenyStatement],
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
],
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
template.Resources[IdentityPoolUnauthenticatedIAMRoleLogicalId] = {
|
|
227
|
+
Type: 'AWS::IAM::Role',
|
|
228
|
+
Properties: {
|
|
229
|
+
AssumeRolePolicyDocument: {
|
|
230
|
+
Version: '2012-10-17' as const,
|
|
231
|
+
Statement: [
|
|
232
|
+
{
|
|
233
|
+
Effect: 'Allow' as const,
|
|
234
|
+
Principal: {
|
|
235
|
+
Federated: 'cognito-identity.amazonaws.com',
|
|
236
|
+
},
|
|
237
|
+
Action: 'sts:AssumeRoleWithWebIdentity',
|
|
238
|
+
Condition: {
|
|
239
|
+
StringEquals: {
|
|
240
|
+
'cognito-identity.amazonaws.com:aud': {
|
|
241
|
+
Ref: CognitoIdentityPoolLogicalId,
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
'ForAnyValue:StringLike': {
|
|
245
|
+
'cognito-identity.amazonaws.com:amr': 'unauthenticated',
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
],
|
|
250
|
+
},
|
|
251
|
+
Policies: identityPool.authenticatedPolicies || [
|
|
252
|
+
{
|
|
253
|
+
PolicyName: 'IdentityPoolUnauthenticatedIAMRolePolicyName',
|
|
254
|
+
PolicyDocument: {
|
|
255
|
+
Version: '2012-10-17' as const,
|
|
256
|
+
Statement: [DenyStatement],
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-identitypoolroleattachment.html
|
|
265
|
+
*/
|
|
266
|
+
template.Resources.CognitoIdentityPoolRoleAttachment = {
|
|
267
|
+
Type: 'AWS::Cognito::IdentityPoolRoleAttachment',
|
|
268
|
+
Properties: {
|
|
269
|
+
IdentityPoolId: {
|
|
270
|
+
Ref: CognitoIdentityPoolLogicalId,
|
|
271
|
+
},
|
|
272
|
+
Roles: {
|
|
273
|
+
authenticated: {
|
|
274
|
+
'Fn::GetAtt': [IdentityPoolAuthenticatedIAMRoleLogicalId, 'Arn'],
|
|
275
|
+
},
|
|
276
|
+
unauthenticated: {
|
|
277
|
+
'Fn::GetAtt': [IdentityPoolUnauthenticatedIAMRoleLogicalId, 'Arn'],
|
|
159
278
|
},
|
|
160
|
-
Roles: roles,
|
|
161
279
|
},
|
|
162
|
-
}
|
|
163
|
-
}
|
|
280
|
+
},
|
|
281
|
+
};
|
|
164
282
|
|
|
165
283
|
if (!template.Outputs) {
|
|
166
284
|
template.Outputs = {};
|
|
@@ -1,80 +1,100 @@
|
|
|
1
1
|
import { createAuthTemplate } from '../../src';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
describe('user pool', () => {
|
|
4
|
+
test('do not add schema if not provided', () => {
|
|
5
|
+
const template = createAuthTemplate();
|
|
6
|
+
expect(
|
|
7
|
+
template.Resources.CognitoUserPool.Properties.Schema
|
|
8
|
+
).toBeUndefined();
|
|
9
|
+
});
|
|
7
10
|
|
|
8
|
-
test('add schema if provided', () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
test('add schema if provided', () => {
|
|
12
|
+
const schema = [
|
|
13
|
+
{
|
|
14
|
+
attributeDataType: 'String' as const,
|
|
15
|
+
developerOnlyAttribute: false,
|
|
16
|
+
mutable: true,
|
|
17
|
+
name: 'email',
|
|
18
|
+
required: true,
|
|
19
|
+
stringAttributeConstraints: {
|
|
20
|
+
maxLength: '2048',
|
|
21
|
+
minLength: '0',
|
|
22
|
+
},
|
|
19
23
|
},
|
|
20
|
-
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
const template = createAuthTemplate({ schema });
|
|
24
|
-
expect(template.Resources.CognitoUserPool.Properties.Schema).toEqual(schema);
|
|
25
|
-
});
|
|
24
|
+
];
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
const template = createAuthTemplate({ schema });
|
|
27
|
+
expect(template.Resources.CognitoUserPool.Properties.Schema).toEqual([
|
|
28
|
+
{
|
|
29
|
+
AttributeDataType: 'String',
|
|
30
|
+
DeveloperOnlyAttribute: false,
|
|
31
|
+
Mutable: true,
|
|
32
|
+
Name: 'email',
|
|
33
|
+
Required: true,
|
|
34
|
+
StringAttributeConstraints: {
|
|
35
|
+
MaxLength: '2048',
|
|
36
|
+
MinLength: '0',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
]);
|
|
40
|
+
});
|
|
33
41
|
|
|
34
|
-
test
|
|
35
|
-
|
|
36
|
-
(autoVerifiedAttributes: any) => {
|
|
37
|
-
const template = createAuthTemplate({ autoVerifiedAttributes });
|
|
42
|
+
test('should have autoVerifiedAttributes equal email by default', () => {
|
|
43
|
+
const template = createAuthTemplate();
|
|
38
44
|
expect(
|
|
39
45
|
template.Resources.CognitoUserPool.Properties.AutoVerifiedAttributes
|
|
40
|
-
).toEqual([]);
|
|
41
|
-
}
|
|
42
|
-
);
|
|
46
|
+
).toEqual(['email']);
|
|
47
|
+
});
|
|
43
48
|
|
|
44
|
-
test
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
);
|
|
49
|
+
test('default usernameAttributes should be email', () => {
|
|
50
|
+
const template = createAuthTemplate();
|
|
51
|
+
expect(
|
|
52
|
+
template.Resources.CognitoUserPool.Properties.UsernameAttributes
|
|
53
|
+
).toEqual(['email']);
|
|
54
|
+
});
|
|
52
55
|
|
|
53
|
-
test(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
test.each([[], null, false])(
|
|
57
|
+
'should have autoVerifiedAttributes undefined: %p',
|
|
58
|
+
(autoVerifiedAttributes: any) => {
|
|
59
|
+
const template = createAuthTemplate({ autoVerifiedAttributes });
|
|
60
|
+
expect(
|
|
61
|
+
template.Resources.CognitoUserPool.Properties.AutoVerifiedAttributes
|
|
62
|
+
).toEqual([]);
|
|
63
|
+
}
|
|
64
|
+
);
|
|
58
65
|
|
|
59
|
-
test('should
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
};
|
|
64
|
-
const template = createAuthTemplate({ roles });
|
|
65
|
-
expect(
|
|
66
|
-
template.Resources.CognitoIdentityPoolRoleAttachment.Properties.Roles
|
|
67
|
-
).toEqual(roles);
|
|
66
|
+
test('should retain user pool', () => {
|
|
67
|
+
const template = createAuthTemplate();
|
|
68
|
+
expect(template.Resources.CognitoUserPool.DeletionPolicy).toEqual('Retain');
|
|
69
|
+
});
|
|
68
70
|
});
|
|
69
71
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
describe('identity pool', () => {
|
|
73
|
+
test.each([false, undefined])(
|
|
74
|
+
'should not have identity pool by default or false: %p',
|
|
75
|
+
(enabled) => {
|
|
76
|
+
const template = createAuthTemplate({ identityPool: { enabled } });
|
|
77
|
+
expect(template.Resources.CognitoIdentityPool).not.toBeDefined();
|
|
78
|
+
expect(template.Outputs?.IdentityPoolId).not.toBeDefined();
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
test('should have identity pool if false', () => {
|
|
83
|
+
const template = createAuthTemplate({
|
|
84
|
+
identityPool: {
|
|
85
|
+
enabled: true,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
expect(template.Resources.CognitoIdentityPool).toBeDefined();
|
|
89
|
+
expect(template.Outputs?.IdentityPoolId).toBeDefined();
|
|
90
|
+
});
|
|
74
91
|
|
|
75
|
-
test('
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
92
|
+
test('should have identity pool role attachment', () => {
|
|
93
|
+
const template = createAuthTemplate({
|
|
94
|
+
identityPool: {
|
|
95
|
+
enabled: true,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
expect(template.Resources.CognitoIdentityPoolRoleAttachment).toBeDefined();
|
|
99
|
+
});
|
|
80
100
|
});
|