Allow customization of ACL http status

emulate existing error on 404
new tests for model and app settings
Signed-off-by: Karl Mikkelsen <karl@karlmikko.com>
This commit is contained in:
Karl Mikkelsen 2014-06-06 11:53:30 +10:00
parent d8c6f9d962
commit a90a5c7e58
2 changed files with 63 additions and 7 deletions

View File

@ -295,6 +295,7 @@ app.dataSources = app.datasources = {};
app.enableAuth = function() {
var remotes = this.remotes();
var app = this;
remotes.before('**', function(ctx, next, method) {
var req = ctx.req;
@ -302,6 +303,12 @@ app.enableAuth = function() {
var modelInstance = ctx.instance;
var modelId = modelInstance && modelInstance.id || req.param('id');
var modelSettings = Model.settings || {};
var errStatusCode = modelSettings.aclErrorStatus || app.get('aclErrorStatus') || 401;
if(!req.accessToken){
errStatusCode = 401;
}
if(Model.checkAccess) {
// Pause the request before checking access
// See https://github.com/strongloop/loopback-storage-service/issues/7
@ -319,8 +326,15 @@ app.enableAuth = function() {
} else if(allowed) {
next();
} else {
var e = new Error('Access Denied');
e.statusCode = 401;
var messages = {
403:'Access Denied',
404: ('could not find a model with id ' + modelId),
401:'Authorization Required'
};
var e = new Error(messages[errStatusCode] || messages[403]);
e.statusCode = errStatusCode;
next(e);
}
}

View File

@ -81,13 +81,38 @@ describe('app.enableAuth()', function() {
beforeEach(createTestingToken);
it('should prevent remote method calls if the accessToken doesnt have access', function (done) {
it('prevents remote call with 401 status on denied ACL', function (done) {
createTestAppAndRequest(this.token, done)
.del('/tests/123')
.expect(401)
.set('authorization', this.token.id)
.end(done);
});
it('prevent remote call with app setting status on denied ACL', function (done) {
createTestAppAndRequest(this.token, {app:{aclErrorStatus:403}}, done)
.del('/tests/123')
.expect(403)
.set('authorization', this.token.id)
.end(done);
});
it('prevent remote call with app setting status on denied ACL', function (done) {
createTestAppAndRequest(this.token, {model:{aclErrorStatus:404}}, done)
.del('/tests/123')
.expect(404)
.set('authorization', this.token.id)
.end(done);
});
it('prevent remote call if the accessToken is missing and required', function (done) {
createTestAppAndRequest(null, done)
.del('/tests/123')
.expect(401)
.set('authorization', null)
.end(done);
});
});
function createTestingToken(done) {
@ -99,12 +124,19 @@ function createTestingToken(done) {
});
}
function createTestAppAndRequest(testToken, done) {
var app = createTestApp(testToken, done);
function createTestAppAndRequest(testToken, settings, done) {
var app = createTestApp(testToken, settings, done);
return request(app);
}
function createTestApp(testToken, done) {
function createTestApp(testToken, settings, done) {
done = arguments[arguments.length-1];
if(settings == done) settings = {};
settings = settings || {};
var appSettings = settings.app || {};
var modelSettings = settings.model || {};
var app = loopback();
app.use(loopback.cookieParser('secret'));
@ -125,7 +157,11 @@ function createTestApp(testToken, done) {
app.use(loopback.rest());
app.enableAuth();
var TestModel = loopback.Model.extend('test', {}, {
Object.keys(appSettings).forEach(function(key){
app.set(key, appSettings[key]);
});
var modelOptions = {
acls: [
{
principalType: "ROLE",
@ -135,8 +171,14 @@ function createTestApp(testToken, done) {
property: 'removeById'
}
]
};
Object.keys(modelSettings).forEach(function(key){
modelOptions[key] = modelSettings[key];
});
var TestModel = loopback.Model.extend('test', {}, modelOptions);
TestModel.attachTo(loopback.memory());
app.model(TestModel);