diff --git a/ui/app/adapters/pki/crl.js b/ui/app/adapters/pki/crl.js new file mode 100644 index 000000000..bdf7e6515 --- /dev/null +++ b/ui/app/adapters/pki/crl.js @@ -0,0 +1,21 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import { encodePath } from 'vault/utils/path-encoding-helpers'; +import ApplicationAdapter from '../application'; + +export default class PkiCrlAdapter extends ApplicationAdapter { + namespace = 'v1'; + + _url(backend) { + return `${this.buildURL()}/${encodePath(backend)}/config/crl`; + } + + findRecord(store, type, backend) { + return this.ajax(this._url(backend), 'GET').then((resp) => { + return resp.data; + }); + } +} diff --git a/ui/app/models/mount-config.js b/ui/app/models/mount-config.js index bb3567c87..54dd1f678 100644 --- a/ui/app/models/mount-config.js +++ b/ui/app/models/mount-config.js @@ -62,4 +62,6 @@ export default class MountConfigModel extends Model { noDefault: true, }) tokenType; + + @attr() allowedManagedKeys; } diff --git a/ui/app/models/pki/crl.js b/ui/app/models/pki/crl.js new file mode 100644 index 000000000..b974fa7c9 --- /dev/null +++ b/ui/app/models/pki/crl.js @@ -0,0 +1,18 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import Model, { attr } from '@ember-data/model'; + +export default class PkiCrlModel extends Model { + // This model uses the backend value as the model ID + get useOpenAPI() { + return true; + } + + @attr('string') expiry; + @attr('boolean') autoRebuild; + @attr('string') ocspExpiry; + @attr('boolean') ocspDisable; +} diff --git a/ui/app/styles/core/helpers.scss b/ui/app/styles/core/helpers.scss index 525364ea1..7e77cf6be 100644 --- a/ui/app/styles/core/helpers.scss +++ b/ui/app/styles/core/helpers.scss @@ -158,6 +158,9 @@ .has-padding-m { padding: $spacing-m; } +.has-bottom-padding-s { + padding-bottom: $spacing-s; +} .has-padding-xs { padding: $spacing-xs; } diff --git a/ui/lib/pki/addon/components/page/pki-configuration-details.hbs b/ui/lib/pki/addon/components/page/pki-configuration-details.hbs new file mode 100644 index 000000000..90f4c8728 --- /dev/null +++ b/ui/lib/pki/addon/components/page/pki-configuration-details.hbs @@ -0,0 +1,33 @@ +

+ Global URLs +

+ + + +

+ Certificate Revocation List (CRL) +

+ + + +

+ Online Certificate Status Protocol (OCSP) +

+ + + +

+ Mount Configuration +

+ + + + + + + + +
\ No newline at end of file diff --git a/ui/lib/pki/addon/routes/configuration/index.js b/ui/lib/pki/addon/routes/configuration/index.js index eddd1a317..a08535c55 100644 --- a/ui/lib/pki/addon/routes/configuration/index.js +++ b/ui/lib/pki/addon/routes/configuration/index.js @@ -4,5 +4,31 @@ */ import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; +import { withConfig } from 'pki/decorators/check-config'; +import { hash } from 'rsvp'; -export default class ConfigurationIndexRoute extends Route {} +@withConfig() +export default class ConfigurationIndexRoute extends Route { + @service store; + @service secretMountPath; + + model() { + const backend = this.secretMountPath.currentPath; + return hash({ + hasConfig: this.shouldPromptConfig, + engine: this.modelFor('application'), + urls: this.store.findRecord('pki/urls', backend), + crl: this.store.findRecord('pki/crl', backend), + mountConfig: this.fetchMountConfig(backend), + }); + } + + async fetchMountConfig(path) { + const mountConfig = await this.store.query('secret-engine', { path }); + + if (mountConfig) { + return mountConfig.get('firstObject'); + } + } +} diff --git a/ui/lib/pki/addon/templates/configuration/index.hbs b/ui/lib/pki/addon/templates/configuration/index.hbs index 3ebc3b546..82621b99f 100644 --- a/ui/lib/pki/addon/templates/configuration/index.hbs +++ b/ui/lib/pki/addon/templates/configuration/index.hbs @@ -1,32 +1,33 @@ -{{! - - - Tidy - - - Edit configuration - - - }} - - - Return to old PKI to configure - - \ No newline at end of file +{{#if this.model.hasConfig}} + + + + Tidy + + + Edit configuration + + + + + +{{else}} + + + + + Configure PKI + + +{{/if}} \ No newline at end of file diff --git a/ui/tests/acceptance/pki/pki-engine-workflow-test.js b/ui/tests/acceptance/pki/pki-engine-workflow-test.js index 115bfd082..15254437e 100644 --- a/ui/tests/acceptance/pki/pki-engine-workflow-test.js +++ b/ui/tests/acceptance/pki/pki-engine-workflow-test.js @@ -75,15 +75,6 @@ module('Acceptance | pki workflow', function (hooks) { await click(SELECTORS.keysTab); assertEmptyState(assert, 'keys'); }); - test('shows pki beta banner to return to old pki on new pki configuration page', async function (assert) { - assert.expect(3); - await authPage.login(this.pkiAdminToken); - await visit(`/vault/secrets/${this.mountPath}/pki/configuration`); - assert.dom(SELECTORS.configTab).exists('Configuration tab is present'); - assert.dom(SELECTORS.configuration.pkiBetaBanner).exists('Configuration beta banner exists'); - await click(SELECTORS.configuration.pkiBetaBannerLink); - assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/configuration`); - }); module('configuration', function (hooks) { hooks.beforeEach(function () { diff --git a/ui/tests/helpers/pki/page/pki-configuration-details.js b/ui/tests/helpers/pki/page/pki-configuration-details.js new file mode 100644 index 000000000..63f7bb9b7 --- /dev/null +++ b/ui/tests/helpers/pki/page/pki-configuration-details.js @@ -0,0 +1,36 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +export const SELECTORS = { + // global urls + issuingCertificatesLabel: '[data-test-row-label="Issuing certificates"]', + issuingCertificatesRowVal: '[data-test-row-value="Issuing certificates"]', + crlDistributionPointsLabel: '[data-test-row-label="CRL distribution points"]', + crlDistributionPointsRowVal: '[data-test-row-value="CRL distribution points"]', + // crl + expiryLabel: '[data-test-row-label="Expiry"]', + expiryRowVal: '[data-test-row-value="Expiry"]', + rebuildLabel: '[data-test-row-label="Auto-rebuild"]', + rebuildRowVal: '[data-test-row-value="Auto-rebuild"]', + responderApiLabel: '[data-test-row-label="Responder APIs"]', + responderApiRowVal: '[data-test-row-value="Responder APIs"]', + intervalLabel: '[data-test-row-label="Interval"]', + intervalRowVal: '[data-test-row-value="Interval"]', + // mount configuration + engineTypeLabel: '[data-test-row-label="Secret engine type"]', + engineTypeRowVal: '[data-test-row-value="Secret engine type"]', + pathLabel: '[data-test-row-label="Path"]', + pathRowVal: '[data-test-row-value="Path"]', + accessorLabel: '[data-test-row-label="Accessor"]', + accessorRowVal: '[data-test-row-value="Accessor"]', + localLabel: '[data-test-row-label="Local"]', + localRowVal: '[data-test-value-div="Local"]', + sealWrapLabel: '[data-test-row-label="Seal wrap"]', + sealWrapRowVal: '[data-test-value-div="Seal wrap"]', + maxLeaseTtlLabel: '[data-test-row-label="Max lease TTL"]', + maxLeaseTtlRowVal: '[data-test-row-value="Max lease TTL"]', + allowedManagedKeysLabel: '[data-test-row-label="Allowed managed keys"]', + allowedManagedKeysRowVal: '[data-test-value-div="Allowed managed keys"]', +}; diff --git a/ui/tests/integration/components/pki/page/pki-configuration-details-test.js b/ui/tests/integration/components/pki/page/pki-configuration-details-test.js new file mode 100644 index 000000000..21c407f36 --- /dev/null +++ b/ui/tests/integration/components/pki/page/pki-configuration-details-test.js @@ -0,0 +1,126 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; +import { setupEngine } from 'ember-engines/test-support'; +import { SELECTORS } from 'vault/tests/helpers/pki/page/pki-configuration-details'; + +module('Integration | Component | Page::PkiConfigurationDetails', function (hooks) { + setupRenderingTest(hooks); + setupEngine(hooks, 'pki'); + + hooks.beforeEach(function () { + this.secretMountPath = this.owner.lookup('service:secret-mount-path'); + this.secretMountPath.currentPath = 'pki-test'; + + this.store = this.owner.lookup('service:store'); + this.urls = this.store.createRecord('pki/urls', { id: 'pki-test', issuingCertificates: 'example.com' }); + this.crl = this.store.createRecord('pki/crl', { + id: 'pki-test', + expiry: '20h', + autoRebuild: false, + ocspExpiry: '77h', + oscpDisable: true, + }); + this.mountConfig = { + id: 'pki-test', + engineType: 'pki', + path: '/pki-test', + accessor: 'pki_33345b0d', + local: false, + sealWrap: true, + config: this.store.createRecord('mount-config', { + defaultLease: '12h', + maxLeaseTtl: '400h', + allowedManagedKeys: true, + }), + }; + }); + + test('shows the correct information on global urls section', async function (assert) { + await render( + hbs`,`, + { owner: this.engine } + ); + + assert + .dom(SELECTORS.issuingCertificatesLabel) + .hasText('Issuing certificates', 'issuing certificate row label renders'); + assert + .dom(SELECTORS.issuingCertificatesRowVal) + .hasText('example.com', 'issuing certificate value renders'); + this.urls.issuingCertificates = null; + await render( + hbs`,`, + { owner: this.engine } + ); + assert + .dom(SELECTORS.issuingCertificatesRowVal) + .hasText('None', 'issuing certificate value renders None if none is configured'); + assert + .dom(SELECTORS.crlDistributionPointsLabel) + .hasText('CRL distribution points', 'crl distribution points row label renders'); + assert + .dom(SELECTORS.crlDistributionPointsRowVal) + .hasText('None', 'crl distribution points value renders None if none is configured'); + }); + + test('shows the correct information on crl section', async function (assert) { + await render( + hbs`,`, + { owner: this.engine } + ); + + assert.dom(SELECTORS.expiryLabel).hasText('Expiry', 'crl expiry row label renders'); + assert.dom(SELECTORS.expiryRowVal).hasText('20h', 'expiry value renders'); + assert.dom(SELECTORS.rebuildLabel).hasText('Auto-rebuild', 'auto rebuild label renders'); + assert + .dom(SELECTORS.rebuildRowVal) + .hasText('Off', 'auto-rebuild value renders off if auto rebuild is false'); + this.crl.autoRebuild = true; + await render( + hbs`,`, + { owner: this.engine } + ); + assert + .dom(SELECTORS.rebuildRowVal) + .hasText('On', 'auto-rebuild value renders on if auto rebuild is true'); + assert.dom(SELECTORS.responderApiLabel).hasText('Responder APIs', 'responder apis row label renders'); + assert + .dom(SELECTORS.responderApiRowVal) + .hasText('Enabled', 'responder apis value renders Enabled if oscpDisable is true'); + assert.dom(SELECTORS.intervalLabel).hasText('Interval', 'interval row label renders'); + assert.dom(SELECTORS.intervalRowVal).hasText('77h', 'interval value renders'); + }); + + test('shows the correct information on mount configuration section', async function (assert) { + await render( + hbs`,`, + { owner: this.engine } + ); + + assert.dom(SELECTORS.engineTypeLabel).hasText('Secret engine type', 'engine type row label renders'); + assert.dom(SELECTORS.engineTypeRowVal).hasText('pki', 'engine type row value renders'); + assert.dom(SELECTORS.pathLabel).hasText('Path', 'path row label renders'); + assert.dom(SELECTORS.pathRowVal).hasText('/pki-test', 'path row value renders'); + assert.dom(SELECTORS.accessorLabel).hasText('Accessor', 'accessor row label renders'); + assert.dom(SELECTORS.accessorRowVal).hasText('pki_33345b0d', 'accessor row value renders'); + assert.dom(SELECTORS.localLabel).hasText('Local', 'local row label renders'); + assert.dom(SELECTORS.localRowVal).hasText('No', 'local row value renders'); + assert.dom(SELECTORS.sealWrapLabel).hasText('Seal wrap', 'seal wrap row label renders'); + assert + .dom(SELECTORS.sealWrapRowVal) + .hasText('Yes', 'seal wrap row value renders Yes if sealWrap is true'); + assert.dom(SELECTORS.maxLeaseTtlLabel).hasText('Max lease TTL', 'max lease label renders'); + assert.dom(SELECTORS.maxLeaseTtlRowVal).hasText('400h', 'max lease value renders'); + assert + .dom(SELECTORS.allowedManagedKeysLabel) + .hasText('Allowed managed keys', 'allowed managed keys label renders'); + assert.dom(SELECTORS.allowedManagedKeysRowVal).hasText('Yes', 'allowed managed keys value renders'); + }); +});