Skip to content

Commit 2a4bc19

Browse files
authored
release(required): Amplify JS release (#14271)
2 parents e9e9901 + d7ada2b commit 2a4bc19

File tree

7 files changed

+157
-78
lines changed

7 files changed

+157
-78
lines changed

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

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,17 @@ import {
1111
import {
1212
CognitoAWSCredentialsAndIdentityIdProvider,
1313
DefaultIdentityIdStore,
14-
} from '../../../src/providers/cognito';
15-
import { AuthError } from '../../../src/errors/AuthError';
16-
17-
import { authAPITestParams } from './testUtils/authApiTestParams';
14+
} from '../../../../src/providers/cognito';
15+
import { AuthError } from '../../../../src/errors/AuthError';
16+
import { authAPITestParams } from '../testUtils/authApiTestParams';
1817

1918
jest.mock('@aws-amplify/core', () => ({
2019
...jest.requireActual('@aws-amplify/core'),
2120
getCredentialsForIdentity: jest.fn(),
2221
}));
2322

2423
jest.mock(
25-
'./../../../src/providers/cognito/credentialsProvider/IdentityIdProvider',
24+
'./../../../../src/providers/cognito/credentialsProvider/IdentityIdProvider',
2625
() => ({
2726
cognitoIdentityIdProvider: jest
2827
.fn()
@@ -70,18 +69,20 @@ describe('Guest Credentials', () => {
7069

7170
describe('Happy Path Cases:', () => {
7271
beforeEach(() => {
72+
const identityIdStore = new DefaultIdentityIdStore(sharedInMemoryStorage);
73+
identityIdStore.setAuthConfig(validAuthConfig.Auth!);
7374
cognitoCredentialsProvider =
74-
new CognitoAWSCredentialsAndIdentityIdProvider(
75-
new DefaultIdentityIdStore(sharedInMemoryStorage),
76-
);
75+
new CognitoAWSCredentialsAndIdentityIdProvider(identityIdStore);
7776
credentialsForIdentityIdSpy.mockImplementationOnce(async () => {
7877
return authAPITestParams.CredentialsForIdentityIdResult as GetCredentialsForIdentityOutput;
7978
});
8079
});
80+
8181
afterEach(() => {
8282
cognitoCredentialsProvider.clearCredentials();
8383
credentialsForIdentityIdSpy?.mockReset();
8484
});
85+
8586
test('Should call identityIdClient with no logins to obtain guest creds', async () => {
8687
const res = await cognitoCredentialsProvider.getCredentialsAndIdentityId({
8788
authenticated: false,
@@ -138,6 +139,7 @@ describe('Guest Credentials', () => {
138139
afterAll(() => {
139140
credentialsForIdentityIdSpy?.mockReset();
140141
});
142+
141143
test('Should not throw AuthError when allowGuestAccess is false in the config', async () => {
142144
expect(
143145
await cognitoCredentialsProvider.getCredentialsAndIdentityId({
@@ -146,6 +148,7 @@ describe('Guest Credentials', () => {
146148
}),
147149
).toBe(undefined);
148150
});
151+
149152
test('Should not throw AuthError when there is no Cognito object in the config', async () => {
150153
expect(
151154
await cognitoCredentialsProvider.getCredentialsAndIdentityId({
@@ -161,31 +164,47 @@ describe('Primary Credentials', () => {
161164
let cognitoCredentialsProvider: CognitoAWSCredentialsAndIdentityIdProvider;
162165
describe('Happy Path Cases:', () => {
163166
beforeEach(() => {
167+
const identityIdStore = new DefaultIdentityIdStore(sharedInMemoryStorage);
168+
identityIdStore.setAuthConfig(validAuthConfig.Auth!);
164169
cognitoCredentialsProvider =
165-
new CognitoAWSCredentialsAndIdentityIdProvider(
166-
new DefaultIdentityIdStore(sharedInMemoryStorage),
167-
);
170+
new CognitoAWSCredentialsAndIdentityIdProvider(identityIdStore);
168171
credentialsForIdentityIdSpy.mockImplementation(async () => {
169172
return authAPITestParams.CredentialsForIdentityIdResult as GetCredentialsForIdentityOutput;
170173
});
171174
});
175+
172176
afterEach(() => {
173177
cognitoCredentialsProvider.clearCredentials();
174178
credentialsForIdentityIdSpy?.mockReset();
175179
});
180+
176181
test('Should call identityIdClient with the logins map to obtain primary creds', async () => {
177182
const res = await cognitoCredentialsProvider.getCredentialsAndIdentityId({
178183
authenticated: true,
179184
authConfig: validAuthConfig.Auth!,
180185
tokens: authAPITestParams.ValidAuthTokens,
181186
});
182-
expect(res?.credentials.accessKeyId).toEqual(
183-
authAPITestParams.CredentialsForIdentityIdResult.Credentials
184-
.AccessKeyId,
185-
);
187+
expect(res).toMatchObject({
188+
credentials: {
189+
accessKeyId:
190+
authAPITestParams.CredentialsForIdentityIdResult.Credentials
191+
.AccessKeyId,
192+
expiration:
193+
authAPITestParams.CredentialsForIdentityIdResult.Credentials
194+
.Expiration,
195+
secretAccessKey:
196+
authAPITestParams.CredentialsForIdentityIdResult.Credentials
197+
.SecretKey,
198+
sessionToken:
199+
authAPITestParams.CredentialsForIdentityIdResult.Credentials
200+
.SessionToken,
201+
},
202+
identityId: authAPITestParams.CredentialsForIdentityIdResult.IdentityId,
203+
});
186204

187205
expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1);
188206
});
207+
189208
test('in-memory primary creds are returned if not expired and not past TTL', async () => {
190209
await cognitoCredentialsProvider.getCredentialsAndIdentityId({
191210
authenticated: true,
@@ -212,6 +231,7 @@ describe('Primary Credentials', () => {
212231
// expecting to be called only once becasue in-memory creds should be returned
213232
expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1);
214233
});
234+
215235
test('Should get new credentials when tokens have changed', async () => {
216236
await cognitoCredentialsProvider.getCredentialsAndIdentityId({
217237
authenticated: true,
@@ -240,19 +260,23 @@ describe('Primary Credentials', () => {
240260
expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(2);
241261
});
242262
});
263+
243264
describe('Error Path Cases:', () => {
244265
beforeEach(() => {
245266
cognitoCredentialsProvider =
246267
new CognitoAWSCredentialsAndIdentityIdProvider(
247268
new DefaultIdentityIdStore(sharedInMemoryStorage),
248269
);
249270
});
271+
250272
afterEach(() => {
251273
cognitoCredentialsProvider.clearCredentials();
252274
});
275+
253276
afterAll(() => {
254277
credentialsForIdentityIdSpy?.mockReset();
255278
});
279+
256280
test('Should throw AuthError if either Credentials, accessKeyId or secretKey is absent in the response', async () => {
257281
credentialsForIdentityIdSpy.mockImplementationOnce(async () => {
258282
return authAPITestParams.NoAccessKeyCredentialsForIdentityIdResult as GetCredentialsForIdentityOutput;

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

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@ import {
88
} from '@aws-amplify/core/internals/aws-clients/cognitoIdentity';
99
import { CognitoIdentityPoolConfig } from '@aws-amplify/core/internals/utils';
1010

11-
import { DefaultIdentityIdStore } from '../../../src/providers/cognito/credentialsProvider/IdentityIdStore';
12-
import { cognitoIdentityIdProvider } from '../../../src/providers/cognito/credentialsProvider/IdentityIdProvider';
13-
14-
import { authAPITestParams } from './testUtils/authApiTestParams';
11+
import { DefaultIdentityIdStore } from '../../../../src/providers/cognito/credentialsProvider/IdentityIdStore';
12+
import { cognitoIdentityIdProvider } from '../../../../src/providers/cognito/credentialsProvider/IdentityIdProvider';
13+
import { authAPITestParams } from '../testUtils/authApiTestParams';
1514

1615
jest.mock('@aws-amplify/core', () => ({
1716
...jest.requireActual('@aws-amplify/core'),
1817
getId: jest.fn(),
1918
}));
2019
jest.mock('@aws-amplify/core/internals/aws-clients/cognitoIdentity');
21-
jest.mock('../../../src/providers/cognito/credentialsProvider/IdentityIdStore');
20+
jest.mock(
21+
'../../../../src/providers/cognito/credentialsProvider/IdentityIdStore',
22+
);
2223

2324
const ampConfig: ResourcesConfig = {
2425
Auth: {
@@ -140,4 +141,59 @@ describe('Cognito IdentityId Provider Happy Path Cases:', () => {
140141
).toBe(authAPITestParams.PrimaryIdentityId.id);
141142
expect(mockGetId).toHaveBeenCalledTimes(1);
142143
});
144+
test('Should return the identityId irresspective of the type if present', async () => {
145+
mockDefaultIdentityIdStoreInstance.loadIdentityId.mockImplementationOnce(
146+
async () => {
147+
return authAPITestParams.PrimaryIdentityId as Identity;
148+
},
149+
);
150+
expect(
151+
await cognitoIdentityIdProvider({
152+
tokens: authAPITestParams.ValidAuthTokens,
153+
authConfig: {
154+
identityPoolId: 'XXXXXXXXXXXXXXXXX',
155+
},
156+
identityIdStore: mockDefaultIdentityIdStoreInstance,
157+
}),
158+
).toBe(authAPITestParams.PrimaryIdentityId.id);
159+
160+
mockDefaultIdentityIdStoreInstance.loadIdentityId.mockImplementationOnce(
161+
async () => {
162+
return authAPITestParams.GuestIdentityId as Identity;
163+
},
164+
);
165+
expect(
166+
await cognitoIdentityIdProvider({
167+
tokens: authAPITestParams.ValidAuthTokens,
168+
authConfig: {
169+
identityPoolId: 'XXXXXXXXXXXXXXXXX',
170+
},
171+
identityIdStore: mockDefaultIdentityIdStoreInstance,
172+
}),
173+
).toBe(authAPITestParams.GuestIdentityId.id);
174+
expect(mockGetId).toHaveBeenCalledTimes(0);
175+
});
176+
test('Should fetch from Cognito when there is no identityId cached', async () => {
177+
mockDefaultIdentityIdStoreInstance.loadIdentityId.mockImplementationOnce(
178+
async () => {
179+
return undefined;
180+
},
181+
);
182+
mockDefaultIdentityIdStoreInstance.storeIdentityId.mockImplementationOnce(
183+
async (identity: Identity) => {
184+
expect(identity.id).toBe(authAPITestParams.PrimaryIdentityId.id);
185+
expect(identity.type).toBe(authAPITestParams.PrimaryIdentityId.type);
186+
},
187+
);
188+
expect(
189+
await cognitoIdentityIdProvider({
190+
tokens: authAPITestParams.ValidAuthTokens,
191+
authConfig: {
192+
identityPoolId: 'us-east-1:test-id',
193+
},
194+
identityIdStore: mockDefaultIdentityIdStoreInstance,
195+
}),
196+
).toBe(authAPITestParams.PrimaryIdentityId.id);
197+
expect(mockGetId).toHaveBeenCalledTimes(1);
198+
});
143199
});

packages/auth/__tests__/providers/cognito/testUtils/authApiTestParams.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ export const authAPITestParams = {
149149
SessionToken: 'SessionToken',
150150
Expiration: new Date('2023-07-29'),
151151
},
152+
IdentityId:
153+
'I am expected to be returned as a part of the result as I am the source of truth',
152154
$metadata: {},
153155
},
154156
NoAccessKeyCredentialsForIdentityIdResult: {

packages/auth/__tests__/providers/cognito/utils/oauth/completeOAuthFlow.test.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ describe('completeOAuthFlow', () => {
151151
token_type: 'token_type',
152152
expires_in: 'expires_in',
153153
};
154+
const executionOrder: string[] = [];
155+
154156
mockValidateState.mockReturnValueOnce('myState-valid_state');
155157
(oAuthStore.loadPKCE as jest.Mock).mockResolvedValueOnce('pkce23234a');
156158
const mockJsonMethod = jest.fn(() => Promise.resolve(expectedTokens));
@@ -162,6 +164,12 @@ describe('completeOAuthFlow', () => {
162164
mockFetch.mockResolvedValueOnce({
163165
json: mockJsonMethod,
164166
});
167+
mockReplaceState.mockImplementation((..._args) =>
168+
executionOrder.push('replaceState'),
169+
);
170+
mockHubDispatch.mockImplementation(() =>
171+
executionOrder.push('hubDispatch'),
172+
);
165173

166174
await completeOAuthFlow(testInput);
167175

@@ -180,17 +188,27 @@ describe('completeOAuthFlow', () => {
180188
TokenType: expectedTokens.token_type,
181189
ExpiresIn: expectedTokens.expires_in,
182190
});
191+
192+
expect(oAuthStore.clearOAuthData).toHaveBeenCalledTimes(1);
193+
expect(oAuthStore.storeOAuthSignIn).toHaveBeenCalledWith(true, undefined);
194+
195+
expect(mockResolveAndClearInflightPromises).toHaveBeenCalledTimes(1);
196+
183197
expect(mockReplaceState).toHaveBeenCalledWith(
184198
'http://localhost:3000/?code=aaaa-111-222&state=aaaaa',
185199
'',
186200
testInput.redirectUri,
187201
);
188202

189-
expect(oAuthStore.clearOAuthData).toHaveBeenCalledTimes(1);
190-
expect(oAuthStore.storeOAuthSignIn).toHaveBeenCalledWith(true, undefined);
191-
192203
expect(mockHubDispatch).toHaveBeenCalledTimes(3);
193-
expect(mockResolveAndClearInflightPromises).toHaveBeenCalledTimes(1);
204+
205+
// Verify we replace browser tab location before dispatching hub events
206+
expect(executionOrder).toEqual([
207+
'replaceState',
208+
'hubDispatch',
209+
'hubDispatch',
210+
'hubDispatch',
211+
]);
194212
});
195213

196214
it('throws when `fetch` call resolves error', async () => {

packages/auth/src/providers/cognito/credentialsProvider/IdentityIdProvider.ts

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

4-
import { AuthTokens, ConsoleLogger, Identity, getId } from '@aws-amplify/core';
4+
import { AuthTokens, Identity, getId } from '@aws-amplify/core';
55
import { CognitoIdentityPoolConfig } from '@aws-amplify/core/internals/utils';
66

77
import { AuthError } from '../../../errors/AuthError';
@@ -11,7 +11,6 @@ import { GetIdException } from '../types/errors';
1111
import { IdentityIdStore } from './types';
1212
import { formLoginsMap } from './utils';
1313

14-
const logger = new ConsoleLogger('CognitoIdentityIdProvider');
1514
/**
1615
* Provides a Cognito identityId
1716
*
@@ -33,46 +32,22 @@ export async function cognitoIdentityIdProvider({
3332
identityIdStore.setAuthConfig({ Cognito: authConfig });
3433

3534
// will return null only if there is no identityId cached or if there is an error retrieving it
36-
let identityId: Identity | null = await identityIdStore.loadIdentityId();
35+
const identityId: Identity | null = await identityIdStore.loadIdentityId();
3736

38-
// Tokens are available so return primary identityId
39-
if (tokens) {
40-
// If there is existing primary identityId in-memory return that
41-
if (identityId && identityId.type === 'primary') {
42-
return identityId.id;
43-
} else {
44-
const logins = tokens.idToken
45-
? formLoginsMap(tokens.idToken.toString())
46-
: {};
47-
48-
const generatedIdentityId = await generateIdentityId(logins, authConfig);
49-
50-
if (identityId && identityId.id === generatedIdentityId) {
51-
logger.debug(
52-
`The guest identity ${identityId.id} has become the primary identity.`,
53-
);
54-
}
55-
identityId = {
56-
id: generatedIdentityId,
57-
type: 'primary',
58-
};
59-
}
60-
} else {
61-
// If there is existing guest identityId cached return that
62-
if (identityId && identityId.type === 'guest') {
63-
return identityId.id;
64-
} else {
65-
identityId = {
66-
id: await generateIdentityId({}, authConfig),
67-
type: 'guest',
68-
};
69-
}
37+
if (identityId) {
38+
return identityId.id;
7039
}
40+
const logins = tokens?.idToken
41+
? formLoginsMap(tokens.idToken.toString())
42+
: {};
43+
const generatedIdentityId = await generateIdentityId(logins, authConfig);
44+
// Store generated identityId
45+
identityIdStore.storeIdentityId({
46+
id: generatedIdentityId,
47+
type: tokens ? 'primary' : 'guest',
48+
});
7149

72-
// Store in-memory or local storage depending on guest or primary identityId
73-
identityIdStore.storeIdentityId(identityId);
74-
75-
return identityId.id;
50+
return generatedIdentityId;
7651
}
7752

7853
async function generateIdentityId(

0 commit comments

Comments
 (0)