Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions test/plugins/auth.test.helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
'use strict';

const fs = require('fs');
const rewiremock = require('rewiremock/node');
const sinon = require('sinon');
const hapi = require('@hapi/hapi');

const jwtPrivateKey = fs.readFileSync(`${__dirname}/data/jwt.private.key`).toString();
const jwtPublicKey = fs.readFileSync(`${__dirname}/data/jwt.public.key`).toString();

const newAuthTestServer = async () => {
const authDeps = ['@hapi/cookie', '@hapi/bell', 'hapi-auth-jwt2', 'hapi-auth-bearer-token'];
const cookiePassword = 'this_is_a_password_that_needs_to_be_atleast_32_characters';
const encryptionPassword = 'this_is_another_password_that_needs_to_be_atleast_32_characters';
const hashingPassword = 'this_is_another_password_that_needs_to_be_atleast_32_characters';
const oauthRedirectUri = 'https://example.com/api';
const scm = {
getReadOnlyInfo: sinon.stub().returns({ enabled: false, username: 'headlessuser', accessToken: 'token' }),
getScmContexts: sinon.stub().returns(['github:github.com']),
getDisplayName: sinon.stub().returns('github'),
getBellConfiguration: sinon.stub().resolves({
'github:github.com': {
clientId: 'abcdefg',
clientSecret: 'hijklmno',
provider: 'github',
scope: ['admin:repo_hook', 'read:org', 'repo:status']
}
}),
scms: {
'github:github.com': {
clientId: 'abcdefg',
clientSecret: 'hijklmno',
provider: 'github',
scope: ['admin:repo_hook', 'read:org', 'repo:status']
}
},
autoDeployKeyGenerationEnabled: sinon.stub().returns(true),
decorateAuthor: sinon.stub(),
isEnterpriseUser: sinon.stub().resolves(false)
};
const baseProfile = {
username: 'batman',
scmUserId: 123,
scmContext: 'github:github.com',
scope: ['user'],
metadata: {}
};
const tokenFactoryMock = {
get: sinon.stub().returns({})
};
const loggerMock = {
info: sinon.stub(),
error: sinon.stub(),
warn: sinon.stub()
};
const server = new hapi.Server({
port: 1234,
routes: {
// ignore request and response validation
validate: { failAction: 'ignore' },
response: { failAction: 'ignore' }
}
});

server.app = {
tokenFactory: tokenFactoryMock
};
// ignore handler for each routes
server.ext('onPreHandler', (request, h) => {
return h
.response({
testAuth: request.auth,
testReachedAfterAuth: true
})
.code(200)
.takeover();
});

for (const pluginName of authDeps) {
// eslint-disable-next-line global-require, import/no-dynamic-require
await server.register({ plugin: require(pluginName) });
}

const authPlugin = rewiremock.proxy('../../plugins/auth', {
'screwdriver-logger': loggerMock
});

await server.register({
plugin: authPlugin,
options: {
cookiePassword,
encryptionPassword,
hashingPassword,
scm,
jwtPrivateKey,
jwtPublicKey,
jwtQueueServicePublicKey: jwtPublicKey,
allowGuestAccess: true,
https: false,
oauthRedirectUri,
sameSite: false,
bell: scm.scms,
path: '/',
admins: ['github:batman', 'batman'],
sdAdmins: ['github:batman:1312'],
authCheckById: true
}
});

server.generateTestJwt = ({ type = 'api_token', permission = 'all' }) => {
const profile = server.plugins.auth.generateProfile({
...baseProfile,
auth: {
type,
apiTokenId: 123
},
options: { permission }
});

return server.plugins.auth.generateToken(profile);
};

return server;
};

const serverInject = async (server, route, jwt) => {
const option = { ...route };

if (jwt) {
option.headers = { authorization: `Bearer ${jwt}` };
}

return server.inject(option);
};

module.exports = {
newAuthTestServer,
serverInject
};
170 changes: 132 additions & 38 deletions test/plugins/banner.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const testBannerPipeline = require('./data/banner-pipeline.json');
const testBanners = require('./data/banners.json');
const testBannersActive = require('./data/banners-active.json');
const updatedBanner = require('./data/updatedBanner.json');
const { newAuthTestServer, serverInject } = require('./auth.test.helper');

sinon.assert.expose(assert, { prefix: '' });

Expand All @@ -30,6 +31,137 @@ const getBannerMock = banner => {
return getMock(banner);
};

