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() { app.enableAuth = function() {
var remotes = this.remotes(); var remotes = this.remotes();
var app = this;
remotes.before('**', function(ctx, next, method) { remotes.before('**', function(ctx, next, method) {
var req = ctx.req; var req = ctx.req;
@ -302,6 +303,12 @@ app.enableAuth = function() {
var modelInstance = ctx.instance; var modelInstance = ctx.instance;
var modelId = modelInstance && modelInstance.id || req.param('id'); 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) { if(Model.checkAccess) {
// Pause the request before checking access // Pause the request before checking access
// See https://github.com/strongloop/loopback-storage-service/issues/7 // See https://github.com/strongloop/loopback-storage-service/issues/7
@ -319,8 +326,15 @@ app.enableAuth = function() {
} else if(allowed) { } else if(allowed) {
next(); next();
} else { } 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); next(e);
} }
} }

View File

@ -81,13 +81,38 @@ describe('app.enableAuth()', function() {
beforeEach(createTestingToken); 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) createTestAppAndRequest(this.token, done)
.del('/tests/123') .del('/tests/123')
.expect(401) .expect(401)
.set('authorization', this.token.id) .set('authorization', this.token.id)
.end(done); .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) { function createTestingToken(done) {
@ -99,12 +124,19 @@ function createTestingToken(done) {
}); });
} }
function createTestAppAndRequest(testToken, done) { function createTestAppAndRequest(testToken, settings, done) {
var app = createTestApp(testToken, done); var app = createTestApp(testToken, settings, done);
return request(app); 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(); var app = loopback();
app.use(loopback.cookieParser('secret')); app.use(loopback.cookieParser('secret'));
@ -125,7 +157,11 @@ function createTestApp(testToken, done) {
app.use(loopback.rest()); app.use(loopback.rest());
app.enableAuth(); app.enableAuth();
var TestModel = loopback.Model.extend('test', {}, { Object.keys(appSettings).forEach(function(key){
app.set(key, appSettings[key]);
});
var modelOptions = {
acls: [ acls: [
{ {
principalType: "ROLE", principalType: "ROLE",
@ -135,8 +171,14 @@ function createTestApp(testToken, done) {
property: 'removeById' property: 'removeById'
} }
] ]
};
Object.keys(modelSettings).forEach(function(key){
modelOptions[key] = modelSettings[key];
}); });
var TestModel = loopback.Model.extend('test', {}, modelOptions);
TestModel.attachTo(loopback.memory()); TestModel.attachTo(loopback.memory());
app.model(TestModel); app.model(TestModel);