[ui] "can list variables" capability refactor (#13996)

* Check against all your policies' namespaces' secvars' paths' capabilities to see if you can list vars

* Changelog and lintfix

* Unit tests for list-vars

* Removed unused computed dep

* Changelog removed
This commit is contained in:
Phil Renaud 2022-08-05 10:45:22 -04:00 committed by GitHub
parent eb933ad27d
commit 4283608bbf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 163 additions and 9 deletions

View File

@ -1,3 +1,4 @@
// @ts-check
import { computed, get } from '@ember/object';
import { or } from '@ember/object/computed';
import AbstractAbility from './abstract';
@ -20,7 +21,7 @@ export default class Variable extends AbstractAbility {
@or(
'bypassAuthorization',
'selfTokenIsManagement',
'policiesSupportVariableView'
'policiesSupportVariableList'
)
canList;
@ -38,10 +39,48 @@ export default class Variable extends AbstractAbility {
)
canDestroy;
@computed('rulesForNamespace.@each.capabilities')
get policiesSupportVariableView() {
return this.rulesForNamespace.some((rules) => {
return get(rules, 'SecureVariables');
@computed('token.selfTokenPolicies')
get policiesSupportVariableList() {
return this.policyNamespacesIncludeSecureVariablesCapabilities(
this.token.selfTokenPolicies,
['list', 'read', 'write', 'destroy']
);
}
/**
*
* Map to your policy's namespaces,
* and each of their SecureVariables blocks' paths,
* and each of their capabilities.
* Then, check to see if any of the permissions you're looking for
* are contained within at least one of them.
*
* @param {Object} policies
* @param {string[]} capabilities
* @returns {boolean}
*/
policyNamespacesIncludeSecureVariablesCapabilities(
policies = [],
capabilities = []
) {
const namespacesWithSecureVariableCapabilities = policies
.toArray()
.map((policy) => get(policy, 'rulesJSON.Namespaces'))
.flat()
.map((namespace = {}) => {
return namespace.SecureVariables?.Paths;
})
.flat()
.compact()
.map((secVarsBlock = {}) => {
return secVarsBlock.Capabilities;
})
.flat()
.compact();
// Check for requested permissions
return namespacesWithSecureVariableCapabilities.some((abilityList) => {
return capabilities.includes(abilityList);
});
}

View File

@ -60,9 +60,7 @@ module('Unit | Ability | variable', function (hooks) {
Name: 'default',
Capabilities: [],
SecureVariables: {
'Path "*"': {
Capabilities: ['list'],
},
Paths: [{ Capabilities: ['list'], PathSpec: '*' }],
},
},
],
@ -76,7 +74,7 @@ module('Unit | Ability | variable', function (hooks) {
assert.ok(this.ability.canList);
});
test('it permits listing variables when token has SecureVariables alone in its rules', function (assert) {
test('it does not permit listing variables when token has SecureVariables alone in its rules', function (assert) {
const mockToken = Service.extend({
aclEnabled: true,
selfToken: { type: 'client' },
@ -97,6 +95,123 @@ module('Unit | Ability | variable', function (hooks) {
this.owner.register('service:token', mockToken);
assert.notOk(this.ability.canList);
});
test('it does not permit listing variables when token has a null SecureVariables block', function (assert) {
const mockToken = Service.extend({
aclEnabled: true,
selfToken: { type: 'client' },
selfTokenPolicies: [
{
rulesJSON: {
Namespaces: [
{
Name: 'default',
Capabilities: [],
SecureVariables: null,
},
],
},
},
],
});
this.owner.register('service:token', mockToken);
assert.notOk(this.ability.canList);
});
test('it does not permit listing variables when token has a SecureVariables block where paths are without capabilities', function (assert) {
const mockToken = Service.extend({
aclEnabled: true,
selfToken: { type: 'client' },
selfTokenPolicies: [
{
rulesJSON: {
Namespaces: [
{
Name: 'default',
Capabilities: [],
SecureVariables: {
Paths: [
{ Capabilities: [], PathSpec: '*' },
{ Capabilities: [], PathSpec: 'foo' },
{ Capabilities: [], PathSpec: 'foo/bar' },
],
},
},
],
},
},
],
});
this.owner.register('service:token', mockToken);
assert.notOk(this.ability.canList);
});
test('it does not permit listing variables when token has no SecureVariables block', function (assert) {
const mockToken = Service.extend({
aclEnabled: true,
selfToken: { type: 'client' },
selfTokenPolicies: [
{
rulesJSON: {
Namespaces: [
{
Name: 'default',
Capabilities: [],
},
],
},
},
],
});
this.owner.register('service:token', mockToken);
assert.notOk(this.ability.canList);
});
test('it permits listing variables when token multiple namespaces, only one of which having a SecureVariables block', function (assert) {
const mockToken = Service.extend({
aclEnabled: true,
selfToken: { type: 'client' },
selfTokenPolicies: [
{
rulesJSON: {
Namespaces: [
{
Name: 'default',
Capabilities: [],
SecureVariables: null,
},
{
Name: 'nonsense',
Capabilities: [],
SecureVariables: {
Paths: [{ Capabilities: [], PathSpec: '*' }],
},
},
{
Name: 'shenanigans',
Capabilities: [],
SecureVariables: {
Paths: [
{ Capabilities: ['list'], PathSpec: 'foo/bar/baz' },
],
},
},
],
},
},
],
});
this.owner.register('service:token', mockToken);
assert.ok(this.ability.canList);
});
});