ACL voters inspired by Symfony voters
npm install node-security-voters --save
or
yarn add node-security-voters
Voters are very similar to middleware mechanism, but different in implementation. In essence, voter is a simple function that tells if some user is granted access to subject using permission(attribute). Voter might or might not be asynchronous.
First you need to add your voter
const security = require('node-security-voters');
security.addVoter(function (attr, subject, user) {
if (!user) {
return 0;
}
if (user.hasPermission(attr, subj)) {
return 1;
}
return -1;
});
Voters should return one of the access resolutions: GRANTED = 1, ABSTAIN = 0 or DENIED = -1. You might use constants from
this package from security.ACCESS
map.
If you need to make asynchronous action during making decision you can return Promise<number>
or get async callback
with var done = this.async();
and after action completed run done(null, resolution)
.
There is no restrictions on types of voter's arguments, thus you can pass any values you want. But keep in mind good practice to use domain objects that you can detect, validate and extract values you need.
To check access use isGranted
method:
const security = require('node-security-voters');
const blog = new MyBlogModel();
const user = new MyUserModel();
security.isGranted('EDIT', blog, user, security.STRATEGIES.AFFIRMATIVE)
.then(resolution => {
if (resolution !== security.ACCESS.GRANTED) {
throw new Error('ACCESS DENIED');
}
// secret stuff
});
// or
security.isGranted('EDIT', blog, user, security.STRATEGIES.AFFIRMATIVE, function (err, resolution) {
// same as above but in callback body
});
As you seen isGranted
method accepts optional parameter strategy. It means that during access calculation the module
will use one of the 3 options:
- AFFIRMATIVE - grant access as soon as there is one voter granting access
- CONSENSUS - grant access if there are more voters granting access than there are denying
- UNANIMOUS - only grant access if none of the voters has denied access
AFFIRMATIVE
is used by default.
node-security-voters goes with ready to use koa2 middleware. It helps to load voters from specific place and run to check
access for specific path. Also it populates context with ctx.isGranted
helper method.
const Koa = require('koa');
const app = new Koa();
const passport = require('koa-passport');
const voters = require('node-security-voters/koa-middleware');
app.use(passport.initialize());
app.use(passport.session());
// Add this middleware as far as your user model is ready,
// for example, after passport middleware initialized and create user instance
app.use(voters(path.join(__dirname, 'path/to/voters/glob/**/*.js')));
You can find example of voter for checking access of routes' path. Checkout folder voters
in this package.
const security = require('node-security-voters');
const accessMapVoter = require('node-security-voters/voters/access-map-voter');
security.addVoter(accessMapVoter({
"^/restricted_area$": security.ACCESS.DENIED,
"^/assets/.+\.(js|css|jpg|png)$": security.ACCESS.GRANTED,
"^/secured$": ["ROLE_ADMIN", "ROLE_EDITOR"],
"^/for_users_only$": "ROLE_USER",
"^/lazy_check_area": user => {
return security.ACCESS.GRANTED;
},
"^/$": security.ACCESS.GRANTED,
}));
- https://github.com/slawus/Voters.js
- https://github.com/wookieb/alpha-ac
- http://symfony.com/doc/current/security/voters.html
- http://docs.spring.io/spring-security/site/docs/3.0.x/reference/authz-arch.html
node-security-voters is released under the MIT license.