From a90a5c7e58aecb49b47cb4e733a94ddba883b82a Mon Sep 17 00:00:00 2001 From: Karl Mikkelsen Date: Fri, 6 Jun 2014 11:53:30 +1000 Subject: [PATCH] Allow customization of ACL http status emulate existing error on 404 new tests for model and app settings Signed-off-by: Karl Mikkelsen --- lib/application.js | 18 ++++++++++++-- test/access-token.test.js | 52 +++++++++++++++++++++++++++++++++++---- 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/lib/application.js b/lib/application.js index 0c373fed..3b75e231 100644 --- a/lib/application.js +++ b/lib/application.js @@ -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); } } diff --git a/test/access-token.test.js b/test/access-token.test.js index 50cf4d9a..1f4e7344 100644 --- a/test/access-token.test.js +++ b/test/access-token.test.js @@ -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);