Merge pull request #102 from strongloop/fix/user
Various Fixes and Behavioral Changes to the User Model
This commit is contained in:
commit
16b790a93a
|
@ -52,6 +52,11 @@ var properties = {
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
acls: [
|
acls: [
|
||||||
|
{
|
||||||
|
principalType: ACL.ROLE,
|
||||||
|
principalId: Role.EVERYONE,
|
||||||
|
permission: ACL.DENY,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
principalType: ACL.ROLE,
|
principalType: ACL.ROLE,
|
||||||
principalId: Role.EVERYONE,
|
principalId: Role.EVERYONE,
|
||||||
|
@ -63,6 +68,30 @@ var options = {
|
||||||
principalId: Role.OWNER,
|
principalId: Role.OWNER,
|
||||||
permission: ACL.ALLOW,
|
permission: ACL.ALLOW,
|
||||||
property: 'removeById'
|
property: 'removeById'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
principalType: ACL.ROLE,
|
||||||
|
principalId: Role.EVERYONE,
|
||||||
|
permission: ACL.ALLOW,
|
||||||
|
property: "login"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
principalType: ACL.ROLE,
|
||||||
|
principalId: Role.EVERYONE,
|
||||||
|
permission: ACL.ALLOW,
|
||||||
|
property: "logout"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
principalType: ACL.ROLE,
|
||||||
|
principalId: Role.OWNER,
|
||||||
|
permission: ACL.ALLOW,
|
||||||
|
property: "findById"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
principalType: ACL.ROLE,
|
||||||
|
principalId: Role.OWNER,
|
||||||
|
permission: ACL.ALLOW,
|
||||||
|
property: "updateAttributes"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
@ -327,7 +356,13 @@ User.setup = function () {
|
||||||
UserModel.logout,
|
UserModel.logout,
|
||||||
{
|
{
|
||||||
accepts: [
|
accepts: [
|
||||||
{arg: 'sid', type: 'string', required: true}
|
{arg: 'access_token', type: 'string', required: true, http: function(ctx) {
|
||||||
|
var req = ctx && ctx.req;
|
||||||
|
var accessToken = req && req.accessToken;
|
||||||
|
var tokenID = accessToken && accessToken.id;
|
||||||
|
|
||||||
|
return tokenID;
|
||||||
|
}}
|
||||||
],
|
],
|
||||||
http: {verb: 'all'}
|
http: {verb: 'all'}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,8 @@
|
||||||
"mocha": "~1.14.0",
|
"mocha": "~1.14.0",
|
||||||
"strong-task-emitter": "0.0.x",
|
"strong-task-emitter": "0.0.x",
|
||||||
"supertest": "~0.8.1",
|
"supertest": "~0.8.1",
|
||||||
"chai": "~1.8.1"
|
"chai": "~1.8.1",
|
||||||
|
"loopback-testing": "0.0.4"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
var loopback = require('loopback');
|
||||||
|
var lt = require('loopback-testing');
|
||||||
|
var path = require('path');
|
||||||
|
var ACCESS_CONTROL_APP = path.join(__dirname, 'fixtures', 'access-control');
|
||||||
|
var app = require(path.join(ACCESS_CONTROL_APP, 'app.js'));
|
||||||
|
var assert = require('assert');
|
||||||
|
var USER = {email: 'test@test.test', password: 'test'};
|
||||||
|
var CURRENT_USER = {email: 'current@test.test', password: 'test'};
|
||||||
|
|
||||||
|
describe('access control - integration', function () {
|
||||||
|
|
||||||
|
lt.beforeEach.withApp(app);
|
||||||
|
|
||||||
|
describe('accessToken', function() {
|
||||||
|
it('should be a sublcass of AccessToken', function () {
|
||||||
|
assert(app.models.accessToken.prototype instanceof loopback.AccessToken);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a validate method', function () {
|
||||||
|
var token = new app.models.accessToken;
|
||||||
|
assert.equal(typeof token.validate, 'function');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('/accessToken', function() {
|
||||||
|
|
||||||
|
lt.beforeEach.givenModel('accessToken', {}, 'randomToken');
|
||||||
|
|
||||||
|
lt.it.shouldBeAllowedWhenCalledAnonymously('POST', '/api/accessTokens');
|
||||||
|
lt.it.shouldBeAllowedWhenCalledUnauthenticated('POST', '/api/accessTokens');
|
||||||
|
lt.it.shouldBeAllowedWhenCalledByUser(USER, 'POST', '/api/accessTokens');
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('GET', '/api/accessTokens');
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('GET', '/api/accessTokens');
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(USER, 'GET', '/api/accessTokens');
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('PUT', '/api/accessTokens');
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('PUT', '/api/accessTokens');
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(USER, 'PUT', '/api/accessTokens');
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('GET', urlForToken);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('GET', urlForToken);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(USER, 'GET', urlForToken);
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('PUT', urlForToken);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('PUT', urlForToken);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(USER, 'PUT', urlForToken);
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('DELETE', urlForToken);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('DELETE', urlForToken);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(USER, 'DELETE', urlForToken);
|
||||||
|
|
||||||
|
function urlForToken() {
|
||||||
|
return '/api/accessTokens/' + this.randomToken.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('/users', function () {
|
||||||
|
|
||||||
|
lt.beforeEach.givenModel('user', USER, 'randomUser');
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('GET', '/api/users');
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('GET', '/api/users');
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'GET', '/api/users');
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('GET', urlForUser);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('GET', urlForUser);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER,'GET', urlForUser);
|
||||||
|
|
||||||
|
lt.it.shouldBeAllowedWhenCalledAnonymously('POST', '/api/users');
|
||||||
|
lt.it.shouldBeAllowedWhenCalledByUser(CURRENT_USER, 'POST', '/api/users');
|
||||||
|
|
||||||
|
lt.it.shouldBeAllowedWhenCalledByUser(CURRENT_USER, 'POST', '/api/users/logout');
|
||||||
|
|
||||||
|
lt.describe.whenCalledRemotely('DELETE', '/api/users', function() {
|
||||||
|
lt.it.shouldNotBeFound();
|
||||||
|
});
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('PUT', urlForUser);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('PUT', urlForUser);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'PUT', urlForUser);
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('PUT', urlForUser);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('PUT', urlForUser);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'PUT', urlForUser);
|
||||||
|
|
||||||
|
lt.describe.whenLoggedInAsUser(CURRENT_USER, function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.url = '/api/users/' + this.user.id + '?ok';
|
||||||
|
});
|
||||||
|
lt.describe.whenCalledRemotely('DELETE', '/api/users/:id', function() {
|
||||||
|
lt.it.shouldBeAllowed();
|
||||||
|
});
|
||||||
|
lt.describe.whenCalledRemotely('GET', '/api/users/:id', function() {
|
||||||
|
lt.it.shouldBeAllowed();
|
||||||
|
});
|
||||||
|
lt.describe.whenCalledRemotely('PUT', '/api/users/:id', function() {
|
||||||
|
lt.it.shouldBeAllowed();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('DELETE', urlForUser);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('DELETE', urlForUser);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'DELETE', urlForUser);
|
||||||
|
|
||||||
|
function urlForUser() {
|
||||||
|
return '/api/users/' + this.randomUser.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('/banks', function () {
|
||||||
|
lt.beforeEach.givenModel('bank');
|
||||||
|
|
||||||
|
lt.it.shouldBeAllowedWhenCalledAnonymously('GET', '/api/banks');
|
||||||
|
lt.it.shouldBeAllowedWhenCalledUnauthenticated('GET', '/api/banks');
|
||||||
|
lt.it.shouldBeAllowedWhenCalledByUser(CURRENT_USER, 'GET', '/api/banks');
|
||||||
|
|
||||||
|
lt.it.shouldBeAllowedWhenCalledAnonymously('GET', urlForBank);
|
||||||
|
lt.it.shouldBeAllowedWhenCalledUnauthenticated('GET', urlForBank);
|
||||||
|
lt.it.shouldBeAllowedWhenCalledByUser(CURRENT_USER, 'GET', urlForBank);
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('POST', '/api/banks');
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('POST', '/api/banks');
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'POST', '/api/banks');
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('PUT', urlForBank);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('PUT', urlForBank);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'PUT', urlForBank);
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('DELETE', urlForBank);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('DELETE', urlForBank);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'DELETE', urlForBank);
|
||||||
|
|
||||||
|
function urlForBank() {
|
||||||
|
return '/api/banks/' + this.bank.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('/accounts', function () {
|
||||||
|
lt.beforeEach.givenModel('account');
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('GET', '/api/accounts');
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('GET', '/api/accounts');
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'GET', '/api/accounts');
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('GET', urlForAccount);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('GET', urlForAccount);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'GET', urlForAccount);
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('POST', '/api/accounts');
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('POST', '/api/accounts');
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'POST', '/api/accounts');
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('PUT', urlForAccount);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('PUT', urlForAccount);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'PUT', urlForAccount);
|
||||||
|
|
||||||
|
lt.describe.whenLoggedInAsUser(CURRENT_USER, function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.url = '/api/accounts/' + this.user.accountId;
|
||||||
|
});
|
||||||
|
lt.describe.whenCalledRemotely('PUT', '/api/accounts/:id', function() {
|
||||||
|
lt.it.shouldBeAllowed();
|
||||||
|
});
|
||||||
|
lt.describe.whenCalledRemotely('DELETE', '/api/accounts/:id', function() {
|
||||||
|
lt.it.shouldBeDenied();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
lt.it.shouldBeDeniedWhenCalledAnonymously('DELETE', urlForAccount);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledUnauthenticated('DELETE', urlForAccount);
|
||||||
|
lt.it.shouldBeDeniedWhenCalledByUser(CURRENT_USER, 'DELETE', urlForAccount);
|
||||||
|
|
||||||
|
function urlForAccount() {
|
||||||
|
return '/api/accounts/' + this.account.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -7,6 +7,7 @@ var role = require('../lib/models/role');
|
||||||
var Role = role.Role;
|
var Role = role.Role;
|
||||||
var RoleMapping = role.RoleMapping;
|
var RoleMapping = role.RoleMapping;
|
||||||
var User = loopback.User;
|
var User = loopback.User;
|
||||||
|
var testModel;
|
||||||
|
|
||||||
function checkResult(err, result) {
|
function checkResult(err, result) {
|
||||||
// console.log(err, result);
|
// console.log(err, result);
|
||||||
|
@ -15,6 +16,17 @@ function checkResult(err, result) {
|
||||||
|
|
||||||
describe('security scopes', function () {
|
describe('security scopes', function () {
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
var ds = this.ds = loopback.createDataSource({connector: loopback.Memory});
|
||||||
|
testModel = loopback.Model.extend('testModel');
|
||||||
|
ACL.attachTo(ds);
|
||||||
|
Role.attachTo(ds);
|
||||||
|
RoleMapping.attachTo(ds);
|
||||||
|
User.attachTo(ds);
|
||||||
|
Scope.attachTo(ds);
|
||||||
|
testModel.attachTo(ds);
|
||||||
|
});
|
||||||
|
|
||||||
it("should allow access to models for the given scope by wildcard", function () {
|
it("should allow access to models for the given scope by wildcard", function () {
|
||||||
Scope.create({name: 'userScope', description: 'access user information'}, function (err, scope) {
|
Scope.create({name: 'userScope', description: 'access user information'}, function (err, scope) {
|
||||||
ACL.create({principalType: ACL.SCOPE, principalId: scope.id, model: 'User', property: ACL.ALL,
|
ACL.create({principalType: ACL.SCOPE, principalId: scope.id, model: 'User', property: ACL.ALL,
|
||||||
|
@ -29,27 +41,24 @@ describe('security scopes', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should allow access to models for the given scope", function () {
|
it("should allow access to models for the given scope", function () {
|
||||||
var ds = loopback.createDataSource({connector: loopback.Memory});
|
Scope.create({name: 'testModelScope', description: 'access testModel information'}, function (err, scope) {
|
||||||
Scope.attachTo(ds);
|
|
||||||
ACL.attachTo(ds);
|
|
||||||
Scope.create({name: 'userScope', description: 'access user information'}, function (err, scope) {
|
|
||||||
ACL.create({principalType: ACL.SCOPE, principalId: scope.id,
|
ACL.create({principalType: ACL.SCOPE, principalId: scope.id,
|
||||||
model: 'User', property: 'name', accessType: ACL.READ, permission: ACL.ALLOW},
|
model: 'testModel', property: 'name', accessType: ACL.READ, permission: ACL.ALLOW},
|
||||||
function (err, resource) {
|
function (err, resource) {
|
||||||
ACL.create({principalType: ACL.SCOPE, principalId: scope.id,
|
ACL.create({principalType: ACL.SCOPE, principalId: scope.id,
|
||||||
model: 'User', property: 'name', accessType: ACL.WRITE, permission: ACL.DENY},
|
model: 'testModel', property: 'name', accessType: ACL.WRITE, permission: ACL.DENY},
|
||||||
function (err, resource) {
|
function (err, resource) {
|
||||||
// console.log(resource);
|
// console.log(resource);
|
||||||
Scope.checkPermission('userScope', 'User', ACL.ALL, ACL.ALL, function (err, perm) {
|
Scope.checkPermission('testModelScope', 'testModel', ACL.ALL, ACL.ALL, function (err, perm) {
|
||||||
assert(perm.permission === ACL.DENY); // because name.WRITE == DENY
|
assert(perm.permission === ACL.DENY); // because name.WRITE == DENY
|
||||||
});
|
});
|
||||||
Scope.checkPermission('userScope', 'User', 'name', ACL.ALL, function (err, perm) {
|
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.ALL, function (err, perm) {
|
||||||
assert(perm.permission === ACL.DENY); // because name.WRITE == DENY
|
assert(perm.permission === ACL.DENY); // because name.WRITE == DENY
|
||||||
});
|
});
|
||||||
Scope.checkPermission('userScope', 'User', 'name', ACL.READ, function (err, perm) {
|
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.READ, function (err, perm) {
|
||||||
assert(perm.permission === ACL.ALLOW);
|
assert(perm.permission === ACL.ALLOW);
|
||||||
});
|
});
|
||||||
Scope.checkPermission('userScope', 'User', 'name', ACL.WRITE, function (err, perm) {
|
Scope.checkPermission('testModelScope', 'testModel', 'name', ACL.WRITE, function (err, perm) {
|
||||||
assert(perm.permission === ACL.DENY);
|
assert(perm.permission === ACL.DENY);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -63,9 +72,6 @@ describe('security scopes', function () {
|
||||||
describe('security ACLs', function () {
|
describe('security ACLs', function () {
|
||||||
|
|
||||||
it("should allow access to models for the given principal by wildcard", function () {
|
it("should allow access to models for the given principal by wildcard", function () {
|
||||||
var ds = loopback.createDataSource({connector: loopback.Memory});
|
|
||||||
ACL.attachTo(ds);
|
|
||||||
|
|
||||||
ACL.create({principalType: ACL.USER, principalId: 'u001', model: 'User', property: ACL.ALL,
|
ACL.create({principalType: ACL.USER, principalId: 'u001', model: 'User', property: ACL.ALL,
|
||||||
accessType: ACL.ALL, permission: ACL.ALLOW}, function (err, acl) {
|
accessType: ACL.ALL, permission: ACL.ALLOW}, function (err, acl) {
|
||||||
|
|
||||||
|
@ -87,28 +93,25 @@ describe('security ACLs', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should allow access to models by exception", function () {
|
it("should allow access to models by exception", function () {
|
||||||
var ds = loopback.createDataSource({connector: loopback.Memory});
|
ACL.create({principalType: ACL.USER, principalId: 'u001', model: 'testModel', property: ACL.ALL,
|
||||||
ACL.attachTo(ds);
|
|
||||||
|
|
||||||
ACL.create({principalType: ACL.USER, principalId: 'u001', model: 'User', property: ACL.ALL,
|
|
||||||
accessType: ACL.ALL, permission: ACL.DENY}, function (err, acl) {
|
accessType: ACL.ALL, permission: ACL.DENY}, function (err, acl) {
|
||||||
|
|
||||||
ACL.create({principalType: ACL.USER, principalId: 'u001', model: 'User', property: ACL.ALL,
|
ACL.create({principalType: ACL.USER, principalId: 'u001', model: 'testModel', property: ACL.ALL,
|
||||||
accessType: ACL.READ, permission: ACL.ALLOW}, function (err, acl) {
|
accessType: ACL.READ, permission: ACL.ALLOW}, function (err, acl) {
|
||||||
|
|
||||||
ACL.checkPermission(ACL.USER, 'u001', 'User', 'name', ACL.READ, function (err, perm) {
|
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.READ, function (err, perm) {
|
||||||
assert(perm.permission === ACL.ALLOW);
|
assert(perm.permission === ACL.ALLOW);
|
||||||
});
|
});
|
||||||
|
|
||||||
ACL.checkPermission(ACL.USER, 'u001', 'User', ACL.ALL, ACL.READ, function (err, perm) {
|
ACL.checkPermission(ACL.USER, 'u001', 'testModel', ACL.ALL, ACL.READ, function (err, perm) {
|
||||||
assert(perm.permission === ACL.ALLOW);
|
assert(perm.permission === ACL.ALLOW);
|
||||||
});
|
});
|
||||||
|
|
||||||
ACL.checkPermission(ACL.USER, 'u001', 'User', 'name', ACL.WRITE, function (err, perm) {
|
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.WRITE, function (err, perm) {
|
||||||
assert(perm.permission === ACL.DENY);
|
assert(perm.permission === ACL.DENY);
|
||||||
});
|
});
|
||||||
|
|
||||||
ACL.checkPermission(ACL.USER, 'u001', 'User', 'name', ACL.ALL, function (err, perm) {
|
ACL.checkPermission(ACL.USER, 'u001', 'testModel', 'name', ACL.ALL, function (err, perm) {
|
||||||
assert(perm.permission === ACL.DENY);
|
assert(perm.permission === ACL.DENY);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -119,8 +122,7 @@ describe('security ACLs', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should honor defaultPermission from the model", function () {
|
it("should honor defaultPermission from the model", function () {
|
||||||
var ds = loopback.createDataSource({connector: loopback.Memory});
|
var ds = this.ds;
|
||||||
ACL.attachTo(ds);
|
|
||||||
var Customer = ds.createModel('Customer', {
|
var Customer = ds.createModel('Customer', {
|
||||||
name: {
|
name: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -152,7 +154,7 @@ describe('security ACLs', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should honor static ACLs from the model", function () {
|
it("should honor static ACLs from the model", function () {
|
||||||
var ds = loopback.createDataSource({connector: loopback.Memory});
|
var ds = this.ds;
|
||||||
var Customer = ds.createModel('Customer', {
|
var Customer = ds.createModel('Customer', {
|
||||||
name: {
|
name: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -188,14 +190,9 @@ describe('security ACLs', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should check access against LDL, ACL, and Role", function () {
|
it("should check access against LDL, ACL, and Role", function () {
|
||||||
var ds = loopback.createDataSource({connector: loopback.Memory});
|
|
||||||
ACL.attachTo(ds);
|
|
||||||
Role.attachTo(ds);
|
|
||||||
RoleMapping.attachTo(ds);
|
|
||||||
User.attachTo(ds);
|
|
||||||
|
|
||||||
// var log = console.log;
|
// var log = console.log;
|
||||||
var log = function() {};
|
var log = function() {};
|
||||||
|
var ds = this.ds;
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function (err, user) {
|
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function (err, user) {
|
||||||
|
@ -246,21 +243,7 @@ describe('security ACLs', function () {
|
||||||
}, function(err, access) {
|
}, function(err, access) {
|
||||||
assert(!err && access.permission === ACL.ALLOW);
|
assert(!err && access.permission === ACL.ALLOW);
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
|
||||||
ACL.checkAccess({
|
|
||||||
principals: [
|
|
||||||
{principalType: ACL.USER, principalId: userId}
|
|
||||||
],
|
|
||||||
model: 'Customer',
|
|
||||||
accessType: ACL.READ
|
|
||||||
}, function(err, access) {
|
|
||||||
assert(!err && access.permission === ACL.DENY);
|
|
||||||
});
|
});
|
||||||
*/
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
var loopback = require('loopback');
|
||||||
|
var path = require('path');
|
||||||
|
var app = module.exports = loopback();
|
||||||
|
|
||||||
|
app.boot(__dirname);
|
||||||
|
|
||||||
|
var apiPath = '/api';
|
||||||
|
app.use(loopback.cookieParser('secret'));
|
||||||
|
app.use(loopback.token({model: app.models.accessToken}));
|
||||||
|
app.use(apiPath, loopback.rest());
|
||||||
|
app.use(app.router);
|
||||||
|
app.use(loopback.urlNotFound());
|
||||||
|
app.use(loopback.errorHandler());
|
||||||
|
app.enableAuth();
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"port": 3000,
|
||||||
|
"host": "0.0.0.0"
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"db": {
|
||||||
|
"defaultForType": "db",
|
||||||
|
"connector": "memory"
|
||||||
|
},
|
||||||
|
"mail": {
|
||||||
|
"defaultForType": "mail",
|
||||||
|
"connector": "mail"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,163 @@
|
||||||
|
{
|
||||||
|
"email": {
|
||||||
|
"options": {
|
||||||
|
"base": "Email",
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"accessType": "*",
|
||||||
|
"permission": "DENY",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dataSource": "mail",
|
||||||
|
"public": false
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"options": {
|
||||||
|
"base": "User",
|
||||||
|
"relations": {
|
||||||
|
"accessTokens": {
|
||||||
|
"model": "accessToken",
|
||||||
|
"type": "hasMany",
|
||||||
|
"foreignKey": "userId"
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"model": "account",
|
||||||
|
"type": "belongsTo"
|
||||||
|
},
|
||||||
|
"transactions": {
|
||||||
|
"model": "transaction",
|
||||||
|
"type": "hasMany"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"accessType": "*",
|
||||||
|
"permission": "DENY",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dataSource": "db",
|
||||||
|
"public": true
|
||||||
|
},
|
||||||
|
"accessToken": {
|
||||||
|
"options": {
|
||||||
|
"base": "AccessToken",
|
||||||
|
"baseUrl": "access-tokens",
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"accessType": "*",
|
||||||
|
"permission": "DENY",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"permission": "ALLOW",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone",
|
||||||
|
"property": "create"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dataSource": "db",
|
||||||
|
"public": true
|
||||||
|
},
|
||||||
|
"bank": {
|
||||||
|
"options": {
|
||||||
|
"relations": {
|
||||||
|
"users": {
|
||||||
|
"model": "user",
|
||||||
|
"type": "hasMany"
|
||||||
|
},
|
||||||
|
"accounts": {
|
||||||
|
"model": "account",
|
||||||
|
"type": "hasMany"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"accessType": "*",
|
||||||
|
"permission": "DENY",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"accessType": "READ",
|
||||||
|
"permission": "ALLOW",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"properties": {},
|
||||||
|
"public": true,
|
||||||
|
"dataSource": "db"
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"options": {
|
||||||
|
"relations": {
|
||||||
|
"transactions": {
|
||||||
|
"model": "transaction",
|
||||||
|
"type": "hasMany"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"accessType": "*",
|
||||||
|
"permission": "DENY",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"accessType": "*",
|
||||||
|
"permission": "ALLOW",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$owner"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"permission": "DENY",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$owner",
|
||||||
|
"property": "removeById"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"properties": {},
|
||||||
|
"public": true,
|
||||||
|
"dataSource": "db"
|
||||||
|
},
|
||||||
|
"transaction": {
|
||||||
|
"options": {
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"accessType": "*",
|
||||||
|
"permission": "DENY",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"properties": {},
|
||||||
|
"public": true,
|
||||||
|
"dataSource": "db"
|
||||||
|
},
|
||||||
|
"alert": {
|
||||||
|
"options": {
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"accessType": "WRITE",
|
||||||
|
"permission": "DENY",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"properties": {},
|
||||||
|
"public": true,
|
||||||
|
"dataSource": "db"
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ describe('User', function(){
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(function (done) {
|
beforeEach(function (done) {
|
||||||
|
app.use(loopback.token());
|
||||||
app.use(loopback.rest());
|
app.use(loopback.rest());
|
||||||
app.model(User);
|
app.model(User);
|
||||||
|
|
||||||
|
@ -153,7 +154,6 @@ describe('User', function(){
|
||||||
|
|
||||||
it('Logout a user by providing the current accessToken id (over rest)', function(done) {
|
it('Logout a user by providing the current accessToken id (over rest)', function(done) {
|
||||||
login(logout);
|
login(logout);
|
||||||
|
|
||||||
function login(fn) {
|
function login(fn) {
|
||||||
request(app)
|
request(app)
|
||||||
.post('/users/login')
|
.post('/users/login')
|
||||||
|
@ -171,22 +171,22 @@ describe('User', function(){
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function logout(err, sid) {
|
function logout(err, token) {
|
||||||
request(app)
|
request(app)
|
||||||
.post('/users/logout')
|
.post('/users/logout')
|
||||||
|
.set('Authorization', token)
|
||||||
.expect(204)
|
.expect(204)
|
||||||
.send({sid: sid})
|
.end(verify(token, done));
|
||||||
.end(verify(sid, done));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function verify(sid, done) {
|
function verify(token, done) {
|
||||||
assert(sid);
|
assert(token);
|
||||||
|
|
||||||
return function (err) {
|
return function (err) {
|
||||||
if(err) return done(err);
|
if(err) return done(err);
|
||||||
|
|
||||||
AccessToken.findById(sid, function (err, accessToken) {
|
AccessToken.findById(token, function (err, accessToken) {
|
||||||
assert(!accessToken, 'accessToken should not exist after logging out');
|
assert(!accessToken, 'accessToken should not exist after logging out');
|
||||||
done(err);
|
done(err);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue