c3c67f68da
* move selectors to helper file * wip cross sign acceptance tests * finish tests
112 lines
5.7 KiB
JavaScript
112 lines
5.7 KiB
JavaScript
/**
|
|
* Copyright (c) HashiCorp, Inc.
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*/
|
|
|
|
import { module, test } from 'qunit';
|
|
import { visit, click, fillIn, find } from '@ember/test-helpers';
|
|
import { setupApplicationTest } from 'vault/tests/helpers';
|
|
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 } from 'vault/tests/helpers/pki/pki-issuer-cross-sign';
|
|
import { verifyCertificates } from 'vault/utils/parse-pki-cert';
|
|
module('Acceptance | pki/pki cross sign', function (hooks) {
|
|
setupApplicationTest(hooks);
|
|
|
|
hooks.beforeEach(async function () {
|
|
await authPage.login();
|
|
this.parentMountPath = `parent-mount-${uuidv4()}`;
|
|
this.oldParentIssuerName = 'old-parent-issuer'; // old parent issuer we're transferring from
|
|
this.parentIssuerName = 'new-parent-issuer'; // issuer where cross-signing action will begin
|
|
this.intMountPath = `intermediate-mount-${uuidv4()}`; // first input box in cross-signing page
|
|
this.intIssuerName = 'my-intermediate-issuer'; // second input box in cross-signing page
|
|
this.newlySignedIssuer = 'my-newly-signed-int'; // third input
|
|
await enablePage.enable('pki', this.parentMountPath);
|
|
await enablePage.enable('pki', this.intMountPath);
|
|
|
|
await runCommands([
|
|
`write "${this.parentMountPath}/root/generate/internal" common_name="Long-Lived Root X1" ttl=8960h issuer_name="${this.oldParentIssuerName}"`,
|
|
`write "${this.parentMountPath}/root/generate/internal" common_name="Long-Lived Root X2" ttl=8960h issuer_name="${this.parentIssuerName}"`,
|
|
`write "${this.parentMountPath}/config/issuers" default="${this.parentIssuerName}"`,
|
|
]);
|
|
});
|
|
|
|
hooks.afterEach(async function () {
|
|
// Cleanup engine
|
|
await runCommands([`delete sys/mounts/${this.intMountPath}`]);
|
|
await runCommands([`delete sys/mounts/${this.parentMountPath}`]);
|
|
await logout.visit();
|
|
});
|
|
|
|
test('it cross-signs an issuer', async function (assert) {
|
|
// configure parent and intermediate mounts to make them cross-signable
|
|
await visit(`/vault/secrets/${this.intMountPath}/pki/configuration/create`);
|
|
await click(SELECTORS.configure.optionByKey('generate-csr'));
|
|
await fillIn(SELECTORS.inputByName('type'), 'internal');
|
|
await fillIn(SELECTORS.inputByName('commonName'), 'Short-Lived Int R1');
|
|
await click('[data-test-save]');
|
|
const csr = find(SELECTORS.copyButton('CSR')).getAttribute('data-clipboard-text');
|
|
await visit(`vault/secrets/${this.parentMountPath}/pki/issuers/${this.oldParentIssuerName}/sign`);
|
|
await fillIn(SELECTORS.inputByName('csr'), csr);
|
|
await fillIn(SELECTORS.inputByName('format'), 'pem_bundle');
|
|
await click('[data-test-pki-sign-intermediate-save]');
|
|
const pemBundle = find(SELECTORS.copyButton('CA Chain'))
|
|
.getAttribute('data-clipboard-text')
|
|
.replace(/,/, '\n');
|
|
await visit(`vault/secrets/${this.intMountPath}/pki/configuration/create`);
|
|
await click(SELECTORS.configure.optionByKey('import'));
|
|
await click('[data-test-text-toggle]');
|
|
await fillIn('[data-test-text-file-textarea]', pemBundle);
|
|
await click(SELECTORS.configure.importSubmit);
|
|
await visit(`vault/secrets/${this.intMountPath}/pki/issuers`);
|
|
await click('[data-test-is-default]');
|
|
// name default issuer of intermediate
|
|
const oldIntIssuerId = find(SELECTORS.rowValue('Issuer ID')).innerText;
|
|
const oldIntCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-clipboard-text');
|
|
await click(SELECTORS.details.configure);
|
|
await fillIn(SELECTORS.inputByName('issuerName'), this.intIssuerName);
|
|
await click('[data-test-save]');
|
|
|
|
// perform cross-sign
|
|
await visit(`vault/secrets/${this.parentMountPath}/pki/issuers/${this.parentIssuerName}/cross-sign`);
|
|
await fillIn(SELECTORS.objectListInput('intermediateMount'), this.intMountPath);
|
|
await fillIn(SELECTORS.objectListInput('intermediateIssuer'), this.intIssuerName);
|
|
await fillIn(SELECTORS.objectListInput('newCrossSignedIssuer'), this.newlySignedIssuer);
|
|
await click(SELECTORS.submitButton);
|
|
assert
|
|
.dom(`${SELECTORS.signedIssuerCol('intermediateMount')} a`)
|
|
.hasAttribute('href', `/ui/vault/secrets/${this.intMountPath}/pki/overview`);
|
|
assert
|
|
.dom(`${SELECTORS.signedIssuerCol('intermediateIssuer')} a`)
|
|
.hasAttribute('href', `/ui/vault/secrets/${this.intMountPath}/pki/issuers/${oldIntIssuerId}/details`);
|
|
|
|
// get certificate data of newly signed issuer
|
|
await click(`${SELECTORS.signedIssuerCol('newCrossSignedIssuer')} a`);
|
|
const newIntCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-clipboard-text');
|
|
|
|
// verify cross-sign was accurate by creating a role to issue a leaf certificate
|
|
const myRole = 'some-role';
|
|
await runCommands([
|
|
`write ${this.intMountPath}/roles/${myRole} \
|
|
issuer_ref=${this.newlySignedIssuer}\
|
|
allow_any_name=true \
|
|
max_ttl="720h"`,
|
|
]);
|
|
await visit(`vault/secrets/${this.intMountPath}/pki/roles/${myRole}/generate`);
|
|
await fillIn(SELECTORS.inputByName('commonName'), 'my-leaf');
|
|
await fillIn('[data-test-ttl-value="TTL"]', '3600');
|
|
await click('[data-test-pki-generate-button]');
|
|
const myLeafCert = find(SELECTORS.copyButton('Certificate')).getAttribute('data-clipboard-text');
|
|
|
|
// see comments in utils/parse-pki-cert.js for step-by-step explanation of of verifyCertificates method
|
|
assert.true(
|
|
await verifyCertificates(oldIntCert, newIntCert, myLeafCert),
|
|
'the leaf certificate validates against both intermediate certificates'
|
|
);
|
|
});
|
|
});
|