|
1 | 1 | import { expect } from 'chai'; |
2 | | -import { AuthorizerFactory, Claims } from '../src'; |
3 | | -import { ADMINISTER_OWN_AUTH, ADMINISTER_OTHER_AUTH, DO_NEARLY_EVERYTHING } from './sample-data'; |
| 2 | +import { AuthorizerFactory, Claims, SubjectAuthorizer } from '../src'; |
| 3 | +import { |
| 4 | + ADMINISTER_OWN_AUTH, |
| 5 | + ADMINISTER_OTHER_AUTH, |
| 6 | + DO_NEARLY_EVERYTHING, |
| 7 | + ALL_ROLES, |
| 8 | + BUDGET_VIEWER_KAZOO_PM, |
| 9 | + BUDGET_VIEWER_SINGLE, |
| 10 | + BUDGET_VIEWER_MFG_HEAD, |
| 11 | +} from './sample-data'; |
4 | 12 |
|
5 | 13 |
|
6 | 14 | describe('SubjectAuthorizer', () => { |
7 | | - const ALL_ROLES_1 = [ |
| 15 | + const allRoles1 = [ |
8 | 16 | ADMINISTER_OWN_AUTH, |
9 | 17 | ADMINISTER_OTHER_AUTH, |
10 | 18 | ]; |
11 | 19 |
|
12 | | - const ALL_ROLES_2 = [ |
| 20 | + const allRoles2 = [ |
13 | 21 | ADMINISTER_OWN_AUTH, |
14 | 22 | ADMINISTER_OTHER_AUTH, |
15 | 23 | DO_NEARLY_EVERYTHING, |
16 | 24 | ]; |
17 | 25 |
|
18 | | - const USER_ID = '73885b55-2e0d-40bd-8cb3-2e59cf78ed87'; |
| 26 | + const userID = '73885b55-2e0d-40bd-8cb3-2e59cf78ed87'; |
19 | 27 |
|
20 | | - const USER: Claims = { |
21 | | - subjectID: USER_ID, |
| 28 | + const user: Claims = { |
| 29 | + subjectID: userID, |
22 | 30 | roles: [ |
23 | 31 | { roleID: ADMINISTER_OWN_AUTH.roleID }, |
24 | 32 | { roleID: ADMINISTER_OTHER_AUTH.roleID, contextValue: '8e0fa760-9a1d-43ea-8686-768318d923b4' }, |
25 | 33 | { roleID: DO_NEARLY_EVERYTHING.roleID }, |
26 | 34 | ], |
27 | 35 | }; |
28 | 36 |
|
29 | | - const factory1 = new AuthorizerFactory(ALL_ROLES_1), |
30 | | - factory2 = new AuthorizerFactory(ALL_ROLES_2); |
| 37 | + const factory1 = new AuthorizerFactory(allRoles1), |
| 38 | + factory2 = new AuthorizerFactory(allRoles2); |
31 | 39 |
|
32 | 40 | it('ignores unknown roles when no opts provided', () => { |
33 | | - expect(factory1.makeAuthorizerForSubject(USER)).to.be.ok; // eslint-disable-line no-unused-expressions |
34 | | - expect(factory2.makeAuthorizerForSubject(USER)).to.be.ok; // eslint-disable-line no-unused-expressions |
| 41 | + expect(factory1.makeAuthorizerForSubject(user)).to.be.ok; // eslint-disable-line no-unused-expressions |
| 42 | + expect(factory2.makeAuthorizerForSubject(user)).to.be.ok; // eslint-disable-line no-unused-expressions |
35 | 43 | }); |
36 | 44 |
|
37 | 45 | it('throws an error on unknown roles when requested', () => { |
38 | | - expect(() => { factory1.makeAuthorizerForSubject(USER, { throwOnUnknownRole: true }); }).to.throw(); |
39 | | - expect(factory2.makeAuthorizerForSubject(USER, { throwOnUnknownRole: true })).to.be.ok; // eslint-disable-line no-unused-expressions |
| 46 | + expect(() => { factory1.makeAuthorizerForSubject(user, { throwOnUnknownRole: true }); }).to.throw(); |
| 47 | + expect(factory2.makeAuthorizerForSubject(user, { throwOnUnknownRole: true })).to.be.ok; // eslint-disable-line no-unused-expressions |
| 48 | + }); |
| 49 | + |
| 50 | + describe('hasPolicyGranting', () => { |
| 51 | + |
| 52 | + it('returns true if the user has a policy for the action', () => { |
| 53 | + const authorizer = new SubjectAuthorizer(ALL_ROLES, BUDGET_VIEWER_SINGLE); |
| 54 | + |
| 55 | + expect(authorizer.hasPolicyGranting('budget:View')).to.strictlyEqual(true); |
| 56 | + }); |
| 57 | + |
| 58 | + it('returns false if the user does not have a policy for the action', () => { |
| 59 | + const authorizer = new SubjectAuthorizer(ALL_ROLES, BUDGET_VIEWER_SINGLE); |
| 60 | + |
| 61 | + expect(authorizer.hasPolicyGranting('budget:Create')).to.strictlyEqual(false); |
| 62 | + }); |
| 63 | + |
| 64 | + it('returns true if the user has a policy matching resource prefix', () => { |
| 65 | + const authorizer = new SubjectAuthorizer(ALL_ROLES, BUDGET_VIEWER_KAZOO_PM); |
| 66 | + |
| 67 | + expect(authorizer.hasPolicyGranting('budget:View', { resourcePrefixPattern: 'budget:kazoo/*' })).to.strictlyEqual(true); |
| 68 | + }); |
| 69 | + |
| 70 | + it('returns true if the policy resource is broader than the requested prefix', () => { |
| 71 | + const authorizer = new SubjectAuthorizer(ALL_ROLES, BUDGET_VIEWER_MFG_HEAD); |
| 72 | + |
| 73 | + // BUDGET_VIEWER_MFG_HEAD has budget:* |
| 74 | + expect(authorizer.hasPolicyGranting('budget:View', { resourcePrefixPattern: 'budget:kazoo/mktg/*' })).to.strictlyEqual(true); |
| 75 | + }); |
| 76 | + |
| 77 | + it('returns false if the user has the action but on different resources', () => { |
| 78 | + const authorizer = new SubjectAuthorizer(ALL_ROLES, BUDGET_VIEWER_KAZOO_PM); |
| 79 | + |
| 80 | + // KAZOO PM has budget:View on budget:* but we can test with a non-matching |
| 81 | + // prefix. |
| 82 | + expect(authorizer.hasPolicyGranting('budget:View', { resourcePrefixPattern: 'budget-v2/*' })).to.strictlyEqual(false); |
| 83 | + }); |
| 84 | + |
| 85 | + it('throws an error if resourcePrefixPattern does not end with a wildcard or contains internal wildcards', () => { |
| 86 | + const authorizer = new SubjectAuthorizer(ALL_ROLES, BUDGET_VIEWER_KAZOO_PM); |
| 87 | + |
| 88 | + expect(() => { authorizer.hasPolicyGranting('budget:View', { resourcePrefixPattern: 'budget:kazoo' }); }).to.throw(); |
| 89 | + |
| 90 | + expect(() => { authorizer.hasPolicyGranting('budget:View', { resourcePrefixPattern: 'budget:*/foo' }); }).to.throw(); |
| 91 | + |
| 92 | + expect(() => { authorizer.hasPolicyGranting('budget:View', { resourcePrefixPattern: '*budget:foo' }); }).to.throw(); |
| 93 | + }); |
| 94 | + |
| 95 | + it('correctly handles prefix match', () => { |
| 96 | + const authorizer = new SubjectAuthorizer(ALL_ROLES, BUDGET_VIEWER_KAZOO_PM); |
| 97 | + |
| 98 | + // BUDGET_VIEWER_KAZOO_PM has policy for budget:kazoo/*. The requested prefix is |
| 99 | + // budget:kazoo/mktg/*. This should be true because the policy resource |
| 100 | + // (budget:kazoo/*) matches the requested prefix (budget:kazoo/mktg/*). |
| 101 | + expect(authorizer.hasPolicyGranting('budget:View', { resourcePrefixPattern: 'budget:kazoo/mktg/*' })).to.strictlyEqual(true); |
| 102 | + |
| 103 | + // Now, if the requested prefix is budget:kaz*, it should still be true because |
| 104 | + // the requested resource prefix (budget:kaz*) matches the policy resource |
| 105 | + // (budget:kazoo/*). |
| 106 | + expect(authorizer.hasPolicyGranting('budget:View', { resourcePrefixPattern: 'budget:kaz*' })).to.strictlyEqual(true); |
| 107 | + }); |
| 108 | + |
40 | 109 | }); |
41 | 110 |
|
42 | 111 | }); |
0 commit comments