Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support unique credential cookie names
Browse files Browse the repository at this point in the history
limhjgrace committed Jun 6, 2024
1 parent 4056e86 commit 667519b
Showing 8 changed files with 312 additions and 116 deletions.
15 changes: 13 additions & 2 deletions src/dispatch/Authentication.ts
Original file line number Diff line number Diff line change
@@ -3,19 +3,22 @@ import { Config } from '../orchestration/Orchestration';
import { AwsCredentialIdentity } from '@aws-sdk/types';
import { FetchHttpHandler } from '@aws-sdk/fetch-http-handler';
import { CRED_KEY, CRED_RENEW_MS } from '../utils/constants';
import { getCookieName } from '../utils/cookies-utils';

export abstract class Authentication {
protected applicationId: string;
protected cognitoIdentityClient: CognitoIdentityClient;
protected config: Config;
protected credentials: AwsCredentialIdentity | undefined;

constructor(config: Config) {
constructor(config: Config, applicationId: string) {
const region: string = config.identityPoolId!.split(':')[0];
this.config = config;
this.cognitoIdentityClient = new CognitoIdentityClient({
fetchRequestHandler: new FetchHttpHandler(),
region
});
this.applicationId = applicationId;
}

/**
@@ -80,7 +83,15 @@ export abstract class Authentication {
return new Promise<AwsCredentialIdentity>((resolve, reject) => {
let credentials: AwsCredentialIdentity;
try {
credentials = JSON.parse(localStorage.getItem(CRED_KEY)!);
credentials = JSON.parse(
localStorage.getItem(
getCookieName(
this.config.cookieAttributes.unique,
CRED_KEY,
this.applicationId
)
)!
);
} catch (e) {
// Error retrieving, decoding or parsing the cred string -- abort
return reject();
11 changes: 8 additions & 3 deletions src/dispatch/BasicAuthentication.ts
Original file line number Diff line number Diff line change
@@ -4,12 +4,13 @@ import { FetchHttpHandler } from '@aws-sdk/fetch-http-handler';
import { StsClient } from './StsClient';
import { CRED_KEY } from '../utils/constants';
import { Authentication } from './Authentication';
import { getCookieName } from '../utils/cookies-utils';

export class BasicAuthentication extends Authentication {
private stsClient: StsClient;

constructor(config: Config) {
super(config);
constructor(config: Config, applicationId: string) {
super(config, applicationId);
const region: string = config.identityPoolId!.split(':')[0];
this.stsClient = new StsClient({
fetchRequestHandler: new FetchHttpHandler(),
@@ -51,7 +52,11 @@ export class BasicAuthentication extends Authentication {
this.credentials = credentials;
try {
localStorage.setItem(
CRED_KEY,
getCookieName(
this.config.cookieAttributes.unique,
CRED_KEY,
this.applicationId
),
JSON.stringify(credentials)
);
} catch (e) {
11 changes: 8 additions & 3 deletions src/dispatch/EnhancedAuthentication.ts
Original file line number Diff line number Diff line change
@@ -2,10 +2,11 @@ import { Config } from '../orchestration/Orchestration';
import { AwsCredentialIdentity } from '@aws-sdk/types';
import { CRED_KEY } from '../utils/constants';
import { Authentication } from './Authentication';
import { getCookieName } from '../utils/cookies-utils';

export class EnhancedAuthentication extends Authentication {
constructor(config: Config) {
super(config);
constructor(config: Config, applicationId: string) {
super(config, applicationId);
}
/**
* Provides credentials for an anonymous (guest) user. These credentials are retrieved from Cognito's enhanced
@@ -34,7 +35,11 @@ export class EnhancedAuthentication extends Authentication {
this.credentials = credentials;
try {
localStorage.setItem(
CRED_KEY,
getCookieName(
this.config.cookieAttributes.unique,
CRED_KEY,
this.applicationId
),
JSON.stringify(credentials)
);
} catch (e) {
171 changes: 125 additions & 46 deletions src/dispatch/__tests__/BasicAuthentication.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BasicAuthentication } from '../BasicAuthentication';
import { CRED_KEY } from '../../utils/constants';
import { DEFAULT_CONFIG } from '../../test-utils/test-utils';
import { APPLICATION_ID, DEFAULT_CONFIG } from '../../test-utils/test-utils';

const assumeRole = jest.fn();
const mockGetId = jest.fn();
@@ -54,7 +54,7 @@ describe('BasicAuthentication tests', () => {
guestRoleArn: GUEST_ROLE_ARN
}
};
const auth = new BasicAuthentication(config);
const auth = new BasicAuthentication(config, APPLICATION_ID);

localStorage.setItem(
CRED_KEY,
@@ -88,7 +88,7 @@ describe('BasicAuthentication tests', () => {
guestRoleArn: GUEST_ROLE_ARN
}
};
const auth = new BasicAuthentication(config);
const auth = new BasicAuthentication(config, APPLICATION_ID);

localStorage.setItem(CRED_KEY, 'corrupt');

@@ -107,13 +107,16 @@ describe('BasicAuthentication tests', () => {

test('when credential is not in localStorage then authentication chain retrieves credential from basic authflow', async () => {
// Init
const auth = new BasicAuthentication({
...DEFAULT_CONFIG,
...{
identityPoolId: IDENTITY_POOL_ID,
guestRoleArn: GUEST_ROLE_ARN
}
});
const auth = new BasicAuthentication(
{
...DEFAULT_CONFIG,
...{
identityPoolId: IDENTITY_POOL_ID,
guestRoleArn: GUEST_ROLE_ARN
}
},
APPLICATION_ID
);

// Run
const credentials = await auth.ChainAnonymousCredentialsProvider();
@@ -139,7 +142,7 @@ describe('BasicAuthentication tests', () => {
}
};

const auth = new BasicAuthentication(config);
const auth = new BasicAuthentication(config, APPLICATION_ID);

localStorage.setItem(
CRED_KEY,
@@ -181,13 +184,16 @@ describe('BasicAuthentication tests', () => {
sessionToken: 'z'
});

const auth = new BasicAuthentication({
...DEFAULT_CONFIG,
...{
identityPoolId: IDENTITY_POOL_ID,
guestRoleArn: GUEST_ROLE_ARN
}
});
const auth = new BasicAuthentication(
{
...DEFAULT_CONFIG,
...{
identityPoolId: IDENTITY_POOL_ID,
guestRoleArn: GUEST_ROLE_ARN
}
},
APPLICATION_ID
);

// Run
await auth.ChainAnonymousCredentialsProvider();
@@ -210,13 +216,16 @@ describe('BasicAuthentication tests', () => {
throw e;
});
// Init
const auth = new BasicAuthentication({
...DEFAULT_CONFIG,
...{
identityPoolId: IDENTITY_POOL_ID,
guestRoleArn: GUEST_ROLE_ARN
}
});
const auth = new BasicAuthentication(
{
...DEFAULT_CONFIG,
...{
identityPoolId: IDENTITY_POOL_ID,
guestRoleArn: GUEST_ROLE_ARN
}
},
APPLICATION_ID
);

// Assert
return expect(auth.ChainAnonymousCredentialsProvider()).rejects.toEqual(
@@ -230,13 +239,16 @@ describe('BasicAuthentication tests', () => {
throw e;
});
// Init
const auth = new BasicAuthentication({
...DEFAULT_CONFIG,
...{
identityPoolId: IDENTITY_POOL_ID,
guestRoleArn: GUEST_ROLE_ARN
}
});
const auth = new BasicAuthentication(
{
...DEFAULT_CONFIG,
...{
identityPoolId: IDENTITY_POOL_ID,
guestRoleArn: GUEST_ROLE_ARN
}
},
APPLICATION_ID
);

// Assert
return expect(auth.ChainAnonymousCredentialsProvider()).rejects.toEqual(
@@ -250,13 +262,16 @@ describe('BasicAuthentication tests', () => {
throw e;
});
// Init
const auth = new BasicAuthentication({
...DEFAULT_CONFIG,
...{
identityPoolId: IDENTITY_POOL_ID,
guestRoleArn: GUEST_ROLE_ARN
}
});
const auth = new BasicAuthentication(
{
...DEFAULT_CONFIG,
...{
identityPoolId: IDENTITY_POOL_ID,
guestRoleArn: GUEST_ROLE_ARN
}
},
APPLICATION_ID
);

// Assert
expect(auth.ChainAnonymousCredentialsProvider()).rejects.toEqual(e);
@@ -272,7 +287,7 @@ describe('BasicAuthentication tests', () => {
guestRoleArn: GUEST_ROLE_ARN
}
};
const auth = new BasicAuthentication(config);
const auth = new BasicAuthentication(config, APPLICATION_ID);

// Run
await auth.ChainAnonymousCredentialsProvider();
@@ -321,7 +336,7 @@ describe('BasicAuthentication tests', () => {
guestRoleArn: GUEST_ROLE_ARN
}
};
const auth = new BasicAuthentication(config);
const auth = new BasicAuthentication(config, APPLICATION_ID);

// Run
await auth.ChainAnonymousCredentialsProvider();
@@ -358,7 +373,7 @@ describe('BasicAuthentication tests', () => {
guestRoleArn: GUEST_ROLE_ARN
}
};
const auth = new BasicAuthentication(config);
const auth = new BasicAuthentication(config, APPLICATION_ID);

// Run
const credentials = await auth.ChainAnonymousCredentialsProvider();
@@ -396,7 +411,7 @@ describe('BasicAuthentication tests', () => {
guestRoleArn: GUEST_ROLE_ARN
}
};
const auth = new BasicAuthentication(config);
const auth = new BasicAuthentication(config, APPLICATION_ID);

// Run
await auth.ChainAnonymousCredentialsProvider();
@@ -414,13 +429,77 @@ describe('BasicAuthentication tests', () => {
throw e;
});
// Init
const auth = new BasicAuthentication({
const auth = new BasicAuthentication(
{
...DEFAULT_CONFIG,
...{
identityPoolId: IDENTITY_POOL_ID,
guestRoleArn: GUEST_ROLE_ARN
}
},
APPLICATION_ID
);

// Run
const credentials = await auth.ChainAnonymousCredentialsProvider();

// Assert
expect(credentials).toEqual(
expect.objectContaining({
accessKeyId: 'x',
secretAccessKey: 'y',
sessionToken: 'z'
})
);
});

test('when unique cookie names are used then cookie name with application id appended is stored', async () => {
// Init
const config = {
...DEFAULT_CONFIG,
...{
identityPoolId: IDENTITY_POOL_ID,
guestRoleArn: GUEST_ROLE_ARN
guestRoleArn: GUEST_ROLE_ARN,
allowCookies: true,
cookieAttributes: {
...DEFAULT_CONFIG.cookieAttributes,
...{ unique: true }
}
}
});
};
const auth = new BasicAuthentication(config, APPLICATION_ID);

// Run
await auth.ChainAnonymousCredentialsProvider();
const credentials = JSON.parse(
localStorage.getItem(`${CRED_KEY}_${APPLICATION_ID}`)!
);

// Assert
expect(credentials).toEqual(
expect.objectContaining({
accessKeyId: 'x',
secretAccessKey: 'y',
sessionToken: 'z'
})
);
});

test('when unique cookie names are used then cookie name with application id appended is retrieved', async () => {
// Init
const config = {
...DEFAULT_CONFIG,
...{
identityPoolId: IDENTITY_POOL_ID,
guestRoleArn: GUEST_ROLE_ARN,
allowCookies: true,
cookieAttributes: {
...DEFAULT_CONFIG.cookieAttributes,
...{ unique: true }
}
}
};
const auth = new BasicAuthentication(config, APPLICATION_ID);

// Run
const credentials = await auth.ChainAnonymousCredentialsProvider();
Loading

0 comments on commit 667519b

Please sign in to comment.