Skip to content

Commit 7c8f816

Browse files
committed
chore: refactor BasicAuthentication to extend Authentication
1 parent 4180544 commit 7c8f816

File tree

6 files changed

+89
-65
lines changed

6 files changed

+89
-65
lines changed

.eslintrc.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ module.exports = {
237237
}
238238
],
239239
'use-isnan': 'error',
240-
'valid-typeof': 'off'
240+
'valid-typeof': 'off',
241+
'@typescript-eslint/unbound-method': 'off'
241242
}
242243
};

src/dispatch/Authentication.ts

Lines changed: 9 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,16 @@ import { CognitoIdentityClient } from './CognitoIdentityClient';
22
import { Config } from '../orchestration/Orchestration';
33
import { Credentials } from '@aws-sdk/types';
44
import { FetchHttpHandler } from '@aws-sdk/fetch-http-handler';
5-
import { StsClient } from './StsClient';
65
import { CRED_KEY, CRED_RENEW_MS } from '../utils/constants';
76

8-
export class Authentication {
9-
private cognitoIdentityClient: CognitoIdentityClient;
10-
private stsClient: StsClient;
11-
private config: Config;
12-
private credentials: Credentials | undefined;
7+
export abstract class Authentication {
8+
protected cognitoIdentityClient: CognitoIdentityClient;
9+
protected config: Config;
10+
protected credentials: Credentials | undefined;
1311

1412
constructor(config: Config) {
1513
const region: string = config.identityPoolId!.split(':')[0];
1614
this.config = config;
17-
this.stsClient = new StsClient({
18-
fetchRequestHandler: new FetchHttpHandler(),
19-
region
20-
});
2115
this.cognitoIdentityClient = new CognitoIdentityClient({
2216
fetchRequestHandler: new FetchHttpHandler(),
2317
region
@@ -33,7 +27,7 @@ export class Authentication {
3327
* re-authenticate every time the client loads, which (1) improves the performance of the RUM web client and (2)
3428
* reduces the load on AWS services Cognito and STS.
3529
*
36-
* While storing credentials in localStorage puts the cookie at greater risk of being leaked through an
30+
* While storing credentials in localStorage puts the credential at greater risk of being leaked through an
3731
* XSS attack, there is no impact if the credentials were to be leaked. This is because (1) the identity pool ID
3832
* and role ARN are public and (2) the credentials are for an anonymous (guest) user.
3933
*
@@ -87,7 +81,7 @@ export class Authentication {
8781
try {
8882
credentials = JSON.parse(localStorage.getItem(CRED_KEY)!);
8983
} catch (e) {
90-
// Error retrieving, decoding or parsing the cred string -- abort
84+
// Error decoding or parsing the cookie -- abort
9185
return reject();
9286
}
9387
// The expiration property of Credentials has a date type. Because the date was serialized as a string,
@@ -106,43 +100,14 @@ export class Authentication {
106100
};
107101

108102
/**
109-
* Provides credentials for an anonymous (guest) user. These credentials are retrieved from Cognito's basic
110-
* (classic) authflow.
103+
* Provides credentials for an anonymous (guest) user. These credentials are retrieved from Cognito's enhanced
104+
* authflow.
111105
*
112106
* See https://docs.aws.amazon.com/cognito/latest/developerguide/authentication-flow.html
113107
*
114108
* Implements CredentialsProvider = Provider<Credentials>
115109
*/
116-
private AnonymousCognitoCredentialsProvider =
117-
async (): Promise<Credentials> => {
118-
return this.cognitoIdentityClient
119-
.getId({
120-
IdentityPoolId: this.config.identityPoolId as string
121-
})
122-
.then((getIdResponse) =>
123-
this.cognitoIdentityClient.getOpenIdToken(getIdResponse)
124-
)
125-
.then((getOpenIdTokenResponse) =>
126-
this.stsClient.assumeRoleWithWebIdentity({
127-
RoleArn: this.config.guestRoleArn as string,
128-
RoleSessionName: 'cwr',
129-
WebIdentityToken: getOpenIdTokenResponse.Token
130-
})
131-
)
132-
.then((credentials: Credentials) => {
133-
this.credentials = credentials;
134-
try {
135-
localStorage.setItem(
136-
CRED_KEY,
137-
JSON.stringify(credentials)
138-
);
139-
} catch (e) {
140-
// Ignore
141-
}
142-
143-
return credentials;
144-
});
145-
};
110+
protected abstract AnonymousCognitoCredentialsProvider(): Promise<Credentials>;
146111

147112
private renewCredentials(): boolean {
148113
if (!this.credentials || !this.credentials.expiration) {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Config } from '../orchestration/Orchestration';
2+
import { Credentials } from '@aws-sdk/types';
3+
import { FetchHttpHandler } from '@aws-sdk/fetch-http-handler';
4+
import { StsClient } from './StsClient';
5+
import { CRED_KEY } from '../utils/constants';
6+
import { Authentication } from './Authentication';
7+
8+
export class BasicAuthentication extends Authentication {
9+
private stsClient: StsClient;
10+
11+
constructor(config: Config) {
12+
super(config);
13+
const region: string = config.identityPoolId!.split(':')[0];
14+
this.stsClient = new StsClient({
15+
fetchRequestHandler: new FetchHttpHandler(),
16+
region
17+
});
18+
}
19+
20+
/**
21+
* Provides credentials for an anonymous (guest) user. These credentials are retrieved from Cognito's basic
22+
* (classic) authflow.
23+
*
24+
* See https://docs.aws.amazon.com/cognito/latest/developerguide/authentication-flow.html
25+
*
26+
* Implements CredentialsProvider = Provider<Credentials>
27+
*/
28+
protected AnonymousCognitoCredentialsProvider =
29+
async (): Promise<Credentials> => {
30+
return this.cognitoIdentityClient
31+
.getId({
32+
IdentityPoolId: this.config.identityPoolId as string
33+
})
34+
.then((getIdResponse) =>
35+
this.cognitoIdentityClient.getOpenIdToken(getIdResponse)
36+
)
37+
.then((getOpenIdTokenResponse) =>
38+
this.stsClient.assumeRoleWithWebIdentity({
39+
RoleArn: this.config.guestRoleArn as string,
40+
RoleSessionName: 'cwr',
41+
WebIdentityToken: getOpenIdTokenResponse.Token
42+
})
43+
)
44+
.then((credentials: Credentials) => {
45+
this.credentials = credentials;
46+
try {
47+
localStorage.setItem(
48+
CRED_KEY,
49+
JSON.stringify(credentials)
50+
);
51+
} catch (e) {
52+
// Ignore
53+
}
54+
55+
return credentials;
56+
});
57+
};
58+
}

src/dispatch/EnhancedAuthentication.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { FetchHttpHandler } from '@aws-sdk/fetch-http-handler';
55
import { CRED_KEY, CRED_RENEW_MS } from '../utils/constants';
66

77
export class EnhancedAuthentication {
8-
private cognitoIdentityClient: CognitoIdentityClient;
9-
private config: Config;
10-
private credentials: Credentials | undefined;
8+
protected cognitoIdentityClient: CognitoIdentityClient;
9+
protected config: Config;
10+
protected credentials: Credentials | undefined;
1111

1212
constructor(config: Config) {
1313
const region: string = config.identityPoolId!.split(':')[0];
@@ -107,7 +107,7 @@ export class EnhancedAuthentication {
107107
*
108108
* Implements CredentialsProvider = Provider<Credentials>
109109
*/
110-
private AnonymousCognitoCredentialsProvider =
110+
protected AnonymousCognitoCredentialsProvider =
111111
async (): Promise<Credentials> => {
112112
return this.cognitoIdentityClient
113113
.getId({ IdentityPoolId: this.config.identityPoolId as string })

src/dispatch/__tests__/Authentication.test.ts renamed to src/dispatch/__tests__/BasicAuthentication.test.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Authentication } from '../Authentication';
1+
import { BasicAuthentication } from '../BasicAuthentication';
22
import { CRED_KEY } from '../../utils/constants';
33
import { DEFAULT_CONFIG } from '../../test-utils/test-utils';
44

@@ -22,7 +22,7 @@ jest.mock('../StsClient', () => ({
2222
const IDENTITY_POOL_ID = 'us-west-2:a-b-c-d';
2323
const GUEST_ROLE_ARN = 'arn:aws:iam::123:role/Unauth';
2424

25-
describe('Authentication tests', () => {
25+
describe('BasicAuthentication tests', () => {
2626
beforeEach(() => {
2727
mockGetId.mockReset();
2828
mockGetIdToken.mockReset();
@@ -54,7 +54,7 @@ describe('Authentication tests', () => {
5454
guestRoleArn: GUEST_ROLE_ARN
5555
}
5656
};
57-
const auth = new Authentication(config);
57+
const auth = new BasicAuthentication(config);
5858

5959
localStorage.setItem(
6060
CRED_KEY,
@@ -88,7 +88,7 @@ describe('Authentication tests', () => {
8888
guestRoleArn: GUEST_ROLE_ARN
8989
}
9090
};
91-
const auth = new Authentication(config);
91+
const auth = new BasicAuthentication(config);
9292

9393
localStorage.setItem(CRED_KEY, 'corrupt');
9494

@@ -107,7 +107,7 @@ describe('Authentication tests', () => {
107107

108108
test('when credential is not in localStorage then authentication chain retrieves credential from basic authflow', async () => {
109109
// Init
110-
const auth = new Authentication({
110+
const auth = new BasicAuthentication({
111111
...DEFAULT_CONFIG,
112112
...{
113113
identityPoolId: IDENTITY_POOL_ID,
@@ -139,7 +139,7 @@ describe('Authentication tests', () => {
139139
}
140140
};
141141

142-
const auth = new Authentication(config);
142+
const auth = new BasicAuthentication(config);
143143

144144
localStorage.setItem(
145145
CRED_KEY,
@@ -181,7 +181,7 @@ describe('Authentication tests', () => {
181181
sessionToken: 'z'
182182
});
183183

184-
const auth = new Authentication({
184+
const auth = new BasicAuthentication({
185185
...DEFAULT_CONFIG,
186186
...{
187187
identityPoolId: IDENTITY_POOL_ID,
@@ -210,7 +210,7 @@ describe('Authentication tests', () => {
210210
throw e;
211211
});
212212
// Init
213-
const auth = new Authentication({
213+
const auth = new BasicAuthentication({
214214
...DEFAULT_CONFIG,
215215
...{
216216
identityPoolId: IDENTITY_POOL_ID,
@@ -230,7 +230,7 @@ describe('Authentication tests', () => {
230230
throw e;
231231
});
232232
// Init
233-
const auth = new Authentication({
233+
const auth = new BasicAuthentication({
234234
...DEFAULT_CONFIG,
235235
...{
236236
identityPoolId: IDENTITY_POOL_ID,
@@ -250,7 +250,7 @@ describe('Authentication tests', () => {
250250
throw e;
251251
});
252252
// Init
253-
const auth = new Authentication({
253+
const auth = new BasicAuthentication({
254254
...DEFAULT_CONFIG,
255255
...{
256256
identityPoolId: IDENTITY_POOL_ID,
@@ -272,7 +272,7 @@ describe('Authentication tests', () => {
272272
guestRoleArn: GUEST_ROLE_ARN
273273
}
274274
};
275-
const auth = new Authentication(config);
275+
const auth = new BasicAuthentication(config);
276276

277277
// Run
278278
await auth.ChainAnonymousCredentialsProvider();
@@ -321,7 +321,7 @@ describe('Authentication tests', () => {
321321
guestRoleArn: GUEST_ROLE_ARN
322322
}
323323
};
324-
const auth = new Authentication(config);
324+
const auth = new BasicAuthentication(config);
325325

326326
// Run
327327
await auth.ChainAnonymousCredentialsProvider();
@@ -358,7 +358,7 @@ describe('Authentication tests', () => {
358358
guestRoleArn: GUEST_ROLE_ARN
359359
}
360360
};
361-
const auth = new Authentication(config);
361+
const auth = new BasicAuthentication(config);
362362

363363
// Run
364364
const credentials = await auth.ChainAnonymousCredentialsProvider();
@@ -396,7 +396,7 @@ describe('Authentication tests', () => {
396396
guestRoleArn: GUEST_ROLE_ARN
397397
}
398398
};
399-
const auth = new Authentication(config);
399+
const auth = new BasicAuthentication(config);
400400

401401
// Run
402402
await auth.ChainAnonymousCredentialsProvider();

src/orchestration/Orchestration.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Plugin } from '../plugins/Plugin';
22
import { PluginContext } from '../plugins/types';
33
import { InternalPlugin } from '../plugins/InternalPlugin';
4-
import { Authentication } from '../dispatch/Authentication';
4+
import { BasicAuthentication } from '../dispatch/BasicAuthentication';
55
import { EnhancedAuthentication } from '../dispatch/EnhancedAuthentication';
66
import { PluginManager } from '../plugins/PluginManager';
77
import {
@@ -417,7 +417,7 @@ export class Orchestration {
417417

418418
if (this.config.identityPoolId && this.config.guestRoleArn) {
419419
dispatch.setAwsCredentials(
420-
new Authentication(this.config)
420+
new BasicAuthentication(this.config)
421421
.ChainAnonymousCredentialsProvider
422422
);
423423
} else if (this.config.identityPoolId) {

0 commit comments

Comments
 (0)