hapi-field-auth
Advanced tools
Comparing version 1.0.0-beta.1 to 1.0.0-beta.2
{ | ||
"name": "hapi-field-auth", | ||
"version": "1.0.0-beta.1", | ||
"version": "1.0.0-beta.2", | ||
"description": "Hapi plug-in for field-level authorization", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -23,9 +23,9 @@ # hapi-field-auth | ||
This plugin provides field-level authorization (not authentication) | ||
for Hapi routes -- particularly useful for *PATCH* routes. | ||
The request payload can have fields with special constraints | ||
in respect to `scope` or `role` of the authenticated user. | ||
for Hapi routes -- particularly for *PATCH* routes. | ||
If the request payload has fields with special constraints | ||
in respect to the `scope` of the authenticated user, | ||
this plugin allows to restrict access on field-level. | ||
A prerequisite is authentication -- use any authentication plugin, e.g., `hapi-auth-basic`. | ||
It is expected that the authentication sets | ||
`request.route.auth.credentials.scope` and/or `request.route.auth.credentials.role` | ||
It is expected that the authentication sets `request.route.auth.credentials.scope` | ||
to the request object. | ||
@@ -32,0 +32,0 @@ |
@@ -29,14 +29,10 @@ const _ = require('lodash'); | ||
const authScope = split(credentials.scope); | ||
const authRole = split(credentials.role); | ||
const keys = Object.keys(payload); | ||
settings.forEach(({ fields, scope, role }) => { | ||
settings.forEach(({ fields, scope }) => { | ||
if (_.intersection(keys, fields).length) { | ||
const requiredScope = split(scope); | ||
// TODO: replace request parameters in scope, e.g., `{params.id}` | ||
if (requiredScope.length && _.intersection(requiredScope, authScope).length === 0) { | ||
throw Boom.forbidden(`fields [${fields}] missing authorization scope [${requiredScope}]`); | ||
} | ||
const requiredRole = split(role); | ||
if (requiredRole.length && _.intersection(requiredRole, authRole).length === 0) { | ||
throw Boom.forbidden(`fields [${fields}] missing authorization role [${requiredRole}]`); | ||
} | ||
} | ||
@@ -43,0 +39,0 @@ }); |
@@ -24,3 +24,2 @@ const Hapi = require('hapi'); | ||
scope: ['write', 'write.extended'], | ||
role: ['admin'], | ||
}, | ||
@@ -35,3 +34,2 @@ }; | ||
scope: ['write'], | ||
role: ['writer'], | ||
}, | ||
@@ -84,24 +82,6 @@ }; | ||
}; | ||
const route3 = { | ||
method: 'PATCH', | ||
path: '/test/role', | ||
options: { | ||
auth: { | ||
access: { | ||
scope: ['write', 'write.extended'], | ||
}, | ||
}, | ||
plugins: { | ||
'hapi-field-auth': [{ | ||
fields: ['protected'], | ||
role: ['admin'], | ||
}], | ||
}, | ||
}, | ||
handler: () => 'ok', | ||
}; | ||
await server.register([hapiAuthBasic, hapiFieldAuth]); | ||
server.auth.strategy('simple', 'basic', { validate }); | ||
server.auth.default('simple'); | ||
await server.route([route1, route2, route3]); | ||
await server.route([route1, route2]); | ||
await server.start(); | ||
@@ -211,32 +191,2 @@ return server; | ||
}); | ||
it('should protect fields if special scope / scope not sufficient / role', async () => { | ||
const res = await server.inject({ | ||
method: 'PATCH', | ||
url: '/test/role', | ||
headers: { | ||
authorization: 'Basic d3JpdGVyOnRlc3Q=', // writer:test | ||
}, | ||
payload: { | ||
bla: true, | ||
protected: true, | ||
}, | ||
}); | ||
expect(res.statusCode).to.be.equal(403); | ||
}); | ||
it('should protect fields if special scope / scope sufficient / role', async () => { | ||
const res = await server.inject({ | ||
method: 'PATCH', | ||
url: '/test/role', | ||
headers: { | ||
authorization: 'Basic YWRtaW46dGVzdA==', // admin:test | ||
}, | ||
payload: { | ||
bla: true, | ||
protected: true, | ||
}, | ||
}); | ||
expect(res.statusCode).to.be.equal(200); | ||
}); | ||
}); |
10663
215