rest-access
Advanced tools
Comparing version 1.0.0 to 1.1.0
@@ -9,2 +9,3 @@ require('should') | ||
const tokenApiWrite = jwt.sign({ scope: ['api:write'] }, 'shared_secret') | ||
const tokenApiRookie = jwt.sign({ scope: ['api:rookie'] }, 'shared_secret') | ||
const tokenByer = jwt.sign({ scope: ['byer'] }, 'shared_secret') | ||
@@ -103,1 +104,11 @@ const baseUrl = 'http://localhost:8080' | ||
}) | ||
test('should not have access with rookie token to /api/info/bye', t => { | ||
superagent | ||
.get(`${baseUrl}/api/info/bye`) | ||
.set('Authorization', `Bearer ${tokenApiRookie}`) | ||
.catch(e => { | ||
t.true(e.status.should.be.exactly(403)) | ||
t.end() | ||
}) | ||
}) |
@@ -7,2 +7,3 @@ const express = require('express') | ||
access([ | ||
['*', '/api/*', 'api:rookie', true], | ||
[['POST', 'PUT', 'DELETE'], '/api/*', 'api:write'], | ||
@@ -30,3 +31,6 @@ [['GET'], '/api/hello', 'api:read'], | ||
app.get('/api/hello', (req, res) => res.send(hello)) | ||
app.post('/api/hello', (req, res) => { hello = req.body; res.send(201) }) | ||
app.post('/api/hello', (req, res) => { | ||
hello = req.body | ||
res.send(201) | ||
}) | ||
app.get('/api/hi', sayHi) | ||
@@ -33,0 +37,0 @@ app.get('/api/bye', sayBye) |
19
index.js
@@ -50,14 +50,11 @@ const wildcard = require('wildcard') | ||
// where (4.argument) optional | ||
if (rule.length > 3) { | ||
return next(new TypeError('access rule `where` argument 4, is not yet implemented')) | ||
} | ||
// permission (3.argument) | ||
// so method and path matched, now the permission has to match to, otherwise access is denied -> new NotPermittedError('access not permitted') | ||
return next(hasPermission(userPermission, rule[2])) | ||
let matches = hasPermission(userPermission, rule[2], rule[3]) | ||
if (rule[3] && !matches) continue | ||
return next(matches) | ||
} | ||
// no matching access definition | ||
return next(new NotPermittedError('access not permitted')) | ||
return next(new NotPermittedError('no matching access rule found')) | ||
} | ||
@@ -72,7 +69,7 @@ } | ||
// general permission query function | ||
function hasPermission (userPermission, routePermission) { | ||
function hasPermission (userPermission, routePermission, block) { | ||
// permission (3.argument) | ||
// so method and path matched, now the permission has to match to, otherwise access is denied -> new NotPermittedError('access not permitted') | ||
if (routePermission === '*') return undefined // with next rule | ||
if (!userPermission) return new NotPermittedError('access not permitted') | ||
if (!userPermission) return new NotPermittedError('not authenticated') | ||
if (typeof userPermission === 'string') userPermission = userPermission.split(termSplitPattern) | ||
@@ -83,3 +80,3 @@ if (typeof routePermission === 'string') routePermission = routePermission.split(termSplitPattern) | ||
} | ||
const allow = routePermission.some(p => { | ||
const matches = routePermission.some(p => { | ||
if (p === '*') return true | ||
@@ -89,3 +86,3 @@ if (wildcard(p, userPermission, permissionSchemeSplitPattern).length) return true | ||
}) | ||
if (!allow) return new NotPermittedError('access not permitted') | ||
if ((!block && !matches) || (block && matches)) return new NotPermittedError('access not permitted') | ||
return undefined | ||
@@ -92,0 +89,0 @@ } |
{ | ||
"name": "rest-access", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "role/scope based REST access control", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -18,5 +18,6 @@ # rest-access | ||
access([ | ||
['*', '/api/*', 'api:rookie', true], | ||
[['POST', 'PUT', 'DELETE'], '/api/*', 'api:write,admin:*'], | ||
[['POST', 'PUT', 'DELETE'], '/api/secret/*', 'normal-admin'], | ||
[['GET'], '/api/*', 'api:read'], | ||
['GET', '/api/*', 'api:read'], | ||
[['GET', 'POST'], '/*', '*'] | ||
@@ -46,5 +47,5 @@ ]) | ||
#### access(roles) | ||
#### access(rules) | ||
This function lets you define the access ruleas all at once: | ||
This function lets you define the access rules all at once: | ||
@@ -59,2 +60,3 @@ ```js | ||
['*', '/account/delete', 'manage'], | ||
['*', '/*', 'view', true], | ||
['*', '/upload/*', 'edit'], | ||
@@ -71,10 +73,16 @@ ['GET', '/translate/*', 'edit,manage'], | ||
#### access(methods, path, role) | ||
#### access(methods, path, role[, block]) | ||
Use This method if you want to define a single access rules a specific place. examples: | ||
Use This method if you want to define access rules in different places. examples: | ||
```js | ||
access(['GET', 'POST'], '/*/glint/role/* ', 'admin:*') | ||
access('POST', '/*/glint/*', 'edit:glint') | ||
``` | ||
The fourth argument is optional. If the fourth argument is "truthy" (boolean:true or string), it means that this role is blocked (instead of allowed) for the given methods and path. | ||
Therefore in the following example, the Role `read:glint` is blocked to `POST` the given path. | ||
```js | ||
access(['GET', 'POST'], '/ */glint / role/* ', 'admin:*') | ||
access('POST', '/ */glint/* /*', 'edit:glint') | ||
access('POST', '/*/glint/*', 'read:glint', true) | ||
``` | ||
@@ -81,0 +89,0 @@ |
12776
244
122