Skip to content

Commit 4db0e63

Browse files
committed
jasmine test specs
1 parent 2ae4a0c commit 4db0e63

File tree

1 file changed

+376
-0
lines changed

1 file changed

+376
-0
lines changed

test/ac.spec.js

Lines changed: 376 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,376 @@
1+
/* eslint brace-style:0, max-statements-per-line:0 */
2+
3+
/**
4+
* Test Suite: AccessControl (Core)
5+
* @author Onur Yıldırım (onur@cutepilot.com)
6+
*/
7+
8+
var AccessControl = require('../index');
9+
10+
describe('Test Suite: Access Control (core)', function () {
11+
'use strict';
12+
13+
// grant list fetched from DB (to be converted to a valid grants object)
14+
var grantList = [
15+
{ role: 'admin', resource: 'video', action: 'create:any', attributes: ['*'] },
16+
{ role: 'admin', resource: 'video', action: 'read:any', attributes: ['*'] },
17+
{ role: 'admin', resource: 'video', action: 'update:any', attributes: ['*'] },
18+
{ role: 'admin', resource: 'video', action: 'delete:any', attributes: ['*'] },
19+
20+
{ role: 'user', resource: 'video', action: 'create:own', attributes: ['*'] },
21+
{ role: 'user', resource: 'video', action: 'read:any', attributes: ['*'] },
22+
{ role: 'user', resource: 'video', action: 'update:own', attributes: ['*'] },
23+
{ role: 'user', resource: 'video', action: 'delete:own', attributes: ['*'] }
24+
];
25+
26+
// valid grants object
27+
var grantsObject = {
28+
admin: {
29+
video: {
30+
'create:any': ['*'],
31+
'read:any': ['*'],
32+
'update:any': ['*'],
33+
'delete:any': ['*']
34+
}
35+
},
36+
user: {
37+
video: {
38+
'create:own': ['*'],
39+
'read:own': ['*'],
40+
'update:own': ['*'],
41+
'delete:own': ['*']
42+
}
43+
}
44+
};
45+
46+
beforeEach(function () {
47+
this.ac = new AccessControl();
48+
});
49+
50+
//----------------------------
51+
// TESTS
52+
//----------------------------
53+
54+
it('should add grants from flat list (db), check/remove roles and resources', function () {
55+
var ac = this.ac;
56+
ac.setGrants(grantList);
57+
// console.log('grants', ac.getGrants());
58+
// console.log('resources', ac.getResources());
59+
// console.log('roles', ac.getRoles());
60+
61+
expect(ac.getRoles().length).toEqual(2);
62+
expect(ac.getResources().length).toEqual(1);
63+
expect(ac.hasRole('admin')).toEqual(true);
64+
expect(ac.hasRole('user')).toEqual(true);
65+
expect(ac.hasRole('moderator')).toEqual(false);
66+
expect(ac.hasResource('video')).toEqual(true);
67+
expect(ac.hasResource('photo')).toEqual(false);
68+
// removeRoles should also accept a string
69+
ac.removeRoles('admin');
70+
expect(ac.hasRole('admin')).toEqual(false);
71+
// no role named moderator but this should work
72+
ac.removeRoles(['user', 'moderator']);
73+
expect(ac.getRoles().length).toEqual(0);
74+
// removeRoles should accept a string or array
75+
ac.removeResources(['video']);
76+
expect(ac.getResources().length).toEqual(0);
77+
expect(ac.hasResource('video')).toEqual(false);
78+
});
79+
80+
it('should grant/deny access and check permissions', function () {
81+
var ac = this.ac,
82+
attrs = ['*', '!size'];
83+
84+
ac.grant('user').createAny('photo', attrs);
85+
expect(ac.getGrants().user.photo['create:any']).toEqual(attrs);
86+
expect(ac.can('user').createAny('photo').attributes).toEqual(attrs);
87+
88+
ac.deny('user').createAny('photo');
89+
expect(ac.can('user').createAny('photo').granted).toEqual(false);
90+
expect(ac.can('user').createAny('photo').attributes).toEqual([]);
91+
92+
ac.grant('user').createOwn('photo', attrs);
93+
// console.log('ac.getGrants()', ac.getGrants());
94+
expect(ac.getGrants().user.photo['create:own']).toEqual(attrs);
95+
expect(ac.can('user').createOwn('photo').attributes).toEqual(attrs);
96+
97+
// grant multiple roles the same permission for the same resource
98+
ac.grant(['user', 'admin']).readAny('photo', attrs);
99+
expect(ac.can('user').readAny('photo').granted).toEqual(true);
100+
expect(ac.can('admin').readAny('photo').granted).toEqual(true);
101+
// deny multiple roles the same permission for the same resource
102+
ac.deny(['user', 'admin']).readAny('photo');
103+
expect(ac.can('user').readAny('photo').granted).toEqual(false);
104+
expect(ac.can('admin').readAny('photo').granted).toEqual(false);
105+
106+
ac.grant('user').updateAny('photo', attrs);
107+
expect(ac.getGrants().user.photo['update:any']).toEqual(attrs);
108+
expect(ac.can('user').updateAny('photo').attributes).toEqual(attrs);
109+
110+
ac.grant('user').updateOwn('photo', attrs);
111+
expect(ac.getGrants().user.photo['update:own']).toEqual(attrs);
112+
expect(ac.can('user').updateOwn('photo').attributes).toEqual(attrs);
113+
114+
ac.grant('user').deleteAny('photo', attrs);
115+
expect(ac.getGrants().user.photo['delete:any']).toEqual(attrs);
116+
expect(ac.can('user').deleteAny('photo').attributes).toEqual(attrs);
117+
118+
ac.grant('user').deleteOwn('photo', attrs);
119+
expect(ac.getGrants().user.photo['delete:own']).toEqual(attrs);
120+
expect(ac.can('user').deleteOwn('photo').attributes).toEqual(attrs);
121+
});
122+
123+
it('should chain grant methods and check permissions', function () {
124+
var ac = this.ac,
125+
attrs = ['*'];
126+
127+
ac.grant('superadmin')
128+
.createAny('profile', attrs)
129+
.readAny('profile', attrs)
130+
.createAny('video', []) // no attributes allowed
131+
.createAny('photo'); // all attributes allowed
132+
133+
expect(ac.can('superadmin').createAny('profile').granted).toEqual(true);
134+
expect(ac.can('superadmin').readAny('profile').granted).toEqual(true);
135+
expect(ac.can('superadmin').createAny('video').granted).toEqual(false);
136+
expect(ac.can('superadmin').createAny('photo').granted).toEqual(true);
137+
});
138+
139+
it('should grant/deny access via object and check permissions', function () {
140+
var ac = this.ac,
141+
attrs = ['*'];
142+
143+
var o1 = {
144+
role: 'moderator',
145+
resource: 'post',
146+
action: 'create:any', // action:possession
147+
attributes: ['*'] // grant only
148+
};
149+
var o2 = {
150+
role: 'moderator',
151+
resource: 'news',
152+
action: 'read', // separate action
153+
possession: 'own', // separate possession
154+
attributes: ['*'] // grant only
155+
};
156+
var o3 = {
157+
role: 'moderator',
158+
resource: 'book',
159+
// no action/possession set
160+
attributes: ['*'] // grant only
161+
};
162+
163+
ac.grant(o1);
164+
ac.grant(o2);
165+
ac.grant(o3).updateAny();
166+
167+
expect(ac.can('moderator').createAny('post').granted).toEqual(true);
168+
expect(ac.can('moderator').readOwn('news').granted).toEqual(true);
169+
expect(ac.can('moderator').updateAny('book').granted).toEqual(true);
170+
171+
ac.deny(o1);
172+
ac.deny(o2);
173+
ac.deny(o3).updateAny();
174+
175+
expect(ac.can('moderator').createAny('post').granted).toEqual(false);
176+
expect(ac.can('moderator').readOwn('news').granted).toEqual(false);
177+
expect(ac.can('moderator').updateAny('book').granted).toEqual(false);
178+
179+
// should overwrite already defined action/possession in o1 object
180+
ac.grant(o1).readOwn();
181+
expect(ac.can('moderator').readOwn('post').granted).toEqual(true);
182+
ac.deny(o1).readOwn();
183+
expect(ac.can('moderator').readOwn('post').granted).toEqual(false);
184+
185+
// non-set action (update:own)
186+
expect(ac.can('moderator').updateOwn('news').granted).toEqual(false);
187+
// non-existent resource
188+
expect(ac.can('moderator').createAny('foo').granted).toEqual(false);
189+
});
190+
191+
it('should grant/deny access (variation, chained)', function () {
192+
var ac = this.ac;
193+
ac.setGrants(grantsObject);
194+
195+
expect(ac.can('admin').createAny('video').granted).toEqual(true);
196+
ac.deny('admin').create('video');
197+
expect(ac.can('admin').createAny('video').granted).toEqual(false);
198+
199+
ac.grant('foo').createOwn('bar');
200+
expect(ac.can('foo').createAny('bar').granted).toEqual(false);
201+
expect(ac.can('foo').createOwn('bar').granted).toEqual(true);
202+
203+
ac.grant('foo').create('baz', []); // no attributes, actually denied instead of granted
204+
expect(ac.can('foo').create('baz').granted).toEqual(false);
205+
206+
ac.grant('qux')
207+
.createOwn('resource1')
208+
.updateOwn('resource2')
209+
.readAny('resource1')
210+
.deleteAny('resource1', []);
211+
expect(ac.can('qux').createOwn('resource1').granted).toEqual(true);
212+
expect(ac.can('qux').updateOwn('resource2').granted).toEqual(true);
213+
expect(ac.can('qux').readAny('resource1').granted).toEqual(true);
214+
expect(ac.can('qux').deleteAny('resource1').granted).toEqual(false);
215+
216+
ac.deny('qux')
217+
.createOwn('resource1')
218+
.updateOwn('resource2')
219+
.readAny('resource1')
220+
.deleteAny('resource1', []);
221+
expect(ac.can('qux').createOwn('resource1').granted).toEqual(false);
222+
expect(ac.can('qux').updateOwn('resource2').granted).toEqual(false);
223+
expect(ac.can('qux').readAny('resource1').granted).toEqual(false);
224+
expect(ac.can('qux').deleteAny('resource1').granted).toEqual(false);
225+
226+
ac.grant('editor').resource('file1').updateAny();
227+
ac.grant().role('editor').updateAny('file2');
228+
ac.grant().role('editor').resource('file3').updateAny();
229+
expect(ac.can('editor').updateAny('file1').granted).toEqual(true);
230+
expect(ac.can('editor').updateAny('file2').granted).toEqual(true);
231+
expect(ac.can('editor').updateAny('file3').granted).toEqual(true);
232+
233+
ac.deny('editor').resource('file1').updateAny();
234+
ac.deny().role('editor').updateAny('file2');
235+
ac.deny().role('editor').resource('file3').updateAny();
236+
expect(ac.can('editor').updateAny('file1').granted).toEqual(false);
237+
expect(ac.can('editor').updateAny('file2').granted).toEqual(false);
238+
expect(ac.can('editor').updateAny('file3').granted).toEqual(false);
239+
240+
ac.grant('editor')
241+
.resource('fileX').readAny().createOwn()
242+
.resource('fileY').updateOwn().deleteOwn();
243+
expect(ac.can('editor').readAny('fileX').granted).toEqual(true);
244+
expect(ac.can('editor').createOwn('fileX').granted).toEqual(true);
245+
expect(ac.can('editor').updateOwn('fileY').granted).toEqual(true);
246+
expect(ac.can('editor').deleteOwn('fileY').granted).toEqual(true);
247+
248+
ac.deny('editor')
249+
.resource('fileX').readAny().createOwn()
250+
.resource('fileY').updateOwn().deleteOwn();
251+
expect(ac.can('editor').readAny('fileX').granted).toEqual(false);
252+
expect(ac.can('editor').createOwn('fileX').granted).toEqual(false);
253+
expect(ac.can('editor').updateOwn('fileY').granted).toEqual(false);
254+
expect(ac.can('editor').deleteOwn('fileY').granted).toEqual(false);
255+
256+
});
257+
258+
it('should switch-chain grant/deny roles', function () {
259+
var ac = this.ac;
260+
ac.grant('r1')
261+
.createOwn('a')
262+
.grant('r2')
263+
.createOwn('b')
264+
.readAny('b')
265+
.deny('r1')
266+
.deleteAny('b')
267+
.grant('r1')
268+
.updateAny('c')
269+
.deny('r2')
270+
.readAny('c');
271+
272+
expect(ac.can('r1').createOwn('a').granted).toEqual(true);
273+
expect(ac.can('r1').deleteAny('b').granted).toEqual(false);
274+
expect(ac.can('r1').updateAny('c').granted).toEqual(true);
275+
expect(ac.can('r2').createOwn('b').granted).toEqual(true);
276+
expect(ac.can('r2').readAny('b').granted).toEqual(true);
277+
expect(ac.can('r2').readAny('c').granted).toEqual(false);
278+
// console.log(JSON.stringify(ac.getGrants(), null, ' '));
279+
});
280+
281+
it('should extend / remove roles', function () {
282+
var ac = this.ac;
283+
284+
ac.extendRole('onur', 'admin');
285+
expect(ac.getGrants().onur.$extend.length).toEqual(1);
286+
expect(ac.getGrants().onur.$extend[0]).toEqual('admin');
287+
288+
ac.extendRole('onur', ['role2', 'role3']);
289+
expect(ac.getGrants().onur.$extend).toEqual(['admin', 'role2', 'role3']);
290+
291+
ac.grant('admin').extend('editor');
292+
expect(ac.getGrants().admin.$extend).toEqual(['editor']);
293+
ac.grant('admin').extend(['viewer', 'editor', 'agent']).readAny('video');
294+
expect(ac.getGrants().admin.$extend).toContain('editor');
295+
expect(ac.getGrants().admin.$extend).toEqual(['editor', 'viewer', 'agent']);
296+
297+
ac.grant(['editor', 'agent']).extend(['role2', 'role3']).updateOwn('photo');
298+
expect(ac.getGrants().editor.$extend).toEqual(['role2', 'role3']);
299+
expect(ac.getGrants().agent.$extend).toEqual(['role2', 'role3']);
300+
301+
ac.removeRoles(['editor', 'agent']);
302+
expect(ac.getGrants().editor).toBeUndefined();
303+
expect(ac.getGrants().agent).toBeUndefined();
304+
expect(ac.getGrants().admin.$extend).not.toContain('editor');
305+
expect(ac.getGrants().admin.$extend).not.toContain('agent');
306+
307+
expect(function () { ac.grant('roleX').extend('roleX'); }).toThrow();
308+
expect(function () { ac.grant(['admin2', 'roleX']).extend(['roleX', 'admin3']); }).toThrow();
309+
310+
// console.log(JSON.stringify(ac.getGrants(), null, ' '));
311+
});
312+
313+
it('should throw if grant or deny objects are invalid', function () {
314+
var o,
315+
ac = this.ac;
316+
317+
o = {
318+
role: '', // invalid role, should be non-empty string or array
319+
resource: 'post',
320+
action: 'create:any',
321+
attributes: ['*'] // grant only
322+
};
323+
expect(function () { ac.grant(o); }).toThrow();
324+
expect(function () { ac.deny(o); }).toThrow();
325+
326+
o = {
327+
role: 'moderator',
328+
resource: null, // invalid resource, should be non-empty string
329+
action: 'create:any',
330+
attributes: ['*'] // grant only
331+
};
332+
expect(function () { ac.grant(o); }).toThrow();
333+
expect(function () { ac.deny(o); }).toThrow();
334+
335+
o = {
336+
role: 'admin',
337+
resource: 'post',
338+
action: 'put:any', // invalid action, should be create|read|update|delete
339+
attributes: ['*'] // grant only
340+
};
341+
expect(function () { ac.grant(o); }).toThrow();
342+
expect(function () { ac.deny(o); }).toThrow();
343+
344+
o = {
345+
role: 'admin',
346+
resource: 'post',
347+
action: null, // invalid action, should be create|read|update|delete
348+
attributes: ['*'] // grant only
349+
};
350+
expect(function () { ac.grant(o); }).toThrow();
351+
expect(function () { ac.deny(o); }).toThrow();
352+
353+
o = {
354+
role: 'admin',
355+
resource: 'post',
356+
action: 'create:all', // invalid possession, should be any|own or omitted
357+
attributes: ['*'] // grant only
358+
};
359+
expect(function () { ac.grant(o); }).toThrow();
360+
expect(function () { ac.deny(o); }).toThrow();
361+
362+
o = {
363+
role: 'admin2',
364+
resource: 'post',
365+
action: 'create', // possession omitted, will be set to any
366+
attributes: ['*'] // grant only
367+
};
368+
expect(function () { ac.grant(o); }).not.toThrow();
369+
expect(ac.can('admin2').createAny('post').granted).toEqual(true);
370+
// possession "any" will also return granted=true for "own"
371+
expect(ac.can('admin2').createOwn('post').granted).toEqual(true);
372+
expect(function () { ac.deny(o); }).not.toThrow();
373+
374+
});
375+
376+
});

0 commit comments

Comments
 (0)