Skip to content

Commit

Permalink
Merge pull request #113 from hapijs/logunauthorized_to_6.x.x
Browse files Browse the repository at this point in the history
Logunauthorized to 6.x.x - addresses #56
  • Loading branch information
geek committed Apr 23, 2018
2 parents 20975d8 + 755e8ab commit 98e3b2d
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 4 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ The following options are available when registering the plugin
* 'cookieOptions' - storage options for the cookie containing the crumb, see the [server.state](http://hapijs.com/api#serverstatename-options) documentation of hapi for more information
* 'restful' - RESTful mode that validates crumb tokens from "X-CSRF-Token" request header for POST, PUT, PATCH and DELETE server routes. Disables payload/query crumb validation (defaults to false)
* 'skip' - a function with the signature of `function (request, reply) {}`, which when provided, is called for every request. If the provided function returns true, validation and generation of crumb is skipped (defaults to false)
* 'logUnauthorized' - whether to add to the request log with tag 'crumb' and data 'validation failed' (defaults to false)

Additionally, some configuration can be passed on a per-route basis

Expand Down
18 changes: 15 additions & 3 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ internals.schema = Joi.object().keys({
addToViewContext: Joi.boolean().optional(),
cookieOptions: Joi.object().keys(null),
restful: Joi.boolean().optional(),
skip: Joi.func().optional()
skip: Joi.func().optional(),
logUnauthorized: Joi.boolean().optional()
});


Expand All @@ -34,7 +35,8 @@ internals.defaults = {
path: '/'
},
restful: false, // Set to true for X-CSRF-Token header crumb validation. Disables payload/query validation
skip: false // Set to a function which returns true when to skip crumb generation and validation
skip: false, // Set to a function which returns true when to skip crumb generation and validation
logUnauthorized: false // Set to true for crumb to write an event to the request log
};


Expand All @@ -57,6 +59,13 @@ exports.register = function (server, options, next) {

server.ext('onPostAuth', (request, reply) => {

const unauthorizedLogger = () => {

if (settings.logUnauthorized) {
request.log(['crumb', 'unauthorized'], 'validation failed');
}
};

// If skip function enabled. Call it and if returns true, do not attempt to do anything with crumb.

if (settings.skip && settings.skip(request, reply)) {
Expand Down Expand Up @@ -101,11 +110,12 @@ exports.register = function (server, options, next) {

const content = request[request.route.settings.plugins._crumb.source];
if (!content || content instanceof Stream) {

unauthorizedLogger();
return reply(Boom.forbidden());
}

if (content[request.route.settings.plugins._crumb.key] !== request.plugins.crumb) {
unauthorizedLogger();
return reply(Boom.forbidden());
}

Expand All @@ -123,10 +133,12 @@ exports.register = function (server, options, next) {
const header = request.headers['x-csrf-token'];

if (!header) {
unauthorizedLogger();
return reply(Boom.forbidden());
}

if (header !== request.plugins.crumb) {
unauthorizedLogger();
return reply(Boom.forbidden());
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"devDependencies": {
"code": "2.x.x",
"handlebars": "^4.0.5",
"hapi": "13.x.x",
"hapi": "16.x.x",
"lab": "10.x.x",
"vision": "^4.0.0"
},
Expand Down
109 changes: 109 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,115 @@ describe('Crumb', () => {
});
});

it('Adds to the request log if plugin option logUnauthorized is set to true', (done) => {

const server = new Hapi.Server();
server.connection();

let logFound;
const preResponse = function (request, reply) {

const logs = request.getLog();
logFound = logs.find((log) => {

return log.tags[0] === 'crumb' && log.data === 'validation failed';
});

return reply.continue();
};

server.ext('onPreResponse', preResponse);

server.route({
method: 'POST',
path: '/1',
config: {
log: true
},
handler: (request, reply) => {

return reply('test');
}
});

server.register([
{
register: Crumb,
options: {
logUnauthorized: true
}
}
], () => {

const headers = {};
headers['X-API-Token'] = 'test';

server.inject({
method: 'POST',
url: '/1',
headers
}, () => {

expect(logFound).to.exist();
done();
});
});
});

it('Does not add to the request log if plugin option logUnauthorized is set to false', (done) => {

const server = new Hapi.Server();
server.connection();

let logFound;
const preResponse = function (request, reply) {

const logs = request.getLog();
logFound = logs.find((log) => {

return log.tags[0] === 'crumb' && log.data === 'validation failed';
});

return reply.continue();
};

server.ext('onPreResponse', preResponse);

server.route({
method: 'POST',
path: '/1',
config: {
log: true
},
handler: (request, reply) => {

return reply('test');
}
});

server.register([
{
register: Crumb,
options: {
logUnauthorized: false
}
}
], () => {

const headers = {};
headers['X-API-Token'] = 'test';

server.inject({
method: 'POST',
url: '/1'
}, () => {

expect(logFound).to.not.exist();
done();
});
});
});

it('should fail to register with bad options', (done) => {

const server = new Hapi.Server();
Expand Down

0 comments on commit 98e3b2d

Please sign in to comment.