299 lines
14 KiB
JavaScript
299 lines
14 KiB
JavaScript
/**
|
|
* Copyright (c) HashiCorp, Inc.
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*/
|
|
|
|
import { module, test } from 'qunit';
|
|
import { setupApplicationTest } from 'ember-qunit';
|
|
import { click, currentURL, fillIn, typeIn, visit } from '@ember/test-helpers';
|
|
import { setupMirage } from 'ember-cli-mirage/test-support';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
|
|
import authPage from 'vault/tests/pages/auth';
|
|
import logout from 'vault/tests/pages/logout';
|
|
import enablePage from 'vault/tests/pages/settings/mount-secret-backend';
|
|
import { runCommands } from 'vault/tests/helpers/pki/pki-run-commands';
|
|
import { SELECTORS as S } from 'vault/tests/helpers/pki/workflow';
|
|
import { issuerPemBundle } from 'vault/tests/helpers/pki/values';
|
|
|
|
module('Acceptance | pki action forms test', function (hooks) {
|
|
setupApplicationTest(hooks);
|
|
|
|
hooks.beforeEach(async function () {
|
|
await authPage.login();
|
|
// Setup PKI engine
|
|
const mountPath = `pki-workflow-${uuidv4()}`;
|
|
await enablePage.enable('pki', mountPath);
|
|
this.mountPath = mountPath;
|
|
await logout.visit();
|
|
});
|
|
|
|
hooks.afterEach(async function () {
|
|
await logout.visit();
|
|
await authPage.login();
|
|
// Cleanup engine
|
|
await runCommands([`delete sys/mounts/${this.mountPath}`]);
|
|
await logout.visit();
|
|
});
|
|
|
|
module('import', function (hooks) {
|
|
setupMirage(hooks);
|
|
|
|
hooks.beforeEach(function () {
|
|
this.pemBundle = issuerPemBundle;
|
|
});
|
|
|
|
test('happy path', async function (assert) {
|
|
await authPage.login(this.pkiAdminToken);
|
|
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
|
|
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
|
|
await click(S.emptyStateLink);
|
|
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration/create`);
|
|
assert.dom(S.configuration.title).hasText('Configure PKI');
|
|
assert.dom(S.configuration.emptyState).exists({ count: 1 }, 'Shows empty state by default');
|
|
await click(S.configuration.optionByKey('import'));
|
|
assert.dom(S.configuration.emptyState).doesNotExist();
|
|
// Submit before filling out form shows an error
|
|
await click('[data-test-pki-import-pem-bundle]');
|
|
assert.dom('[data-test-alert-banner="alert"]').hasText('Error please upload your PEM bundle');
|
|
// Fill in form data
|
|
await click('[data-test-text-toggle]');
|
|
await fillIn('[data-test-text-file-textarea]', this.pemBundle);
|
|
await click('[data-test-pki-import-pem-bundle]');
|
|
|
|
assert.strictEqual(
|
|
currentURL(),
|
|
`/vault/secrets/${this.mountPath}/pki/configuration/create`,
|
|
'stays on page on success'
|
|
);
|
|
assert.dom(S.configuration.title).hasText('View imported items');
|
|
assert.dom(S.configuration.importForm).doesNotExist('import form is hidden after save');
|
|
assert.dom(S.configuration.importMapping).exists('import mapping is shown after save');
|
|
await click('[data-test-done]');
|
|
assert.strictEqual(
|
|
currentURL(),
|
|
`/vault/secrets/${this.mountPath}/pki/overview`,
|
|
'redirects to overview when done'
|
|
);
|
|
});
|
|
test('with many imports', async function (assert) {
|
|
this.server.post(`${this.mountPath}/config/ca`, () => {
|
|
return {
|
|
request_id: 'some-config-id',
|
|
data: {
|
|
imported_issuers: ['my-imported-issuer', 'imported2'],
|
|
imported_keys: ['my-imported-key', 'imported3'],
|
|
mapping: {
|
|
'my-imported-issuer': 'my-imported-key',
|
|
imported2: '',
|
|
},
|
|
},
|
|
};
|
|
});
|
|
await authPage.login(this.pkiAdminToken);
|
|
await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`);
|
|
await click(S.configuration.optionByKey('import'));
|
|
assert.dom(S.configuration.importForm).exists('import form is shown save');
|
|
await click('[data-test-text-toggle]');
|
|
await fillIn('[data-test-text-file-textarea]', this.pemBundle);
|
|
await click('[data-test-pki-import-pem-bundle]');
|
|
|
|
assert.strictEqual(
|
|
currentURL(),
|
|
`/vault/secrets/${this.mountPath}/pki/configuration/create`,
|
|
'stays on page on success'
|
|
);
|
|
assert.dom(S.configuration.title).hasText('View imported items');
|
|
assert.dom(S.configuration.importForm).doesNotExist('import form is hidden after save');
|
|
assert.dom(S.configuration.importMapping).exists('import mapping is shown after save');
|
|
assert.dom(S.configuration.importedIssuer).hasText('my-imported-issuer', 'Issuer value is displayed');
|
|
assert.dom(S.configuration.importedKey).hasText('my-imported-key', 'Key value is displayed');
|
|
await click('[data-test-done]');
|
|
assert.strictEqual(
|
|
currentURL(),
|
|
`/vault/secrets/${this.mountPath}/pki/overview`,
|
|
'redirects to overview when done'
|
|
);
|
|
});
|
|
test('shows imported items when keys is empty', async function (assert) {
|
|
this.server.post(`${this.mountPath}/config/ca`, () => {
|
|
return {
|
|
request_id: 'some-config-id',
|
|
data: {
|
|
imported_issuers: ['my-imported-issuer', 'my-imported-issuer2'],
|
|
imported_keys: null,
|
|
mapping: {
|
|
'my-imported-issuer': '',
|
|
'my-imported-issuer2': '',
|
|
},
|
|
},
|
|
};
|
|
});
|
|
await authPage.login(this.pkiAdminToken);
|
|
await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`);
|
|
await click(S.configuration.optionByKey('import'));
|
|
assert.dom(S.configuration.importForm).exists('import form is shown save');
|
|
await click('[data-test-text-toggle]');
|
|
await fillIn('[data-test-text-file-textarea]', this.pemBundle);
|
|
await click('[data-test-pki-import-pem-bundle]');
|
|
|
|
assert.dom(S.configuration.importForm).doesNotExist('import form is hidden after save');
|
|
assert.dom(S.configuration.importMapping).exists('import mapping is shown after save');
|
|
assert.dom(S.configuration.importedIssuer).hasText('my-imported-issuer', 'Issuer value is displayed');
|
|
assert.dom(S.configuration.importedKey).hasText('None', 'Shows placeholder value for key');
|
|
});
|
|
test('shows None for imported items if nothing new imported', async function (assert) {
|
|
this.server.post(`${this.mountPath}/config/ca`, () => {
|
|
return {
|
|
request_id: 'some-config-id',
|
|
data: {
|
|
imported_issuers: null,
|
|
imported_keys: null,
|
|
mapping: {},
|
|
},
|
|
};
|
|
});
|
|
await authPage.login(this.pkiAdminToken);
|
|
await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`);
|
|
await click(S.configuration.optionByKey('import'));
|
|
assert.dom(S.configuration.importForm).exists('import form is shown save');
|
|
await click('[data-test-text-toggle]');
|
|
await fillIn('[data-test-text-file-textarea]', this.pemBundle);
|
|
await click('[data-test-pki-import-pem-bundle]');
|
|
|
|
assert.dom(S.configuration.importForm).doesNotExist('import form is hidden after save');
|
|
assert.dom(S.configuration.importMapping).exists('import mapping is shown after save');
|
|
assert.dom(S.configuration.importedIssuer).hasText('None', 'Shows placeholder value for issuer');
|
|
assert.dom(S.configuration.importedKey).hasText('None', 'Shows placeholder value for key');
|
|
});
|
|
});
|
|
|
|
module('generate root', function () {
|
|
test('happy path', async function (assert) {
|
|
const commonName = 'my-common-name';
|
|
const issuerName = 'my-first-issuer';
|
|
const keyName = 'my-first-key';
|
|
await authPage.login();
|
|
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
|
|
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
|
|
await click(S.emptyStateLink);
|
|
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration/create`);
|
|
assert.dom(S.configuration.title).hasText('Configure PKI');
|
|
assert.dom(S.configuration.emptyState).exists({ count: 1 }, 'Shows empty state by default');
|
|
await click(S.configuration.optionByKey('generate-root'));
|
|
assert.dom(S.configuration.emptyState).doesNotExist();
|
|
// The URLs section is populated based on params returned from OpenAPI. This test will break when
|
|
// the backend adds fields. We should update the count accordingly.
|
|
assert.dom(S.configuration.urlField).exists({ count: 4 });
|
|
// Fill in form
|
|
await fillIn(S.configuration.typeField, 'internal');
|
|
await typeIn(S.configuration.inputByName('commonName'), commonName);
|
|
await typeIn(S.configuration.inputByName('issuerName'), issuerName);
|
|
await click(S.configuration.keyParamsGroupToggle);
|
|
await typeIn(S.configuration.inputByName('keyName'), keyName);
|
|
await click(S.configuration.generateRootSave);
|
|
|
|
assert.strictEqual(
|
|
currentURL(),
|
|
`/vault/secrets/${this.mountPath}/pki/configuration/create`,
|
|
'stays on page on success'
|
|
);
|
|
assert.dom(S.configuration.title).hasText('View root certificate');
|
|
assert.dom('[data-test-alert-banner="alert"]').doesNotExist('no private key warning');
|
|
assert.dom(S.configuration.title).hasText('View root certificate', 'Updates title on page');
|
|
assert.dom(S.configuration.saved.certificate).hasClass('allow-copy', 'copyable certificate is masked');
|
|
assert.dom(S.configuration.saved.issuerName).hasText(issuerName);
|
|
assert.dom(S.configuration.saved.issuerLink).exists('Issuer link exists');
|
|
assert.dom(S.configuration.saved.keyLink).exists('Key link exists');
|
|
assert.dom(S.configuration.saved.keyName).hasText(keyName);
|
|
assert.dom('[data-test-done]').exists('Done button exists');
|
|
// Check that linked issuer has correct common name
|
|
await click(S.configuration.saved.issuerLink);
|
|
assert.dom(S.issuerDetails.valueByName('Common name')).hasText(commonName);
|
|
});
|
|
test('type=exported', async function (assert) {
|
|
const commonName = 'my-exported-name';
|
|
await authPage.login();
|
|
await visit(`/vault/secrets/${this.mountPath}/pki/configuration/create`);
|
|
await click(S.configuration.optionByKey('generate-root'));
|
|
// Fill in form
|
|
await fillIn(S.configuration.typeField, 'exported');
|
|
await typeIn(S.configuration.inputByName('commonName'), commonName);
|
|
await click(S.configuration.generateRootSave);
|
|
|
|
assert.strictEqual(
|
|
currentURL(),
|
|
`/vault/secrets/${this.mountPath}/pki/configuration/create`,
|
|
'stays on page on success'
|
|
);
|
|
assert.dom(S.configuration.title).hasText('View root certificate');
|
|
assert
|
|
.dom('[data-test-alert-banner="alert"]')
|
|
.hasText('Next steps The private_key is only available once. Make sure you copy and save it now.');
|
|
assert.dom(S.configuration.title).hasText('View root certificate', 'Updates title on page');
|
|
assert
|
|
.dom(S.configuration.saved.certificate)
|
|
.hasClass('allow-copy', 'copyable masked certificate exists');
|
|
assert
|
|
.dom(S.configuration.saved.issuerName)
|
|
.doesNotExist('Issuer name not shown because it was not named');
|
|
assert.dom(S.configuration.saved.issuerLink).exists('Issuer link exists');
|
|
assert.dom(S.configuration.saved.keyLink).exists('Key link exists');
|
|
assert
|
|
.dom(S.configuration.saved.privateKey)
|
|
.hasClass('allow-copy', 'copyable masked private key exists');
|
|
assert.dom(S.configuration.saved.keyName).doesNotExist('Key name not shown because it was not named');
|
|
assert.dom('[data-test-done]').exists('Done button exists');
|
|
// Check that linked issuer has correct common name
|
|
await click(S.configuration.saved.issuerLink);
|
|
assert.dom(S.issuerDetails.valueByName('Common name')).hasText(commonName);
|
|
});
|
|
});
|
|
|
|
module('generate CSR', function () {
|
|
test('happy path', async function (assert) {
|
|
await authPage.login();
|
|
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
|
|
await click(S.emptyStateLink);
|
|
assert.dom(S.configuration.title).hasText('Configure PKI');
|
|
await click(S.configuration.optionByKey('generate-csr'));
|
|
await fillIn(S.configuration.typeField, 'internal');
|
|
await fillIn(S.configuration.inputByName('commonName'), 'my-common-name');
|
|
await click('[data-test-save]');
|
|
assert.dom(S.configuration.title).hasText('View generated CSR');
|
|
await assert.dom(S.configuration.csrDetails).exists('renders CSR details after save');
|
|
await click('[data-test-done]');
|
|
assert.strictEqual(
|
|
currentURL(),
|
|
`/vault/secrets/${this.mountPath}/pki/overview`,
|
|
'Transitions to overview after viewing csr details'
|
|
);
|
|
});
|
|
test('type = exported', async function (assert) {
|
|
await authPage.login();
|
|
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
|
|
await click(S.emptyStateLink);
|
|
await click(S.configuration.optionByKey('generate-csr'));
|
|
await fillIn(S.configuration.typeField, 'exported');
|
|
await fillIn(S.configuration.inputByName('commonName'), 'my-common-name');
|
|
await click('[data-test-save]');
|
|
await assert.dom(S.configuration.csrDetails).exists('renders CSR details after save');
|
|
assert.dom(S.configuration.title).hasText('View generated CSR');
|
|
assert
|
|
.dom('[data-test-alert-banner="alert"]')
|
|
.hasText(
|
|
'Next steps Copy the CSR below for a parent issuer to sign and then import the signed certificate back into this mount. The private_key is only available once. Make sure you copy and save it now.'
|
|
);
|
|
assert
|
|
.dom(S.configuration.saved.privateKey)
|
|
.hasClass('allow-copy', 'copyable masked private key exists');
|
|
await click('[data-test-done]');
|
|
assert.strictEqual(
|
|
currentURL(),
|
|
`/vault/secrets/${this.mountPath}/pki/overview`,
|
|
'Transitions to overview after viewing csr details'
|
|
);
|
|
});
|
|
});
|
|
});
|