Skip to content

Commit

Permalink
fix: add ignoreAllowList flag (#331)
Browse files Browse the repository at this point in the history
* feat(cli): Adds --allowList parameter to cli

e.g.

```
opentdf.mjs --allowList https://kas.a,https://kas.b
```

---------

Signed-off-by: Tyler Biscoe <[email protected]>
Co-authored-by: David Mihalcik <[email protected]>
Co-authored-by: elizabethhealy <[email protected]>
  • Loading branch information
3 people authored Aug 23, 2024
1 parent 297cec6 commit 29a9b82
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 11 deletions.
8 changes: 4 additions & 4 deletions cli/package-lock.json

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

14 changes: 13 additions & 1 deletion cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ export const handleArgs = (args: string[]) => {
type: 'string',
validate: (attributes: string) => attributes.split(','),
})
.boolean('ignoreAllowList')
.option('auth', {
group: 'Authentication:',
type: 'string',
Expand Down Expand Up @@ -293,6 +294,7 @@ export const handleArgs = (args: string[]) => {
async (argv) => {
log('DEBUG', 'Running decrypt command');
const allowedKases = argv.allowList?.split(',');
const ignoreAllowList = !!argv.ignoreAllowList;
const authProvider = await processAuth(argv);
log('DEBUG', `Initialized auth provider ${JSON.stringify(authProvider)}`);

Expand All @@ -301,6 +303,7 @@ export const handleArgs = (args: string[]) => {
log('DEBUG', `TDF3 Client`);
const client = new TDF3Client({
allowedKases,
ignoreAllowList,
authProvider,
kasEndpoint,
dpopEnabled: argv.dpop,
Expand All @@ -318,9 +321,16 @@ export const handleArgs = (args: string[]) => {
const dpopEnabled = !!argv.dpop;
const client =
argv.containerType === 'nano'
? new NanoTDFClient({ allowedKases, authProvider, kasEndpoint, dpopEnabled })
? new NanoTDFClient({
allowedKases,
ignoreAllowList,
authProvider,
kasEndpoint,
dpopEnabled,
})
: new NanoTDFDatasetClient({
allowedKases,
ignoreAllowList,
authProvider,
kasEndpoint,
dpopEnabled,
Expand Down Expand Up @@ -376,12 +386,14 @@ export const handleArgs = (args: string[]) => {
const authProvider = await processAuth(argv);
log('DEBUG', `Initialized auth provider ${JSON.stringify(authProvider)}`);
const kasEndpoint = argv.kasEndpoint;
const ignoreAllowList = !!argv.ignoreAllowList;
const allowedKases = argv.allowList?.split(',');

if ('tdf3' === argv.containerType) {
log('DEBUG', `TDF3 Client`);
const client = new TDF3Client({
allowedKases,
ignoreAllowList,
authProvider,
kasEndpoint,
dpopEnabled: argv.dpop,
Expand Down
7 changes: 6 additions & 1 deletion lib/src/access.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,16 @@ const origin = (u: string): string => {

export class OriginAllowList {
origins: string[];
constructor(urls: string[]) {
allowAll: boolean;
constructor(urls: string[], allowAll?: boolean) {
this.origins = urls.map(origin);
urls.forEach(validateSecureUrl);
this.allowAll = !!allowAll;
}
allows(url: string): boolean {
if (this.allowAll) {
return true;
}
return this.origins.includes(origin(url));
}
}
14 changes: 11 additions & 3 deletions lib/src/nanotdf/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { cryptoPublicToPem, pemToCryptoPublicKey, validateSecureUrl } from '../u

export interface ClientConfig {
allowedKases?: string[];
ignoreAllowList?: boolean;
authProvider: AuthProvider;
dpopEnabled?: boolean;
dpopKeys?: Promise<CryptoKeyPair>;
Expand Down Expand Up @@ -145,13 +146,20 @@ export default class Client {
}
this.iv = 1;
} else {
const { allowedKases, authProvider, dpopEnabled, dpopKeys, ephemeralKeyPair, kasEndpoint } =
optsOrOldAuthProvider;
const {
allowedKases,
ignoreAllowList,
authProvider,
dpopEnabled,
dpopKeys,
ephemeralKeyPair,
kasEndpoint,
} = optsOrOldAuthProvider;
this.authProvider = authProvider;
// TODO Disallow http KAS. For now just log as error
validateSecureUrl(kasEndpoint);
this.kasUrl = kasEndpoint;
this.allowedKases = new OriginAllowList(allowedKases || [kasEndpoint]);
this.allowedKases = new OriginAllowList(allowedKases || [kasEndpoint], !!ignoreAllowList);
this.dpopEnabled = !!dpopEnabled;
if (dpopKeys) {
this.requestSignerKeyPair = dpopKeys;
Expand Down
8 changes: 6 additions & 2 deletions lib/tdf3/src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export interface ClientConfig {
* Defaults to `[kasEndpoint]`.
*/
allowedKases?: string[];
ignoreAllowList?: boolean;
easEndpoint?: string;
// DEPRECATED Ignored
keyRewrapEndpoint?: string;
Expand Down Expand Up @@ -275,7 +276,10 @@ export class Client {

const kasOrigin = new URL(this.kasEndpoint).origin;
if (clientConfig.allowedKases) {
this.allowedKases = new OriginAllowList(clientConfig.allowedKases);
this.allowedKases = new OriginAllowList(
clientConfig.allowedKases,
!!clientConfig.ignoreAllowList
);
if (!validateSecureUrl(this.kasEndpoint) && !this.allowedKases.allows(kasOrigin)) {
throw new TdfError(`Invalid KAS endpoint [${this.kasEndpoint}]`);
}
Expand All @@ -285,7 +289,7 @@ export class Client {
`Invalid KAS endpoint [${this.kasEndpoint}]; to force, please list it among allowedKases`
);
}
this.allowedKases = new OriginAllowList([kasOrigin]);
this.allowedKases = new OriginAllowList([kasOrigin], !!clientConfig.ignoreAllowList);
}

this.authProvider = config.authProvider;
Expand Down
15 changes: 15 additions & 0 deletions lib/tests/mocha/unit/tdf.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,21 @@ describe('splitLookupTableFactory', () => {
});
});

it('should return a correct split table for valid input with ignoreAllowList', () => {
const keyAccess: KeyAccessObject[] = [
{ sid: 'split1', type: 'remote', url: 'https://kas1', protocol: 'kas' },
{ sid: 'split2', type: 'remote', url: 'https://kas2', protocol: 'kas' },
];
const allowedKases = new OriginAllowList([], true);

const result = TDF.splitLookupTableFactory(keyAccess, allowedKases);

expect(result).to.deep.equal({
split1: { 'https://kas1': keyAccess[0] },
split2: { 'https://kas2': keyAccess[1] },
});
});

it('should throw KasDecryptError for disallowed KASes', () => {
const keyAccess: KeyAccessObject[] = [
{ sid: 'split1', type: 'remote', url: 'https://kas1', protocol: 'kas' },
Expand Down

0 comments on commit 29a9b82

Please sign in to comment.