README
flex-acl
Authorize http requests with a json based authorization control list.
Features:
- Simple to implement
- JSON based acl rules
- Any property/ies in the http request at any depth can be used for authorization
- Wide flexibility in establishing user groups and/or roles for authorizations
- Variables can be used for repeated acl rule patterns
flex-acl does not authenticate users. Users should be authenticated before authorizing requests.
Simple Example
var getAclRules = function(callback) {
var rules = [
{'id': 'ClientGet',
'method': 'GET',
'baseUrl': '/api',
'path':'/clients/[A-Fa-f0-9]{24}'}, //reg exp for the client id
{'id': 'ClientCrt',
'method': 'POST',
'baseUrl': '/api',
'path':'/clients'},
{'id': 'ClientUpd',
'method': 'PUT',
'baseUrl': '/api',
'path':'/clients'},
{'id': 'ClientLstOpen',
'method': 'GET',
'baseUrl': '/api',
'path':'/clients',
'query':{'status': 'open'}},
{'id': 'UsersCrt',
'method': 'POST',
'baseUrl': '/api',
'path':'/users'},
];
return callback(null, rules);
};
var getAuthzdAclIds = function(req, callback) {
// returns the access ids for the user making the http request
var authzdAclIds = {
admin: ['.*'], // Access to all rules
paul: ['Client.*'], // Access to all "Client" rules
jane: ['ClientGet'], // Access to just viewing a client
dot: ['ClientCrt','ClientGet','ClientPut'], // Access to create,get,update clients
};
if(req && req.user && req.user.id && authzdAclIds.hasOwnProperty(req.user.id)) {
return callback(null, authzdAclIds[req.user.id]);
} else {
return callback('Error: User access id does not exist');
}
};
var isAuthorized = flexAcl.makeIsAuthorized(
getAclRules, // function with callback to get acl rules
getAuthzdAclIds, // function with callback to get authorized acl ids (usually for a user)
['method','baseUrl','path','query.status']); // which properties to test
req = { // just including relevant request properties for this example
method: 'GET',
baseUrl: '/api',
path:'/clients/573de77bcaa00c068a92b1b4',
user: {id:'jane'}};
isAuthorized(req, function (err, passes) {
//err => null
//passes => true
});
req = {
method: 'GET',
baseUrl: '/api',
path:'/clients',
query: {status:'open'},
user: {id:'paul'}};
isAuthorized(req, function (err, passes) {
//err => null
//passes => true
});
req = {method: 'POST', baseUrl: '/api', path:'/users', user: {id:'admin'}};
isAuthorized(req, function (err, passes) {
//err => null
//passes => true
});
req = {method: 'POST', baseUrl: '/api', path:'/clients', user: {id:'jane'}};
isAuthorized(req, function (err, passes) {
/* err: { [Error: Not authorized: at least one acl rule does not have authorization]
authznIds: [ 'ClientGet' ],
aclRulesMatchingReq:
[ { id: 'ClientCrt',
method: 'POST',
baseUrl: '/api',
path: '/clients' } ] }
/*
//passes => undefined
});
Abbreviated example of implementing on Express (see example folder for less abreviated example):
var myapi = require('./app/modules/my-api');
app.use('/api', function (req, res, next) {
auth.isAuthorized(req, function(err) {
if(err) {
handleErrorAndRespond(err,req, res, 401);
} else {
next();
}
});
});
app.use(myapi); // won't get to /api routes here if doesn't pass isAuthorized above
//---- my api:
app.get('/api/my', function (req, res) {
something.getMy(req.query, function(err, my){
if (err) {
error.handleErrorAndRespond(err,req, res);
} else {
res.json(my);
}
});
})
Install with npm install flex-acl
.
Tested on Node versions 0.10, 0.12, 4, 5, 6.
Documentation
Rules for authorizing a request
API
makeIsAuthorized
returns isAuthorized
Helper Functions
Other Examples
Performance
Rules for authorizing a request
The http request is authorized based on these two rules :
- The http request has at least one matching acl rule. See matching rule examples below.
By default, (see options), a rule is matched if every property being tested conforms to the following : * Rule is matched if property exists in both the acl rule and the request and the property value matches * Rule is not matched if the property does not exist in the request but exists in the acl rule * Rule is not excluded if the property exists in the request and does not exist in the acl rule * Rule is not excluded if the property does not exist in both the request and acl rule
And these are the basic defaults (see options) for properties and how they're tested. Which properties are tested and how each property is tested, as well as global defaults, can be modified with options.
* method
, baseUrl
and path
are the default properties to be tested.
* All properties included match by regular expression from the acl rule to the request property except method
which is a string comparison. ACL rules that are strings are converted to regular expression objects.
* All regular expression tests are case insensitive by default except query
properties which are case sensitive by default.
- Every acl rule matched from # 1 has at least one matching authorized acl id. These are the acl ids returned from the getAuthzdAclIds function passed into makeIsAuthorized. See examples below.
A regular expression test determines if an acl id retrieved from getAuthzdAclIds matches an acl id from a matched acl rule. If an acl id retrieved from getAuthzdAclIds is a string, then it is converted to a regular expression with '^' and '