Start to build the ACL models
This commit is contained in:
parent
492aca7724
commit
67b934357b
|
@ -90,7 +90,7 @@ loopback.errorHandler.title = 'Loopback';
|
|||
*/
|
||||
|
||||
loopback.createDataSource = function (name, options) {
|
||||
var ds = new DataSource(name, options);
|
||||
var ds = new DataSource(name, options, loopback.Model.dataSource);
|
||||
ds.createModel = function (name, properties, settings) {
|
||||
var ModelCtor = loopback.createModel(name, properties, settings);
|
||||
ModelCtor.attachTo(ds);
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
/**
|
||||
Schema ACL options
|
||||
Schema ACL options
|
||||
|
||||
Object level permissions, for example, an album owned by a user
|
||||
Object level permissions, for example, an album owned by a user
|
||||
|
||||
Factors to be authorized against:
|
||||
Factors to be authorized against:
|
||||
|
||||
* model name: Album
|
||||
* model instance properties: userId of the album, friends, shared
|
||||
* methods
|
||||
* app and/or user ids/roles
|
||||
* model name: Album
|
||||
* model instance properties: userId of the album, friends, shared
|
||||
* methods
|
||||
* app and/or user ids/roles
|
||||
** loggedIn
|
||||
** roles
|
||||
** userId
|
||||
|
@ -17,69 +17,127 @@ Factors to be authorized against:
|
|||
** everyone
|
||||
** relations: owner/friend/granted
|
||||
|
||||
Class level permissions, for example, Album
|
||||
Class level permissions, for example, Album
|
||||
* model name: Album
|
||||
* methods
|
||||
|
||||
URL/Route level permissions
|
||||
URL/Route level permissions
|
||||
* url pattern
|
||||
* application id
|
||||
* ip addresses
|
||||
* http headers
|
||||
|
||||
Map to oAuth 2.0 scopes
|
||||
Map to oAuth 2.0 scopes
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
var loopback = require('loopback');
|
||||
var loopback = require('../loopback');
|
||||
|
||||
var ACLEntrySchema = {
|
||||
/**
|
||||
* Type of the principal - Application/User/Role
|
||||
*/
|
||||
principalType: String,
|
||||
/**
|
||||
* Id of the principal - such as appId, userId or roleId
|
||||
*/
|
||||
principalId: String,
|
||||
|
||||
/**
|
||||
* Name of the access type - READ/WRITE/EXEC
|
||||
*/
|
||||
accessType: String,
|
||||
|
||||
/**
|
||||
* ALARM - Generate an alarm, in a system dependent way, the access specified in the permissions component of the ACL entry.
|
||||
* ALLOW - Explicitly grants access to the resource.
|
||||
* AUDIT - Log, in a system dependent way, the access specified in the permissions component of the ACL entry.
|
||||
* DENY - Explicitly denies access to the resource.
|
||||
*/
|
||||
permission: String
|
||||
var ScopeSchema = {
|
||||
name: {type: String, required: true},
|
||||
description: String
|
||||
};
|
||||
|
||||
var AccessSchema = {
|
||||
publicReadAccess: Boolean,
|
||||
publicWriteAccess: Boolean,
|
||||
publicExecAccess: Boolean,
|
||||
permissions: [ACLEntrySchema]
|
||||
var ScopeResourceAccessSchema = {
|
||||
model: String, // The name of the model
|
||||
property: String, // The name of the property, method, scope, or relation
|
||||
|
||||
/**
|
||||
* Name of the access type - READ/WRITE/EXEC
|
||||
*/
|
||||
accessType: String,
|
||||
|
||||
/**
|
||||
* ALARM - Generate an alarm, in a system dependent way, the access specified in the permissions component of the ACL entry.
|
||||
* ALLOW - Explicitly grants access to the resource.
|
||||
* AUDIT - Log, in a system dependent way, the access specified in the permissions component of the ACL entry.
|
||||
* DENY - Explicitly denies access to the resource.
|
||||
*/
|
||||
permission: String,
|
||||
scopeId: Number
|
||||
};
|
||||
|
||||
var ScopeResourceAccess = loopback.createModel('ScopeResourceAccess', ScopeResourceAccessSchema, {
|
||||
relations: {
|
||||
scope: {
|
||||
type: 'belongsTo',
|
||||
model: 'Scope',
|
||||
foreignKey: 'scopeId'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Scope has many resource access entries
|
||||
* @type {createModel|*}
|
||||
*/
|
||||
var Scope = loopback.createModel('Scope', ScopeSchema, {
|
||||
relations: {
|
||||
resources: {
|
||||
type: 'hasMany',
|
||||
model: 'ScopeResourceAccess',
|
||||
foreignKey: 'scopeId'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var ACLSchema = {
|
||||
/**
|
||||
* Resource
|
||||
*/
|
||||
model: String, // The name of the model
|
||||
property: String, // The name of the property
|
||||
method: String, // The name of the method
|
||||
model: String, // The name of the model
|
||||
property: String, // The name of the property, method, scope, or relation
|
||||
|
||||
access: AccessSchema, // The access
|
||||
/**
|
||||
* Name of the access type - READ/WRITE/EXEC
|
||||
*/
|
||||
accessType: String,
|
||||
|
||||
status: String,
|
||||
created: Date,
|
||||
modified: Date
|
||||
/**
|
||||
* ALARM - Generate an alarm, in a system dependent way, the access specified in the permissions component of the ACL entry.
|
||||
* ALLOW - Explicitly grants access to the resource.
|
||||
* AUDIT - Log, in a system dependent way, the access specified in the permissions component of the ACL entry.
|
||||
* DENY - Explicitly denies access to the resource.
|
||||
*/
|
||||
permission: String,
|
||||
/**
|
||||
* Type of the principal - Application/User/Role
|
||||
*/
|
||||
principalType: String,
|
||||
/**
|
||||
* Id of the principal - such as appId, userId or roleId
|
||||
*/
|
||||
principalId: String
|
||||
};
|
||||
|
||||
|
||||
var ACL = loopback.createModel('ACL', ACLSchema);
|
||||
|
||||
module.exports = ACL;
|
||||
module.exports = {
|
||||
ACL: ACL,
|
||||
Scope: Scope,
|
||||
ScopeResourceAccess: ScopeResourceAccess
|
||||
};
|
||||
|
||||
Scope.isAllowed = function (scope, model, property, accessType, callback) {
|
||||
Scope.findOne({where: {name: scope}}, function (err, scope) {
|
||||
if (err) {
|
||||
callback && callback(err);
|
||||
} else {
|
||||
scope.resources({where: {model: model, property: {inq: [property, '*']}, accessType: {inq: [accessType, '*']}}}, function (err, resources)
|
||||
{
|
||||
if (err) {
|
||||
callback && callback(err);
|
||||
} else {
|
||||
console.log('Resources: ', resources);
|
||||
for (var r = 0; r < resources.length; r++) {
|
||||
if (resources[r].permission === 'Allow') {
|
||||
callback && callback(null, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback && callback(null, false);
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
;
|
||||
}
|
||||
});
|
||||
};
|
|
@ -1,23 +1,43 @@
|
|||
var loopback = require('loopback');
|
||||
var loopback = require('../loopback');
|
||||
|
||||
// Role model
|
||||
var RoleSchema = {
|
||||
id: {type: String, id: true}, // Id
|
||||
name: {type: String, required: true}, // The name of a role
|
||||
description: String, // Description
|
||||
roles: [String], // A role can be an aggregate of other roles
|
||||
users: [String], // A role contains a list of user ids
|
||||
id: {type: String, id: true}, // Id
|
||||
name: {type: String, required: true}, // The name of a role
|
||||
description: String, // Description
|
||||
// roles: [String], // A role can be an aggregate of other roles
|
||||
// users: [String], // A role contains a list of user ids
|
||||
|
||||
// Timestamps
|
||||
created: {type: Date, default: Date},
|
||||
modified: {type: Date, default: Date}
|
||||
parent: String,
|
||||
// Timestamps
|
||||
created: {type: Date, default: Date},
|
||||
modified: {type: Date, default: Date}
|
||||
};
|
||||
|
||||
var Role = loopback.createModel('Role', RoleSchema);
|
||||
var Role = loopback.createModel('Role', RoleSchema, {
|
||||
relations: {
|
||||
roles: {
|
||||
type: 'hasMany',
|
||||
model: 'Role',
|
||||
foreignKey: 'parent'
|
||||
},
|
||||
users: {
|
||||
type: 'hasAndBelongsToMany',
|
||||
model: 'user',
|
||||
foreignKey: 'userId'
|
||||
},
|
||||
applications: {
|
||||
type: 'hasAndBelongsToMany',
|
||||
model: 'Application',
|
||||
foreignKey: 'appId'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Role;
|
||||
|
||||
Role.OWNER ='$owner'; // owner of the object
|
||||
// Special roles
|
||||
Role.OWNER = '$owner'; // owner of the object
|
||||
Role.RELATED = "$related"; // any User with a relationship to the object
|
||||
Role.AUTHENTICATED = "$authenticated"; // authenticated user
|
||||
Role.EVERYONE = "$everyone"; // everyone
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
var assert = require('assert');
|
||||
var loopback = require('../index');
|
||||
var acl = require('../lib/models/acl');
|
||||
var User = loopback.User;
|
||||
|
||||
describe('security scopes', function () {
|
||||
|
||||
it("should allow access to models", function () {
|
||||
var ds = loopback.createDataSource({connector: loopback.Memory});
|
||||
acl.Scope.attachTo(ds);
|
||||
acl.ScopeResourceAccess.attachTo(ds);
|
||||
|
||||
// console.log(acl.Scope.relations);
|
||||
|
||||
acl.Scope.create({name: 'user', description: 'access user information'}, function (err, scope) {
|
||||
console.log(scope);
|
||||
scope.resources.create({model: 'user', property: '*', accessType: '*', permission: 'Allow'}, function (err, resource) {
|
||||
console.log(resource);
|
||||
acl.Scope.isAllowed('user', 'user', '*', '*', console.log);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
var assert = require('assert');
|
||||
var loopback = require('../index');
|
||||
var Role = require('../lib/models/role');
|
||||
var User = loopback.User;
|
||||
|
||||
describe('security models', function () {
|
||||
|
||||
describe('roles', function () {
|
||||
|
||||
it("Defines role/role relations", function () {
|
||||
var ds = loopback.createDataSource({connector: loopback.Memory});
|
||||
Role.attachTo(ds);
|
||||
|
||||
Role.create({name: 'user'}, function (err, role) {
|
||||
role.roles.create({name: 'admin'}, function (err, role2) {
|
||||
Role.find(console.log);
|
||||
role.roles(console.log);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("Defines role/user relations", function () {
|
||||
var ds = loopback.createDataSource({connector: loopback.Memory});
|
||||
User.attachTo(ds);
|
||||
Role.attachTo(ds);
|
||||
|
||||
Role.create({name: 'user'}, function (err, role) {
|
||||
role.users.create({name: 'Raymond'}, function (err, user) {
|
||||
console.log('User: ', user);
|
||||
Role.find(console.log);
|
||||
role.users(console.log);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue