Skip to content

Commit

Permalink
feat: implement partition specific auth (#456)
Browse files Browse the repository at this point in the history
fixes #274
  • Loading branch information
tripodsan authored Nov 15, 2023
1 parent 7786e4c commit 89fa4f1
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 12 deletions.
39 changes: 29 additions & 10 deletions src/steps/authenticate.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* governing permissions and limitations under the License.
*/
import { getAuthInfo, makeAuthError } from '../utils/auth.js';
import { toArray } from './utils.js';

/**
* Checks if the given email is allowed.
Expand All @@ -27,6 +28,26 @@ export function isAllowed(email = '', allows = []) {
return allows.findIndex((a) => a === email || a === wild) >= 0;
}

/**
* Returns the normalized access configuration for the current partition.
* @param state
* @return {{}}
*/
export function getAccessConfig(state) {
const { access } = state.config;
if (!access) {
return {
allow: [],
apiKeyId: [],
};
}
const { partition } = state;
return {
allow: toArray(access[partition]?.allow ?? access.allow),
apiKeyId: toArray(access[partition]?.apiKeyId ?? access.apiKeyId),
};
}

/**
* Handles authentication
* @type PipelineStep
Expand All @@ -43,8 +64,11 @@ export async function authenticate(state, req, res) {
return;
}

// get partition relative auth info
const access = getAccessConfig(state);

// if not protected, do nothing
if (!state.config?.access?.allow) {
if (!access.allow.length) {
return;
}

Expand Down Expand Up @@ -77,20 +101,15 @@ export async function authenticate(state, req, res) {

// validate jti
if (jti) {
const ids = Array.isArray(state.config.access.apiKeyId)
? state.config.access.apiKeyId
: [state.config.access.apiKeyId];
if (ids.indexOf(jti) < 0) {
state.log.warn(`[auth] invalid jti ${jti}: does not match configured id ${state.config.access.apiKeyId}`);
if (access.apiKeyId.indexOf(jti) < 0) {
state.log.warn(`[auth] invalid jti ${jti}: does not match configured id ${access.apiKeyId}`);
makeAuthError(state, req, res, 'invalid-jti');
}
}

// check profile is allowed
const { allow } = state.config.access;
const allows = Array.isArray(allow) ? allow : [allow];
if (!isAllowed(email, allows)) {
state.log.warn(`[auth] profile not allowed for ${allows}`);
if (!isAllowed(email, access.allow)) {
state.log.warn(`[auth] profile not allowed for ${access.allow}`);
makeAuthError(state, req, res, 'forbidden', 403);
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/steps/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,10 @@ export function rewriteUrl(state, url) {

return url;
}

export function toArray(v) {
if (!v) {
return [];
}
return Array.isArray(v) ? v : [v];
}
3 changes: 2 additions & 1 deletion src/utils/json-filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* governing permissions and limitations under the License.
*/
import { PipelineStatusError } from '../PipelineStatusError.js';
import { toArray } from '../steps/utils.js';

const TYPE_KEY = ':type';

Expand Down Expand Up @@ -78,7 +79,7 @@ export default function jsonFilter(state, res, query) {
}

state.timer?.update('json-filter');
const requestedSheets = Array.isArray(sheet) ? sheet : [sheet];
const requestedSheets = toArray(sheet);
if (requestedSheets.length === 0 && 'default' in json) {
requestedSheets.push('default');
}
Expand Down
44 changes: 43 additions & 1 deletion test/steps/authenticate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import assert from 'assert';
import esmock from 'esmock';
import {
authenticate,
authenticate, getAccessConfig,
isAllowed,
isOwnerRepoAllowed,
requireProject,
Expand Down Expand Up @@ -383,3 +383,45 @@ describe('Authenticate Test', () => {
assert.strictEqual(res.status, 200);
});
});

describe('Access config tests', () => {
it('returns empty access config', () => {
const state = new PipelineState({});
assert.deepStrictEqual(getAccessConfig(state), {
allow: [],
apiKeyId: [],
});
});

it('returns default access config', () => {
const state = new PipelineState({});
state.config = {
access: {
allow: '*@adobe.com',
},
};
assert.deepStrictEqual(getAccessConfig(state), {
allow: ['*@adobe.com'],
apiKeyId: [],
});
});

it('can partially overwrite access config', () => {
const state = new PipelineState({
partition: 'live',
});
state.config = {
access: {
allow: '*@adobe.com',
apiKeyId: '1234',
live: {
allow: ['foo@adobe.com', 'bar@adobe.com'],
},
},
};
assert.deepStrictEqual(getAccessConfig(state), {
allow: ['foo@adobe.com', 'bar@adobe.com'],
apiKeyId: ['1234'],
});
});
});

0 comments on commit 89fa4f1

Please sign in to comment.