Skip to content

Commit fd56414

Browse files
HuiSFwhummer
andauthored
feat(auth): support custom identity pool endpoint (#14382)
Co-authored-by: Waldemar Hummer <waldemar.hummer@gmail.com>
1 parent 2f5cdf6 commit fd56414

File tree

35 files changed

+589
-353
lines changed

35 files changed

+589
-353
lines changed

packages/auth/__tests__/providers/cognito/credentialsProvider/credentialsProvider.test.ts

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
import {
5-
GetCredentialsForIdentityOutput,
65
ResourcesConfig,
7-
getCredentialsForIdentity,
6+
createGetCredentialsForIdentityClient,
87
sharedInMemoryStorage,
98
} from '@aws-amplify/core';
109

@@ -17,7 +16,7 @@ import { authAPITestParams } from '../testUtils/authApiTestParams';
1716

1817
jest.mock('@aws-amplify/core', () => ({
1918
...jest.requireActual('@aws-amplify/core'),
20-
getCredentialsForIdentity: jest.fn(),
19+
createGetCredentialsForIdentityClient: jest.fn(),
2120
}));
2221

2322
jest.mock(
@@ -62,9 +61,23 @@ const disallowGuestAccessConfig: ResourcesConfig = {
6261
},
6362
};
6463

65-
const credentialsForIdentityIdSpy = getCredentialsForIdentity as jest.Mock;
64+
const mockCreateGetIdentityForIdentityClient = jest.mocked(
65+
createGetCredentialsForIdentityClient,
66+
);
67+
68+
const mockGetCredentialsForIdentity: jest.MockedFunction<
69+
ReturnType<typeof createGetCredentialsForIdentityClient>
70+
> = jest.fn(
71+
async (_config, _params) => authAPITestParams.CredentialsForIdentityIdResult,
72+
);
6673

6774
describe('credentialsProvider', () => {
75+
beforeAll(() => {
76+
mockCreateGetIdentityForIdentityClient.mockReturnValue(
77+
mockGetCredentialsForIdentity,
78+
);
79+
});
80+
6881
describe('Guest Credentials', () => {
6982
let cognitoCredentialsProvider: CognitoAWSCredentialsAndIdentityIdProvider;
7083

@@ -76,14 +89,14 @@ describe('credentialsProvider', () => {
7689
identityIdStore.setAuthConfig(validAuthConfig.Auth!);
7790
cognitoCredentialsProvider =
7891
new CognitoAWSCredentialsAndIdentityIdProvider(identityIdStore);
79-
credentialsForIdentityIdSpy.mockImplementationOnce(async () => {
92+
mockGetCredentialsForIdentity.mockImplementationOnce(async () => {
8093
return authAPITestParams.CredentialsForIdentityIdResult;
8194
});
8295
});
8396

8497
afterEach(() => {
8598
cognitoCredentialsProvider.clearCredentials();
86-
credentialsForIdentityIdSpy?.mockReset();
99+
mockGetCredentialsForIdentity?.mockReset();
87100
});
88101

89102
test('Should call identityIdClient with no logins to obtain guest creds', async () => {
@@ -97,8 +110,8 @@ describe('credentialsProvider', () => {
97110
.AccessKeyId,
98111
);
99112

100-
expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1);
101-
expect(credentialsForIdentityIdSpy).toHaveBeenCalledWith(
113+
expect(mockGetCredentialsForIdentity).toHaveBeenCalledTimes(1);
114+
expect(mockGetCredentialsForIdentity).toHaveBeenCalledWith(
102115
{ region: 'us-east-1' },
103116
{ IdentityId: 'identity-id-test' },
104117
);
@@ -112,7 +125,7 @@ describe('credentialsProvider', () => {
112125
authenticated: false,
113126
authConfig: validAuthConfig.Auth!,
114127
});
115-
expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1);
128+
expect(mockGetCredentialsForIdentity).toHaveBeenCalledTimes(1);
116129
const res =
117130
await cognitoCredentialsProvider.getCredentialsAndIdentityId({
118131
authenticated: false,
@@ -123,7 +136,7 @@ describe('credentialsProvider', () => {
123136
.AccessKeyId,
124137
);
125138
// expecting to be called only once becasue in-memory creds should be returned
126-
expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1);
139+
expect(mockGetCredentialsForIdentity).toHaveBeenCalledTimes(1);
127140
});
128141
});
129142

@@ -133,7 +146,7 @@ describe('credentialsProvider', () => {
133146
new CognitoAWSCredentialsAndIdentityIdProvider(
134147
new DefaultIdentityIdStore(sharedInMemoryStorage),
135148
);
136-
credentialsForIdentityIdSpy.mockImplementationOnce(async () => {
149+
mockGetCredentialsForIdentity.mockImplementationOnce(async () => {
137150
return authAPITestParams.NoAccessKeyCredentialsForIdentityIdResult;
138151
});
139152
});
@@ -142,7 +155,7 @@ describe('credentialsProvider', () => {
142155
cognitoCredentialsProvider.clearCredentials();
143156
});
144157
afterAll(() => {
145-
credentialsForIdentityIdSpy?.mockReset();
158+
mockGetCredentialsForIdentity?.mockReset();
146159
});
147160

148161
test('Should not throw AuthError when allowGuestAccess is false in the config', async () => {
@@ -173,8 +186,8 @@ describe('credentialsProvider', () => {
173186
requestId: '123',
174187
},
175188
};
176-
credentialsForIdentityIdSpy.mockReset();
177-
credentialsForIdentityIdSpy.mockRejectedValue(mockServiceErrorParams);
189+
mockGetCredentialsForIdentity.mockReset();
190+
mockGetCredentialsForIdentity.mockRejectedValue(mockServiceErrorParams);
178191
try {
179192
await cognitoCredentialsProvider.getCredentialsAndIdentityId({
180193
authenticated: false,
@@ -198,14 +211,14 @@ describe('credentialsProvider', () => {
198211
identityIdStore.setAuthConfig(validAuthConfig.Auth!);
199212
cognitoCredentialsProvider =
200213
new CognitoAWSCredentialsAndIdentityIdProvider(identityIdStore);
201-
credentialsForIdentityIdSpy.mockImplementation(async () => {
202-
return authAPITestParams.CredentialsForIdentityIdResult as GetCredentialsForIdentityOutput;
214+
mockGetCredentialsForIdentity.mockImplementation(async () => {
215+
return authAPITestParams.CredentialsForIdentityIdResult;
203216
});
204217
});
205218

206219
afterEach(() => {
207220
cognitoCredentialsProvider.clearCredentials();
208-
credentialsForIdentityIdSpy?.mockReset();
221+
mockGetCredentialsForIdentity?.mockReset();
209222
});
210223

211224
test('Should call identityIdClient with the logins map to obtain primary creds', async () => {
@@ -234,7 +247,7 @@ describe('credentialsProvider', () => {
234247
authAPITestParams.CredentialsForIdentityIdResult.IdentityId,
235248
});
236249

237-
expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1);
250+
expect(mockGetCredentialsForIdentity).toHaveBeenCalledTimes(1);
238251
});
239252

240253
test('in-memory primary creds are returned if not expired and not past TTL', async () => {
@@ -243,13 +256,13 @@ describe('credentialsProvider', () => {
243256
authConfig: validAuthConfig.Auth!,
244257
tokens: authAPITestParams.ValidAuthTokens,
245258
});
246-
expect(credentialsForIdentityIdSpy).toHaveBeenCalledWith(
259+
expect(mockGetCredentialsForIdentity).toHaveBeenCalledWith(
247260
{
248261
region: authAPITestParams.CredentialsClientRequest.region,
249262
},
250263
authAPITestParams.CredentialsClientRequest.withValidAuthToken,
251264
);
252-
expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1);
265+
expect(mockGetCredentialsForIdentity).toHaveBeenCalledTimes(1);
253266

254267
const res =
255268
await cognitoCredentialsProvider.getCredentialsAndIdentityId({
@@ -262,7 +275,7 @@ describe('credentialsProvider', () => {
262275
.AccessKeyId,
263276
);
264277
// expecting to be called only once becasue in-memory creds should be returned
265-
expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1);
278+
expect(mockGetCredentialsForIdentity).toHaveBeenCalledTimes(1);
266279
});
267280

268281
test('Should get new credentials when tokens have changed', async () => {
@@ -271,26 +284,26 @@ describe('credentialsProvider', () => {
271284
authConfig: validAuthConfig.Auth!,
272285
tokens: authAPITestParams.ValidAuthTokens,
273286
});
274-
expect(credentialsForIdentityIdSpy).toHaveBeenCalledWith(
287+
expect(mockGetCredentialsForIdentity).toHaveBeenCalledWith(
275288
{
276289
region: authAPITestParams.CredentialsClientRequest.region,
277290
},
278291
authAPITestParams.CredentialsClientRequest.withValidAuthToken,
279292
);
280-
expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1);
293+
expect(mockGetCredentialsForIdentity).toHaveBeenCalledTimes(1);
281294

282295
await cognitoCredentialsProvider.getCredentialsAndIdentityId({
283296
authenticated: true,
284297
authConfig: validAuthConfig.Auth!,
285298
tokens: authAPITestParams.NewValidAuthTokens,
286299
});
287-
expect(credentialsForIdentityIdSpy).toHaveBeenCalledWith(
300+
expect(mockGetCredentialsForIdentity).toHaveBeenCalledWith(
288301
{
289302
region: authAPITestParams.CredentialsClientRequest.region,
290303
},
291304
authAPITestParams.CredentialsClientRequest.withNewValidAuthToken,
292305
);
293-
expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(2);
306+
expect(mockGetCredentialsForIdentity).toHaveBeenCalledTimes(2);
294307
});
295308
});
296309

@@ -307,11 +320,11 @@ describe('credentialsProvider', () => {
307320
});
308321

309322
afterAll(() => {
310-
credentialsForIdentityIdSpy?.mockReset();
323+
mockGetCredentialsForIdentity?.mockReset();
311324
});
312325

313326
test('Should throw AuthError if either Credentials, accessKeyId or secretKey is absent in the response', async () => {
314-
credentialsForIdentityIdSpy.mockImplementationOnce(async () => {
327+
mockGetCredentialsForIdentity.mockImplementationOnce(async () => {
315328
return authAPITestParams.NoAccessKeyCredentialsForIdentityIdResult;
316329
});
317330
expect(
@@ -321,8 +334,8 @@ describe('credentialsProvider', () => {
321334
tokens: authAPITestParams.ValidAuthTokens,
322335
}),
323336
).rejects.toThrow(AuthError);
324-
credentialsForIdentityIdSpy.mockClear();
325-
credentialsForIdentityIdSpy.mockImplementationOnce(async () => {
337+
mockGetCredentialsForIdentity.mockClear();
338+
mockGetCredentialsForIdentity.mockImplementationOnce(async () => {
326339
return authAPITestParams.NoCredentialsForIdentityIdResult;
327340
});
328341
expect(
@@ -332,8 +345,8 @@ describe('credentialsProvider', () => {
332345
tokens: authAPITestParams.ValidAuthTokens,
333346
}),
334347
).rejects.toThrow(AuthError);
335-
credentialsForIdentityIdSpy.mockClear();
336-
credentialsForIdentityIdSpy.mockImplementationOnce(async () => {
348+
mockGetCredentialsForIdentity.mockClear();
349+
mockGetCredentialsForIdentity.mockImplementationOnce(async () => {
337350
return authAPITestParams.NoSecretKeyInCredentialsForIdentityIdResult;
338351
});
339352
expect(
@@ -355,8 +368,8 @@ describe('credentialsProvider', () => {
355368
requestId: '123',
356369
},
357370
};
358-
credentialsForIdentityIdSpy.mockReset();
359-
credentialsForIdentityIdSpy.mockRejectedValue(mockServiceErrorParams);
371+
mockGetCredentialsForIdentity.mockReset();
372+
mockGetCredentialsForIdentity.mockRejectedValue(mockServiceErrorParams);
360373
try {
361374
await cognitoCredentialsProvider.getCredentialsAndIdentityId({
362375
authenticated: true,

packages/auth/__tests__/providers/cognito/credentialsProvider/identityIdProvider.test.ts

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import { Amplify, Identity, ResourcesConfig, getId } from '@aws-amplify/core';
54
import {
6-
GetIdInput,
7-
GetIdOutput,
8-
} from '@aws-amplify/core/internals/aws-clients/cognitoIdentity';
5+
Amplify,
6+
Identity,
7+
ResourcesConfig,
8+
createGetIdClient,
9+
} from '@aws-amplify/core';
910
import {
1011
AmplifyError,
1112
CognitoIdentityPoolConfig,
@@ -18,9 +19,8 @@ import { authAPITestParams } from '../testUtils/authApiTestParams';
1819

1920
jest.mock('@aws-amplify/core', () => ({
2021
...jest.requireActual('@aws-amplify/core'),
21-
getId: jest.fn(),
22+
createGetIdClient: jest.fn(),
2223
}));
23-
jest.mock('@aws-amplify/core/internals/aws-clients/cognitoIdentity');
2424
jest.mock(
2525
'../../../../src/providers/cognito/credentialsProvider/IdentityIdStore',
2626
);
@@ -35,7 +35,7 @@ const ampConfig: ResourcesConfig = {
3535
},
3636
};
3737

38-
const mockGetId = getId as jest.Mock;
38+
const mockCreateGetIdClient = jest.mocked(createGetIdClient);
3939
const mockKeyValueStorage = {
4040
setItem: jest.fn(),
4141
getItem: jest.fn(),
@@ -48,23 +48,26 @@ describe('Cognito IdentityId Provider', () => {
4848
const _ = new DefaultIdentityIdStore(mockKeyValueStorage);
4949
const mockDefaultIdentityIdStoreInstance =
5050
MockDefaultIdentityIdStore.mock.instances[0];
51+
const mockGetId: jest.MockedFunction<ReturnType<typeof createGetIdClient>> =
52+
jest.fn(async (_config, params) => {
53+
if (params.Logins && Object.keys(params.Logins).length === 0) {
54+
return {
55+
IdentityId: authAPITestParams.GuestIdentityId.id,
56+
$metadata: {},
57+
};
58+
} else {
59+
return {
60+
IdentityId: authAPITestParams.PrimaryIdentityId.id,
61+
$metadata: {},
62+
};
63+
}
64+
});
65+
5166
describe('Happy Path Cases:', () => {
5267
beforeAll(() => {
5368
jest.spyOn(Amplify, 'getConfig').mockImplementationOnce(() => ampConfig);
5469

55-
mockGetId.mockImplementation(
56-
async (_config: object, params: GetIdInput) => {
57-
if (params.Logins && Object.keys(params.Logins).length === 0) {
58-
return {
59-
IdentityId: authAPITestParams.GuestIdentityId.id,
60-
} as GetIdOutput;
61-
} else {
62-
return {
63-
IdentityId: authAPITestParams.PrimaryIdentityId.id,
64-
} as GetIdOutput;
65-
}
66-
},
67-
);
70+
mockCreateGetIdClient.mockReturnValue(mockGetId);
6871
});
6972

7073
afterEach(() => {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { AmplifyUrl } from '@aws-amplify/core/internals/utils';
2+
import { cognitoIdentityPoolEndpointResolver } from '@aws-amplify/core';
3+
4+
import { createCognitoIdentityPoolEndpointResolver } from '../../../../src/providers/cognito/factories/createCognitoIdentityPoolEndpointResolver';
5+
6+
jest.mock('@aws-amplify/core');
7+
8+
const mockCognitoIdentityPoolEndpointResolver = jest.mocked(
9+
cognitoIdentityPoolEndpointResolver,
10+
);
11+
12+
describe('createCognitoIdentityPoolEndpointResolver()', () => {
13+
afterEach(() => {
14+
mockCognitoIdentityPoolEndpointResolver.mockClear();
15+
});
16+
17+
describe('creating a resolver with overrideEndpoint as `undefined`', () => {
18+
const resolver = createCognitoIdentityPoolEndpointResolver({
19+
endpointOverride: undefined,
20+
});
21+
22+
it('invokes cognitoUserPoolEndpointResolver with the expected region', () => {
23+
const expectedReturningUrl = {
24+
url: new AmplifyUrl(
25+
'https://cognito-identity.us-west-2.amazonaws.com/',
26+
),
27+
};
28+
mockCognitoIdentityPoolEndpointResolver.mockReturnValueOnce(
29+
expectedReturningUrl,
30+
);
31+
32+
const expectedRegion = 'us-west-2';
33+
const { url } = resolver({ region: expectedRegion });
34+
35+
expect(mockCognitoIdentityPoolEndpointResolver).toHaveBeenCalledWith({
36+
region: expectedRegion,
37+
});
38+
expect(url).toStrictEqual(expectedReturningUrl.url);
39+
});
40+
});
41+
42+
describe('creating a resolver with overrideEndpoint', () => {
43+
const endpointOverride = 'https://cognito-identity.example.com';
44+
const resolver = createCognitoIdentityPoolEndpointResolver({
45+
endpointOverride,
46+
});
47+
48+
it('returns the endpoint override', () => {
49+
const expectedRegion = 'us-west-2';
50+
const { url } = resolver({ region: expectedRegion });
51+
expect(mockCognitoIdentityPoolEndpointResolver).not.toHaveBeenCalled();
52+
expect(url).toStrictEqual(
53+
new AmplifyUrl('https://cognito-identity.example.com'),
54+
);
55+
});
56+
});
57+
});

0 commit comments

Comments
 (0)