backport UI: PKI show missing info on generated cert (#21652)
Co-authored-by: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com>
This commit is contained in:
parent
4c3c3ebb2a
commit
d2b396bd2a
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:bug
|
||||||
|
ui: Adds missing values to details view after generating PKI certificate
|
||||||
|
```
|
|
@ -87,8 +87,8 @@ export default class PkiCertificateBaseModel extends Model {
|
||||||
@attr('string', { masked: true }) certificate;
|
@attr('string', { masked: true }) certificate;
|
||||||
@attr('number') expiration;
|
@attr('number') expiration;
|
||||||
@attr('string', { label: 'Issuing CA', masked: true }) issuingCa;
|
@attr('string', { label: 'Issuing CA', masked: true }) issuingCa;
|
||||||
@attr('string') privateKey; // only returned for type=exported
|
@attr('string', { masked: true }) privateKey; // only returned for type=exported and /issue
|
||||||
@attr('string') privateKeyType; // only returned for type=exported
|
@attr('string') privateKeyType; // only returned for type=exported and /issue
|
||||||
@attr('number', { formatDate: true }) revocationTime;
|
@attr('number', { formatDate: true }) revocationTime;
|
||||||
@attr('string') serialNumber;
|
@attr('string') serialNumber;
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,18 @@ const generateFromRole = [
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@withFormFields(null, generateFromRole)
|
// Extra fields returned on the /issue endpoint
|
||||||
|
const certDisplayFields = [
|
||||||
|
'certificate',
|
||||||
|
'commonName',
|
||||||
|
'revocationTime',
|
||||||
|
'serialNumber',
|
||||||
|
'caChain',
|
||||||
|
'issuingCa',
|
||||||
|
'privateKey',
|
||||||
|
'privateKeyType',
|
||||||
|
];
|
||||||
|
@withFormFields(certDisplayFields, generateFromRole)
|
||||||
export default class PkiCertificateGenerateModel extends PkiCertificateBaseModel {
|
export default class PkiCertificateGenerateModel extends PkiCertificateBaseModel {
|
||||||
getHelpUrl(backend) {
|
getHelpUrl(backend) {
|
||||||
return `/v1/${backend}/issue/example?help=1`;
|
return `/v1/${backend}/issue/example?help=1`;
|
||||||
|
|
|
@ -18,10 +18,23 @@
|
||||||
</ToolbarActions>
|
</ToolbarActions>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
|
|
||||||
|
{{#if @model.privateKey}}
|
||||||
|
<div class="has-top-margin-m">
|
||||||
|
<Hds::Alert data-test-cert-detail-next-steps @type="inline" @color="highlight" class="has-bottom-margin-s" as |A|>
|
||||||
|
<A.Title>Next steps</A.Title>
|
||||||
|
<A.Description>
|
||||||
|
The
|
||||||
|
<code>private_key</code>
|
||||||
|
is only available once. Make sure you copy and save it now.
|
||||||
|
</A.Description>
|
||||||
|
</Hds::Alert>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{#each @model.formFields as |field|}}
|
{{#each @model.formFields as |field|}}
|
||||||
{{#if (eq field.name "certificate")}}
|
{{#if field.options.masked}}
|
||||||
<InfoTableRow @label="Certificate">
|
<InfoTableRow @label={{or field.options.label (capitalize (humanize (dasherize field.name)))}}>
|
||||||
<MaskedInput @value={{@model.certificate}} @displayOnly={{true}} @allowCopy={{true}} />
|
<MaskedInput @value={{or (get @model field.name) null}} @displayOnly={{true}} @allowCopy={{true}} />
|
||||||
</InfoTableRow>
|
</InfoTableRow>
|
||||||
{{else if (eq field.name "serialNumber")}}
|
{{else if (eq field.name "serialNumber")}}
|
||||||
<InfoTableRow @label="Serial number">
|
<InfoTableRow @label="Serial number">
|
||||||
|
|
|
@ -40,7 +40,25 @@ module('Integration | Component | pki | Page::PkiCertificateDetails', function (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
store.pushPayload('pki/certificate/generate', {
|
||||||
|
modelName: 'pki/certificate/generate',
|
||||||
|
data: {
|
||||||
|
certificate: '-----BEGIN CERTIFICATE-----',
|
||||||
|
ca_chain: '-----BEGIN CERTIFICATE-----',
|
||||||
|
issuer_ca: '-----BEGIN CERTIFICATE-----',
|
||||||
|
private_key: '-----BEGIN PRIVATE KEY-----',
|
||||||
|
private_key_type: 'rsa',
|
||||||
|
common_name: 'example.com Intermediate Authority',
|
||||||
|
issue_date: 1673540867000,
|
||||||
|
serial_number: id,
|
||||||
|
parsed_certificate: {
|
||||||
|
not_valid_after: 1831220897000,
|
||||||
|
not_valid_before: 1673540867000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
this.model = store.peekRecord('pki/certificate/base', id);
|
this.model = store.peekRecord('pki/certificate/base', id);
|
||||||
|
this.generatedModel = store.peekRecord('pki/certificate/generate', id);
|
||||||
|
|
||||||
this.server.post('/sys/capabilities-self', () => ({
|
this.server.post('/sys/capabilities-self', () => ({
|
||||||
data: {
|
data: {
|
||||||
|
@ -50,7 +68,7 @@ module('Integration | Component | pki | Page::PkiCertificateDetails', function (
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it should render actions and fields', async function (assert) {
|
test('it should render actions and fields for base cert', async function (assert) {
|
||||||
assert.expect(6);
|
assert.expect(6);
|
||||||
|
|
||||||
this.server.post('/pki/revoke', (schema, req) => {
|
this.server.post('/pki/revoke', (schema, req) => {
|
||||||
|
@ -90,6 +108,56 @@ module('Integration | Component | pki | Page::PkiCertificateDetails', function (
|
||||||
assert.dom('[data-test-value-div="Revocation time"]').exists('Revocation time is displayed');
|
assert.dom('[data-test-value-div="Revocation time"]').exists('Revocation time is displayed');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('it should render actions and fields for generated cert', async function (assert) {
|
||||||
|
assert.expect(10);
|
||||||
|
|
||||||
|
this.server.post('/pki/revoke', (schema, req) => {
|
||||||
|
const data = JSON.parse(req.requestBody);
|
||||||
|
assert.strictEqual(
|
||||||
|
data.serial_number,
|
||||||
|
this.model.serialNumber,
|
||||||
|
'Revoke request made with serial number'
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
revocation_time: 1673972804,
|
||||||
|
revocation_time_rfc3339: '2023-01-17T16:26:44.960933411Z',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
await render(hbs`<Page::PkiCertificateDetails @model={{this.generatedModel}} />`, { owner: this.engine });
|
||||||
|
assert.dom('[data-test-cert-detail-next-steps]').exists('Private key next steps warning shows');
|
||||||
|
assert
|
||||||
|
.dom('[data-test-component="info-table-row"]')
|
||||||
|
.exists({ count: 9 }, 'Correct number of fields render when certificate has not been revoked');
|
||||||
|
assert
|
||||||
|
.dom('[data-test-value-div="Certificate"] [data-test-masked-input]')
|
||||||
|
.exists('Masked input renders for certificate');
|
||||||
|
assert.dom('[data-test-value-div="Serial number"] code').exists('Serial number renders as monospace');
|
||||||
|
assert
|
||||||
|
.dom('[data-test-value-div="CA Chain"] [data-test-masked-input]')
|
||||||
|
.exists('CA Chain shows with masked value');
|
||||||
|
assert
|
||||||
|
.dom('[data-test-value-div="Issuing CA"] [data-test-masked-input]')
|
||||||
|
.exists('Issuing CA shows with masked value');
|
||||||
|
assert
|
||||||
|
.dom('[data-test-value-div="Private key"] [data-test-masked-input]')
|
||||||
|
.exists('Private key shows with masked value');
|
||||||
|
|
||||||
|
await click('[data-test-pki-cert-download-button]');
|
||||||
|
const { serialNumber, certificate } = this.model;
|
||||||
|
assert.ok(
|
||||||
|
this.downloadSpy.calledWith(serialNumber.replace(/(\s|:)+/g, '-'), certificate),
|
||||||
|
'Download pem method called with correct args'
|
||||||
|
);
|
||||||
|
|
||||||
|
await click('[data-test-confirm-action-trigger]');
|
||||||
|
await click('[data-test-confirm-button]');
|
||||||
|
|
||||||
|
assert.dom('[data-test-value-div="Revocation time"]').exists('Revocation time is displayed');
|
||||||
|
});
|
||||||
|
|
||||||
test('it should render back button', async function (assert) {
|
test('it should render back button', async function (assert) {
|
||||||
assert.expect(1);
|
assert.expect(1);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue