diff --git a/ui/app/abilities/client.js b/ui/app/abilities/client.js index 465f1b4a1..cd1fc8ed1 100644 --- a/ui/app/abilities/client.js +++ b/ui/app/abilities/client.js @@ -7,6 +7,9 @@ import classic from 'ember-classic-decorator'; export default class Client extends AbstractAbility { // Map abilities to policy options (which are coarse for nodes) // instead of specific behaviors. + @or('bypassAuthorization', 'selfTokenIsManagement', 'policiesIncludeNodeRead') + canRead; + @or( 'bypassAuthorization', 'selfTokenIsManagement', @@ -15,14 +18,28 @@ export default class Client extends AbstractAbility { canWrite; @computed('token.selfTokenPolicies.[]') - get policiesIncludeNodeWrite() { - // For each policy record, extract the Node policy - const policies = (this.get('token.selfTokenPolicies') || []) - .toArray() - .map((policy) => get(policy, 'rulesJSON.Node.Policy')) - .compact(); + get policiesIncludeNodeRead() { + return policiesIncludePermissions(this.get('token.selfTokenPolicies'), [ + 'read', + 'write', + ]); + } - // Node write is allowed if any policy allows it - return policies.some((policy) => policy === 'write'); + @computed('token.selfTokenPolicies.[]') + get policiesIncludeNodeWrite() { + return policiesIncludePermissions(this.get('token.selfTokenPolicies'), [ + 'write', + ]); } } + +function policiesIncludePermissions(policies = [], permissions = []) { + // For each policy record, extract the Node policy + const nodePolicies = policies + .toArray() + .map((policy) => get(policy, 'rulesJSON.Node.Policy')) + .compact(); + + // Check for requested permissions + return nodePolicies.some((policy) => permissions.includes(policy)); +} diff --git a/ui/tests/unit/abilities/client-test.js b/ui/tests/unit/abilities/client-test.js index 08850b60f..8d2c2a731 100644 --- a/ui/tests/unit/abilities/client-test.js +++ b/ui/tests/unit/abilities/client-test.js @@ -8,26 +8,28 @@ module('Unit | Ability | client', function (hooks) { setupTest(hooks); setupAbility('client')(hooks); - test('it permits client write when ACLs are disabled', function (assert) { + test('it permits client read and write when ACLs are disabled', function (assert) { const mockToken = Service.extend({ aclEnabled: false, }); this.owner.register('service:token', mockToken); + assert.ok(this.ability.canRead); assert.ok(this.ability.canWrite); }); - test('it permits client write for management tokens', function (assert) { + test('it permits client read and write for management tokens', function (assert) { const mockToken = Service.extend({ aclEnabled: true, selfToken: { type: 'management' }, }); this.owner.register('service:token', mockToken); + assert.ok(this.ability.canRead); assert.ok(this.ability.canWrite); }); - test('it permits client write for tokens with a policy that has node-write', function (assert) { + test('it permits client read and write for tokens with a policy that has node-write', function (assert) { const mockToken = Service.extend({ aclEnabled: true, selfToken: { type: 'client' }, @@ -43,10 +45,11 @@ module('Unit | Ability | client', function (hooks) { }); this.owner.register('service:token', mockToken); + assert.ok(this.ability.canRead); assert.ok(this.ability.canWrite); }); - test('it permits client write for tokens with a policy that allows write and another policy that disallows it', function (assert) { + test('it permits client read and write for tokens with a policy that allows write and another policy that disallows it', function (assert) { const mockToken = Service.extend({ aclEnabled: true, selfToken: { type: 'client' }, @@ -69,10 +72,11 @@ module('Unit | Ability | client', function (hooks) { }); this.owner.register('service:token', mockToken); + assert.ok(this.ability.canRead); assert.ok(this.ability.canWrite); }); - test('it blocks client write for tokens with a policy that does not allow node-write', function (assert) { + test('it permits client read and blocks client write for tokens with a policy that does not allow node-write', function (assert) { const mockToken = Service.extend({ aclEnabled: true, selfToken: { type: 'client' }, @@ -88,6 +92,23 @@ module('Unit | Ability | client', function (hooks) { }); this.owner.register('service:token', mockToken); + assert.ok(this.ability.canRead); + assert.notOk(this.ability.canWrite); + }); + + test('it blocks client read and write for tokens without a node policy', function (assert) { + const mockToken = Service.extend({ + aclEnabled: true, + selfToken: { type: 'client' }, + selfTokenPolicies: [ + { + rulesJSON: {}, + }, + ], + }); + this.owner.register('service:token', mockToken); + + assert.notOk(this.ability.canRead); assert.notOk(this.ability.canWrite); }); });