vault/ui/tests/integration/components/pki/page/pki-issuer-rotate-root-test.js
claire bontempo 0496c6107b
UI: pki rotate root cert (#19739)
* add rotate root route

* add page component

* add modal

* fix modal image styling

* add radio buttons

* add jsonToCert function to pki parser

* add verify function

* add verify to details route

* nest rotate-root under issuer/

* copy values from old root ca

* pull detail info rows into a separate component

* add type declaration files

* add parsing error warning to rotate root component file

* add comments

* add capabilities to controller

* update icon

* revert issuer details

* refactor pki info table rows

* add parsedparameters to pki helper

* add alert banner

* update attrs, fix info rows

* add endpoint to action router

* update alert banner

* hide toolbar from generate root display

* add download buttons to toolbar

* add banner getter

* fix typo in issuer details

* fix assertion

* move alert banner after generating root to parent

* rename issuer index route file

* refactor routing so model can be passed from route

* add confirmLeave and done button to use existin settings done form

* rename serial number to differentiate between two types

* fix links, update ids to issuerId not response id

* update ts declaration

* change variable names add comments

* update existing tests

* fix comment typo

* add download button test

* update serializer to change subject_serial_number to serial_number for backend

* remove pageTitle getter

* remove old arg

* round 1 of testing complete..

* finish endpoint tests

* finish component tests

* move toolbars to parent route

* add acceptance test for rotate route

* add const to hold radio button string values

* remove action, fix link
2023-03-31 15:47:23 -06:00

258 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import { module, test } from 'qunit';
import { setupRenderingTest } from 'vault/tests/helpers';
import { click, fillIn, findAll, render } from '@ember/test-helpers';
import { setupEngine } from 'ember-engines/test-support';
import { setupMirage } from 'ember-cli-mirage/test-support';
import sinon from 'sinon';
import { hbs } from 'ember-cli-htmlbars';
import { loadedCert } from 'vault/tests/helpers/pki/values';
import camelizeKeys from 'vault/utils/camelize-object-keys';
import { parseCertificate } from 'vault/utils/parse-pki-cert';
import { SELECTORS as S } from 'vault/tests/helpers/pki/pki-generate-root';
const SELECTORS = {
pageTitle: '[data-test-pki-page-title]',
alertBanner: '[data-test-alert-banner="alert"]',
toolbarCrossSign: '[data-test-pki-issuer-cross-sign]',
toolbarSignInt: '[data-test-pki-issuer-sign-int]',
toolbarDownload: '[data-test-issuer-download]',
oldRadioSelect: 'input#use-old-root-settings',
customRadioSelect: 'input#customize-new-root-certificate',
toggle: '[data-test-details-toggle]',
input: (attr) => `[data-test-input="${attr}"]`,
infoRowValue: (attr) => `[data-test-value-div="${attr}"]`,
validationError: '[data-test-pki-rotate-root-validation-error]',
rotateRootForm: '[data-test-pki-rotate-old-settings-form]',
rotateRootSave: '[data-test-pki-rotate-root-save]',
rotateRootCancel: '[data-test-pki-rotate-root-cancel]',
doneButton: '[data-test-done]',
// root form
generateRootForm: '[data-test-pki-config-generate-root-form]',
...S,
};
module('Integration | Component | page/pki-issuer-rotate-root', function (hooks) {
setupRenderingTest(hooks);
setupEngine(hooks, 'pki');
setupMirage(hooks);
hooks.beforeEach(async function () {
this.store = this.owner.lookup('service:store');
this.backend = 'test-pki';
this.owner.lookup('service:secret-mount-path').update(this.backend);
this.onCancel = sinon.spy();
this.onComplete = sinon.spy();
this.breadcrumbs = [{ label: 'rotate root' }];
this.oldRootData = {
certificate: loadedCert,
issuer_id: 'old-issuer-id',
issuer_name: 'old-issuer',
};
this.parsedRootCert = camelizeKeys(parseCertificate(loadedCert));
this.store.pushPayload('pki/issuer', { modelName: 'pki/issuer', data: this.oldRootData });
this.oldRoot = this.store.peekRecord('pki/issuer', 'old-issuer-id');
this.newRootModel = this.store.createRecord('pki/action', {
actionType: 'rotate-root',
type: 'internal',
...this.parsedRootCert, // copy old root settings over to new one
});
this.returnedData = {
id: 'response-id',
certificate: loadedCert,
expiration: 1682735724,
issuer_id: 'some-issuer-id',
issuer_name: 'my issuer',
issuing_ca: loadedCert,
key_id: 'my-key-id',
key_name: 'my-key',
serial_number: '3a:3c:17:..',
};
});
test('it renders', async function (assert) {
assert.expect(17);
await render(
hbs`
<Page::PkiIssuerRotateRoot
@oldRoot={{this.oldRoot}}
@newRootModel={{this.newRootModel}}
@breadcrumbs={{this.breadcrumbs}}
@onCancel={{this.onCancel}}
@onComplete={{this.onComplete}}
/>
`,
{ owner: this.engine }
);
assert.dom(SELECTORS.pageTitle).hasText('Generate new root');
assert.dom(SELECTORS.oldRadioSelect).isChecked('defaults to use-old-settings');
assert.dom(SELECTORS.rotateRootForm).exists('it renders old settings form');
assert
.dom(SELECTORS.input('commonName'))
.hasValue(this.parsedRootCert.commonName, 'common name prefilled with root cert cn');
assert.dom(SELECTORS.toggle).hasText('Old root settings', 'toggle renders correct text');
assert.dom(SELECTORS.input('issuerName')).exists('renders issuer name input');
assert.strictEqual(findAll('[data-test-row-label]').length, 0, 'it hides the old root info table rows');
await click(SELECTORS.toggle);
assert.strictEqual(findAll('[data-test-row-label]').length, 11, 'it shows the old root info table rows');
assert
.dom(SELECTORS.infoRowValue('Issuer name'))
.hasText(this.oldRoot.issuerName, 'renders correct issuer data');
await click(SELECTORS.toggle);
assert.strictEqual(findAll('[data-test-row-label]').length, 0, 'it hides again');
// customize form
await click(SELECTORS.customRadioSelect);
assert.dom(SELECTORS.generateRootForm).exists('it renders generate root form');
assert
.dom(SELECTORS.input('permittedDnsDomains'))
.hasValue(this.parsedRootCert.permittedDnsDomains, 'form is prefilled with values from old root');
await click(SELECTORS.generateRootCancel);
assert.ok(this.onCancel.calledOnce, 'custom form calls @onCancel passed from parent');
await click(SELECTORS.oldRadioSelect);
await click(SELECTORS.rotateRootCancel);
assert.ok(this.onCancel.calledTwice, 'old root settings form calls @onCancel from parent');
// validations
await fillIn(SELECTORS.input('commonName'), '');
await fillIn(SELECTORS.input('issuerName'), 'default');
await click(SELECTORS.rotateRootSave);
assert.dom(SELECTORS.validationError).hasText('There are 2 errors with this form.');
assert.dom(SELECTORS.input('commonName')).hasClass('has-error-border', 'common name has error border');
assert.dom(SELECTORS.input('issuerName')).hasClass('has-error-border', 'issuer name has error border');
});
test('it sends request to rotate/internal on save when using old root settings', async function (assert) {
assert.expect(1);
this.server.post(`/${this.backend}/root/rotate/internal`, () => {
assert.ok('request made to correct default endpoint type=internal');
});
await render(
hbs`
<Page::PkiIssuerRotateRoot
@oldRoot={{this.oldRoot}}
@newRootModel={{this.newRootModel}}
@breadcrumbs={{this.breadcrumbs}}
@onCancel={{this.onCancel}}
@onComplete={{this.onComplete}}
/>
`,
{ owner: this.engine }
);
await click(SELECTORS.rotateRootSave);
});
function testEndpoint(test, type) {
test(`it sends request to rotate/${type} endpoint on save with custom root settings`, async function (assert) {
assert.expect(1);
this.server.post(`/${this.backend}/root/rotate/${type}`, () => {
assert.ok('request is made to correct endpoint');
});
await render(
hbs`
<Page::PkiIssuerRotateRoot
@oldRoot={{this.oldRoot}}
@newRootModel={{this.newRootModel}}
@breadcrumbs={{this.breadcrumbs}}
@onCancel={{this.onCancel}}
@onComplete={{this.onComplete}}
/>
`,
{ owner: this.engine }
);
await click(SELECTORS.customRadioSelect);
await fillIn(SELECTORS.typeField, type);
await click(SELECTORS.generateRootSave);
});
}
testEndpoint(test, 'internal');
testEndpoint(test, 'exported');
testEndpoint(test, 'existing');
testEndpoint(test, 'kms');
test('it renders details after save for exported key type', async function (assert) {
assert.expect(10);
const keyData = {
private_key: `-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAtc9yU`,
private_key_type: 'rsa',
};
this.store.pushPayload('pki/action', {
modelName: 'pki/action',
data: { ...this.returnedData, ...keyData },
});
this.newRootModel = this.store.peekRecord('pki/action', 'response-id');
await render(
hbs`
<Page::PkiIssuerRotateRoot
@oldRoot={{this.oldRoot}}
@newRootModel={{this.newRootModel}}
@breadcrumbs={{this.breadcrumbs}}
@onCancel={{this.onCancel}}
@onComplete={{this.onComplete}}
/>
`,
{ owner: this.engine }
);
assert.dom(SELECTORS.pageTitle).hasText('View issuer certificate');
assert
.dom(SELECTORS.alertBanner)
.hasText(
'Next steps Your new root has been generated. Make sure to copy and save the private_key as it is only available once. If youre ready, you can begin cross-signing issuers now. If not, the option to cross-sign is available when you use this certificate. Cross-sign issuers'
);
assert.dom(SELECTORS.infoRowValue('Certificate')).exists();
assert.dom(SELECTORS.infoRowValue('Issuer name')).exists();
assert.dom(SELECTORS.infoRowValue('Issuing CA')).exists();
assert.dom(`${SELECTORS.infoRowValue('Private key')} .masked-input`).hasClass('allow-copy');
assert.dom(`${SELECTORS.infoRowValue('Private key type')} span`).hasText('rsa');
assert.dom(SELECTORS.infoRowValue('Serial number')).hasText(this.returnedData.serial_number);
assert.dom(SELECTORS.infoRowValue('Key ID')).hasText(this.returnedData.key_id);
await click(SELECTORS.doneButton);
assert.ok(this.onComplete.calledOnce, 'clicking done fires @onComplete from parent');
});
test('it renders details after save for internal key type', async function (assert) {
assert.expect(13);
this.store.pushPayload('pki/action', {
modelName: 'pki/action',
data: this.returnedData,
});
this.newRootModel = this.store.peekRecord('pki/action', 'response-id');
await render(
hbs`
<Page::PkiIssuerRotateRoot
@oldRoot={{this.oldRoot}}
@newRootModel={{this.newRootModel}}
@breadcrumbs={{this.breadcrumbs}}
@onCancel={{this.onCancel}}
@onComplete={{this.onComplete}}
/>
`,
{ owner: this.engine }
);
assert.dom(SELECTORS.pageTitle).hasText('View issuer certificate');
assert.dom(SELECTORS.toolbarCrossSign).exists();
assert.dom(SELECTORS.toolbarSignInt).exists();
assert.dom(SELECTORS.toolbarDownload).exists();
assert
.dom(SELECTORS.alertBanner)
.hasText(
'Next steps Your new root has been generated. If youre ready, you can begin cross-signing issuers now. If not, the option to cross-sign is available when you use this certificate. Cross-sign issuers'
);
assert.dom(SELECTORS.infoRowValue('Certificate')).exists();
assert.dom(SELECTORS.infoRowValue('Issuer name')).exists();
assert.dom(SELECTORS.infoRowValue('Issuing CA')).exists();
assert.dom(`${SELECTORS.infoRowValue('Private key')} span`).hasText('internal');
assert.dom(`${SELECTORS.infoRowValue('Private key type')} span`).hasText('internal');
assert.dom(SELECTORS.infoRowValue('Serial number')).hasText(this.returnedData.serial_number);
assert.dom(SELECTORS.infoRowValue('Key ID')).hasText(this.returnedData.key_id);
await click(SELECTORS.doneButton);
assert.ok(this.onComplete.calledOnce, 'clicking done fires @onComplete from parent');
});
});