vault/ui/tests/integration/components/pki/pki-issuer-cross-sign-test.js
Hamid Ghaf e55c18ed12
adding copyright header (#19555)
* adding copyright header

* fix fmt and a test
2023-03-15 09:00:52 -07:00

355 lines
13 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, render } from '@ember/test-helpers';
import { setupEngine } from 'ember-engines/test-support';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { Response } from 'miragejs';
import { hbs } from 'ember-cli-htmlbars';
import {
intIssuerCert,
newCSR,
newlySignedCert,
oldParentIssuerCert,
parentIssuerCert,
unsupportedOids,
} from 'vault/tests/helpers/pki/values';
const SELECTORS = {
input: (key, row = 0) => `[data-test-object-list-input="${key}-${row}"]`,
addRow: '[data-test-object-list-add-button',
submitButton: '[data-test-cross-sign-submit]',
cancelButton: '[data-test-cross-sign-cancel]',
statusCount: '[data-test-cross-sign-status-count]',
signedIssuerRow: (row = 0) => `[data-test-info-table-row="${row}"]`,
signedIssuerCol: (attr) => `[data-test-info-table-column="${attr}"]`,
};
const FIELDS = [
{
label: 'Mount path',
key: 'intermediateMount',
placeholder: 'Mount path',
helpText: 'The mount in which your new certificate can be found.',
},
{
label: "Issuer's current name",
key: 'intermediateIssuer',
placeholder: 'Current issuer name',
helpText: 'The API name of the previous intermediate which was cross-signed.',
},
{
label: 'New issuer name',
key: 'newCrossSignedIssuer',
placeholder: 'Enter a new issuer name',
helpText: `This is your new issuers name in the API.`,
},
];
module('Integration | Component | pki issuer cross sign', function (hooks) {
setupRenderingTest(hooks);
setupEngine(hooks, 'pki');
setupMirage(hooks);
hooks.beforeEach(async function () {
const store = this.owner.lookup('service:store');
this.backend = 'my-parent-issuer-mount';
this.intMountPath = 'int-mount';
this.owner.lookup('service:secret-mount-path').update(this.backend);
// parent issuer
this.parentIssuerData = {
ca_chain: [parentIssuerCert],
certificate: parentIssuerCert,
crl_distribution_points: [],
issuer_id: '0c983955-6426-22b2-1b3f-c0bdca40fd15',
issuer_name: 'my-parent-issuer-name',
issuing_certificates: [],
key_id: '8b8d0017-a067-ac50-c5cf-475876f9aac5',
leaf_not_after_behavior: 'err',
manual_chain: null,
ocsp_servers: [],
revocation_signature_algorithm: 'SHA256WithRSA',
revoked: false,
usage: 'crl-signing,issuing-certificates,ocsp-signing,read-only',
};
// intermediate issuer
this.intIssuerData = {
ca_chain: [intIssuerCert, oldParentIssuerCert],
certificate: intIssuerCert,
crl_distribution_points: [],
issuer_id: '6c286455-7904-5698-bf86-8aba81e680e6',
issuer_name: 'source-int-name',
issuing_certificates: [],
key_id: '2e2b8baf-4dac-c46f-cee4-8afbc7f2d8b2',
leaf_not_after_behavior: 'err',
manual_chain: null,
ocsp_servers: [],
revocation_signature_algorithm: '',
revoked: false,
usage: 'crl-signing,issuing-certificates,ocsp-signing,read-only',
};
// newly cross signed issuer
this.newIssuerData = {
ca_chain: [newlySignedCert, parentIssuerCert],
certificate: newlySignedCert,
crl_distribution_points: [],
issuer_id: 'bc159ba8-930c-c894-e871-2f3e889e8e02',
issuer_name: 'newly-cross-signed-cert',
issuing_certificates: [],
key_id: '2e2b8baf-4dac-c46f-cee4-8afbc7f2d8b2',
leaf_not_after_behavior: 'err',
manual_chain: null,
ocsp_servers: [],
revocation_signature_algorithm: '',
revoked: false,
usage: 'crl-signing,issuing-certificates,ocsp-signing,read-only',
};
this.testInputs = {
intermediateMount: this.intMountPath,
intermediateIssuer: this.intIssuerData.issuer_name,
newCrossSignedIssuer: this.newIssuerData.issuer_name,
};
store.pushPayload('pki/issuer', { modelName: 'pki/issuer', data: this.parentIssuerData });
this.parentIssuerModel = store.peekRecord('pki/issuer', this.parentIssuerData.issuer_id);
});
test('it makes requests to the correct endpoints', async function (assert) {
assert.expect(18);
this.server.get(`/${this.intMountPath}/issuer/${this.intIssuerData.issuer_name}`, () => {
assert.ok(true, 'Step 1. GET request is made to fetch existing issuer data');
return { data: this.intIssuerData };
});
this.server.post(`/${this.intMountPath}/intermediate/generate/existing`, (schema, req) => {
assert.ok(true, 'Step 2. POST request is made to generate new CSR');
assert.propEqual(
JSON.parse(req.requestBody),
{
common_name: newCSR.common_name,
country: null,
exclude_cn_from_sans: false,
format: 'pem',
locality: null,
organization: null,
ou: null,
province: null,
key_ref: this.intIssuerData.key_id,
},
'payload contains correct key ref'
);
return { data: { csr: newCSR.csr, key_id: this.intIssuerData.key_id } };
});
this.server.post(
`/${this.backend}/issuer/${this.parentIssuerData.issuer_name}/sign-intermediate`,
(schema, req) => {
assert.ok(true, 'Step 3. POST request is made to sign CSR with new parent issuer');
assert.propEqual(JSON.parse(req.requestBody), newCSR, 'payload has common name and csr');
return { data: { ca_chain: [newlySignedCert, parentIssuerCert] } };
}
);
this.server.post(`/${this.intMountPath}/issuers/import/bundle`, (schema, req) => {
assert.ok(true, 'Step 4. POST request made to import issuer');
assert.propEqual(
JSON.parse(req.requestBody),
{ pem_bundle: [newlySignedCert, parentIssuerCert].join('\n') },
'payload contains pem bundle'
);
return {
data: {
imported_issuers: null,
imported_keys: null,
mapping: { [this.newIssuerData.issuer_id]: this.intIssuerData.key_id },
},
};
});
this.server.get(`/${this.intMountPath}/issuer/${this.newIssuerData.issuer_id}`, () => {
assert.ok(true, 'Step 5. GET request is made to newly imported issuer');
return { data: this.newIssuerData };
});
this.server.post(`/${this.intMountPath}/issuer/${this.newIssuerData.issuer_id}`, (schema, req) => {
assert.ok(true, 'Step 6. POST request is made to update issuer name');
assert.propEqual(
JSON.parse(req.requestBody),
{
issuer_name: 'newly-cross-signed-cert',
leaf_not_after_behavior: 'err',
usage: 'crl-signing,issuing-certificates,ocsp-signing,read-only',
},
'payload has correct data '
);
return { data: this.newIssuerData };
});
await render(hbs`<PkiIssuerCrossSign @parentIssuer={{this.parentIssuerModel}} /> `, {
owner: this.engine,
});
// fill out form and submit
for (const field of FIELDS) {
await fillIn(SELECTORS.input(field.key), this.testInputs[field.key]);
}
await click(SELECTORS.submitButton);
assert.dom(SELECTORS.statusCount).hasText('Cross-signing complete (1 successful, 0 errors)');
assert
.dom(`${SELECTORS.signedIssuerRow()} [data-test-icon="check-circle"]`)
.exists('row has success icon');
for (const field of FIELDS) {
assert
.dom(`${SELECTORS.signedIssuerCol(field.key)}`)
.hasText(this.testInputs[field.key], `${field.key} displays correct value`);
assert.dom(`${SELECTORS.signedIssuerCol(field.key)} a`).hasTagName('a');
}
});
test('it cross-signs multiple certs', async function (assert) {
assert.expect(13);
const nonexistentIssuer = {
intermediateMount: this.intMountPath,
intermediateIssuer: 'some-fake-issuer',
newCrossSignedIssuer: 'failed-cert-1',
};
const unsupportedCert = {
intermediateMount: this.intMountPath,
intermediateIssuer: 'some-fancy-issuer',
newCrossSignedIssuer: 'failed-cert-2',
};
this.server.get(`/${this.intMountPath}/issuer/${this.intIssuerData.issuer_name}`, () => {
assert.ok(true, 'request is made to sign first cert');
return { data: this.intIssuerData };
});
this.server.get(`/${this.intMountPath}/issuer/${nonexistentIssuer.intermediateIssuer}`, () => {
assert.ok(true, 'request is made to second cert');
return new Response(
500,
{ 'Content-Type': 'application/json' },
JSON.stringify({
errors: [
`1 error occurred:\n\t* unable to find PKI issuer for reference: ${nonexistentIssuer.intermediateIssuer}\n\n`,
],
})
);
});
this.server.get(`/${this.intMountPath}/issuer/${unsupportedCert.intermediateIssuer}`, () => {
assert.ok(true, 'request is made to third cert');
return { data: { isser_name: unsupportedCert.intermediateIssuer, certificate: unsupportedOids } };
});
await render(hbs`<PkiIssuerCrossSign @parentIssuer={{this.parentIssuerModel}} /> `, {
owner: this.engine,
});
// fill out form and submit
for (const field of FIELDS) {
await fillIn(SELECTORS.input(field.key), this.testInputs[field.key]);
}
await click(SELECTORS.addRow);
for (const field of FIELDS) {
await fillIn(SELECTORS.input(field.key, 1), nonexistentIssuer[field.key]);
}
await click(SELECTORS.addRow);
for (const field of FIELDS) {
await fillIn(SELECTORS.input(field.key, 2), unsupportedCert[field.key]);
}
await click(SELECTORS.submitButton);
assert.dom(SELECTORS.statusCount).hasText('Cross-signing complete (0 successful, 3 errors)');
for (const field of FIELDS) {
assert
.dom(`${SELECTORS.signedIssuerRow()} ${SELECTORS.signedIssuerCol(field.key)}`)
.hasText(this.testInputs[field.key], `first row has correct values`);
}
for (const field of FIELDS) {
assert
.dom(`${SELECTORS.signedIssuerRow(1)} ${SELECTORS.signedIssuerCol(field.key)}`)
.hasText(nonexistentIssuer[field.key], `second row has correct values`);
}
for (const field of FIELDS) {
assert
.dom(`${SELECTORS.signedIssuerRow(2)} ${SELECTORS.signedIssuerCol(field.key)}`)
.hasText(unsupportedCert[field.key], `third row has correct values`);
}
});
test('it returns API errors when a request fails', async function (assert) {
assert.expect(7);
this.server.get(`/${this.intMountPath}/issuer/${this.intIssuerData.issuer_name}`, () => {
return new Response(
500,
{ 'Content-Type': 'application/json' },
JSON.stringify({
errors: ['1 error occurred:\n\t* unable to find PKI issuer for reference: nonexistent-mount\n\n'],
})
);
});
await render(hbs`<PkiIssuerCrossSign @parentIssuer={{this.parentIssuerModel}} /> `, {
owner: this.engine,
});
// fill out form and submit
for (const field of FIELDS) {
await fillIn(SELECTORS.input(field.key), this.testInputs[field.key]);
}
await click(SELECTORS.submitButton);
assert.dom(SELECTORS.statusCount).hasText('Cross-signing complete (0 successful, 1 error)');
assert
.dom(`${SELECTORS.signedIssuerRow()} [data-test-icon="alert-circle-fill"]`)
.exists('row has failure icon');
assert.dom('[data-test-alert-banner="alert"] .message-title').hasText('Cross-sign failed');
assert
.dom('[data-test-alert-banner="alert"] .alert-banner-message-body')
.hasText('1 error occurred: * unable to find PKI issuer for reference: nonexistent-mount');
for (const field of FIELDS) {
assert
.dom(`${SELECTORS.signedIssuerCol(field.key)}`)
.hasText(this.testInputs[field.key], `${field.key} displays correct value`);
}
});
test('it returns an error when a certificate contains unsupported values', async function (assert) {
assert.expect(7);
const unsupportedIssuerCert = { ...this.intIssuerData, certificate: unsupportedOids };
this.server.get(`/${this.intMountPath}/issuer/${this.intIssuerData.issuer_name}`, () => {
return { data: unsupportedIssuerCert };
});
await render(hbs`<PkiIssuerCrossSign @parentIssuer={{this.parentIssuerModel}} /> `, {
owner: this.engine,
});
// fill out form and submit
for (const field of FIELDS) {
await fillIn(SELECTORS.input(field.key), this.testInputs[field.key]);
}
await click(SELECTORS.submitButton);
assert.dom(SELECTORS.statusCount).hasText('Cross-signing complete (0 successful, 1 error)');
assert
.dom(`${SELECTORS.signedIssuerRow()} [data-test-icon="alert-circle-fill"]`)
.exists('row has failure icon');
assert
.dom('[data-test-alert-banner="alert"] .message-title')
.hasText('Certificate must be manually cross-signed using the CLI.');
assert
.dom('[data-test-alert-banner="alert"] .alert-banner-message-body')
.hasText(
'certificate contains unsupported subject OIDs: 1.2.840.113549.1.9.1, certificate contains unsupported extension OIDs: 2.5.29.37'
);
for (const field of FIELDS) {
assert
.dom(`${SELECTORS.signedIssuerCol(field.key)}`)
.hasText(this.testInputs[field.key], `${field.key} displays correct value`);
}
});
});