Skip to content
This repository has been archived by the owner on Aug 22, 2024. It is now read-only.

feat: Support for request verification #31

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
87 changes: 83 additions & 4 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ objects against the schemas.</p>
<dd></dd>
<dt><del><a href="#extractSqsRecords">extractSqsRecords()</a></del></dt>
<dd></dd>
<dt><a href="#Security.">Security.(allowedPermissions, actualPermissions)</a> ⇒ <code>boolean</code></dt>
<dd><p>Checks to see if any of the allowed permissions are present in the actual permissions,
using globbing expansion</p>
</dd>
</dl>

## Typedefs
Expand All @@ -45,11 +49,19 @@ objects against the schemas.</p>
<dd></dd>
<dt><a href="#QueueRecord">QueueRecord</a> : <code>Object</code></dt>
<dd></dd>
<dt><a href="#SecurityConfig">SecurityConfig</a></dt>
<dd></dd>
<dt><a href="#Handler">Handler</a> ⇒ <code>Promise.&lt;Response&gt;</code></dt>
<dd><p>Function for handling a routes inside Frankin / Content Lake services</p>
<dd><p>Function for handling a routes inside Franklin / Content Lake services</p>
</dd>
<dt><a href="#SecretConfig">SecretConfig</a> : <code><a href="#AwsConfig">AwsConfig</a></code> | <code>SecretConfigExt</code></dt>
<dd></dd>
<dt><a href="#AuthenticationRequirement">AuthenticationRequirement</a> : <code>Object</code></dt>
<dd></dd>
<dt><a href="#TokenRequest">TokenRequest</a> : <code>Object</code></dt>
<dd></dd>
<dt><a href="#TokenPayload">TokenPayload</a> : <code>Object</code></dt>
<dd></dd>
</dl>

<a name="SchemaValidator"></a>
Expand Down Expand Up @@ -97,6 +109,19 @@ as specified in https://wiki.corp.adobe.com/display/WEM/Ingestor+API+Contract
***Deprecated***

**Kind**: global function
<a name="Security."></a>

## Security.(allowedPermissions, actualPermissions) ⇒ <code>boolean</code>
Checks to see if any of the allowed permissions are present in the actual permissions,
using globbing expansion

**Kind**: global function

| Param | Type | Description |
| --- | --- | --- |
| allowedPermissions | <code>Array.&lt;string&gt;</code> | the list of permissions which are allowed |
| actualPermissions | <code>Array.&lt;string&gt;</code> | the actual permissions from the request |

<a name="BlobStorageConfig"></a>

## BlobStorageConfig : <code>Object</code>
Expand Down Expand Up @@ -197,19 +222,30 @@ as specified in https://wiki.corp.adobe.com/display/WEM/Ingestor+API+Contract
| messageAttributes | <code>Record.&lt;string, any&gt;</code> |
| eventSource | <code>string</code> |

<a name="SecurityConfig"></a>

## SecurityConfig
**Kind**: global typedef
**Properties**

| Name | Type |
| --- | --- |
| authRequired; | <code>boolean</code> |
| [allowedRoles] | <code>Array.&lt;string&gt;</code> |
| [allowedPermissions] | <code>Array.&lt;string&gt;</code> |

<a name="Handler"></a>

## Handler ⇒ <code>Promise.&lt;Response&gt;</code>
Function for handling a routes inside Frankin / Content Lake services
Function for handling a routes inside Franklin / Content Lake services

**Kind**: global typedef
**Returns**: <code>Promise.&lt;Response&gt;</code> - the response from the request

| Param | Type | Description |
| --- | --- | --- |
| req | <code>Request</code> | the request |
| context | <code>UniversalContext</code> | the context of the request |
| params | <code>Record.&lt;string, string&gt;</code> | the parameters parsed from the request |
| info | <code>Object</code> | the additional request information |

<a name="SecretConfig"></a>

Expand All @@ -220,4 +256,47 @@ Function for handling a routes inside Frankin / Content Lake services
| Name | Type |
| --- | --- |
| [client] | <code>SecretsManagerClient</code> |
| application | <code>string</code> |
| [companyId] | <code>string</code> |
| [scope] | <code>string</code> |

<a name="AuthenticationRequirement"></a>

## AuthenticationRequirement : <code>Object</code>
**Kind**: global typedef
**Properties**

| Name | Type |
| --- | --- |
| [allowedRoles] | <code>Array.&lt;string&gt;</code> |
| [allowedPermissions] | <code>Array.&lt;string&gt;</code> |

