From d5af0658ef549e43e90d05746e2855876f44d957 Mon Sep 17 00:00:00 2001 From: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com> Date: Fri, 5 Jan 2024 14:40:55 -0600 Subject: [PATCH] UI: fix PKI issuer capabilities (#24686) --- changelog/24686.txt | 3 + ui/app/models/pki/issuer.js | 13 ++- .../pki/pki-engine-workflow-test.js | 109 +++++++++++------- ui/tests/acceptance/pki/pki-overview-test.js | 4 +- ui/tests/acceptance/policies-acl-old-test.js | 2 + ui/tests/helpers/pki/pki-run-commands.js | 18 +++ 6 files changed, 99 insertions(+), 50 deletions(-) create mode 100644 changelog/24686.txt diff --git a/changelog/24686.txt b/changelog/24686.txt new file mode 100644 index 000000000000..30ef696f491e --- /dev/null +++ b/changelog/24686.txt @@ -0,0 +1,3 @@ +```release-note:bug +ui: fix incorrectly calculated capabilities on PKI issuer endpoints +``` diff --git a/ui/app/models/pki/issuer.js b/ui/app/models/pki/issuer.js index a06ea671690b..6e51d469d5fc 100644 --- a/ui/app/models/pki/issuer.js +++ b/ui/app/models/pki/issuer.js @@ -135,13 +135,14 @@ export default class PkiIssuerModel extends Model { @attr importedKeys; @attr mapping; - @lazyCapabilities(apiPath`${'backend'}/issuer/${'issuerId'}`) issuerPath; - @lazyCapabilities(apiPath`${'backend'}/root/rotate/exported`) rotateExported; - @lazyCapabilities(apiPath`${'backend'}/root/rotate/internal`) rotateInternal; - @lazyCapabilities(apiPath`${'backend'}/root/rotate/existing`) rotateExisting; + @lazyCapabilities(apiPath`${'backend'}/issuer/${'issuerId'}`, 'backend', 'issuerId') issuerPath; + @lazyCapabilities(apiPath`${'backend'}/root/rotate/exported`, 'backend') rotateExported; + @lazyCapabilities(apiPath`${'backend'}/root/rotate/internal`, 'backend') rotateInternal; + @lazyCapabilities(apiPath`${'backend'}/root/rotate/existing`, 'backend') rotateExisting; @lazyCapabilities(apiPath`${'backend'}/root`, 'backend') deletePath; - @lazyCapabilities(apiPath`${'backend'}/intermediate/cross-sign`) crossSignPath; - @lazyCapabilities(apiPath`${'backend'}/issuer/${'issuerId'}/sign-intermediate`) signIntermediate; + @lazyCapabilities(apiPath`${'backend'}/intermediate/cross-sign`, 'backend') crossSignPath; + @lazyCapabilities(apiPath`${'backend'}/issuer/${'issuerId'}/sign-intermediate`, 'backend', 'issuerId') + signIntermediate; get canRotateIssuer() { return ( this.rotateExported.get('canUpdate') !== false || diff --git a/ui/tests/acceptance/pki/pki-engine-workflow-test.js b/ui/tests/acceptance/pki/pki-engine-workflow-test.js index 3afc02b25db9..2e47be583573 100644 --- a/ui/tests/acceptance/pki/pki-engine-workflow-test.js +++ b/ui/tests/acceptance/pki/pki-engine-workflow-test.js @@ -13,7 +13,7 @@ import enablePage from 'vault/tests/pages/settings/mount-secret-backend'; import { click, currentURL, fillIn, find, isSettled, visit } from '@ember/test-helpers'; import { SELECTORS } from 'vault/tests/helpers/pki/workflow'; import { adminPolicy, readerPolicy, updatePolicy } from 'vault/tests/helpers/policy-generator/pki'; -import { tokenWithPolicy, runCommands } from 'vault/tests/helpers/pki/pki-run-commands'; +import { tokenWithPolicy, runCommands, clearRecords } from 'vault/tests/helpers/pki/pki-run-commands'; import { unsupportedPem } from 'vault/tests/helpers/pki/values'; /** @@ -25,12 +25,14 @@ module('Acceptance | pki workflow', function (hooks) { setupApplicationTest(hooks); hooks.beforeEach(async function () { + this.store = this.owner.lookup('service:store'); await authPage.login(); // Setup PKI engine const mountPath = `pki-workflow-${uuidv4()}`; await enablePage.enable('pki', mountPath); this.mountPath = mountPath; await logout.visit(); + clearRecords(this.store); }); hooks.afterEach(async function () { @@ -40,40 +42,50 @@ module('Acceptance | pki workflow', function (hooks) { await runCommands([`delete sys/mounts/${this.mountPath}`]); }); - test('empty state messages are correct when PKI not configured', async function (assert) { - assert.expect(21); - const assertEmptyState = (assert, resource) => { - assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/${resource}`); - assert - .dom(SELECTORS.emptyStateTitle) - .hasText( - 'PKI not configured', - `${resource} index renders correct empty state title when PKI not configured` - ); - assert.dom(SELECTORS.emptyStateLink).hasText('Configure PKI'); - assert - .dom(SELECTORS.emptyStateMessage) - .hasText( - `This PKI mount hasn't yet been configured with a certificate issuer.`, - `${resource} index empty state message correct when PKI not configured` - ); - }; - await authPage.login(this.pkiAdminToken); - await visit(`/vault/secrets/${this.mountPath}/pki/overview`); - assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`); - - await click(SELECTORS.rolesTab); - assertEmptyState(assert, 'roles'); - - await click(SELECTORS.issuersTab); - assertEmptyState(assert, 'issuers'); - - await click(SELECTORS.certsTab); - assertEmptyState(assert, 'certificates'); - await click(SELECTORS.keysTab); - assertEmptyState(assert, 'keys'); - await click(SELECTORS.tidyTab); - assertEmptyState(assert, 'tidy'); + module('not configured', function (hooks) { + hooks.beforeEach(async function () { + await authPage.login(); + const pki_admin_policy = adminPolicy(this.mountPath, 'roles'); + this.pkiAdminToken = await tokenWithPolicy(`pki-admin-${this.mountPath}`, pki_admin_policy); + await logout.visit(); + clearRecords(this.store); + }); + + test('empty state messages are correct when PKI not configured', async function (assert) { + assert.expect(21); + const assertEmptyState = (assert, resource) => { + assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/${resource}`); + assert + .dom(SELECTORS.emptyStateTitle) + .hasText( + 'PKI not configured', + `${resource} index renders correct empty state title when PKI not configured` + ); + assert.dom(SELECTORS.emptyStateLink).hasText('Configure PKI'); + assert + .dom(SELECTORS.emptyStateMessage) + .hasText( + `This PKI mount hasn't yet been configured with a certificate issuer.`, + `${resource} index empty state message correct when PKI not configured` + ); + }; + await authPage.login(this.pkiAdminToken); + await visit(`/vault/secrets/${this.mountPath}/pki/overview`); + assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`); + + await click(SELECTORS.rolesTab); + assertEmptyState(assert, 'roles'); + + await click(SELECTORS.issuersTab); + assertEmptyState(assert, 'issuers'); + + await click(SELECTORS.certsTab); + assertEmptyState(assert, 'certificates'); + await click(SELECTORS.keysTab); + assertEmptyState(assert, 'keys'); + await click(SELECTORS.tidyTab); + assertEmptyState(assert, 'tidy'); + }); }); module('roles', function (hooks) { @@ -91,10 +103,11 @@ module('Acceptance | pki workflow', function (hooks) { const pki_admin_policy = adminPolicy(this.mountPath, 'roles'); const pki_reader_policy = readerPolicy(this.mountPath, 'roles'); const pki_editor_policy = updatePolicy(this.mountPath, 'roles'); - this.pkiRoleReader = await tokenWithPolicy('pki-reader', pki_reader_policy); - this.pkiRoleEditor = await tokenWithPolicy('pki-editor', pki_editor_policy); - this.pkiAdminToken = await tokenWithPolicy('pki-admin', pki_admin_policy); + this.pkiRoleReader = await tokenWithPolicy(`pki-reader-${this.mountPath}`, pki_reader_policy); + this.pkiRoleEditor = await tokenWithPolicy(`pki-editor-${this.mountPath}`, pki_editor_policy); + this.pkiAdminToken = await tokenWithPolicy(`pki-admin-${this.mountPath}`, pki_admin_policy); await logout.visit(); + clearRecords(this.store); }); test('shows correct items if user has all permissions', async function (assert) { @@ -222,10 +235,11 @@ module('Acceptance | pki workflow', function (hooks) { const pki_admin_policy = adminPolicy(this.mountPath); const pki_reader_policy = readerPolicy(this.mountPath, 'keys', true); const pki_editor_policy = updatePolicy(this.mountPath, 'keys'); - this.pkiKeyReader = await tokenWithPolicy('pki-reader', pki_reader_policy); - this.pkiKeyEditor = await tokenWithPolicy('pki-editor', pki_editor_policy); - this.pkiAdminToken = await tokenWithPolicy('pki-admin', pki_admin_policy); + this.pkiKeyReader = await tokenWithPolicy(`pki-reader-${this.mountPath}`, pki_reader_policy); + this.pkiKeyEditor = await tokenWithPolicy(`pki-editor-${this.mountPath}`, pki_editor_policy); + this.pkiAdminToken = await tokenWithPolicy(`pki-admin-${this.mountPath}`, pki_admin_policy); await logout.visit(); + clearRecords(this.store); }); test('shows correct items if user has all permissions', async function (assert) { @@ -339,11 +353,14 @@ module('Acceptance | pki workflow', function (hooks) { module('issuers', function (hooks) { hooks.beforeEach(async function () { await authPage.login(); + const pki_admin_policy = adminPolicy(this.mountPath); + this.pkiAdminToken = await tokenWithPolicy(`pki-admin-${this.mountPath}`, pki_admin_policy); // Configure engine with a default issuer await runCommands([ `write ${this.mountPath}/root/generate/internal common_name="Hashicorp Test" name="Hashicorp Test"`, ]); await logout.visit(); + clearRecords(this.store); }); test('lists the correct issuer metadata info', async function (assert) { assert.expect(6); @@ -373,7 +390,10 @@ module('Acceptance | pki workflow', function (hooks) { capabilities = ["deny"] } `; - this.token = await tokenWithPolicy('pki-issuer-denied-policy', pki_issuer_denied_policy); + this.token = await tokenWithPolicy( + `pki-issuer-denied-policy-${this.mountPath}`, + pki_issuer_denied_policy + ); await logout.visit(); await authPage.login(this.token); await visit(`/vault/secrets/${this.mountPath}/pki/overview`); @@ -487,7 +507,10 @@ module('Acceptance | pki workflow', function (hooks) { ${adminPolicy(this.mountPath)} ${readerPolicy(this.mountPath, 'config/cluster')} `; - this.mixedConfigCapabilities = await tokenWithPolicy('pki-reader', mixed_config_policy); + this.mixedConfigCapabilities = await tokenWithPolicy( + `pki-reader-${this.mountPath}`, + mixed_config_policy + ); await logout.visit(); }); diff --git a/ui/tests/acceptance/pki/pki-overview-test.js b/ui/tests/acceptance/pki/pki-overview-test.js index a8234e0d31fc..05a09dd87dbb 100644 --- a/ui/tests/acceptance/pki/pki-overview-test.js +++ b/ui/tests/acceptance/pki/pki-overview-test.js @@ -10,12 +10,13 @@ import logout from 'vault/tests/pages/logout'; import enablePage from 'vault/tests/pages/settings/mount-secret-backend'; import { click, currentURL, currentRouteName, visit } from '@ember/test-helpers'; import { SELECTORS } from 'vault/tests/helpers/pki/overview'; -import { tokenWithPolicy, runCommands } from 'vault/tests/helpers/pki/pki-run-commands'; +import { tokenWithPolicy, runCommands, clearRecords } from 'vault/tests/helpers/pki/pki-run-commands'; module('Acceptance | pki overview', function (hooks) { setupApplicationTest(hooks); hooks.beforeEach(async function () { + this.store = this.owner.lookup('service:store'); await authPage.login(); // Setup PKI engine const mountPath = `pki`; @@ -42,6 +43,7 @@ module('Acceptance | pki overview', function (hooks) { this.pkiIssuersList = await tokenWithPolicy('pki-issuers-list', pki_issuers_list_policy); this.pkiAdminToken = await tokenWithPolicy('pki-admin', pki_admin_policy); await logout.visit(); + clearRecords(this.store); }); hooks.afterEach(async function () { diff --git a/ui/tests/acceptance/policies-acl-old-test.js b/ui/tests/acceptance/policies-acl-old-test.js index 3415f0e5d63a..35eccecf4bc6 100644 --- a/ui/tests/acceptance/policies-acl-old-test.js +++ b/ui/tests/acceptance/policies-acl-old-test.js @@ -45,6 +45,7 @@ module('Acceptance | policies (old)', function (hooks) { assert.dom('[data-test-policy-name]').hasText(policyLower, 'displays the policy name on the show page'); assert.dom('[data-test-flash-message].is-info').doesNotExist('no flash message is displayed on save'); await click('[data-test-policy-list-link] a'); + await fillIn('[data-test-component="navigate-input"]', policyLower); assert .dom(`[data-test-policy-link="${policyLower}"]`) .exists({ count: 1 }, 'new policy shown in the list'); @@ -63,6 +64,7 @@ module('Acceptance | policies (old)', function (hooks) { `/vault/policies/acl`, 'navigates to policy list on successful deletion' ); + await fillIn('[data-test-component="navigate-input"]', policyLower); assert .dom(`[data-test-policy-item="${policyLower}"]`) .doesNotExist('deleted policy is not shown in the list'); diff --git a/ui/tests/helpers/pki/pki-run-commands.js b/ui/tests/helpers/pki/pki-run-commands.js index ac60ec513efd..291aab176fdd 100644 --- a/ui/tests/helpers/pki/pki-run-commands.js +++ b/ui/tests/helpers/pki/pki-run-commands.js @@ -34,3 +34,21 @@ export const runCommands = async function (commands) { throw error; } }; + +// Clears pki-related data and capabilities so that admin +// capabilities from setup don't rollover +export function clearRecords(store) { + store.unloadAll('pki/action'); + store.unloadAll('pki/issuer'); + store.unloadAll('pki/key'); + store.unloadAll('pki/role'); + store.unloadAll('pki/sign-intermediate'); + store.unloadAll('pki/tidy'); + store.unloadAll('pki/config/urls'); + store.unloadAll('pki/config/crl'); + store.unloadAll('pki/config/cluster'); + store.unloadAll('pki/config/acme'); + store.unloadAll('pki/certificate/generate'); + store.unloadAll('pki/certificate/sign'); + store.unloadAll('capabilities'); +}