diff --git a/lib/application.js b/lib/application.js index 3d448d67..062394d0 100644 --- a/lib/application.js +++ b/lib/application.js @@ -291,10 +291,37 @@ app.dataSources = app.datasources = {}; * Enable app wide authentication. */ -app.enableAuth = function() { +app.enableAuth = function(options) { + var AUTH_MODELS = ['User', 'AccessToken', 'ACL', 'Role', 'RoleMapping']; + var remotes = this.remotes(); var app = this; + if (options && options.dataSource) { + var appModels = app.registry.modelBuilder.models; + AUTH_MODELS.forEach(function(m) { + var Model = app.registry.findModel(m); + if (!Model) { + throw new Error( + 'Authentication requires model ' + m + ' to be defined.'); + } + + if (m.dataSource || m.app) return; + + for (var name in appModels) { + var candidate = appModels[name]; + var isSubclass = candidate.prototype instanceof Model; + var isAttached = !!candidate.dataSource || !!candidate.app; + if (isSubclass && isAttached) return; + } + + app.model(Model, { + dataSource: options.dataSource, + public: m === 'User' + }); + }); + } + remotes.authorization = function(ctx, next) { var method = ctx.method; var req = ctx.req; diff --git a/lib/loopback.js b/lib/loopback.js index e1b162dc..70529fff 100644 --- a/lib/loopback.js +++ b/lib/loopback.js @@ -99,6 +99,9 @@ function createApplication(options) { if (loopback.localRegistry || options && options.localRegistry === true) { // setup the app registry var registry = app.registry = new Registry(); + if (options && options.loadBuiltinModels === true) { + require('./builtin-models')(registry); + } } else { app.registry = loopback.registry; } diff --git a/test/app.test.js b/test/app.test.js index 78870372..47988ff6 100644 --- a/test/app.test.js +++ b/test/app.test.js @@ -796,6 +796,34 @@ describe('app', function() { app.enableAuth(); expect(app.isAuthEnabled).to.equal(true); }); + + it('auto-configures required models to provided dataSource', function() { + var AUTH_MODELS = ['User', 'ACL', 'AccessToken', 'Role', 'RoleMapping']; + var app = loopback({ localRegistry: true, loadBuiltinModels: true }); + require('../lib/builtin-models')(app.registry); + var db = app.dataSource('db', { connector: 'memory' }); + + app.enableAuth({ dataSource: 'db' }); + + expect(Object.keys(app.models)).to.include.members(AUTH_MODELS); + + AUTH_MODELS.forEach(function(m) { + var Model = app.models[m]; + expect(Model.dataSource, m + '.dataSource').to.equal(db); + expect(Model.shared, m + '.shared').to.equal(m === 'User'); + }); + }); + + it('detects already configured subclass of a required model', function() { + var app = loopback({ localRegistry: true, loadBuiltinModels: true }); + var db = app.dataSource('db', { connector: 'memory' }); + var Customer = app.registry.createModel('Customer', {}, { base: 'User' }); + app.model(Customer, { dataSource: 'db' }); + + app.enableAuth({ dataSource: 'db' }); + + expect(Object.keys(app.models)).to.not.include('User'); + }); }); describe.onServer('app.get(\'/\', loopback.status())', function() { diff --git a/test/loopback.test.js b/test/loopback.test.js index 9b39709e..ce45aa14 100644 --- a/test/loopback.test.js +++ b/test/loopback.test.js @@ -115,6 +115,24 @@ describe('loopback', function() { }); }); + describe('loopback(options)', function() { + it('supports localRegistry:true', function() { + var app = loopback({ localRegistry: true }); + expect(app.registry).to.not.equal(loopback.registry); + }); + + it('does not load builtin models into the local registry', function() { + var app = loopback({ localRegistry: true }); + expect(app.registry.findModel('User')).to.equal(undefined); + }); + + it('supports loadBuiltinModels:true', function() { + var app = loopback({ localRegistry: true, loadBuiltinModels: true }); + expect(app.registry.findModel('User')) + .to.have.property('modelName', 'User'); + }); + }); + describe('loopback.createDataSource(options)', function() { it('Create a data source with a connector.', function() { var dataSource = loopback.createDataSource({