<a name="TokenRequest"></a>

## TokenRequest : <code>Object</code>
**Kind**: global typedef
**Properties**

| Name | Type | Description |
| --- | --- | --- |
| spaceId | <code>string</code> | the space for which the token will be generated |
| roleKeys | <code>Array.&lt;string&gt;</code> | the role keys for which the token should be generated |
| generator | <code>string</code> | provides attribution for the key in the description |
| [expiresInMinutes] | <code>number</code> | the number of minutes before the token expires (or 14 days) |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

qs: why isn't the companyId needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not used for validating the token, but it does make sense that we need to validate that as well as the space id.


<a name="TokenPayload"></a>

## TokenPayload : <code>Object</code>
**Kind**: global typedef
**Properties**

| Name | Type | Description |
| --- | --- | --- |
| permissions | <code>Array.&lt;string&gt;</code> | the permissions granted to this token |
| roles | <code>Array.&lt;string&gt;</code> | the permissions granted to this token |
| sub | <code>string</code> | the subject (or identifier) for this token |
| tenantId | <code>string</code> | the primary tenant for the token |
| [tenantIds] | <code>Array.&lt;string&gt;</code> | the optional list of additional allowed tenants for the token |
| type | <code>string</code> | the type of the token |
| exp | <code>number</code> | the timestamp at which the token will expire |

22 changes: 16 additions & 6 deletions it/secret.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,21 @@ import {
DeleteSecretCommand,
ListSecretsCommand,
} from '@aws-sdk/client-secrets-manager';
import { extractAwsConfig } from '../src/context.js';
import { ContextHelper } from '../src/context.js';
import { SecretsManager } from '../src/secret.js';

dotenv.config();

const SLOW_TEST_TIMEOUT = 5000;

describe('Secrets Manager Integration Tests', async () => {
const extractor = 'it';
const defaultConfig = { scope: 'test', application: 'commons-secrets-it' };
const helper = new ContextHelper(process);
it('fails on non-existing secret', async () => {
const mgr = new SecretsManager(extractor, extractAwsConfig(process));
const mgr = new SecretsManager({
...defaultConfig,
...helper.extractAwsConfig(),
});
let caught;
try {
await mgr.getSecret('not-a-secret');
Expand All @@ -41,7 +45,10 @@ describe('Secrets Manager Integration Tests', async () => {

it('can create, get and delete secret', async () => {
const secretId = randomUUID();
const mgr = new SecretsManager(extractor, extractAwsConfig(process));
const mgr = new SecretsManager({
...defaultConfig,
...helper.extractAwsConfig(),
});
let caught;
try {
await mgr.getSecret(secretId);
Expand All @@ -64,7 +71,10 @@ describe('Secrets Manager Integration Tests', async () => {
}).timeout(SLOW_TEST_TIMEOUT);

after(async () => {
const secretManager = new SecretsManagerClient(extractAwsConfig(process));
const secretManager = new SecretsManagerClient({
...defaultConfig,
...helper.extractAwsConfig(),
});
await secretManager
.send(
new ListSecretsCommand({
Expand All @@ -75,7 +85,7 @@ describe('Secrets Manager Integration Tests', async () => {
.then((res) => {
Promise.all(
res.SecretList.filter(
(secret) => secret.Name.startsWith('test') || secret.Name.startsWith('it'),
(secret) => secret.Name.startsWith('test/shared/commons-secrets-it/'),
).map((secret) => secretManager.send(
new DeleteSecretCommand({
SecretId: secret.Name,
Expand Down
43 changes: 43 additions & 0 deletions it/security.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2021 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

/* eslint-env mocha */
import assert from 'assert';
import * as dotenv from 'dotenv';
import { Security } from '../src/security.js';

dotenv.config();

const SLOW_TEST_TIMEOUT = 5000;
const spaceId = process.env.SPACE_ID;

function createRequest(token) {
return new Request('http://localhost/', {
headers: {
'x-space-id': spaceId,
authorization: `Bearer ${token}`,
},
});
}

describe('Security Integration Tests', async () => {
const security = new Security({ ...process, scope: 'test' });
klcodanr marked this conversation as resolved.
Show resolved Hide resolved
it('can generate and authorize tokens', async () => {
const token = await security.generateToken({
generator: 'Commons Security IT',
spaceId,
roleKeys: ['Admin'],
});
assert.ok(token);
await security.authorize(createRequest(token));
}).timeout(SLOW_TEST_TIMEOUT);
});
klcodanr marked this conversation as resolved.
Show resolved Hide resolved
Loading