describe('authorization settings test for banner routes', () => {
let server;
let readJwt;
let executeJwt;
let writeJwt;
let allJwt;
let oauthJwt;
let invalidJwt;

beforeEach(async () => {
/* eslint-disable global-require */
const plugin = require('../../plugins/banners');
/* eslint-enable global-require */

server = await newAuthTestServer();

await server.register({ plugin });

readJwt = server.generateTestJwt({ permission: 'read' });
executeJwt = server.generateTestJwt({ permission: 'execute' });
writeJwt = server.generateTestJwt({ permission: 'write' });
allJwt = server.generateTestJwt({ permission: 'all' });
oauthJwt = server.generateTestJwt({ type: 'oauth' });
invalidJwt = server.generateTestJwt({ permission: 'invalid' });
});

afterEach(() => {
server = null;
});

it('GET /banners does not requires permission', async () => {
const route = { method: 'GET', url: '/banners' };

const noAuthResult = await serverInject(server, route);
const invalidJwtResult = await serverInject(server, route, invalidJwt);
const readJwtResult = await serverInject(server, route, readJwt);
const executeJwtResult = await serverInject(server, route, executeJwt);
const writeJwtResult = await serverInject(server, route, writeJwt);
const allJwtResult = await serverInject(server, route, allJwt);
const oAuthJwtResult = await serverInject(server, route, oauthJwt);

assert.equal(noAuthResult.statusCode, 200);
assert.equal(invalidJwtResult.statusCode, 200);
assert.equal(readJwtResult.statusCode, 200);
assert.equal(executeJwtResult.statusCode, 200);
assert.equal(writeJwtResult.statusCode, 200);
assert.equal(allJwtResult.statusCode, 200);
assert.equal(oAuthJwtResult.statusCode, 200);
});

it('GET /banners/{id} does not requires permission', async () => {
const route = { method: 'GET', url: '/banners/123' };

const noAuthResult = await serverInject(server, route);
const invalidJwtResult = await serverInject(server, route, invalidJwt);
const readJwtResult = await serverInject(server, route, readJwt);
const executeJwtResult = await serverInject(server, route, executeJwt);
const writeJwtResult = await serverInject(server, route, writeJwt);
const allJwtResult = await serverInject(server, route, allJwt);
const oAuthJwtResult = await serverInject(server, route, oauthJwt);

assert.equal(noAuthResult.statusCode, 200);
assert.equal(invalidJwtResult.statusCode, 200);
assert.equal(readJwtResult.statusCode, 200);
assert.equal(executeJwtResult.statusCode, 200);
assert.equal(writeJwtResult.statusCode, 200);
assert.equal(allJwtResult.statusCode, 200);
assert.equal(oAuthJwtResult.statusCode, 200);
});

it('POST /banners requires all permission', async () => {
const route = { method: 'POST', url: '/banners' };

const noAuthResult = await serverInject(server, route);
const invalidJwtResult = await serverInject(server, route, invalidJwt);
const readJwtResult = await serverInject(server, route, readJwt);
const executeJwtResult = await serverInject(server, route, executeJwt);
const writeJwtResult = await serverInject(server, route, writeJwt);
const allJwtResult = await serverInject(server, route, allJwt);
const oAuthJwtResult = await serverInject(server, route, oauthJwt);

assert.equal(noAuthResult.statusCode, 401);
assert.equal(invalidJwtResult.statusCode, 403);
assert.equal(readJwtResult.statusCode, 403);
assert.equal(executeJwtResult.statusCode, 403);
assert.equal(writeJwtResult.statusCode, 403);
assert.equal(allJwtResult.statusCode, 200);
assert.equal(oAuthJwtResult.statusCode, 200);
});

it('PUT /banners/{id} requires all permission', async () => {
const route = { method: 'PUT', url: '/banners/123' };

const noAuthResult = await serverInject(server, route);
const invalidJwtResult = await serverInject(server, route, invalidJwt);
const readJwtResult = await serverInject(server, route, readJwt);
const executeJwtResult = await serverInject(server, route, executeJwt);
const writeJwtResult = await serverInject(server, route, writeJwt);
const allJwtResult = await serverInject(server, route, allJwt);
const oAuthJwtResult = await serverInject(server, route, oauthJwt);

assert.equal(noAuthResult.statusCode, 401);
assert.equal(invalidJwtResult.statusCode, 403);
assert.equal(readJwtResult.statusCode, 403);
assert.equal(executeJwtResult.statusCode, 403);
assert.equal(writeJwtResult.statusCode, 403);
assert.equal(allJwtResult.statusCode, 200);
assert.equal(oAuthJwtResult.statusCode, 200);
});

it('DELETE /banners/{id} requires all permission', async () => {
const route = { method: 'DELETE', url: '/banners/123' };

const noAuthResult = await serverInject(server, route);
const invalidJwtResult = await serverInject(server, route, invalidJwt);
const readJwtResult = await serverInject(server, route, readJwt);
const executeJwtResult = await serverInject(server, route, executeJwt);
const writeJwtResult = await serverInject(server, route, writeJwt);
const allJwtResult = await serverInject(server, route, allJwt);
const oAuthJwtResult = await serverInject(server, route, oauthJwt);

assert.equal(noAuthResult.statusCode, 401);
assert.equal(invalidJwtResult.statusCode, 403);
assert.equal(readJwtResult.statusCode, 403);
assert.equal(executeJwtResult.statusCode, 403);
assert.equal(writeJwtResult.statusCode, 403);
assert.equal(allJwtResult.statusCode, 200);
assert.equal(oAuthJwtResult.statusCode, 200);
});
});

describe('banner plugin test', () => {
let bannerMock;
let bannerFactoryMock;
Expand Down Expand Up @@ -104,44 +236,6 @@ describe('banner plugin test', () => {
assert.isOk(server.registrations.banners);
});

describe('authorization settings for banner routes', () => {
const routesRequiringAuthorization = [
['post', '/banners'],
['put', '/banners/{id}'],
['delete', '/banners/{id}']
];
const publicRoutes = [
['get', '/banners'],
['get', '/banners/{id}']
];

routesRequiringAuthorization.forEach(([method, path]) => {
it(`requires all permission for ${method.toUpperCase()} ${path}`, () => {
const route = server.table().find(r => r.method === method && r.path === path);

assert.isOk(route, `${method.toUpperCase()} ${path} should be registered`);
assert.equal(
route.settings.plugins.authorization.permission,
'all',
`${method.toUpperCase()} ${path} should require all permission`
);
});
});

publicRoutes.forEach(([method, path]) => {
it(`does not require permission for ${method.toUpperCase()} ${path}`, () => {
const route = server.table().find(r => r.method === method && r.path === path);

assert.isOk(route, `${method.toUpperCase()} ${path} should be registered`);
assert.notProperty(
route.settings.plugins,
'authorization',
`${method.toUpperCase()} ${path} should remain publicly accessible`
);
});
});
});

describe('POST /banners', () => {
let options;
const username = 'jimgrund';
Expand Down
Loading