UI: PKI URLs section on generate-root form (#18781)

This commit is contained in:
Chelsea Shaw 2023-01-23 13:36:34 -06:00 committed by GitHub
parent fc378c0908
commit 2702902120
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 626 additions and 183 deletions

View File

@ -0,0 +1,20 @@
import { encodePath } from 'vault/utils/path-encoding-helpers';
import ApplicationAdapter from '../application';
export default class PkiUrlsAdapter extends ApplicationAdapter {
namespace = 'v1';
_url(backend) {
return `${this.buildURL()}/${encodePath(backend)}/config/urls`;
}
urlForCreateRecord(modelName, snapshot) {
return this._url(snapshot.record.id);
}
urlForFindRecord(id) {
return this._url(id);
}
urlForUpdateRecord(store, type, snapshot) {
return this._url(snapshot.record.id);
}
}

View File

@ -151,6 +151,8 @@ export default class PkiActionModel extends Model {
@attr('string') ttl;
@attr('date') notAfter;
@attr('string', { readOnly: true }) issuerId; // returned from generate-root action
get backend() {
return this.secretMountPath.currentPath;
}

42
ui/app/models/pki/urls.js Normal file
View File

@ -0,0 +1,42 @@
import Model, { attr } from '@ember-data/model';
import { withFormFields } from 'vault/decorators/model-form-fields';
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
@withFormFields()
export default class PkiUrlsModel extends Model {
// This model uses the backend value as the model ID
get useOpenAPI() {
return true;
}
getHelpUrl(backendPath) {
return `/v1/${backendPath}/config/urls?help=1`;
}
@attr({
label: 'Issuing certificates',
subText:
'The URL values for the Issuing Certificate field. These are different URLs for the same resource, and should be added individually, not in a comma-separated list.',
showHelpText: false,
})
issuingCertificates;
@attr({
label: 'CRL distribution points',
subText: 'Specifies the URL values for the CRL Distribution Points field.',
showHelpText: false,
})
crlDistributionPoints;
@attr({
label: 'OSCP Servers',
subText: 'Specifies the URL values for the OCSP Servers field.',
showHelpText: false,
})
ocspServers;
@lazyCapabilities(apiPath`${'id'}/config/urls`, 'id') urlsPath;
get canSet() {
return this.urlsPath.get('canCreate') !== false;
}
}

View File

@ -1,3 +1,5 @@
import { underscore } from '@ember/string';
import { keyParamsByType } from 'pki/utils/action-params';
import ApplicationSerializer from '../application';
export default class PkiActionSerializer extends ApplicationSerializer {
@ -9,7 +11,7 @@ export default class PkiActionSerializer extends ApplicationSerializer {
serialize(snapshot, requestType) {
const data = super.serialize(snapshot);
// requestType is a custom value specified from the pki/action adapter
const allowedPayloadAttributes = this._allowedParamsByType(requestType);
const allowedPayloadAttributes = this._allowedParamsByType(requestType, snapshot.record.type);
if (!allowedPayloadAttributes) return data;
const payload = {};
@ -21,7 +23,8 @@ export default class PkiActionSerializer extends ApplicationSerializer {
return payload;
}
_allowedParamsByType(actionType) {
_allowedParamsByType(actionType, type) {
const keyFields = keyParamsByType(type).map((attrName) => underscore(attrName).toLowerCase());
switch (actionType) {
case 'import':
return ['pem_bundle'];
@ -34,13 +37,7 @@ export default class PkiActionSerializer extends ApplicationSerializer {
'format',
'ip_sans',
'issuer_name',
'key_bits',
'key_name',
'key_ref',
'key_type',
'locality',
'managed_key_id',
'managed_key_name',
'max_path_length',
'not_after',
'not_before_duration',
@ -53,7 +50,9 @@ export default class PkiActionSerializer extends ApplicationSerializer {
'province',
'serial_number',
'street_address',
'ttl',
'type',
...keyFields,
];
default:
// if type doesn't match, serialize all

View File

@ -31,20 +31,24 @@
<PkiCaCertificateImport
@model={{@config}}
@onCancel={{transition-to "vault.cluster.secrets.backend.pki.overview"}}
@onSave={{transition-to "vault.cluster.secrets.backend.pki.overview"}}
@onSave={{transition-to "vault.cluster.secrets.backend.pki.issuers"}}
@adapterOptions={{hash actionType=this.actionType useIssuer=@config.canImportBundle}}
/>
{{else if (eq this.actionType "generate-root")}}
<PkiGenerateRoot
@model={{@config}}
@onSave={{transition-to "vault.cluster.secrets.backend.pki.issuers"}}
@urls={{@urls}}
@onCancel={{this.cancel}}
@adapterOptions={{hash actionType="generate-root" useIssuer=@config.canGenerateIssuerRoot}}
/>
{{else if (eq this.actionType "generate-csr")}}
<code>POST /intermediate/generate/:type ~or~ /issuers/generate/intermediate/:type</code>
{{else}}
<EmptyState @title="Choose an option" @message="To see configuration options, choose your desired output above." />
<EmptyState
@title="Choose an option"
@message="To see configuration options, choose your desired output above."
data-test-configuration-empty-state
/>
<div class="field is-grouped box is-fullwidth is-bottomless">
<div class="control">
<button type="button" class="button is-primary" disabled={{true}} data-test-pki-config-save>

View File

@ -1,4 +1,4 @@
<form {{on "submit" this.generateRoot}} data-test-pki-config-generate-root-form>
<form {{on "submit" (perform this.save)}} data-test-pki-config-generate-root-form>
<MessageError @errorMessage={{this.errorBanner}} class="has-top-margin-s" />
<h2 class="title is-size-5 has-border-bottom-light page-header" data-test-generate-root-title="Root parameters">
Root parameters
@ -73,11 +73,34 @@
{{/if}}
{{/each-in}}
{{!-- TODO: this section
<fieldset class="box is-shadowless is-marginless is-borderless is-fullwidth">
<h2 class="title is-size-5 has-border-bottom-light page-header" data-test-generate-root-title="Issuer URLs">Issuer URLs</h2>
{{! Updating this area of the form will require a secondary call to issuer/:issuer_ref/update once the initial request is complete }}
</fieldset> --}}
{{#if @urls}}
<fieldset class="box is-shadowless is-marginless is-borderless is-fullwidth" data-test-urls-section>
<h2
class="title is-size-5 page-header {{if @urls.canCreate 'has-border-bottom-light' 'is-borderless'}}"
data-test-generate-root-title="Issuer URLs"
>
Issuer URLs
</h2>
{{#if @urls.canSet}}
{{#each @urls.allFields as |attr|}}
{{#if (not (eq attr.name "mountPath"))}}
<FormField
@attr={{attr}}
@mode="create"
@model={{@urls}}
@showHelpText={{attr.options.showHelpText}}
data-test-urls-field
/>
{{/if}}
{{/each}}
{{else}}
<EmptyState
@title="You do not have permissions to set URLs."
@message="These are not required but will need to be configured later. You can do this via the CLI or by changing your permissions and returning to this form."
/>
{{/if}}
</fieldset>
{{/if}}
<div class="field is-grouped box is-fullwidth is-bottomless">
<div class="control">

View File

@ -1,7 +1,10 @@
import { action } from '@ember/object';
import { service } from '@ember/service';
import { waitFor } from '@ember/test-waiters';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { task } from 'ember-concurrency';
import { keyParamsByType } from 'pki/utils/action-params';
import errorMessage from 'vault/utils/error-message';
/**
@ -19,11 +22,11 @@ import errorMessage from 'vault/utils/error-message';
*
* @param {Object} model - pki/action model.
* @callback onCancel - Callback triggered when cancel button is clicked, after model is unloaded
* @callback onSave - Callback triggered after model save success.
* @param {Object} adapterOptions - object passed as adapterOptions on the model.save method
*/
export default class PkiGenerateRootComponent extends Component {
@service flashMessages;
@service router;
@tracked showGroup = null;
@tracked modelValidations = null;
@tracked errorBanner = '';
@ -49,12 +52,7 @@ export default class PkiGenerateRootComponent extends Component {
get keyParamFields() {
const { type } = this.args.model;
if (!type) return null;
let fields = ['keyName', 'keyType', 'keyBits'];
if (type === 'existing') {
fields = ['keyRef'];
} else if (type === 'kms') {
fields = ['keyName', 'managedKeyName', 'managedKeyId'];
}
const fields = keyParamsByType(type);
return fields.map((fieldName) => {
return this.args.model.allFields.find((attr) => attr.name === fieldName);
});
@ -100,18 +98,29 @@ export default class PkiGenerateRootComponent extends Component {
return true;
}
@action
async generateRoot(event) {
@task
@waitFor
*save(event) {
event.preventDefault();
const continueSave = this.checkFormValidity();
if (!continueSave) return;
try {
await this.args.model.save({ adapterOptions: this.args.adapterOptions });
yield this.setUrls();
const result = yield this.args.model.save({ adapterOptions: this.args.adapterOptions });
this.flashMessages.success('Successfully generated root.');
this.args.onSave();
this.router.transitionTo(
'vault.cluster.secrets.backend.pki.issuers.issuer.details',
result.backend,
result.issuerId
);
} catch (e) {
this.errorBanner = errorMessage(e);
this.invalidFormAlert = 'There was a problem generating the root.';
}
}
async setUrls() {
if (!this.args.urls || !this.args.urls.canSet || !this.args.urls.hasDirtyAttributes) return;
return this.args.urls.save();
}
}

View File

@ -1,12 +1,22 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { hash } from 'rsvp';
export default class PkiConfigurationCreateRoute extends Route {
@service secretMountPath;
@service store;
@service pathHelp;
beforeModel() {
// pki/urls uses openApi to hydrate model
return this.pathHelp.getNewModel('pki/urls', this.secretMountPath.currentPath);
}
model() {
return this.store.createRecord('pki/action', {});
return hash({
config: this.store.createRecord('pki/action'),
urls: this.getOrCreateUrls(this.secretMountPath.currentPath),
});
}
setupController(controller, resolvedModel) {
@ -18,4 +28,12 @@ export default class PkiConfigurationCreateRoute extends Route {
{ label: 'configure' },
];
}
async getOrCreateUrls(backend) {
try {
return this.store.findRecord('pki/urls', backend);
} catch (e) {
return this.store.createRecord('pki/urls', { id: backend });
}
}
}

View File

@ -3,10 +3,10 @@
<Page::Breadcrumbs @breadcrumbs={{this.breadcrumbs}} />
</p.top>
<p.levelLeft>
<h1 class="title is-3" data-test-pki-key-page-title>
<h1 class="title is-3" data-test-pki-configuration-page-title>
Configure PKI
</h1>
</p.levelLeft>
</PageHeader>
<PkiConfigureForm @config={{this.model}} />
<PkiConfigureForm @config={{this.model.config}} @urls={{this.model.urls}} />

View File

@ -12,6 +12,5 @@
<PkiGenerateRoot
@model={{this.model}}
@onCancel={{transition-to "vault.cluster.secrets.backend.pki.issuers.index"}}
@onSave={{transition-to "vault.cluster.secrets.backend.pki.issuers.index"}}
@adapterOptions={{hash actionType="generate-root" useIssuer=this.model.canGenerateIssuerRoot}}
/>

View File

@ -0,0 +1,14 @@
/**
* keyParamsByType
* @param {string} type - refers to `type` attribute on the pki/action model. Should be one of 'exported', 'internal', 'existing', 'kms'
* @returns array of valid key-related attribute names (camelCase). NOTE: Key params are not used on all action endpoints
*/
export function keyParamsByType(type) {
let fields = ['keyName', 'keyType', 'keyBits'];
if (type === 'existing') {
fields = ['keyRef'];
} else if (type === 'kms') {
fields = ['keyName', 'managedKeyName', 'managedKeyId'];
}
return fields;
}

View File

@ -0,0 +1,2 @@
// Necessary so that the pki-generate-root component tests work
export { keyParamsByType } from 'pki/utils/action-params';

View File

@ -7,6 +7,7 @@ import { click, currentURL, fillIn, find, isSettled, visit } from '@ember/test-h
import { SELECTORS } from 'vault/tests/helpers/pki/workflow';
import { adminPolicy, readerPolicy, updatePolicy } from 'vault/tests/helpers/policy-generator/pki';
import { tokenWithPolicy, runCommands } from 'vault/tests/helpers/pki/pki-run-commands';
import { rootPem } from 'vault/tests/helpers/pki/values';
/**
* This test module should test the PKI workflow, including:
@ -68,6 +69,57 @@ module('Acceptance | pki workflow', function (hooks) {
assertEmptyState(assert, 'keys');
});
module('configuration', function (hooks) {
hooks.beforeEach(function () {
this.pemBundle = rootPem;
});
test('import 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(SELECTORS.emptyStateLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration/create`);
assert.dom(SELECTORS.configuration.title).hasText('Configure PKI');
assert.dom(SELECTORS.configuration.emptyState).exists({ count: 1 }, 'Shows empty state by default');
await click(SELECTORS.configuration.optionByKey('import'));
assert.dom(SELECTORS.configuration.emptyState).doesNotExist();
await click('[data-test-text-toggle]');
await fillIn('[data-test-text-file-textarea]', this.pemBundle);
await click('[data-test-pki-ca-cert-import]');
assert.strictEqual(
currentURL(),
`/vault/secrets/${this.mountPath}/pki/issuers`,
'redirects to issuers list on success'
);
});
test('generate-root 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(SELECTORS.emptyStateLink);
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/configuration/create`);
assert.dom(SELECTORS.configuration.title).hasText('Configure PKI');
assert.dom(SELECTORS.configuration.emptyState).exists({ count: 1 }, 'Shows empty state by default');
await click(SELECTORS.configuration.optionByKey('generate-root'));
assert.dom(SELECTORS.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(SELECTORS.configuration.urlField).exists({ count: 4 });
// Fill in form
await fillIn(SELECTORS.configuration.typeField, 'exported');
await fillIn(SELECTORS.configuration.inputByName('commonName'), 'my-common-name');
await fillIn(SELECTORS.configuration.inputByName('issuerName'), 'my-first-issuer');
await click(SELECTORS.configuration.generateRootSave);
assert
.dom(SELECTORS.issuerDetails.title)
.hasText('View issuer certificate', 'Redirects to view issuer page');
assert.dom(SELECTORS.issuerDetails.valueByName('Common name')).hasText('my-common-name');
assert.dom(SELECTORS.issuerDetails.valueByName('Issuer name')).hasText('my-first-issuer');
});
});
module('roles', function (hooks) {
hooks.beforeEach(async function () {
await authPage.login();

View File

@ -8,6 +8,7 @@ import configPage from 'vault/tests/pages/settings/configure-secret-backends/pki
import enablePage from 'vault/tests/pages/settings/mount-secret-backend';
import authPage from 'vault/tests/pages/auth';
import { SELECTORS } from 'vault/tests/helpers/pki';
import { csr } from 'vault/tests/helpers/pki/values';
module('Acceptance | secrets/pki/list?tab=cert', function (hooks) {
setupApplicationTest(hooks);
@ -17,22 +18,7 @@ module('Acceptance | secrets/pki/list?tab=cert', function (hooks) {
});
// important for this comment to stay here otherwise the formatting mangles the CSR
// prettier-ignore
const CSR = `-----BEGIN CERTIFICATE REQUEST-----
MIICdDCCAVwCAQAwDjEMMAoGA1UEAxMDbG9sMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA4Dz2b/nAP/M6bqyk5mctqqYAAcoME//xPBy0wREHuZ776Pu4
l45kDL3dPXiY8U2P9pn8WIr2KpLK6oWUfSsiG2P082bpWDL20UymkWqDhhrA4unf
ZRq68UIDbcetlLw15YKnlNdvNZ7Qr8Se8KV0YGR/wFqI7QfS6VE3lhxZWEBUayI0
egqOuDbXAcZTON1AZ92/F+WFSbc43iYdDk16XfAPFKhtvLr6zQQuzebAb7HG04Hc
GhRskixxyJ8XY6XUplfsa1HcpUXE4f1GeUvq3g6ltVCSJ0p7qI9FFjV4t+DCLVVV
LnwHUi9Vzz6i2wjMt7P6+gHR+RrOWBgRMn38fwIDAQABoCEwHwYJKoZIhvcNAQkO
MRIwEDAOBgNVHREEBzAFggNsb2wwDQYJKoZIhvcNAQELBQADggEBAAm3AHQ1ctdV
8HCrMOXGVLgI2cB1sFd6VYVxPBxIk812Y4wyO8Q6POE5VZNTIgMcSeIaFu5lgHNL
Peeb54F+zEa+OJYkcWgCAX5mY/0HoML4p2bxFTSjllSpcX7ktjq4IEIY/LRpqSgc
jgZHHRwanFfkeIOhN4Q5qJWgBPNhDAcNPE7T0M/4mxqYDqMSJvMYmC67hq1UOOug
/QVDUDJRC1C0aDw9if+DbG/bt1V6HpMQhDIEUjzfu4zG8pcag3cJpOA8JhW1hnG0
XA2ZOCA7s34/szr2FczXtIoKiYmv3UzPyO9/4mc0Q2+/nR4CG8NU9WW/XJCne9ID
elRplAzrMF4=
-----END CERTIFICATE REQUEST-----`;
const CSR = csr;
// mount, generate CA, nav to create role page
const setup = async (assert, action = 'issue') => {

View File

@ -0,0 +1,13 @@
import { SELECTORS as GENERATE_ROOT } from './pki-generate-root';
export const SELECTORS = {
// pki-configure-form
option: '[data-test-pki-config-option]',
optionByKey: (key) => `[data-test-pki-config-option="${key}"]`,
cancelButton: '[data-test-pki-config-cancel]',
saveButton: '[data-test-pki-config-save]',
// pki-generate-root
...GENERATE_ROOT,
// pki-ca-cert-import
importForm: '[data-test-pki-ca-cert-import-form]',
};

View File

@ -0,0 +1,17 @@
export const SELECTORS = {
mainSectionTitle: '[data-test-generate-root-title="Root parameters"]',
urlSectionTitle: '[data-test-generate-root-title="Issuer URLs"]',
keyParamsGroupToggle: '[data-test-toggle-group="Key parameters"]',
sanGroupToggle: '[data-test-toggle-group="Subject Alternative Name (SAN) Options"]',
additionalGroupToggle: '[data-test-toggle-group="Additional subject fields"]',
toggleGroupDescription: '[data-test-toggle-group-description]',
formField: '[data-test-field]',
typeField: '[data-test-input="type"]',
inputByName: (name) => `[data-test-input="${name}"]`,
fieldByName: (name) => `[data-test-field="${name}"]`,
generateRootSave: '[data-test-pki-generate-root-save]',
generateRootCancel: '[data-test-pki-generate-root-cancel]',
formInvalidError: '[data-test-pki-generate-root-validation-error]',
urlsSection: '[data-test-urls-section]',
urlField: '[data-test-urls-section] [data-test-input]',
};

View File

@ -8,4 +8,5 @@ export const SELECTORS = {
signIntermediate: '[data-test-pki-issuer-sign-int]',
download: '[data-test-issuer-download]',
configure: '[data-test-pki-issuer-configure]',
valueByName: (name) => `[data-test-value-div="${name}"]`,
};

View File

@ -0,0 +1,126 @@
// Expires Jan 10, 2033
export const rootPem = `-----BEGIN CERTIFICATE-----
MIIDezCCAmOgAwIBAgIUTBbQcZijQsmd0rjd6COikPsrGyowDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAxMJdGVzdC1yb290MB4XDTIzMDEyMDE3NTcxMloXDTIzMDIy
MTE3NTc0MlowFDESMBAGA1UEAxMJdGVzdC1yb290MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAlUHfvQLsocXtvwRCpTnXGzwMCD+3KKK7y1+SUCgpAD9Y
RV2xLAbqh0iK3x2WI4+Pek1Ub6dYaWczzBob6wRq9iFB72uLPpbL8yRf+tc1egmP
wwJQS9qidb1hcSi4p6x/JwOpr2v2PDqJPDoHrfaHeJgCuBGS00qUFH7oHQz9Usim
lHjIbVNF3Qa1Hq2bgwkZmRjRn3Bez/xy3YEiQ41GTicUBqY4NAGWuS1LiHyEUW81
iQ+1iGlbpuAL4H7lpKmrhv1xZXEsF9vNL6H0Y7kjjAImTQnmo+ozcArnKnwh2wmS
f/TrVnN4RRc8dvN8P8nWvVsJYK/D40yc7YMljIESKQIDAQABo4HEMIHBMA4GA1Ud
DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBT6rcf5twb19wLL
JjhPOVywd41d2jAfBgNVHSMEGDAWgBT6rcf5twb19wLLJjhPOVywd41d2jArBggr
BgEFBQcBAQQfMB0wGwYIKwYBBQUHMAKGD2Z1bmZvcmVjYXN0LmNvbTAUBgNVHREE
DTALggl0ZXN0LXJvb3QwGwYDVR0fBBQwEjAQoA6gDIYKZ29vZ2xlLmNvbTANBgkq
hkiG9w0BAQsFAAOCAQEAjG7km+QsIuW7KNY3h8YHJZhdr+tIx57k9tUR4w1+d8QI
t44FTdCYdN8n89lsFK9bONZatd0LY3qqcOARE2ni0Hg/zV9u8TTVKTKAOOx8zBd1
TnwzhXb8mssqnXK9lcECexuWf/s5lkyHjcWOuzNVI0PohrX9tGZwdzsZEgH4Y49i
o8I9DD+uBHknwByRLXSDmgggwgOYsyTg/IfYoHlLHDD3CaOpkCvUCZvM9bI7nrlx
2GByQ/WDT4ArAHcf+Z1iaSIbV6WG6QWoPsu2/WKybcuN2fznaXtJMwgRl50BUv2h
DU3c2oZTc0mPYGft6U8mVwLqfYTcEduGidTLAQPE5w==
-----END CERTIFICATE-----`;
export const issuerPemBundle = `
-----BEGIN CERTIFICATE-----
MIIDRTCCAi2gAwIBAgIUdKagCL6TnN5xLkwhPbNY8JEcY0YwDQYJKoZIhvcNAQEL
BQAwGzEZMBcGA1UEAxMQd3d3LnRlc3QtaW50LmNvbTAeFw0yMzAxMDkxOTA1NTBa
Fw0yMzAyMTAxOTA2MjBaMBsxGTAXBgNVBAMTEHd3dy50ZXN0LWludC5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfd5o9JfyRAXH+E1vE2U0xjSqs
A/cxDqsDXRHBnNJvzAa+7gPKXCDQZbr6chjxLXpP6Bv2/O+dZHq1fo/f6q9PDDGW
JYIluwbACpe7W1UB7q9xFkZg85yQsNYokGZlwv/AMGpFBxDwVlNGL+4fxvFTv7uF
mIlDzSIPrzByyCrqAFMNNqNwlAerDt/C6DMZae/rTGXIXsTfUpxPy21bzkeA+70I
YCV1ffK8UnAeBYNUJ+v8+XgTQ5KhRyQ+fscUkO3T2s6f3O9Q2sWxswkf2YmZB+V1
cTZ5w6hqiuFdBXz7GRnACi1/gbWbaExQTJRplArFwIHka7dqJh8tYkXDjai3AgMB
AAGjgYAwfjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
FgQU68/xXIgvsleKkuA8clK/6YslB/IwHwYDVR0jBBgwFoAU68/xXIgvsleKkuA8
clK/6YslB/IwGwYDVR0RBBQwEoIQd3d3LnRlc3QtaW50LmNvbTANBgkqhkiG9w0B
AQsFAAOCAQEAWSff0BH3SJv/XqwN/flqc1CVzOios72/IJ+KBBv0AzFCZ8wJPi+c
hH1bw7tqi01Bgh595TctogDFN1b6pjN+jrlIP4N+FF9Moj79Q+jHQMnuJomyPuI7
i07vqUcxgSmvEBBWOWS+/vxe6TfWDg18nyPf127CWQN8IHTo1f/GavX+XmRve6XT
EWoqcQshEk9i87oqCbaT7B40jgjTAd1r4Cc6P4s1fAGPt9e9eqMj13kTyVDNuCoD
FSZYalrlkASpg+c9oDQIh2MikGQINXHv/zIEHOW93siKMWeA4ni6phHtMg/p5eJt
SxnVZsSzj8QLy2uwX1AADR0QUvJzMxptyA==
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAn3eaPSX8kQFx/hNbxNlNMY0qrAP3MQ6rA10RwZzSb8wGvu4D
ylwg0GW6+nIY8S16T+gb9vzvnWR6tX6P3+qvTwwxliWCJbsGwAqXu1tVAe6vcRZG
YPOckLDWKJBmZcL/wDBqRQcQ8FZTRi/uH8bxU7+7hZiJQ80iD68wcsgq6gBTDTaj
cJQHqw7fwugzGWnv60xlyF7E31KcT8ttW85HgPu9CGAldX3yvFJwHgWDVCfr/Pl4
E0OSoUckPn7HFJDt09rOn9zvUNrFsbMJH9mJmQfldXE2ecOoaorhXQV8+xkZwAot
f4G1m2hMUEyUaZQKxcCB5Gu3aiYfLWJFw42otwIDAQABAoIBADC+vZ4Ne4vTtkWl
Izsj9Y29Chs0xx3uzuWjUGcvib/0zOcWGICF8t3hCuu9btRiQ24jlFDGdnRVH5FV
E6OtuFLgdlPgOU1RQzn2wvTZcT26+VQHLBI8xVIRTBVwNmzK06Sq6AEbrNjaenAM
/KwoAuLHzAmFXAgmr0++DIA5oayPWyi5IoyFO7EoRv79Xz5LWfu5j8CKOFXmI5MT
vEVYM6Gb2xHRa2Ng0SJ4VzwC09GcXlHKRAz+CubJuncvjbcM/EryvexozKkUq4XA
KqGr9xxdZ4XDlo3Rj9S9P9JaOin0I1mwwz6p+iwMF0zr+/ldjE4oPBdB1PUgSJ7j
2CZcS1kCgYEAwIZ3UsMIXqkMlkMz/7nu2sqzV3EgQjY5QRoz98ligKg4fhYKz+K4
yXvJrRyLkwEBaPdLppCZbs4xsuuv3jiqUHV5n7sfpUA5HVKkKh6XY7jnszbqV732
iB1mQVEjzM92/amew2hDKLGQDW0nglrg6uV+bx0Lnp6Glahr8NOAyk0CgYEA1Ar3
jTqTkU+NQX7utlxx0HPVL//JH/erp/Gnq9fN8dZhK/yjwX5savUlNHpgePoXf1pE
lgi21/INQsvp7O2AUKuj96k+jBHQ0SS58AQGFv8iNDkLE57N74vCO6+Xdi1rHj/Y
7jglr00box/7SOmvb4SZz2o0jm0Ejsg2M0aBuRMCgYEAgTB6F34qOqMDgD1eQka5
QfXs/Es8E1Ihf08e+jIXuC+poOoXnUINL56ySUizXBS7pnzzNbUoUFNqxB4laF/r
4YvC7m15ocED0mpnIKBghBlK2VaLUA93xAS+XiwdcszwkuzkTUnEbyUfffL2JSHo
dZdEDTmXV3wW4Ywfyn2Sma0CgYAeNNG/FLEg6iw9QE/ROqob/+RGyjFklGunqQ0x
tbRo1xlQotTRI6leMz3xk91aXoYqZjmPBf7GFH0/Hr1cOxkkZM8e4MVAPul4Ybr7
LheP/xhoSBgD24OKtGYfCoyRETdJP98vUGBN8LYXLt8lK+UKBeHDYmXKRE156ZuP
AmRIcQKBgFvp+xMoyAsBeOlTjVDZ0mTnFh1yp8f7N3yXdHPpFShwjXjlqLmLO5RH
mZAvaH0Ux/wCfvwHhdC46jBrs9S4zLBvj3+44NYOzvz2dBWP/5MuXgzFe30h9Yd0
zUlyEaWm0jY2Ylzax8ECKRL0td2bv36vxOYtTax8MSB15szsnPJ+
-----END RSA PRIVATE KEY-----
`;
export const csr = `-----BEGIN CERTIFICATE REQUEST-----
MIICdDCCAVwCAQAwDjEMMAoGA1UEAxMDbG9sMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA4Dz2b/nAP/M6bqyk5mctqqYAAcoME//xPBy0wREHuZ776Pu4
l45kDL3dPXiY8U2P9pn8WIr2KpLK6oWUfSsiG2P082bpWDL20UymkWqDhhrA4unf
ZRq68UIDbcetlLw15YKnlNdvNZ7Qr8Se8KV0YGR/wFqI7QfS6VE3lhxZWEBUayI0
egqOuDbXAcZTON1AZ92/F+WFSbc43iYdDk16XfAPFKhtvLr6zQQuzebAb7HG04Hc
GhRskixxyJ8XY6XUplfsa1HcpUXE4f1GeUvq3g6ltVCSJ0p7qI9FFjV4t+DCLVVV
LnwHUi9Vzz6i2wjMt7P6+gHR+RrOWBgRMn38fwIDAQABoCEwHwYJKoZIhvcNAQkO
MRIwEDAOBgNVHREEBzAFggNsb2wwDQYJKoZIhvcNAQELBQADggEBAAm3AHQ1ctdV
8HCrMOXGVLgI2cB1sFd6VYVxPBxIk812Y4wyO8Q6POE5VZNTIgMcSeIaFu5lgHNL
Peeb54F+zEa+OJYkcWgCAX5mY/0HoML4p2bxFTSjllSpcX7ktjq4IEIY/LRpqSgc
jgZHHRwanFfkeIOhN4Q5qJWgBPNhDAcNPE7T0M/4mxqYDqMSJvMYmC67hq1UOOug
/QVDUDJRC1C0aDw9if+DbG/bt1V6HpMQhDIEUjzfu4zG8pcag3cJpOA8JhW1hnG0
XA2ZOCA7s34/szr2FczXtIoKiYmv3UzPyO9/4mc0Q2+/nR4CG8NU9WW/XJCne9ID
elRplAzrMF4=
-----END CERTIFICATE REQUEST-----`;
export const csr2 = `-----BEGIN CERTIFICATE REQUEST-----
MIIChDCCAWwCAQAwFjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCuW9C58M1wO0vdGmtLcJbbCkKyfsHJJae1j4LL
xdGqs1j9UKD66UALSzZEeMCBdtTNNzThAgYJqCSA5swqpbRf6WZ3K/X7oHbfcrHi
SAm8v/0QsJDF5Rphiy6wyggaoaHEsbSp83kYy9r+h48vFW5Dr8UvJTsp5kdRn31L
bTHr56iqOaHQbu6hDj4Ompg/0OElPH1tV2X947o8timR+L89utZzR+d8x/eeTdPl
H7TEkMEomRvt7NTRHGYRsm3Gzq4AA6PalzIxzwJrNgXfJDutNn/QwcVd5sImwYCO
GaHsOvGfc02w+Vqqva9EOEQSr6B90kA+vc30I6uSiugzV9TFAgMBAAGgKTAnBgkq
hkiG9w0BCQ4xGjAYMBYGA1UdEQQPMA2CC2V4YW1wbGUuY29tMA0GCSqGSIb3DQEB
CwUAA4IBAQAjm6JTU7axU6TzLlXlOp7hZ4+nep2/8vvJ9EOXzL8x/qtTTizctdG9
Op70gywoUxAS2tatwa4fmW9DbA2eGiLU+Ibj/5b0Veq5DQdp1Qg3MLBP/+AcM/7m
rrgA9MhkpQahXCj4vXo6NeXYaTh6Jo/s8C9h3WxTD6ptDMiaPFcEuWcx0e3AjjH0
pe7k9/MfB2wLfQ7+5wee/tCFWZN4tk8YfjQeQA1extXYKM/f8eu3Z/wjbbMOVpwb
xst+VTY7X9T8cU/hjDEoNG677meI+W5MgiwX0rxTpoz991fqr3vp7PELYj3GMyii
D1YfvqXieNij4UrduRqCXj1m8SVZlM+X
-----END CERTIFICATE REQUEST-----`;
export const componentPemBundle = `-----BEGIN CERTIFICATE-----
MIIDGjCCAgKgAwIBAgIUFvnhb2nQ8+KNS3SzjlfYDMHGIRgwDQYJKoZIhvcNAQEL
BQAwDTELMAkGA1UEAxMCZmEwHhcNMTgwMTEwMTg1NDI5WhcNMTgwMjExMTg1NDU5
WjANMQswCQYDVQQDEwJmYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AN2VtBn6EMlA4aYre/xoKHxlgNDxJnfSQWfs6yF/K201qPnt4QF9AXChatbmcKVn
OaURq+XEJrGVgF/u2lSos3NRZdhWVe8o3/sOetsGxcrd0gXAieOSmkqJjp27bYdl
uY3WsxhyiPvdfS6xz39OehsK/YCB6qCzwB4eEfSKqbkvfDL9sLlAiOlaoHC9pczf
6/FANKp35UDwInSwmq5vxGbnWk9zMkh5Jq6hjOWHZnVc2J8J49PYvkIM8uiHDgOE
w71T2xM5plz6crmZnxPCOcTKIdF7NTEP2lUfiqc9lONV9X1Pi4UclLPHJf5bwTmn
JaWgbKeY+IlF61/mgxzhC7cCAwEAAaNyMHAwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
EwEB/wQFMAMBAf8wHQYDVR0OBBYEFLDtc6+HZN2lv60JSDAZq3+IHoq7MB8GA1Ud
IwQYMBaAFLDtc6+HZN2lv60JSDAZq3+IHoq7MA0GA1UdEQQGMASCAmZhMA0GCSqG
SIb3DQEBCwUAA4IBAQDVt6OddTV1MB0UvF5v4zL1bEB9bgXvWx35v/FdS+VGn/QP
cC2c4ZNukndyHhysUEPdqVg4+up1aXm4eKXzNmGMY/ottN2pEhVEWQyoIIA1tH0e
8Kv/bysYpHZKZuoGg5+mdlHS2p2Dh2bmYFyBLJ8vaeP83NpTs2cNHcmEvWh/D4UN
UmYDODRN4qh9xYruKJ8i89iMGQfbdcq78dCC4JwBIx3bysC8oF4lqbTYoYNVTnAi
LVqvLdHycEOMlqV0ecq8uMLhPVBalCmIlKdWNQFpXB0TQCsn95rCCdi7ZTsYk5zv
Q4raFvQrZth3Cz/X5yPTtQL78oBYrmHzoQKDFJ2z
-----END CERTIFICATE-----`;

View File

@ -3,6 +3,7 @@ import { SELECTORS as GENERATECERT } from './pki-role-generate';
import { SELECTORS as KEYFORM } from './pki-key-form';
import { SELECTORS as KEYPAGES } from './page/pki-keys';
import { SELECTORS as ISSUERDETAILS } from './pki-issuer-details';
import { SELECTORS as CONFIGURATION } from './pki-configure-form';
export const SELECTORS = {
breadcrumbContainer: '[data-test-breadcrumbs]',
@ -43,4 +44,10 @@ export const SELECTORS = {
title: '[data-test-pki-issuer-page-title]',
...ISSUERDETAILS,
},
// CONFIGURATION
configuration: {
title: '[data-test-pki-configuration-page-title]',
emptyState: '[data-test-configuration-empty-state]',
...CONFIGURATION,
},
};

View File

@ -3,13 +3,8 @@ import { setupRenderingTest } from 'vault/tests/helpers';
import { click, render } from '@ember/test-helpers';
import { setupEngine } from 'ember-engines/test-support';
import { hbs } from 'ember-cli-htmlbars';
import { SELECTORS } from 'vault/tests/helpers/pki/pki-configure-form';
const SELECTORS = {
option: '[data-test-pki-config-option]',
optionByKey: (key) => `[data-test-pki-config-option="${key}"]`,
cancelButton: '[data-test-pki-config-cancel]',
saveButton: '[data-test-pki-config-save]',
};
module('Integration | Component | pki-configure-form', function (hooks) {
setupRenderingTest(hooks);
setupEngine(hooks, 'pki');

View File

@ -6,21 +6,7 @@ import { setupEngine } from 'ember-engines/test-support';
import { setupMirage } from 'ember-cli-mirage/test-support';
import Sinon from 'sinon';
import { allowAllCapabilitiesStub } from 'vault/tests/helpers/stubs';
const SELECTORS = {
mainSectionTitle: '[data-test-generate-root-title="Root parameters"]',
urlSectionTitle: '[data-test-generate-root-title="Issuer URLs"]',
keyParamsGroupToggle: '[data-test-toggle-group="Key parameters"]',
sanGroupToggle: '[data-test-toggle-group="Subject Alternative Name (SAN) Options"]',
additionalGroupToggle: '[data-test-toggle-group="Additional subject fields"]',
toggleGroupDescription: '[data-test-toggle-group-description]',
formField: '[data-test-field]',
typeField: '[data-test-input="type"]',
fieldByName: (name) => `[data-test-field="${name}"]`,
saveButton: '[data-test-pki-generate-root-save]',
cancelButton: '[data-test-pki-generate-root-cancel]',
formInvalidError: '[data-test-pki-generate-root-validation-error]',
};
import { SELECTORS } from 'vault/tests/helpers/pki/pki-generate-root';
module('Integration | Component | pki-generate-root', function (hooks) {
setupRenderingTest(hooks);
@ -32,9 +18,8 @@ module('Integration | Component | pki-generate-root', function (hooks) {
this.store = this.owner.lookup('service:store');
this.secretMountPath = this.owner.lookup('service:secret-mount-path');
this.secretMountPath.currentPath = 'pki-test';
this.model = this.store.createRecord('pki/action', {
role: 'my-role',
});
this.urls = this.store.createRecord('pki/urls', { id: 'pki-test' });
this.model = this.store.createRecord('pki/action');
this.onSave = Sinon.spy();
this.onCancel = Sinon.spy();
});
@ -47,12 +32,8 @@ module('Integration | Component | pki-generate-root', function (hooks) {
}
);
// Titles
assert.dom('h2').exists({ count: 1 }, 'One H2 title without @urls');
assert.dom(SELECTORS.mainSectionTitle).hasText('Root parameters');
// TODO: Add this back once URLs section is added
// assert.dom('h2').exists({ count: 2 }, 'two H2 titles are visible on page load');
// assert.dom(SELECTORS.urlSectionTitle).hasText('Issuer URLs');
assert.dom('[data-test-toggle-group]').exists({ count: 3 }, '3 toggle groups shown');
});
@ -184,8 +165,33 @@ module('Integration | Component | pki-generate-root', function (hooks) {
}
);
await click(SELECTORS.saveButton);
await click(SELECTORS.generateRootSave);
assert.dom(SELECTORS.formInvalidError).exists('Shows overall error form');
assert.ok(saveSpy.notCalled);
});
module('URLs section', function () {
test('it does not render when no urls passed', async function (assert) {
await render(
hbs`<PkiGenerateRoot @model={{this.model}} @onSave={{this.onSave}} @onCancel={{this.onCancel}} />`,
{
owner: this.engine,
}
);
assert.dom(SELECTORS.urlsSection).doesNotExist();
});
test('it renders when urls model passed', async function (assert) {
await render(
hbs`<PkiGenerateRoot @model={{this.model}} @urls={{this.urls}} @onSave={{this.onSave}} @onCancel={{this.onCancel}} />`,
{
owner: this.engine,
}
);
assert.dom(SELECTORS.urlsSection).exists();
assert.dom('h2').exists({ count: 2 }, 'two H2 titles are visible on page load');
assert.dom(SELECTORS.urlSectionTitle).hasText('Issuer URLs');
});
});
});

View File

@ -4,6 +4,7 @@ import { render, click, fillIn } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import { setupEngine } from 'ember-engines/test-support';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { issuerPemBundle } from 'vault/tests/helpers/pki/values';
module('Integration | Component | pki issuer import', function (hooks) {
setupRenderingTest(hooks);
@ -16,55 +17,7 @@ module('Integration | Component | pki issuer import', function (hooks) {
this.backend = 'pki-test';
this.secretMountPath = this.owner.lookup('service:secret-mount-path');
this.secretMountPath.currentPath = this.backend;
this.pemBundle = `
-----BEGIN CERTIFICATE-----
MIIDRTCCAi2gAwIBAgIUdKagCL6TnN5xLkwhPbNY8JEcY0YwDQYJKoZIhvcNAQEL
BQAwGzEZMBcGA1UEAxMQd3d3LnRlc3QtaW50LmNvbTAeFw0yMzAxMDkxOTA1NTBa
Fw0yMzAyMTAxOTA2MjBaMBsxGTAXBgNVBAMTEHd3dy50ZXN0LWludC5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfd5o9JfyRAXH+E1vE2U0xjSqs
A/cxDqsDXRHBnNJvzAa+7gPKXCDQZbr6chjxLXpP6Bv2/O+dZHq1fo/f6q9PDDGW
JYIluwbACpe7W1UB7q9xFkZg85yQsNYokGZlwv/AMGpFBxDwVlNGL+4fxvFTv7uF
mIlDzSIPrzByyCrqAFMNNqNwlAerDt/C6DMZae/rTGXIXsTfUpxPy21bzkeA+70I
YCV1ffK8UnAeBYNUJ+v8+XgTQ5KhRyQ+fscUkO3T2s6f3O9Q2sWxswkf2YmZB+V1
cTZ5w6hqiuFdBXz7GRnACi1/gbWbaExQTJRplArFwIHka7dqJh8tYkXDjai3AgMB
AAGjgYAwfjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
FgQU68/xXIgvsleKkuA8clK/6YslB/IwHwYDVR0jBBgwFoAU68/xXIgvsleKkuA8
clK/6YslB/IwGwYDVR0RBBQwEoIQd3d3LnRlc3QtaW50LmNvbTANBgkqhkiG9w0B
AQsFAAOCAQEAWSff0BH3SJv/XqwN/flqc1CVzOios72/IJ+KBBv0AzFCZ8wJPi+c
hH1bw7tqi01Bgh595TctogDFN1b6pjN+jrlIP4N+FF9Moj79Q+jHQMnuJomyPuI7
i07vqUcxgSmvEBBWOWS+/vxe6TfWDg18nyPf127CWQN8IHTo1f/GavX+XmRve6XT
EWoqcQshEk9i87oqCbaT7B40jgjTAd1r4Cc6P4s1fAGPt9e9eqMj13kTyVDNuCoD
FSZYalrlkASpg+c9oDQIh2MikGQINXHv/zIEHOW93siKMWeA4ni6phHtMg/p5eJt
SxnVZsSzj8QLy2uwX1AADR0QUvJzMxptyA==
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAn3eaPSX8kQFx/hNbxNlNMY0qrAP3MQ6rA10RwZzSb8wGvu4D
ylwg0GW6+nIY8S16T+gb9vzvnWR6tX6P3+qvTwwxliWCJbsGwAqXu1tVAe6vcRZG
YPOckLDWKJBmZcL/wDBqRQcQ8FZTRi/uH8bxU7+7hZiJQ80iD68wcsgq6gBTDTaj
cJQHqw7fwugzGWnv60xlyF7E31KcT8ttW85HgPu9CGAldX3yvFJwHgWDVCfr/Pl4
E0OSoUckPn7HFJDt09rOn9zvUNrFsbMJH9mJmQfldXE2ecOoaorhXQV8+xkZwAot
f4G1m2hMUEyUaZQKxcCB5Gu3aiYfLWJFw42otwIDAQABAoIBADC+vZ4Ne4vTtkWl
Izsj9Y29Chs0xx3uzuWjUGcvib/0zOcWGICF8t3hCuu9btRiQ24jlFDGdnRVH5FV
E6OtuFLgdlPgOU1RQzn2wvTZcT26+VQHLBI8xVIRTBVwNmzK06Sq6AEbrNjaenAM
/KwoAuLHzAmFXAgmr0++DIA5oayPWyi5IoyFO7EoRv79Xz5LWfu5j8CKOFXmI5MT
vEVYM6Gb2xHRa2Ng0SJ4VzwC09GcXlHKRAz+CubJuncvjbcM/EryvexozKkUq4XA
KqGr9xxdZ4XDlo3Rj9S9P9JaOin0I1mwwz6p+iwMF0zr+/ldjE4oPBdB1PUgSJ7j
2CZcS1kCgYEAwIZ3UsMIXqkMlkMz/7nu2sqzV3EgQjY5QRoz98ligKg4fhYKz+K4
yXvJrRyLkwEBaPdLppCZbs4xsuuv3jiqUHV5n7sfpUA5HVKkKh6XY7jnszbqV732
iB1mQVEjzM92/amew2hDKLGQDW0nglrg6uV+bx0Lnp6Glahr8NOAyk0CgYEA1Ar3
jTqTkU+NQX7utlxx0HPVL//JH/erp/Gnq9fN8dZhK/yjwX5savUlNHpgePoXf1pE
lgi21/INQsvp7O2AUKuj96k+jBHQ0SS58AQGFv8iNDkLE57N74vCO6+Xdi1rHj/Y
7jglr00box/7SOmvb4SZz2o0jm0Ejsg2M0aBuRMCgYEAgTB6F34qOqMDgD1eQka5
QfXs/Es8E1Ihf08e+jIXuC+poOoXnUINL56ySUizXBS7pnzzNbUoUFNqxB4laF/r
4YvC7m15ocED0mpnIKBghBlK2VaLUA93xAS+XiwdcszwkuzkTUnEbyUfffL2JSHo
dZdEDTmXV3wW4Ywfyn2Sma0CgYAeNNG/FLEg6iw9QE/ROqob/+RGyjFklGunqQ0x
tbRo1xlQotTRI6leMz3xk91aXoYqZjmPBf7GFH0/Hr1cOxkkZM8e4MVAPul4Ybr7
LheP/xhoSBgD24OKtGYfCoyRETdJP98vUGBN8LYXLt8lK+UKBeHDYmXKRE156ZuP
AmRIcQKBgFvp+xMoyAsBeOlTjVDZ0mTnFh1yp8f7N3yXdHPpFShwjXjlqLmLO5RH
mZAvaH0Ux/wCfvwHhdC46jBrs9S4zLBvj3+44NYOzvz2dBWP/5MuXgzFe30h9Yd0
zUlyEaWm0jY2Ylzax8ECKRL0td2bv36vxOYtTax8MSB15szsnPJ+
-----END RSA PRIVATE KEY-----
`;
this.pemBundle = issuerPemBundle;
});
test('it renders import and updates model', async function (assert) {

View File

@ -3,6 +3,7 @@ import { setupRenderingTest } from 'vault/tests/helpers';
import { click, fillIn, render, triggerEvent } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import sinon from 'sinon';
import { componentPemBundle } from 'vault/tests/helpers/pki/values';
const SELECTORS = {
label: '[data-test-text-file-label]',
@ -60,25 +61,7 @@ module('Integration | Component | text-file', function (hooks) {
});
test('it correctly submits text input', async function (assert) {
const PEM_BUNDLE = `-----BEGIN CERTIFICATE-----
MIIDGjCCAgKgAwIBAgIUFvnhb2nQ8+KNS3SzjlfYDMHGIRgwDQYJKoZIhvcNAQEL
BQAwDTELMAkGA1UEAxMCZmEwHhcNMTgwMTEwMTg1NDI5WhcNMTgwMjExMTg1NDU5
WjANMQswCQYDVQQDEwJmYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AN2VtBn6EMlA4aYre/xoKHxlgNDxJnfSQWfs6yF/K201qPnt4QF9AXChatbmcKVn
OaURq+XEJrGVgF/u2lSos3NRZdhWVe8o3/sOetsGxcrd0gXAieOSmkqJjp27bYdl
uY3WsxhyiPvdfS6xz39OehsK/YCB6qCzwB4eEfSKqbkvfDL9sLlAiOlaoHC9pczf
6/FANKp35UDwInSwmq5vxGbnWk9zMkh5Jq6hjOWHZnVc2J8J49PYvkIM8uiHDgOE
w71T2xM5plz6crmZnxPCOcTKIdF7NTEP2lUfiqc9lONV9X1Pi4UclLPHJf5bwTmn
JaWgbKeY+IlF61/mgxzhC7cCAwEAAaNyMHAwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
EwEB/wQFMAMBAf8wHQYDVR0OBBYEFLDtc6+HZN2lv60JSDAZq3+IHoq7MB8GA1Ud
IwQYMBaAFLDtc6+HZN2lv60JSDAZq3+IHoq7MA0GA1UdEQQGMASCAmZhMA0GCSqG
SIb3DQEBCwUAA4IBAQDVt6OddTV1MB0UvF5v4zL1bEB9bgXvWx35v/FdS+VGn/QP
cC2c4ZNukndyHhysUEPdqVg4+up1aXm4eKXzNmGMY/ottN2pEhVEWQyoIIA1tH0e
8Kv/bysYpHZKZuoGg5+mdlHS2p2Dh2bmYFyBLJ8vaeP83NpTs2cNHcmEvWh/D4UN
UmYDODRN4qh9xYruKJ8i89iMGQfbdcq78dCC4JwBIx3bysC8oF4lqbTYoYNVTnAi
LVqvLdHycEOMlqV0ecq8uMLhPVBalCmIlKdWNQFpXB0TQCsn95rCCdi7ZTsYk5zv
Q4raFvQrZth3Cz/X5yPTtQL78oBYrmHzoQKDFJ2z
-----END CERTIFICATE-----`;
const PEM_BUNDLE = componentPemBundle;
await render(hbs`<TextFile @onChange={{this.onChange}} />`);
await click(SELECTORS.toggle);

View File

@ -2,6 +2,7 @@ import { module, test } from 'qunit';
import { setupTest } from 'vault/tests/helpers';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { allowAllCapabilitiesStub } from 'vault/tests/helpers/stubs';
import { rootPem } from 'vault/tests/helpers/pki/values';
module('Unit | Adapter | pki/action', function (hooks) {
setupTest(hooks);
@ -23,22 +24,7 @@ module('Unit | Adapter | pki/action', function (hooks) {
module('actionType import', function (hooks) {
hooks.beforeEach(function () {
this.payload = {
pem_bundle: `-----BEGIN CERTIFICATE REQUEST-----
MIIChDCCAWwCAQAwFjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCuW9C58M1wO0vdGmtLcJbbCkKyfsHJJae1j4LL
xdGqs1j9UKD66UALSzZEeMCBdtTNNzThAgYJqCSA5swqpbRf6WZ3K/X7oHbfcrHi
SAm8v/0QsJDF5Rphiy6wyggaoaHEsbSp83kYy9r+h48vFW5Dr8UvJTsp5kdRn31L
bTHr56iqOaHQbu6hDj4Ompg/0OElPH1tV2X947o8timR+L89utZzR+d8x/eeTdPl
H7TEkMEomRvt7NTRHGYRsm3Gzq4AA6PalzIxzwJrNgXfJDutNn/QwcVd5sImwYCO
GaHsOvGfc02w+Vqqva9EOEQSr6B90kA+vc30I6uSiugzV9TFAgMBAAGgKTAnBgkq
hkiG9w0BCQ4xGjAYMBYGA1UdEQQPMA2CC2V4YW1wbGUuY29tMA0GCSqGSIb3DQEB
CwUAA4IBAQAjm6JTU7axU6TzLlXlOp7hZ4+nep2/8vvJ9EOXzL8x/qtTTizctdG9
Op70gywoUxAS2tatwa4fmW9DbA2eGiLU+Ibj/5b0Veq5DQdp1Qg3MLBP/+AcM/7m
rrgA9MhkpQahXCj4vXo6NeXYaTh6Jo/s8C9h3WxTD6ptDMiaPFcEuWcx0e3AjjH0
pe7k9/MfB2wLfQ7+5wee/tCFWZN4tk8YfjQeQA1extXYKM/f8eu3Z/wjbbMOVpwb
xst+VTY7X9T8cU/hjDEoNG677meI+W5MgiwX0rxTpoz991fqr3vp7PELYj3GMyii
D1YfvqXieNij4UrduRqCXj1m8SVZlM+X
-----END CERTIFICATE REQUEST-----`,
pem_bundle: rootPem,
};
});

View File

@ -1,6 +1,7 @@
import { module, test } from 'qunit';
import { setupTest } from 'vault/tests/helpers';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { csr2 } from 'vault/tests/helpers/pki/values';
module('Unit | Adapter | pki/certificate/sign', function (hooks) {
setupTest(hooks);
@ -21,22 +22,7 @@ module('Unit | Adapter | pki/certificate/sign', function (hooks) {
assert.expect(1);
const generateData = {
role: 'my-role',
csr: `-----BEGIN CERTIFICATE REQUEST-----
MIIChDCCAWwCAQAwFjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCuW9C58M1wO0vdGmtLcJbbCkKyfsHJJae1j4LL
xdGqs1j9UKD66UALSzZEeMCBdtTNNzThAgYJqCSA5swqpbRf6WZ3K/X7oHbfcrHi
SAm8v/0QsJDF5Rphiy6wyggaoaHEsbSp83kYy9r+h48vFW5Dr8UvJTsp5kdRn31L
bTHr56iqOaHQbu6hDj4Ompg/0OElPH1tV2X947o8timR+L89utZzR+d8x/eeTdPl
H7TEkMEomRvt7NTRHGYRsm3Gzq4AA6PalzIxzwJrNgXfJDutNn/QwcVd5sImwYCO
GaHsOvGfc02w+Vqqva9EOEQSr6B90kA+vc30I6uSiugzV9TFAgMBAAGgKTAnBgkq
hkiG9w0BCQ4xGjAYMBYGA1UdEQQPMA2CC2V4YW1wbGUuY29tMA0GCSqGSIb3DQEB
CwUAA4IBAQAjm6JTU7axU6TzLlXlOp7hZ4+nep2/8vvJ9EOXzL8x/qtTTizctdG9
Op70gywoUxAS2tatwa4fmW9DbA2eGiLU+Ibj/5b0Veq5DQdp1Qg3MLBP/+AcM/7m
rrgA9MhkpQahXCj4vXo6NeXYaTh6Jo/s8C9h3WxTD6ptDMiaPFcEuWcx0e3AjjH0
pe7k9/MfB2wLfQ7+5wee/tCFWZN4tk8YfjQeQA1extXYKM/f8eu3Z/wjbbMOVpwb
xst+VTY7X9T8cU/hjDEoNG677meI+W5MgiwX0rxTpoz991fqr3vp7PELYj3GMyii
D1YfvqXieNij4UrduRqCXj1m8SVZlM+X
-----END CERTIFICATE REQUEST-----`,
csr: csr2,
};
this.server.post(`${this.backend}/sign/${generateData.role}`, () => {
assert.ok(true, 'request made to correct endpoint on create');

View File

@ -0,0 +1,48 @@
import { module, test } from 'qunit';
import { resolve } from 'rsvp';
import { setupTest } from 'vault/tests/helpers';
const storeStub = {
pushPayload() {},
serializerFor() {
return {
serializeIntoHash() {},
};
},
};
const makeSnapshot = (obj) => {
const snapshot = {
id: obj.id,
record: {
...obj,
},
};
snapshot.attr = (attr) => snapshot[attr];
return snapshot;
};
module('Unit | Adapter | pki/urls', function (hooks) {
setupTest(hooks);
test('pki url endpoints', function (assert) {
let url, method;
const adapter = this.owner.factoryFor('adapter:pki/urls').create({
ajax: (...args) => {
[url, method] = args;
return resolve({});
},
});
adapter.createRecord(storeStub, 'pki/urls', makeSnapshot({ id: 'pki-create' }));
assert.strictEqual(url, '/v1/pki-create/config/urls', 'create url OK');
assert.strictEqual(method, 'POST', 'create method OK');
adapter.updateRecord(storeStub, 'pki/urls', makeSnapshot({ id: 'pki-update' }));
assert.strictEqual(url, '/v1/pki-update/config/urls', 'update url OK');
assert.strictEqual(method, 'PUT', 'update method OK');
adapter.findRecord(null, 'capabilities', 'pki-find');
assert.strictEqual(url, '/v1/pki-find/config/urls', 'find url OK');
assert.strictEqual(method, 'GET', 'find method OK');
});
});

View File

@ -1,5 +1,6 @@
import { module, test } from 'qunit';
import { setupTest } from 'vault/tests/helpers';
import { rootPem } from 'vault/tests/helpers/pki/values';
module('Unit | Serializer | pki/action', function (hooks) {
setupTest(hooks);
@ -11,12 +12,163 @@ module('Unit | Serializer | pki/action', function (hooks) {
assert.ok(serializer);
});
test('it serializes records', function (assert) {
module('actionType import', function (hooks) {
hooks.beforeEach(function () {
this.actionType = 'import';
this.pemBundle = rootPem;
});
test('it serializes only valid params', function (assert) {
const store = this.owner.lookup('service:store');
const record = store.createRecord('pki/action', {});
const record = store.createRecord('pki/action', {
pemBundle: this.pemBundle,
issuerName: 'do-not-send',
keyType: 'do-not-send',
});
const expectedResult = {
pem_bundle: this.pemBundle,
};
const serializedRecord = record.serialize(this.actionType);
assert.deepEqual(
serializedRecord,
expectedResult,
'Serializes only parameters valid for import action'
);
});
});
module('actionType generate-root', function (hooks) {
hooks.beforeEach(function () {
this.actionType = 'generate-root';
this.allKeyFields = {
keyName: 'key name',
keyType: 'rsa',
keyBits: '0',
keyRef: 'key ref',
managedKeyName: 'managed name',
managedKeyId: 'managed id',
};
this.withDefaults = {
exclude_cn_from_sans: false,
format: 'pem',
max_path_length: -1,
not_before_duration: '30s',
private_key_format: 'der',
};
});
test('it serializes only params with values', function (assert) {
const store = this.owner.lookup('service:store');
const record = store.createRecord('pki/action', {
excludeCnFromSans: false,
format: 'pem',
maxPathLength: -1,
notBeforeDuration: '30s',
privateKeyFormat: 'der',
type: 'external', // only used for endpoint in adapter
customTtl: '40m', // UI-only value
issuerName: 'my issuer',
commonName: undefined,
foo: 'bar',
});
const expectedResult = {
...this.withDefaults,
key_bits: '0',
key_ref: 'default',
key_type: 'rsa',
issuer_name: 'my issuer',
};
// without passing `actionType` it will not compare against an allowlist
const serializedRecord = record.serialize();
assert.deepEqual(serializedRecord, expectedResult);
});
assert.ok(serializedRecord);
test('it serializes only valid params for type = external', function (assert) {
const store = this.owner.lookup('service:store');
const record = store.createRecord('pki/action', {
...this.allKeyFields,
type: 'external',
customTtl: '40m',
issuerName: 'my issuer',
commonName: 'my common name',
});
const expectedResult = {
...this.withDefaults,
issuer_name: 'my issuer',
common_name: 'my common name',
key_name: 'key name',
key_type: 'rsa',
key_bits: '0',
};
const serializedRecord = record.serialize(this.actionType);
assert.deepEqual(serializedRecord, expectedResult);
});
test('it serializes only valid params for type = internal', function (assert) {
const store = this.owner.lookup('service:store');
const record = store.createRecord('pki/action', {
...this.allKeyFields,
type: 'internal',
customTtl: '40m',
issuerName: 'my issuer',
commonName: 'my common name',
});
const expectedResult = {
...this.withDefaults,
issuer_name: 'my issuer',
common_name: 'my common name',
key_name: 'key name',
key_type: 'rsa',
key_bits: '0',
};
const serializedRecord = record.serialize(this.actionType);
assert.deepEqual(serializedRecord, expectedResult);
});
test('it serializes only valid params for type = existing', function (assert) {
const store = this.owner.lookup('service:store');
const record = store.createRecord('pki/action', {
...this.allKeyFields,
type: 'existing',
customTtl: '40m',
issuerName: 'my issuer',
commonName: 'my common name',
});
const expectedResult = {
...this.withDefaults,
issuer_name: 'my issuer',
common_name: 'my common name',
key_ref: 'key ref',
};
const serializedRecord = record.serialize(this.actionType);
assert.deepEqual(serializedRecord, expectedResult);
});
test('it serializes only valid params for type = kms', function (assert) {
const store = this.owner.lookup('service:store');
const record = store.createRecord('pki/action', {
...this.allKeyFields,
type: 'kms',
customTtl: '40m',
issuerName: 'my issuer',
commonName: 'my common name',
});
const expectedResult = {
...this.withDefaults,
issuer_name: 'my issuer',
common_name: 'my common name',
key_name: 'key name',
managed_key_name: 'managed name',
managed_key_id: 'managed id',
};
const serializedRecord = record.serialize(this.actionType);
assert.deepEqual(serializedRecord, expectedResult);
});
});
});