Skip to content

Commit

Permalink
feat: Adding support for cloudfront user principal
Browse files Browse the repository at this point in the history
  • Loading branch information
alejandromendeza authored and tdpauw committed Aug 11, 2024
1 parent 7fc752d commit e5d42d1
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 8 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@

#Visual Studio Code settings
/.vscode/

#Jetbrains settings
.idea
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export * from './principals/account';
export * from './principals/root-account';
export * from './principals/federated';
export * from './principals/wildcard';
export * from './principals/cloudfront';
export * from './condition/condition';
23 changes: 23 additions & 0 deletions src/principals/cloudfront.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {AbstractBasePrincipal} from './base';

class CloudFrontPrincipal extends AbstractBasePrincipal {
private arn: string;

constructor(arn: string) {
super();
this.arn = arn;
}

static validate(input: string): string | undefined {
const regex = new RegExp(
'^arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E(?=.*[A-Z])(?=.*[0-9])[A-Z0-9]{6,14}$');
const result = regex.exec(input) as RegExpExecArray;
return result ? result[0] : undefined;
}

toJSON() {
return {AWS: this.arn};
}
}

export {CloudFrontPrincipal};
11 changes: 9 additions & 2 deletions src/principals/deserialiser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import {AccountPrincipal} from './account';
import {ServicePrincipal} from './service';
import {FederatedPrincipal} from './federated';
import {parseArray} from '../arrays';
import {CloudFrontPrincipal} from './cloudfront';

class PrincipalJSONDeserialiser {
static fromJSON(input: {[key:string]: PrincipalValues} | AnonymousValue | undefined): Principal[] {
static fromJSON(input: { [key: string]: PrincipalValues } | AnonymousValue | undefined): Principal[] {
if (input === undefined) {
return [];
}
Expand All @@ -19,7 +20,7 @@ class PrincipalJSONDeserialiser {

const result: Principal[] = [];

const principals = input as {[key:string]: string[] | string};
const principals = input as { [key: string]: string[] | string };
const principalTypes = Object.keys(principals);
principalTypes.forEach((principalType) => {
const principalValues = parseArray(principals[principalType]);
Expand Down Expand Up @@ -52,11 +53,17 @@ class PrincipalJSONDeserialiser {
if (validation) {
return new AnonymousUserPrincipal();
}
validation = CloudFrontPrincipal.validate(value);
if (validation) {
return new CloudFrontPrincipal(value);
}
throw new Error(`Unsupported AWS principal value "${value}"`);
}

function parseService(value: string) {
return new ServicePrincipal(value);
}

function parseFederated(value: string) {
return new FederatedPrincipal(value);
}
Expand Down
48 changes: 44 additions & 4 deletions tests/principals/deserialiser.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {expect} from 'chai';
import {PrincipalJSONDeserialiser} from '../../src/principals/deserialiser';
import {
ArnPrincipal,
ServicePrincipal,
RootAccountPrincipal,
AccountPrincipal,
AnonymousUserPrincipal,
WildcardPrincipal,
ArnPrincipal,
CloudFrontPrincipal,
FederatedPrincipal,
RootAccountPrincipal,
ServicePrincipal,
WildcardPrincipal,
} from '../../src';

describe('#PrincipalJSONDeserialise', function() {
Expand Down Expand Up @@ -76,6 +77,45 @@ describe('#PrincipalJSONDeserialise', function() {
});
});

describe('with an CloudFront user', function() {
it('should return a CloudFrontPrincipal', function() {
const validCloudFrontIds = [
'E1ABCDEFGHIJ',
'E12345ABCDE',
'EABCD1234567',
'E1A2B3C4D5E6F',
'E12345678ABCDE',
];
for (const validCloudFrontId of validCloudFrontIds) {
const arn = `arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${validCloudFrontId}`;
const input = {AWS: arn};
expect(PrincipalJSONDeserialiser.fromJSON(input)).to.deep.equal([new CloudFrontPrincipal(arn)]);
}
});
it('should fail with invalid cloud front ids', function() {
const invalidCloudFrontIds = [
'EABCDEFGHIJKL',
'E123456789',
'EABCDEFGHIJKLMNO',
'1EABC1234567',
'EFGHJKLMNOP',
];
let arn: string | undefined;
for (const invalidCloudFrontId of invalidCloudFrontIds) {
arn = `arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${invalidCloudFrontId}`;
const input = {AWS: arn};
try {
PrincipalJSONDeserialiser.fromJSON(input);
} catch (error) {
const error_ = error as Error;
if (error_.message !== `Unsupported AWS principal value "${arn}"`) {
throw error;
}
}
}
});
});

describe('with an unsupported ARN', function() {
it('should throw an error', function() {
expect(() => PrincipalJSONDeserialiser.fromJSON({AWS: ['anArn']})).to.throw(Error)
Expand Down

0 comments on commit e5d42d1

Please sign in to comment.