diff --git a/.changelog/11472.txt b/.changelog/11472.txt new file mode 100644 index 0000000000..24624d6333 --- /dev/null +++ b/.changelog/11472.txt @@ -0,0 +1,3 @@ +```release-note:bug +ui: **(Enterprise only)** When no namespace is selected, make sure to default to the tokens default namespace when requesting permissions +``` diff --git a/ui/packages/consul-ui/app/adapters/permission.js b/ui/packages/consul-ui/app/adapters/permission.js index cb89f07730..33493b375a 100644 --- a/ui/packages/consul-ui/app/adapters/permission.js +++ b/ui/packages/consul-ui/app/adapters/permission.js @@ -3,6 +3,7 @@ import { inject as service } from '@ember/service'; export default class PermissionAdapter extends Adapter { @service('env') env; + @service('settings') settings; requestForAuthorize(request, { dc, ns, partition, resources = [], index }) { // the authorize endpoint is slightly different to all others in that it @@ -29,8 +30,30 @@ export default class PermissionAdapter extends Adapter { authorize(store, type, id, snapshot) { return this.rpc( - function(adapter, request, serialized, unserialized) { - return adapter.requestForAuthorize(request, serialized, unserialized); + async (adapter, request, serialized, unserialized) => { + // the authorize endpoint does not automatically take into account the + // default namespace of the token on the backend. This means that we + // need to add the default namespace of the token on the frontend + // instead. Decided this is the best place for it as its almost hidden + // from the rest of the app so from an app eng point of view it almost + // feels like it does happen on the backend. + // Same goes ^ for partitions + const nspacesEnabled = this.env.var('CONSUL_NSPACES_ENABLED'); + const partitionsEnabled = this.env.var('CONSUL_PARTITIONS_ENABLED'); + if(nspacesEnabled || partitionsEnabled) { + const token = await this.settings.findBySlug('token'); + if(nspacesEnabled) { + if(typeof serialized.ns === 'undefined' || serialized.ns.length === 0) { + serialized.ns = token.Namespace; + } + } + if(partitionsEnabled) { + if(typeof serialized.partition === 'undefined' || serialized.partition.length === 0) { + serialized.partition = token.Partition; + } + } + } + return adapter.requestForAuthorize(request, serialized); }, function(serializer, respond, serialized, unserialized) { // Completely skip the serializer here diff --git a/ui/packages/consul-ui/tests/unit/adapters/permission-test.js b/ui/packages/consul-ui/tests/unit/adapters/permission-test.js index 6f09aa8bcf..4b338fbdad 100644 --- a/ui/packages/consul-ui/tests/unit/adapters/permission-test.js +++ b/ui/packages/consul-ui/tests/unit/adapters/permission-test.js @@ -1,12 +1,154 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; +const assertAuthorize = function(assertion, params = {}, token, $, adapter) { + const rpc = adapter.rpc; + const env = adapter.env; + const settings = adapter.settings; + adapter.env = { + var: str => $[str] + }; + adapter.settings = { + findBySlug: _ => token + }; + + adapter.rpc = function(request, respond) { + request( + { + requestForAuthorize: (request, params) => { + assertion(request, params); + } + }, + () => {}, + params, + params + ) + }; + adapter.authorize({}, {modelName: 'permission'}, 1, {}); + adapter.rpc = rpc; + adapter.env = env; + adapter.settings = settings; +} module('Unit | Adapter | permission', function(hooks) { setupTest(hooks); - // Replace this with your real tests. test('it exists', function(assert) { let adapter = this.owner.lookup('adapter:permission'); assert.ok(adapter); }); + + test(`authorize adds the tokens default namespace if one isn't specified`, function(assert) { + const adapter = this.owner.lookup('adapter:permission'); + const expected = 'test'; + const token = { + Namespace: expected + }; + const env = { + CONSUL_NSPACES_ENABLED: true + }; + const cases = [ + undefined, + { + ns: undefined + }, + { + ns: '' + } + ]; + assert.expect(cases.length); + cases.forEach( + (params) => { + assertAuthorize( + (request, params) => { + assert.equal(params.ns, expected) + }, + params, + token, + env, + adapter + ) + } + ); + }); + + test(`authorize doesn't add the tokens default namespace if one is specified`, function(assert) { + assert.expect(1); + const adapter = this.owner.lookup('adapter:permission'); + const notExpected = 'test'; + const expected = 'default'; + const token = { + Namespace: notExpected + }; + const env = { + CONSUL_NSPACES_ENABLED: true + }; + assertAuthorize( + (request, params) => { + assert.equal(params.ns, expected) + }, + { + ns: expected + }, + token, + env, + adapter + ) + }); + test(`authorize adds the tokens default partition if one isn't specified`, function(assert) { + const adapter = this.owner.lookup('adapter:permission'); + const expected = 'test'; + const token = { + Partition: expected + }; + const env = { + CONSUL_PARTITIONS_ENABLED: true + }; + const cases = [ + undefined, + { + partition: undefined + }, + { + partition: '' + } + ]; + assert.expect(cases.length); + cases.forEach( + (params) => { + assertAuthorize( + (request, params) => { + assert.equal(params.partition, expected) + }, + params, + token, + env, + adapter + ) + } + ); + }); + + test(`authorize doesn't add the tokens default partition if one is specified`, function(assert) { + assert.expect(1); + const adapter = this.owner.lookup('adapter:permission'); + const notExpected = 'test'; + const expected = 'default'; + const token = { + Partition: notExpected + }; + const env = { + CONSUL_PARTITIONS_ENABLED: true + }; + assertAuthorize( + (request, params) => { + assert.equal(params.partition, expected) + }, + { + partition: expected + }, + token, + env, + adapter + ) + }); });