Skip to content

Commit

Permalink
validate apiKey headers
Browse files Browse the repository at this point in the history
  • Loading branch information
Carmine DiMascio committed Oct 11, 2019
1 parent 6907097 commit 4b19b5a
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export class OpenApiValidator {
);

const securityMiddleware = middlewares.security(
this.context,
this.options.securityHandlers,
);

Expand Down
46 changes: 42 additions & 4 deletions src/middlewares/openapi.security.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { SecurityHandlers } from '../index';
import { OpenAPIV3 } from '../framework/types';
import { validationError } from './util';
import { OpenApiContext } from '../framework/openapi.context';

export function security(securityHandlers: SecurityHandlers) {
export function security(
context: OpenApiContext,
securityHandlers: SecurityHandlers,
) {
return (req, res, next) => {
if (!req.openapi) {
// this path was not found in open api and
Expand All @@ -21,14 +25,48 @@ export function security(securityHandlers: SecurityHandlers) {
return next();
}

const securitySchemes =
context.apiDoc.components && context.apiDoc.components.securitySchemes;
if (!securitySchemes) {
// TODO throw error securitySchemes don't exist, but a security is referenced in this model
}

// TODO security could be boolean or promise bool, handle both
const promises = securitySchema.map(s => {
const securityKey = Object.keys(s)[0];
const f = securityHandlers[securityKey];
const scheme: any = securitySchemes[securityKey];
const handler = securityHandlers[securityKey];
if (!scheme) {
const message = `components.securitySchemes.${securityKey} does not exist`;
return Promise.reject(validationError(401, path, message));
}
if (!handler) {
const message = `a handler for ${securityKey} does not exist`;
return Promise.reject(validationError(401, path, message));
}
if (scheme.type === 'apiKey') {
// check defined header
if (scheme.in === 'header') {
if (!req.headers[scheme.name.toLowerCase()]) {
return Promise.reject(validationError(401, path, `'${scheme.name}' header required.`));
}
} else if (scheme.in === 'query') {
if (!req.headers[scheme.name]) {
return Promise.reject(validationError(401, path, `query parameter '${scheme.name}' required.`));
}
}
}
if (['http'].includes(scheme.type)) {
if (!req.headers['authorization']) {
return Promise.reject(validationError(401, path, `'authorization' header required.`));
}
}
// TODO handle other security types

// TODO get scopes
const scopes = [];
try {
return Promise.resolve(f(req, scopes, securitySchema));
return Promise.resolve(handler(req, scopes, securitySchema));
} catch (e) {
return Promise.reject(e);
}
Expand All @@ -41,7 +79,7 @@ export function security(securityHandlers: SecurityHandlers) {
else next();
})
.catch(e => {
const message = (e && e.message) || 'unauthorized'
const message = (e && e.message) || 'unauthorized';
const err = validationError(401, path, message);
next(err);
});
Expand Down
35 changes: 31 additions & 4 deletions test/security.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { config } from 'chai/lib/chai';

const packageJson = require('../package.json');

describe(packageJson.name, () => {
describe.only(packageJson.name, () => {
let app = null;
let basePath = null;
const eovConf = {
Expand Down Expand Up @@ -39,7 +39,7 @@ describe(packageJson.name, () => {
it('should return 401 if apikey handler throws exception', async () =>
request(app)
.get(`${basePath}/api_key`)
.send({})
.set('X-API-Key', 'test')
.expect(401)
.then(r => {
const body = r.body;
Expand All @@ -55,7 +55,7 @@ describe(packageJson.name, () => {
};
return request(app)
.get(`${basePath}/api_key`)
.send({})
.set('X-API-Key', 'test')
.expect(401)
.then(r => {
const body = r.body;
Expand All @@ -72,7 +72,7 @@ describe(packageJson.name, () => {
};
return request(app)
.get(`${basePath}/api_key`)
.send({})
.set('X-API-Key', 'test')
.expect(401)
.then(r => {
const body = r.body;
Expand All @@ -81,4 +81,31 @@ describe(packageJson.name, () => {
expect(body.errors[0].message).to.equals('unauthorized');
});
});

it('should return 401 if apikey header is missing', async () => {
eovConf.securityHandlers.ApiKeyAuth = <any>function(req, scopes, schema) {
console.log('apikey handler returns promise false');
return true;
};
return request(app)
.get(`${basePath}/api_key`)
.expect(401)
.then(r => {
const body = r.body;
expect(body.errors).to.be.an('array');
expect(body.errors).to.have.length(1);
expect(body.errors[0].message).to.include('X-API-Key');
});
});

it('should return 200 if apikey header exists and handler returns true', async () => {
eovConf.securityHandlers.ApiKeyAuth = <any>function(req, scopes, schema) {
return true;
};
return request(app)
.get(`${basePath}/api_key`)
.set('X-API-Key', 'test')
.send({})
.expect(200);
});
});

0 comments on commit 4b19b5a

Please sign in to comment.