role-acl
Version:
Role, Attribute and Condition based Access Control for Node.js
990 lines (989 loc) • 167 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var AccessControl = require('../src').AccessControl;
function type(o) {
return Object.prototype.toString.call(o).match(/\s(\w+)/i)[1].toLowerCase();
}
function throwsAccessControlError(fn, errMsg) {
// expect(fn).toThrow();
// try {
// fn();
// fail('should throw error');
// } catch (err) {
// expect(err instanceof AccessControl.Error).toEqual(true);
// expect(AccessControl.isACError(err)).toEqual(true);
// if (errMsg) expect(err.message).toContain(errMsg);
// }
throwsError(fn, errMsg, AccessControl.Error.name);
}
function promiseThrowsError(promise, errMsg) {
return __awaiter(this, void 0, void 0, function () {
var err_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 3]);
return [4 /*yield*/, promise];
case 1:
_a.sent();
fail('should throw error');
return [3 /*break*/, 3];
case 2:
err_1 = _a.sent();
if (errMsg)
expect(err_1.message).toContain(errMsg);
return [3 /*break*/, 3];
case 3: return [2 /*return*/];
}
});
});
}
function throwsError(fn, errMsg, errName) {
expect(fn).toThrow();
try {
fn();
fail('should throw error');
}
catch (err) {
if (errName)
expect(err.constructor.name).toEqual(errName);
if (errMsg)
expect(err.message).toContain(errMsg);
}
}
describe('Test Suite: Access Control', function () {
// grant list fetched from DB (to be converted to a valid grants object)
var grantList = [
{ role: 'admin', resource: 'video', action: 'create', attributes: ['*'] },
{ role: 'admin', resource: 'video', action: 'read', attributes: ['*'] },
{ role: 'admin', resource: 'video', action: 'update', attributes: ['*'] },
{ role: 'admin', resource: 'video', action: 'delete', attributes: ['*'] },
{ role: 'user', resource: 'video', action: 'create', attributes: ['*'] },
{ role: 'user', resource: 'video', action: 'read', attributes: ['*'] },
{ role: 'user', resource: 'video', action: 'update', attributes: ['*'] },
{ role: 'user', resource: 'video', action: 'delete', attributes: ['*'] }
];
var grantListWithExtendRoles = grantList.concat([
{ role: 'editor', resource: 'post', action: 'create', attributes: ['*'] },
{ role: 'editor', extend: ['user'] },
{ role: 'editor', resource: 'post', action: 'delete', attributes: ['*'] }
]);
// valid grants object
var grantsObject = {
admin: {
grants: [
{
resource: 'video', action: 'create'
},
{
resource: 'video', action: 'read'
},
{
resource: 'video', action: 'update'
},
{
resource: 'video', action: 'delete'
}
]
},
user: {
grants: [
{
resource: 'video', action: 'create', attributes: ['*']
},
{
resource: 'video', action: 'read', attributes: ['*']
},
{
resource: 'video', action: 'update', attributes: ['*']
},
{
resource: 'video', action: 'delete', attributes: ['*']
}
]
}
};
var categorySportsCondition = { 'Fn': 'EQUALS', 'args': { 'category': 'sports' } };
var categoryPoliticsCondition = { 'Fn': 'EQUALS', 'args': { 'category': 'politics' } };
var categoryHealthCondition = { 'Fn': 'EQUALS', 'args': { 'category': 'health' } };
var categoryBusinessCondition = { 'Fn': 'EQUALS', 'args': { 'category': 'business' } };
var categorySportsContext = { category: 'sports' };
var categoryPoliticsContext = { category: 'politics' };
var categoryHealthContext = { category: 'health' };
var categoryBusinessContext = { category: 'business' };
var customContextAllowed = { loginUserId: '1', resourceProfileId: '1' };
var customContextNotAllowed = { loginUserId: '1', resourceProfileId: '2' };
var conditionalGrantList = [
{
role: 'sports/editor', resource: 'article', action: 'create', attributes: ['*'],
condition: categorySportsCondition
},
{
role: 'sports/editor', resource: 'article', action: 'update', attributes: ['*'],
condition: categorySportsCondition
},
{
role: 'sports/writer', resource: 'article', action: 'create', attributes: ['*', '!status'],
condition: categorySportsCondition
},
{
role: 'sports/writer', resource: 'article', action: 'update', attributes: ['*', '!status'],
condition: categorySportsCondition
}
];
var conditionalGrantObject = {
'sports/editor': {
grants: [
{
resource: 'article', action: 'create', attributes: ['*'],
condition: categorySportsCondition
},
{
resource: 'article', action: 'update', attributes: ['*'],
condition: categorySportsCondition
}
]
},
'sports/writer': {
grants: [{
resource: 'article', action: 'create', attributes: ['*', '!status'],
condition: categorySportsCondition
},
{
resource: 'article', action: 'update', attributes: ['*', '!status'],
condition: categorySportsCondition
}]
}
};
var conditionalGrantObjectWithCustomAsyncFunction = {
'sports/custom': {
grants: [
{
resource: 'profile', action: ['create', 'edit'], attributes: ['*'],
condition: function (context) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(context.loginUserId === context.resourceProfileId);
}, 200);
});
}
}
]
}
};
var conditionalGrantObjectWithCustomSyncFunction = {
'sports/custom': {
grants: [
{
resource: 'profile', action: ['create', 'edit'], attributes: ['*'],
condition: function (context) {
return context.loginUserId === context.resourceProfileId;
}
}
]
}
};
var conditionalGrantArrayWithCustomAsyncFunction = [
{
role: 'sports/custom',
resource: 'profile', action: ['create', 'edit'], attributes: ['*'],
condition: function (context) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(context.loginUserId === context.resourceProfileId);
}, 200);
});
}
}
];
var conditionalGrantArrayWithCustomSyncFunction = [
{
role: 'sports/custom',
resource: 'profile', action: ['create', 'edit'], attributes: ['*'],
condition: function (context) {
return context.loginUserId === context.resourceProfileId;
}
}
];
beforeEach(function () {
this.ac = new AccessControl();
});
// ----------------------------
// TESTS
// ----------------------------
it('should add grants from flat list (db), check/remove roles and resources', function () {
return __awaiter(this, void 0, void 0, function () {
var ac;
return __generator(this, function (_a) {
ac = this.ac;
ac.setGrants(grantList);
// console.log("grants", ac.getGrants());
// console.log("resources", ac.getResources());
// console.log("roles", ac.getRoles());
expect(ac.getRoles().length).toEqual(2);
expect(ac.hasRole('admin')).toEqual(true);
expect(ac.hasRole('user')).toEqual(true);
expect(ac.hasRole('moderator')).toEqual(false);
// removeRoles should also accept a string
ac.removeRoles('admin');
expect(ac.hasRole('admin')).toEqual(false);
// no role named moderator but this should work
ac.removeRoles(['user', 'moderator']);
expect(ac.getRoles().length).toEqual(0);
return [2 /*return*/];
});
});
});
it('should add grants from flat list (db) with extendRoles', function () {
return __awaiter(this, void 0, void 0, function () {
var ac;
return __generator(this, function (_a) {
ac = this.ac;
ac.setGrants(grantListWithExtendRoles);
expect((ac.can('user').execute('create').sync().on('video')).granted).toBeTruthy();
expect((ac.can('editor').execute('create').sync().on('post')).granted).toBeTruthy();
expect((ac.can('editor').execute('create').sync().on('video')).granted).toBeTruthy();
expect((ac.can('editor').execute('delete').sync().on('post')).granted).toBeTruthy();
return [2 /*return*/];
});
});
});
it('should add conditional grants from flat list (db), check/remove roles and resources', function () {
return __awaiter(this, void 0, void 0, function () {
var ac;
return __generator(this, function (_a) {
ac = this.ac;
ac.setGrants(conditionalGrantList);
// console.log("grants", ac.getGrants());
// console.log("resources", ac.getResources());
// console.log("roles", ac.getRoles());
expect(ac.getRoles().length).toEqual(2);
expect(ac.hasRole('sports/editor')).toEqual(true);
expect(ac.hasRole('sports/writer')).toEqual(true);
expect(ac.hasRole('sports/moderator')).toEqual(false);
ac.removeRoles('sports/editor');
expect(ac.hasRole('sports/editor')).toEqual(false);
// no role named moderator but this should work
ac.removeRoles(['sports/writer', 'moderator']);
expect(ac.getRoles().length).toEqual(0);
return [2 /*return*/];
});
});
});
it('should grant access and check permissions', function () {
return __awaiter(this, void 0, void 0, function () {
var ac, attrs, conditionalAttrs, _a, _b, _c, _d, _e;
return __generator(this, function (_f) {
switch (_f.label) {
case 0:
ac = this.ac;
attrs = ['*', '!size'];
conditionalAttrs = [{
attributes: attrs,
condition: undefined
}];
ac.grant('user').execute('create').on('photo', attrs);
_a = expect;
return [4 /*yield*/, ac.can('user').execute('create').on('photo')];
case 1:
_a.apply(void 0, [(_f.sent()).attributes]).toEqual(attrs);
// grant multiple roles the same permission for the same resource
ac.grant(['user', 'admin']).execute('read').on('photo', attrs);
_b = expect;
return [4 /*yield*/, ac.can('user').execute('read').on('photo')];
case 2:
_b.apply(void 0, [(_f.sent()).granted]).toEqual(true);
_c = expect;
return [4 /*yield*/, ac.can('admin').execute('read').on('photo')];
case 3:
_c.apply(void 0, [(_f.sent()).granted]).toEqual(true);
ac.grant('user').execute('update').on('photo', attrs);
_d = expect;
return [4 /*yield*/, ac.can('user').execute('update').on('photo')];
case 4:
_d.apply(void 0, [(_f.sent()).attributes]).toEqual(attrs);
ac.grant('user').execute('delete').on('photo', attrs);
_e = expect;
return [4 /*yield*/, ac.can('user').execute('delete').on('photo')];
case 5:
_e.apply(void 0, [(_f.sent()).attributes]).toEqual(attrs);
return [2 /*return*/];
}
});
});
});
it('should grant access and check permissions synchronously', function () {
var ac = this.ac;
var attrs = ['*', '!size'];
ac.grant('user').execute('create').on('photo', attrs);
expect((ac.can('user').execute('create').sync().on('photo')).attributes).toEqual(attrs);
// grant multiple roles the same permission for the same resource
ac.grant(['user', 'admin']).execute('read').on('photo', attrs);
expect((ac.can('user').execute('read').sync().on('photo')).granted).toEqual(true);
expect((ac.can('admin').execute('read').sync().on('photo')).granted).toEqual(true);
ac.grant('user').execute('update').on('photo', attrs);
expect((ac.can('user').execute('update').sync().on('photo')).attributes).toEqual(attrs);
ac.grant('user').execute('delete').on('photo', attrs);
expect((ac.can('user').execute('delete').sync().on('photo')).attributes).toEqual(attrs);
});
it('should grant access and check permissions for wildcard resources', function () {
return __awaiter(this, void 0, void 0, function () {
var ac, attrs, _a, _b, _c, _d, _e, _f;
return __generator(this, function (_g) {
switch (_g.label) {
case 0:
ac = this.ac;
attrs = ['*', '!size'];
ac.grant('user1').execute('create').on('!photo', attrs);
_a = expect;
return [4 /*yield*/, ac.can('user1').execute('create').on('photo')];
case 1:
_a.apply(void 0, [(_g.sent()).granted]).toEqual(false);
_b = expect;
return [4 /*yield*/, ac.can('user1').execute('create').on('video')];
case 2:
_b.apply(void 0, [(_g.sent()).granted]).toEqual(true);
ac.grant('user2').execute('create').on(['photo', 'video'], attrs);
_c = expect;
return [4 /*yield*/, ac.can('user2').execute('create').on('photo')];
case 3:
_c.apply(void 0, [(_g.sent()).granted]).toEqual(true);
_d = expect;
return [4 /*yield*/, ac.can('user2').execute('create').on('video')];
case 4:
_d.apply(void 0, [(_g.sent()).granted]).toEqual(true);
ac.grant('user3').execute('create').on(['!photo'], attrs);
_e = expect;
return [4 /*yield*/, ac.can('user3').execute('create').on('photo')];
case 5:
_e.apply(void 0, [(_g.sent()).granted]).toEqual(false);
_f = expect;
return [4 /*yield*/, ac.can('user3').execute('create').on('video')];
case 6:
_f.apply(void 0, [(_g.sent()).granted]).toEqual(true);
return [2 /*return*/];
}
});
});
});
it('should grant access and check permissions for wildcard resources synchronously', function () {
var ac = this.ac;
var attrs = ['*', '!size'];
var conditionalAttrs = [{
attributes: attrs,
condition: undefined
}];
ac.grant('user1').execute('create').on('!photo', attrs);
expect((ac.can('user1').execute('create').sync().on('photo')).granted).toEqual(false);
expect((ac.can('user1').execute('create').sync().on('video')).granted).toEqual(true);
ac.grant('user2').execute('create').on(['photo', 'video'], attrs);
expect((ac.can('user2').execute('create').sync().on('photo')).granted).toEqual(true);
expect((ac.can('user2').execute('create').sync().on('video')).granted).toEqual(true);
ac.grant('user3').execute('create').on(['!photo'], attrs);
expect((ac.can('user3').execute('create').sync().on('photo')).granted).toEqual(false);
expect((ac.can('user3').execute('create').sync().on('video')).granted).toEqual(true);
});
it('should grant access and check permissions for wildcard actions', function () {
return __awaiter(this, void 0, void 0, function () {
var ac, attrs, conditionalAttrs, _a, _b, _c, _d, _e, _f, _g, _h, _j;
return __generator(this, function (_k) {
switch (_k.label) {
case 0:
ac = this.ac;
attrs = ['*', '!size'];
conditionalAttrs = [{
attributes: attrs,
condition: undefined
}];
ac.grant('user1').execute('!create').on('photo', attrs);
_a = expect;
return [4 /*yield*/, ac.can('user1').execute('create').on('photo')];
case 1:
_a.apply(void 0, [(_k.sent()).granted]).toEqual(false);
_b = expect;
return [4 /*yield*/, ac.can('user1').execute('update').on('photo')];
case 2:
_b.apply(void 0, [(_k.sent()).granted]).toEqual(true);
ac.grant('user1').execute(['*', '!create']).on('photo', attrs);
_c = expect;
return [4 /*yield*/, ac.can('user1').execute('create').on('photo')];
case 3:
_c.apply(void 0, [(_k.sent()).granted]).toEqual(false);
_d = expect;
return [4 /*yield*/, ac.can('user1').execute('update').on('photo')];
case 4:
_d.apply(void 0, [(_k.sent()).granted]).toEqual(true);
_e = expect;
return [4 /*yield*/, ac.can('user1').execute('update').on('photo')];
case 5:
_e.apply(void 0, [(_k.sent()).granted]).toEqual(true);
ac.grant('user2').execute(['create', 'update']).on(['photo'], attrs);
_f = expect;
return [4 /*yield*/, ac.can('user2').execute('update').on('photo')];
case 6:
_f.apply(void 0, [(_k.sent()).granted]).toEqual(true);
_g = expect;
return [4 /*yield*/, ac.can('user2').execute('create').on('photo')];
case 7:
_g.apply(void 0, [(_k.sent()).granted]).toEqual(true);
ac.grant('user3').execute(['*', '!create']).on(['photo'], attrs);
_h = expect;
return [4 /*yield*/, ac.can('user3').execute('update').on('photo')];
case 8:
_h.apply(void 0, [(_k.sent()).granted]).toEqual(true);
_j = expect;
return [4 /*yield*/, ac.can('user3').execute('create').on('photo')];
case 9:
_j.apply(void 0, [(_k.sent()).granted]).toEqual(false);
return [2 /*return*/];
}
});
});
});
it('should grant access and check permissions for wildcard actions synchronously', function () {
var ac = this.ac;
var attrs = ['*', '!size'];
ac.grant('user1').execute('!create').on('photo', attrs);
expect((ac.can('user1').execute('create').sync().on('photo')).granted).toEqual(false);
expect((ac.can('user1').execute('update').sync().on('photo')).granted).toEqual(true);
ac.grant('user1').execute(['*', '!create']).on('photo', attrs);
expect((ac.can('user1').execute('create').sync().on('photo')).granted).toEqual(false);
expect((ac.can('user1').execute('update').sync().on('photo')).granted).toEqual(true);
expect((ac.can('user1').execute('update').sync().on('photo')).granted).toEqual(true);
ac.grant('user2').execute(['create', 'update']).on(['photo'], attrs);
expect((ac.can('user2').execute('update').sync().on('photo')).granted).toEqual(true);
expect((ac.can('user2').execute('create').sync().on('photo')).granted).toEqual(true);
ac.grant('user3').execute(['*', '!create']).on(['photo'], attrs);
expect((ac.can('user3').execute('update').sync().on('photo')).granted).toEqual(true);
expect((ac.can('user3').execute('create').sync().on('photo')).granted).toEqual(false);
});
it('should filter object properties', function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
expect(AccessControl.filter({ status: 'approved', id: 123 }, ['*', '!status'])).toEqual({ id: 123 });
expect(AccessControl.filter({ status: 'approved', id: 123 }, ['*'])).toEqual({ status: 'approved', id: 123 });
return [2 /*return*/];
});
});
});
it('should grant access with custom actions and check permissions', function () {
return __awaiter(this, void 0, void 0, function () {
var ac, attrs, conditionalAttrs, permission, _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
ac = this.ac;
attrs = ['*', '!status'];
conditionalAttrs = [{
attributes: attrs,
condition: undefined
}];
ac.grant('editor').execute('publish').on('article', attrs);
return [4 /*yield*/, ac.can('editor').execute('publish').on('article')];
case 1:
permission = _b.sent();
expect(permission.attributes).toEqual(attrs);
_a = expect;
return [4 /*yield*/, (permission.granted)];
case 2:
_a.apply(void 0, [_b.sent()]).toEqual(true);
ac.grant('sports/editor').execute('publish').when(categorySportsCondition).on('article', attrs);
return [4 /*yield*/, ac.can('sports/editor').execute('publish').with(categorySportsContext).on('article')];
case 3:
permission = _b.sent();
expect(permission.attributes).toEqual(attrs);
expect(permission.granted).toEqual(true);
return [4 /*yield*/, ac.can('sports/editor').execute('publish').with(categoryPoliticsContext).on('article')];
case 4:
permission = _b.sent();
expect(permission.attributes).toEqual([]);
expect(permission.granted).toEqual(false);
ac.grant({
role: 'politics/editor',
action: 'publish',
resource: 'article',
condition: categoryPoliticsCondition,
attributes: attrs
});
return [4 /*yield*/, ac.can('politics/editor').execute('publish').with(categoryPoliticsContext).on('article')];
case 5:
permission = _b.sent();
expect(permission.attributes).toEqual(attrs);
expect(permission.granted).toEqual(true);
// Simply set all the fields and call commit at the end
ac.grant('user')
.action('post')
.resource('blog')
.attributes(attrs)
.condition({ Fn: 'EQUALS', args: { logged: true } })
.commit();
return [4 /*yield*/, ac.can('user').execute('post').with({ logged: true }).on('blog')];
case 6:
permission = _b.sent();
expect(permission.attributes).toEqual(attrs);
expect(permission.granted).toEqual(true);
return [2 /*return*/];
}
});
});
});
it('should grant access with custom actions and check permissions synchronously', function () {
var ac = this.ac;
var attrs = ['*', '!status'];
var conditionalAttrs = [{
attributes: attrs,
condition: undefined
}];
ac.grant('editor').execute('publish').on('article', attrs);
var permission = ac.can('editor').execute('publish').sync().on('article');
expect(permission.attributes).toEqual(attrs);
expect((permission.granted)).toEqual(true);
ac.grant('sports/editor').execute('publish').when(categorySportsCondition).on('article', attrs);
permission = ac.can('sports/editor').execute('publish').sync().with(categorySportsContext).on('article');
expect(permission.attributes).toEqual(attrs);
expect(permission.granted).toEqual(true);
permission = ac.can('sports/editor').execute('publish').sync().with(categoryPoliticsContext).on('article');
expect(permission.attributes).toEqual([]);
expect(permission.granted).toEqual(false);
ac.grant({
role: 'politics/editor',
action: 'publish',
resource: 'article',
condition: categoryPoliticsCondition,
attributes: attrs
});
permission = ac.can('politics/editor').execute('publish').sync().with(categoryPoliticsContext).on('article');
expect(permission.attributes).toEqual(attrs);
expect(permission.granted).toEqual(true);
// Simply set all the fields and call commit at the end
ac.grant('user')
.action('post')
.resource('blog')
.attributes(attrs)
.condition({ Fn: 'EQUALS', args: { logged: true } })
.commit();
permission = ac.can('user').execute('post').sync().with({ logged: true }).on('blog');
expect(permission.attributes).toEqual(attrs);
expect(permission.granted).toEqual(true);
});
it('should grant access with OR condition and check permissions', function () {
return __awaiter(this, void 0, void 0, function () {
var ac, _a, _b, _c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
ac = this.ac;
ac.grant('user').condition({
Fn: 'OR',
args: [
categorySportsCondition,
categoryPoliticsCondition
]
}).execute('create').on('article');
_a = expect;
return [4 /*yield*/, ac.can('user').context(categorySportsContext).execute('create').on('article')];
case 1:
_a.apply(void 0, [(_d.sent()).granted]).toEqual(true);
_b = expect;
return [4 /*yield*/, ac.can('user').context(categoryPoliticsContext).execute('create').on('article')];
case 2:
_b.apply(void 0, [(_d.sent()).granted]).toEqual(true);
_c = expect;
return [4 /*yield*/, ac.can('user').context({ category: 'tech' }).execute('create').on('article')];
case 3:
_c.apply(void 0, [(_d.sent()).granted]).toEqual(false);
return [2 /*return*/];
}
});
});
});
it('should grant access with OR condition and check permissions synchronously', function () {
var ac = this.ac;
ac.grant('user').condition({
Fn: 'OR',
args: [
categorySportsCondition,
categoryPoliticsCondition
]
}).execute('create').on('article');
expect((ac.can('user').context(categorySportsContext).execute('create').sync().on('article')).granted).toEqual(true);
expect((ac.can('user').context(categoryPoliticsContext).execute('create').sync().on('article')).granted).toEqual(true);
expect((ac.can('user').context({ category: 'tech' }).execute('create').sync().on('article')).granted).toEqual(false);
});
it('should grant access with equals conditions with null values', function () {
var ac = new AccessControl([{
role: 'user',
resource: 'task',
action: ['update'],
attributes: ['*'],
condition: {
Fn: 'AND',
args: [
{ 'Fn': 'EQUALS', 'args': { 'userId': '$.AssignedId' } },
{ 'Fn': 'EQUALS', 'args': { 'CompletedAt': null } }
]
}
}]);
expect((ac.can('user').context({
AssignedId: 'abc123',
CompletedAt: null,
userId: 'abc123'
}).execute('update').sync().on('task')).granted).toEqual(true);
});
it('should grant access with equals condition with list of values and check permissions ', function () {
return __awaiter(this, void 0, void 0, function () {
var ac, _a, _b, _c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
ac = this.ac;
ac.grant('user').condition({
Fn: 'EQUALS',
args: {
'category': ['sports', 'politics']
}
}).execute('create').on('article');
_a = expect;
return [4 /*yield*/, ac.can('user').context(categorySportsContext).execute('create').on('article')];
case 1:
_a.apply(void 0, [(_d.sent()).granted]).toEqual(true);
_b = expect;
return [4 /*yield*/, ac.can('user').context(categoryPoliticsContext).execute('create').on('article')];
case 2:
_b.apply(void 0, [(_d.sent()).granted]).toEqual(true);
_c = expect;
return [4 /*yield*/, ac.can('user').context({ tag: 'tech' }).execute('create').on('article')];
case 3:
_c.apply(void 0, [(_d.sent()).granted]).toEqual(false);
return [2 /*return*/];
}
});
});
});
it('should grant access with equals condition with list of values and check permissions synchronously', function () {
var ac = this.ac;
ac.grant('user').condition({
Fn: 'EQUALS',
args: {
'category': ['sports', 'politics']
}
}).execute('create').on('article');
expect((ac.can('user').context(categorySportsContext).execute('create').sync().on('article')).granted).toEqual(true);
expect((ac.can('user').context(categoryPoliticsContext).execute('create').sync().on('article')).granted).toEqual(true);
expect((ac.can('user').context({ tag: 'tech' }).execute('create').sync().on('article')).granted).toEqual(false);
});
it('should grant access with equals condition with single and check permissions', function () {
return __awaiter(this, void 0, void 0, function () {
var ac, _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
ac = this.ac;
ac.grant('user').condition({
Fn: 'EQUALS',
args: {
'category': 'sports'
}
}).execute('create').on('article');
_a = expect;
return [4 /*yield*/, ac.can('user').context(categorySportsContext).execute('create').on('article')];
case 1:
_a.apply(void 0, [(_c.sent()).granted]).toEqual(true);
_b = expect;
return [4 /*yield*/, ac.can('user').context({ category: 'tech' }).execute('create').on('article')];
case 2:
_b.apply(void 0, [(_c.sent()).granted]).toEqual(false);
return [2 /*return*/];
}
});
});
});
it('should grant access with equals condition with single and check permissions synchronously', function () {
var ac = this.ac;
ac.grant('user').condition({
Fn: 'EQUALS',
args: {
'category': 'sports'
}
}).execute('create').on('article');
expect((ac.can('user').context(categorySportsContext).execute('create').sync().on('article')).granted).toEqual(true);
expect((ac.can('user').context({ category: 'tech' }).execute('create').sync().on('article')).granted).toEqual(false);
});
it('should grant access with not equals condition with list of values and check permissions', function () {
return __awaiter(this, void 0, void 0, function () {
var ac, _a, _b, _c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
ac = this.ac;
ac.grant('user').condition({
Fn: 'NOT_EQUALS',
args: {
'category': ['sports', 'politics']
}
}).execute('create').on('article');
_a = expect;
return [4 /*yield*/, ac.can('user').context(categorySportsContext).execute('create').on('article')];
case 1:
_a.apply(void 0, [(_d.sent()).granted]).toEqual(false);
_b = expect;
return [4 /*yield*/, ac.can('user').context(categoryPoliticsContext).execute('create').on('article')];
case 2:
_b.apply(void 0, [(_d.sent()).granted]).toEqual(false);
_c = expect;
return [4 /*yield*/, ac.can('user').context({ category: 'tech' }).execute('create').on('article')];
case 3:
_c.apply(void 0, [(_d.sent()).granted]).toEqual(true);
return [2 /*return*/];
}
});
});
});
it('should grant access with not equals condition with list of values and check permissions synchronously', function () {
var ac = this.ac;
ac.grant('user').condition({
Fn: 'NOT_EQUALS',
args: {
'category': ['sports', 'politics']
}
}).execute('create').on('article');
expect((ac.can('user').context(categorySportsContext).execute('create').sync().on('article')).granted).toEqual(false);
expect((ac.can('user').context(categoryPoliticsContext).execute('create').sync().on('article')).granted).toEqual(false);
expect((ac.can('user').context({ category: 'tech' }).execute('create').sync().on('article')).granted).toEqual(true);
});
it('should grant access with not equals condition with single value and check permissions', function () {
return __awaiter(this, void 0, void 0, function () {
var ac, _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
ac = this.ac;
ac.grant('user').condition({
Fn: 'NOT_EQUALS',
args: {
'category': 'sports'
}
}).execute('create').on('article');
_a = expect;
return [4 /*yield*/, ac.can('user').context(categorySportsContext).execute('create').on('article')];
case 1:
_a.apply(void 0, [(_c.sent()).granted]).toEqual(false);
_b = expect;
return [4 /*yield*/, ac.can('user').context({ category: 'tech' }).execute('create').on('article')];
case 2:
_b.apply(void 0, [(_c.sent()).granted]).toEqual(true);
return [2 /*return*/];
}
});
});
});
it('should grant access with not equals condition with single value and check permissions synchronously', function () {
var ac = this.ac;
ac.grant('user').condition({
Fn: 'NOT_EQUALS',
args: {
'category': 'sports'
}
}).execute('create').on('article');
expect((ac.can('user').context(categorySportsContext).execute('create').sync().on('article')).granted).toEqual(false);
expect((ac.can('user').context({ category: 'tech' }).execute('create').sync().on('article')).granted).toEqual(true);
});
it('should grant access with and condition with list value and check permissions', function () {
return __awaiter(this, void 0, void 0, function () {
var ac, _a, _b, _c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
ac = this.ac;
ac.grant('user').condition({
Fn: 'AND',
args: [
{
Fn: 'NOT_EQUALS',
args: {
'category': 'sports'
}
},
{
Fn: 'NOT_EQUALS',
args: {
'category': 'politics'
}
}
]
}).execute('create').on('article');
_a = expect;
return [4 /*yield*/, ac.can('user').context(categorySportsContext).execute('create').on('article')];
case 1:
_a.apply(void 0, [(_d.sent()).granted]).toEqual(false);
_b = expect;
return [4 /*yield*/, ac.can('user').context(categoryPoliticsContext).execute('create').on('article')];
case 2:
_b.apply(void 0, [(_d.sent()).granted]).toEqual(false);
_c = expect;
return [4 /*yield*/, ac.can('user').context({ category: 'tech' }).execute('create').on('article')];
case 3:
_c.apply(void 0, [(_d.sent()).granted]).toEqual(true);
return [2 /*return*/];
}
});
});
});
it('should grant access with and condition with list value and check permissions synchronously', function () {
var ac = this.ac;
ac.grant('user').condition({
Fn: 'AND',
args: [
{
Fn: 'NOT_EQUALS',
args: {
'category': 'sports'
}
},
{
Fn: 'NOT_EQUALS',
args: {
'category': 'politics'
}
}
]
}).execute('create').on('article');
expect((ac.can('user').context(categorySportsContext).execute('create').sync().on('article')).granted).toEqual(false);
expect((ac.can('user').context(categoryPoliticsContext).execute('create').sync().on('article')).granted).toEqual(false);
expect((ac.can('user').context({ category: 'tech' }).execute('create').sync().on('article')).granted).toEqual(true);
});
it('should grant access with JSONPath context keys or values with EQUALS condition', function () {
return __awaiter(this, void 0, void 0, function () {
var ac, _a, _b, _c, _d;
return __generator(this, function (_e) {
switch (_e.label) {
case 0:
ac = this.ac;
ac.grant('user').condition({
Fn: 'EQUALS',
args: {
'requester': '$.owner'
}
}).execute('edit').on('article');
_a = expect;
return [4 /*yield*/, ac.can('user').context({ owner: 'dilip', requester: 'dilip' })
.execute('edit').on('article')];
case 1:
_a.apply(void 0, [(_e.sent()).granted]).toEqual(true);
_b = expect;
return [4 /*yield*/, ac.can('user').context({ owner: 'tensult', requester: 'dilip' })
.execute('edit').on('article')];
case 2:
_b.apply(void 0, [(_e.sent()).granted]).toEqual(false);
ac.grant('user').condition({
Fn: 'EQUALS',
args: {
'$.request.initiator': '$.owner'
}
}).execute('edit').on('article');
_c = expect;
return [4 /*yield*/, ac.can('user').context({ owner: 'dilip', request: { initiator: 'dilip' } })
.execute('edit').on('article')];
case 3:
_c.apply(void 0, [(_e.sent()).granted]).toEqual(true);
_d = expect;
return [4 /*yield*/, ac.can('user').context({ owner: 'tensult', request: { initiator: 'dilip' } })
.execute('edit').on('article')];
case 4:
_d.apply(void 0, [(_e.sent()).granted]).toEqual(false);
return [2 /*return*/];
}
});
});
});
it('should grant access with JSONPath context values with EQUALS condition synchronously', function () {
var ac = this.ac;
ac.grant('user').condition({
Fn: 'EQUALS',
args: {
'requester': '$.owner'
}
}).execute('edit').on('article');
expect((ac.can('user').context({ owner: 'dilip', requester: 'dilip' })
.execute('edit').sync().on('article')).granted).toEqual(true);
expect((ac.can('user').context({ owner: 'tensult', requester: 'dilip' })
.execute('edit').sync().on('article')).granted).toEqual(false);
});
it('should grant access with JSONPath context values with NOT_EQUALS condition', function () {
return __awaiter(this, void 0, void 0, function () {
var ac, _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
ac = this.ac;
ac.grant('user').condition({
Fn: 'NOT_EQUALS',
args: {
'$.requester': '$.owner'
}
}).execute('approve').on('article');
_a = expect;
return [4 /*yield*/, ac.can('user').context({ owner: 'dilip', requester: 'dilip' })
.execute('approve').on('article')];
case 1:
_a.apply(void 0, [(_c.sent()).granted]).toEqual(false);
_b = expect;
return [4 /*yield*/, ac.can('user').context({ owner: 'tensult', requester: 'dilip' })
.execute('approve').on('article')];
case 2:
_b.apply(void 0, [(_c.sent()).granted]).toEqual(true);
return [2 /*return*/];
}
});
});
});
it('should grant access with JSONPath context values with NOT_EQUALS condition synchronously', function () {
var ac = this.ac;
ac.grant('user').condition({
Fn: 'NOT_EQUALS',
args: {
'$.requester': '$.owner'
}
}).execute('approve').on('article');
expect((ac.can('user').context({ owner: 'dilip', requester: 'dilip' })
.execute('approve').sync().on('article')).granted).toEqual(false);
expect((ac.can('user').context({ owner: 'tensult', requester: 'dilip' })
.execute('approve').sync().on('article')).granted).toEqual(true);
});
it('should grant access with and with custom condition function', function () {
return __awaiter(this, void 0, void 0, function () {
var ac, _a, _b, _c;