UI: add pki cluster config parameters (#20724)
* add config directory, rename crl and urls models * fix imports * add cluster config fields to edit form * reorder url save * update tests * add to details page * add details test; * fix adapter name * fix cluster adapter test name * combine adapter tests * update imports * fix git diff * move crl and urls adapters to config folder * add config file * woops add config adapter * final renaming!! * fix imports after naming to base * add cluster to beforeModel hook * hide help text * maybe you should write tests that actually pass, claire * seriously claire its embarrassing
This commit is contained in:
parent
83d32240c7
commit
527f4fe2ba
|
@ -3,16 +3,11 @@
|
||||||
* SPDX-License-Identifier: MPL-2.0
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { encodePath } from 'vault/utils/path-encoding-helpers';
|
import ApplicationAdapter from '../../application';
|
||||||
import ApplicationAdapter from '../application';
|
|
||||||
|
|
||||||
export default class PkiCrlAdapter extends ApplicationAdapter {
|
export default class PkiConfigBaseAdapter extends ApplicationAdapter {
|
||||||
namespace = 'v1';
|
namespace = 'v1';
|
||||||
|
|
||||||
_url(backend) {
|
|
||||||
return `${this.buildURL()}/${encodePath(backend)}/config/crl`;
|
|
||||||
}
|
|
||||||
|
|
||||||
findRecord(store, type, backend) {
|
findRecord(store, type, backend) {
|
||||||
return this.ajax(this._url(backend), 'GET').then((resp) => {
|
return this.ajax(this._url(backend), 'GET').then((resp) => {
|
||||||
return resp.data;
|
return resp.data;
|
|
@ -0,0 +1,15 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { encodePath } from 'vault/utils/path-encoding-helpers';
|
||||||
|
import PkiConfigBaseAdapter from './base';
|
||||||
|
|
||||||
|
export default class PkiConfigClusterAdapter extends PkiConfigBaseAdapter {
|
||||||
|
namespace = 'v1';
|
||||||
|
|
||||||
|
_url(backend) {
|
||||||
|
return `${this.buildURL()}/${encodePath(backend)}/config/cluster`;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { encodePath } from 'vault/utils/path-encoding-helpers';
|
||||||
|
import PkiConfigBaseAdapter from './base';
|
||||||
|
|
||||||
|
export default class PkiConfigCrlAdapter extends PkiConfigBaseAdapter {
|
||||||
|
namespace = 'v1';
|
||||||
|
|
||||||
|
_url(backend) {
|
||||||
|
return `${this.buildURL()}/${encodePath(backend)}/config/crl`;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { encodePath } from 'vault/utils/path-encoding-helpers';
|
||||||
|
import PkiConfigBaseAdapter from './base';
|
||||||
|
|
||||||
|
export default class PkiConfigUrlsAdapter extends PkiConfigBaseAdapter {
|
||||||
|
namespace = 'v1';
|
||||||
|
|
||||||
|
_url(backend) {
|
||||||
|
return `${this.buildURL()}/${encodePath(backend)}/config/urls`;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,24 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) HashiCorp, Inc.
|
|
||||||
* SPDX-License-Identifier: MPL-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
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`;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateRecord(store, type, snapshot) {
|
|
||||||
const data = snapshot.serialize();
|
|
||||||
return this.ajax(this._url(snapshot.record.id), 'POST', { data });
|
|
||||||
}
|
|
||||||
|
|
||||||
urlForFindRecord(id) {
|
|
||||||
return this._url(id);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 PkiConfigClusterModel extends Model {
|
||||||
|
// This model uses the backend value as the model ID
|
||||||
|
get useOpenAPI() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getHelpUrl(backendPath) {
|
||||||
|
return `/v1/${backendPath}/config/cluster?help=1`;
|
||||||
|
}
|
||||||
|
|
||||||
|
@attr('string', {
|
||||||
|
label: "Mount's API path",
|
||||||
|
subText:
|
||||||
|
"Specifies the path to this performance replication cluster's API mount path, including any namespaces as path components. This address is used for the ACME directories, which must be served over a TLS-enabled listener.",
|
||||||
|
})
|
||||||
|
path;
|
||||||
|
@attr('string', {
|
||||||
|
label: 'AIA path',
|
||||||
|
subText:
|
||||||
|
"Specifies the path to this performance replication cluster's AIA distribution point; may refer to an external, non-Vault responder.",
|
||||||
|
})
|
||||||
|
aiaPath;
|
||||||
|
|
||||||
|
// this is for pki-only cluster config, not the universal vault cluster
|
||||||
|
@lazyCapabilities(apiPath`${'id'}/config/cluster`, 'id') clusterPath;
|
||||||
|
|
||||||
|
get canSet() {
|
||||||
|
return this.clusterPath.get('canCreate') !== false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ const formFieldGroups = [
|
||||||
{ 'Unified Revocation': ['crossClusterRevocation', 'unifiedCrl', 'unifiedCrlOnExistingPaths'] },
|
{ 'Unified Revocation': ['crossClusterRevocation', 'unifiedCrl', 'unifiedCrlOnExistingPaths'] },
|
||||||
];
|
];
|
||||||
@withFormFields(null, formFieldGroups)
|
@withFormFields(null, formFieldGroups)
|
||||||
export default class PkiCrlModel extends Model {
|
export default class PkiConfigCrlModel extends Model {
|
||||||
// This model uses the backend value as the model ID
|
// This model uses the backend value as the model ID
|
||||||
|
|
||||||
@attr('boolean') autoRebuild;
|
@attr('boolean') autoRebuild;
|
|
@ -8,7 +8,7 @@ import { withFormFields } from 'vault/decorators/model-form-fields';
|
||||||
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
|
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
|
||||||
|
|
||||||
@withFormFields()
|
@withFormFields()
|
||||||
export default class PkiUrlsModel extends Model {
|
export default class PkiConfigUrlsModel extends Model {
|
||||||
// This model uses the backend value as the model ID
|
// This model uses the backend value as the model ID
|
||||||
get useOpenAPI() {
|
get useOpenAPI() {
|
||||||
return true;
|
return true;
|
|
@ -23,8 +23,20 @@
|
||||||
</ToolbarActions>
|
</ToolbarActions>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
|
|
||||||
|
{{#if (not (eq @cluster 403))}}
|
||||||
|
<h2 class="title is-4 has-bottom-margin-xs has-top-margin-xl has-border-bottom-light has-bottom-padding-s">
|
||||||
|
Cluster Config
|
||||||
|
</h2>
|
||||||
|
{{#each @cluster.allFields as |attr|}}
|
||||||
|
<InfoTableRow
|
||||||
|
@label={{or attr.options.label (humanize (dasherize attr.name))}}
|
||||||
|
@value={{or (get @cluster attr.name) "None"}}
|
||||||
|
/>
|
||||||
|
{{/each}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{#if (not (eq @urls 403))}}
|
{{#if (not (eq @urls 403))}}
|
||||||
<h2 class="title is-4 has-bottom-margin-xs has-top-margin-m has-border-bottom-light has-bottom-padding-s">
|
<h2 class="title is-4 has-bottom-margin-xs has-top-margin-xl has-border-bottom-light has-bottom-padding-s">
|
||||||
Global URLs
|
Global URLs
|
||||||
</h2>
|
</h2>
|
||||||
<InfoTableRow @label="Issuing certificates" @value={{or @urls.issuingCertificates "None"}} />
|
<InfoTableRow @label="Issuing certificates" @value={{or @urls.issuingCertificates "None"}} />
|
||||||
|
|
|
@ -14,7 +14,7 @@ import type Store from '@ember-data/store';
|
||||||
import type VersionService from 'vault/services/version';
|
import type VersionService from 'vault/services/version';
|
||||||
|
|
||||||
interface Args {
|
interface Args {
|
||||||
currentPath: string;
|
backend: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class PkiConfigurationDetails extends Component<Args> {
|
export default class PkiConfigurationDetails extends Component<Args> {
|
||||||
|
@ -32,7 +32,7 @@ export default class PkiConfigurationDetails extends Component<Args> {
|
||||||
async deleteAllIssuers() {
|
async deleteAllIssuers() {
|
||||||
try {
|
try {
|
||||||
const issuerAdapter = this.store.adapterFor('pki/issuer');
|
const issuerAdapter = this.store.adapterFor('pki/issuer');
|
||||||
await issuerAdapter.deleteAllIssuers(this.args.currentPath);
|
await issuerAdapter.deleteAllIssuers(this.args.backend);
|
||||||
this.flashMessages.success('Successfully deleted all issuers and keys');
|
this.flashMessages.success('Successfully deleted all issuers and keys');
|
||||||
this.showDeleteAllIssuers = false;
|
this.showDeleteAllIssuers = false;
|
||||||
this.router.transitionTo('vault.cluster.secrets.backend.pki.configuration.index');
|
this.router.transitionTo('vault.cluster.secrets.backend.pki.configuration.index');
|
||||||
|
|
|
@ -3,6 +3,25 @@
|
||||||
<AlertBanner @type="danger" @message={{this.errorBanner}} data-test-error-banner />
|
<AlertBanner @type="danger" @message={{this.errorBanner}} data-test-error-banner />
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<form {{on "submit" (perform this.save)}}>
|
<form {{on "submit" (perform this.save)}}>
|
||||||
|
<fieldset class="is-shadowless is-marginless is-borderless is-fullwidth" data-test-cluster-config-edit-section>
|
||||||
|
<h2 class="title is-size-5 has-border-bottom-light page-header">
|
||||||
|
Cluster Config
|
||||||
|
</h2>
|
||||||
|
{{#if @cluster.canSet}}
|
||||||
|
{{#each @cluster.allFields as |attr|}}
|
||||||
|
<FormField @attr={{attr}} @model={{@cluster}} @showHelpText={{false}} />
|
||||||
|
{{/each}}
|
||||||
|
{{else}}
|
||||||
|
<EmptyState
|
||||||
|
class="is-box-shadowless"
|
||||||
|
@title="You do not have permission to set the cluster config"
|
||||||
|
@message="Ask your administrator if you think you should have access to:"
|
||||||
|
>
|
||||||
|
<code>POST /{{@backend}}/config/cluster</code>
|
||||||
|
</EmptyState>
|
||||||
|
{{/if}}
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<fieldset class="box is-shadowless is-marginless is-borderless is-fullwidth" data-test-urls-edit-section>
|
<fieldset class="box is-shadowless is-marginless is-borderless is-fullwidth" data-test-urls-edit-section>
|
||||||
<h2 class="title is-size-5 has-border-bottom-light page-header">
|
<h2 class="title is-size-5 has-border-bottom-light page-header">
|
||||||
Global URLs
|
Global URLs
|
||||||
|
|
|
@ -13,21 +13,21 @@ import errorMessage from 'vault/utils/error-message';
|
||||||
import type RouterService from '@ember/routing/router-service';
|
import type RouterService from '@ember/routing/router-service';
|
||||||
import type FlashMessageService from 'vault/services/flash-messages';
|
import type FlashMessageService from 'vault/services/flash-messages';
|
||||||
import type VersionService from 'vault/services/version';
|
import type VersionService from 'vault/services/version';
|
||||||
import type PkiCrlModel from 'vault/models/pki/crl';
|
import type PkiConfigCrlModel from 'vault/models/pki/config/crl';
|
||||||
import type PkiUrlsModel from 'vault/models/pki/urls';
|
import type PkiConfigUrlsModel from 'vault/models/pki/config/urls';
|
||||||
import type { FormField, TtlEvent } from 'vault/app-types';
|
import type { FormField, TtlEvent } from 'vault/app-types';
|
||||||
|
|
||||||
interface Args {
|
interface Args {
|
||||||
crl: PkiCrlModel;
|
crl: PkiConfigCrlModel;
|
||||||
urls: PkiUrlsModel;
|
urls: PkiConfigUrlsModel;
|
||||||
}
|
}
|
||||||
interface PkiCrlTtls {
|
interface PkiConfigCrlTtls {
|
||||||
autoRebuildGracePeriod: string;
|
autoRebuildGracePeriod: string;
|
||||||
expiry: string;
|
expiry: string;
|
||||||
deltaRebuildInterval: string;
|
deltaRebuildInterval: string;
|
||||||
ocspExpiry: string;
|
ocspExpiry: string;
|
||||||
}
|
}
|
||||||
interface PkiCrlBooleans {
|
interface PkiConfigCrlBooleans {
|
||||||
autoRebuild: boolean;
|
autoRebuild: boolean;
|
||||||
enableDelta: boolean;
|
enableDelta: boolean;
|
||||||
disable: boolean;
|
disable: boolean;
|
||||||
|
@ -69,10 +69,10 @@ export default class PkiConfigurationEditComponent extends Component<Args> {
|
||||||
handleTtl(attr: FormField, e: TtlEvent) {
|
handleTtl(attr: FormField, e: TtlEvent) {
|
||||||
const { enabled, goSafeTimeString } = e;
|
const { enabled, goSafeTimeString } = e;
|
||||||
const ttlAttr = attr.name;
|
const ttlAttr = attr.name;
|
||||||
this.args.crl[ttlAttr as keyof PkiCrlTtls] = goSafeTimeString;
|
this.args.crl[ttlAttr as keyof PkiConfigCrlTtls] = goSafeTimeString;
|
||||||
// expiry and ocspExpiry both correspond to 'disable' booleans
|
// expiry and ocspExpiry both correspond to 'disable' booleans
|
||||||
// so when ttl is enabled, the booleans are set to false
|
// so when ttl is enabled, the booleans are set to false
|
||||||
this.args.crl[attr.options.mapToBoolean as keyof PkiCrlBooleans] = attr.options.isOppositeValue
|
this.args.crl[attr.options.mapToBoolean as keyof PkiConfigCrlBooleans] = attr.options.isOppositeValue
|
||||||
? !enabled
|
? !enabled
|
||||||
: enabled;
|
: enabled;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { tracked } from '@glimmer/tracking';
|
||||||
import { task } from 'ember-concurrency';
|
import { task } from 'ember-concurrency';
|
||||||
import errorMessage from 'vault/utils/error-message';
|
import errorMessage from 'vault/utils/error-message';
|
||||||
import type PkiActionModel from 'vault/models/pki/action';
|
import type PkiActionModel from 'vault/models/pki/action';
|
||||||
import type PkiUrlsModel from 'vault/models/pki/urls';
|
import type PkiConfigUrlsModel from 'vault/models/pki/config/urls';
|
||||||
import type FlashMessageService from 'vault/services/flash-messages';
|
import type FlashMessageService from 'vault/services/flash-messages';
|
||||||
import type RouterService from '@ember/routing/router-service';
|
import type RouterService from '@ember/routing/router-service';
|
||||||
import type { ValidationMap } from 'vault/vault/app-types';
|
import type { ValidationMap } from 'vault/vault/app-types';
|
||||||
|
@ -22,7 +22,7 @@ interface AdapterOptions {
|
||||||
}
|
}
|
||||||
interface Args {
|
interface Args {
|
||||||
model: PkiActionModel;
|
model: PkiActionModel;
|
||||||
urls: PkiUrlsModel;
|
urls: PkiConfigUrlsModel;
|
||||||
onCancel: CallableFunction;
|
onCancel: CallableFunction;
|
||||||
onComplete: CallableFunction;
|
onComplete: CallableFunction;
|
||||||
onSave?: CallableFunction;
|
onSave?: CallableFunction;
|
||||||
|
@ -107,8 +107,10 @@ export default class PkiGenerateRootComponent extends Component<Args> {
|
||||||
const continueSave = this.checkFormValidity();
|
const continueSave = this.checkFormValidity();
|
||||||
if (!continueSave) return;
|
if (!continueSave) return;
|
||||||
try {
|
try {
|
||||||
yield this.setUrls();
|
|
||||||
yield this.args.model.save({ adapterOptions: this.args.adapterOptions });
|
yield this.args.model.save({ adapterOptions: this.args.adapterOptions });
|
||||||
|
// root generation must occur first in case templates are used for URL fields
|
||||||
|
// this way an issuer_id exists for backend to interpolate into the template
|
||||||
|
yield this.setUrls();
|
||||||
this.flashMessages.success('Successfully generated root.');
|
this.flashMessages.success('Successfully generated root.');
|
||||||
if (this.args.onSave) {
|
if (this.args.onSave) {
|
||||||
this.args.onSave();
|
this.args.onSave();
|
||||||
|
|
|
@ -18,7 +18,8 @@ export default class PkiRoute extends Route {
|
||||||
const mountPath = this.secretMountPath.currentPath;
|
const mountPath = this.secretMountPath.currentPath;
|
||||||
return hash({
|
return hash({
|
||||||
role: this.pathHelp.getNewModel('pki/role', mountPath),
|
role: this.pathHelp.getNewModel('pki/role', mountPath),
|
||||||
urls: this.pathHelp.getNewModel('pki/urls', mountPath),
|
urls: this.pathHelp.getNewModel('pki/config/urls', mountPath),
|
||||||
|
cluster: this.pathHelp.getNewModel('pki/config/cluster', mountPath),
|
||||||
key: this.pathHelp.getNewModel('pki/key', mountPath),
|
key: this.pathHelp.getNewModel('pki/key', mountPath),
|
||||||
signCsr: this.pathHelp.getNewModel('pki/sign-intermediate', mountPath),
|
signCsr: this.pathHelp.getNewModel('pki/sign-intermediate', mountPath),
|
||||||
certGenerate: this.pathHelp.getNewModel('pki/certificate/generate', mountPath),
|
certGenerate: this.pathHelp.getNewModel('pki/certificate/generate', mountPath),
|
||||||
|
|
|
@ -14,8 +14,9 @@ export default class PkiConfigurationRoute extends Route {
|
||||||
const engine = this.modelFor('application');
|
const engine = this.modelFor('application');
|
||||||
return hash({
|
return hash({
|
||||||
engine,
|
engine,
|
||||||
urls: this.store.findRecord('pki/urls', engine.id).catch((e) => e.httpStatus),
|
cluster: this.store.findRecord('pki/config/cluster', engine.id).catch((e) => e.httpStatus),
|
||||||
crl: this.store.findRecord('pki/crl', engine.id).catch((e) => e.httpStatus),
|
urls: this.store.findRecord('pki/config/urls', engine.id).catch((e) => e.httpStatus),
|
||||||
|
crl: this.store.findRecord('pki/config/crl', engine.id).catch((e) => e.httpStatus),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,10 @@ export default class PkiConfigurationEditRoute extends Route {
|
||||||
@service secretMountPath;
|
@service secretMountPath;
|
||||||
|
|
||||||
model() {
|
model() {
|
||||||
const { urls, crl, engine } = this.modelFor('configuration');
|
const { cluster, urls, crl, engine } = this.modelFor('configuration');
|
||||||
return {
|
return {
|
||||||
engineId: engine.id,
|
engineId: engine.id,
|
||||||
|
cluster,
|
||||||
urls,
|
urls,
|
||||||
crl,
|
crl,
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,10 +20,11 @@ export default class ConfigurationIndexRoute extends Route {
|
||||||
}
|
}
|
||||||
|
|
||||||
model() {
|
model() {
|
||||||
const { urls, crl, engine } = this.modelFor('configuration');
|
const { cluster, urls, crl, engine } = this.modelFor('configuration');
|
||||||
return hash({
|
return hash({
|
||||||
hasConfig: this.shouldPromptConfig,
|
hasConfig: this.shouldPromptConfig,
|
||||||
engine,
|
engine,
|
||||||
|
cluster,
|
||||||
urls,
|
urls,
|
||||||
crl,
|
crl,
|
||||||
mountConfig: this.fetchMountConfig(engine.id),
|
mountConfig: this.fetchMountConfig(engine.id),
|
||||||
|
|
|
@ -10,4 +10,9 @@
|
||||||
</p.levelLeft>
|
</p.levelLeft>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
<Page::PkiConfigurationEdit @urls={{this.model.urls}} @crl={{this.model.crl}} @backend={{this.model.engineId}} />
|
<Page::PkiConfigurationEdit
|
||||||
|
@cluster={{this.model.cluster}}
|
||||||
|
@urls={{this.model.urls}}
|
||||||
|
@crl={{this.model.crl}}
|
||||||
|
@backend={{this.model.engineId}}
|
||||||
|
/>
|
|
@ -10,10 +10,11 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Page::PkiConfigurationDetails
|
<Page::PkiConfigurationDetails
|
||||||
|
@cluster={{this.model.cluster}}
|
||||||
@urls={{this.model.urls}}
|
@urls={{this.model.urls}}
|
||||||
@crl={{this.model.crl}}
|
@crl={{this.model.crl}}
|
||||||
@mountConfig={{this.model.mountConfig}}
|
@mountConfig={{this.model.mountConfig}}
|
||||||
@currentPath={{this.model.engine.id}}
|
@backend={{this.model.engine.id}}
|
||||||
@canDeleteAllIssuers={{this.model.issuerModel.canDeleteAllIssuers}}
|
@canDeleteAllIssuers={{this.model.issuerModel.canDeleteAllIssuers}}
|
||||||
@hasConfig={{this.model.hasConfig}}
|
@hasConfig={{this.model.hasConfig}}
|
||||||
/>
|
/>
|
|
@ -45,7 +45,7 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
|
||||||
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
|
await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
|
||||||
await click(SELECTORS.emptyStateLink);
|
await click(SELECTORS.emptyStateLink);
|
||||||
configs = this.store.peekAll('pki/action');
|
configs = this.store.peekAll('pki/action');
|
||||||
urls = this.store.peekRecord('pki/urls', this.mountPath);
|
urls = this.store.peekRecord('pki/config/urls', this.mountPath);
|
||||||
config = configs.objectAt(0);
|
config = configs.objectAt(0);
|
||||||
assert.strictEqual(configs.length, 1, 'One config model present');
|
assert.strictEqual(configs.length, 1, 'One config model present');
|
||||||
assert.false(urls.hasDirtyAttributes, 'URLs is loaded from endpoint');
|
assert.false(urls.hasDirtyAttributes, 'URLs is loaded from endpoint');
|
||||||
|
@ -54,13 +54,13 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
|
||||||
// Cancel button rolls it back
|
// Cancel button rolls it back
|
||||||
await click(SELECTORS.configuration.cancelButton);
|
await click(SELECTORS.configuration.cancelButton);
|
||||||
configs = this.store.peekAll('pki/action');
|
configs = this.store.peekAll('pki/action');
|
||||||
urls = this.store.peekRecord('pki/urls', this.mountPath);
|
urls = this.store.peekRecord('pki/config/urls', this.mountPath);
|
||||||
assert.strictEqual(configs.length, 0, 'config model is rolled back on cancel');
|
assert.strictEqual(configs.length, 0, 'config model is rolled back on cancel');
|
||||||
assert.strictEqual(urls.id, this.mountPath, 'Urls still exists on exit');
|
assert.strictEqual(urls.id, this.mountPath, 'Urls still exists on exit');
|
||||||
|
|
||||||
await click(SELECTORS.emptyStateLink);
|
await click(SELECTORS.emptyStateLink);
|
||||||
configs = this.store.peekAll('pki/action');
|
configs = this.store.peekAll('pki/action');
|
||||||
urls = this.store.peekRecord('pki/urls', this.mountPath);
|
urls = this.store.peekRecord('pki/config/urls', this.mountPath);
|
||||||
config = configs.objectAt(0);
|
config = configs.objectAt(0);
|
||||||
assert.strictEqual(configs.length, 1, 'One config model present');
|
assert.strictEqual(configs.length, 1, 'One config model present');
|
||||||
assert.false(urls.hasDirtyAttributes, 'URLs is loaded from endpoint');
|
assert.false(urls.hasDirtyAttributes, 'URLs is loaded from endpoint');
|
||||||
|
@ -69,7 +69,7 @@ module('Acceptance | pki engine route cleanup test', function (hooks) {
|
||||||
// Exit page via link rolls it back
|
// Exit page via link rolls it back
|
||||||
await click(SELECTORS.overviewBreadcrumb);
|
await click(SELECTORS.overviewBreadcrumb);
|
||||||
configs = this.store.peekAll('pki/action');
|
configs = this.store.peekAll('pki/action');
|
||||||
urls = this.store.peekRecord('pki/urls', this.mountPath);
|
urls = this.store.peekRecord('pki/config/urls', this.mountPath);
|
||||||
assert.strictEqual(configs.length, 0, 'config model is rolled back on cancel');
|
assert.strictEqual(configs.length, 0, 'config model is rolled back on cancel');
|
||||||
assert.strictEqual(urls.id, this.mountPath, 'Urls still exists on exit');
|
assert.strictEqual(urls.id, this.mountPath, 'Urls still exists on exit');
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
export const SELECTORS = {
|
export const SELECTORS = {
|
||||||
errorBanner: '[data-test-error-banner]',
|
errorBanner: '[data-test-error-banner]',
|
||||||
|
configEditSection: '[data-test-cluster-config-edit-section]',
|
||||||
|
configInput: (attr) => `[data-test-input="${attr}"]`,
|
||||||
urlsEditSection: '[data-test-urls-edit-section]',
|
urlsEditSection: '[data-test-urls-edit-section]',
|
||||||
urlFieldInput: (attr) => `[data-test-input="${attr}"] textarea`,
|
urlFieldInput: (attr) => `[data-test-input="${attr}"] textarea`,
|
||||||
urlFieldLabel: (attr) => `[data-test-input="${attr}"] label`,
|
urlFieldLabel: (attr) => `[data-test-input="${attr}"] label`,
|
||||||
|
|
|
@ -24,8 +24,15 @@ module('Integration | Component | Page::PkiConfigurationDetails', function (hook
|
||||||
this.secretMountPath.currentPath = 'pki-test';
|
this.secretMountPath.currentPath = 'pki-test';
|
||||||
|
|
||||||
this.store = this.owner.lookup('service:store');
|
this.store = this.owner.lookup('service:store');
|
||||||
this.urls = this.store.createRecord('pki/urls', { id: 'pki-test', issuingCertificates: 'example.com' });
|
this.cluster = this.store.createRecord('pki/config/cluster', {
|
||||||
this.crl = this.store.createRecord('pki/crl', {
|
id: 'pki-test',
|
||||||
|
path: 'https://pr-a.vault.example.com/v1/ns1/pki-root',
|
||||||
|
});
|
||||||
|
this.urls = this.store.createRecord('pki/config/urls', {
|
||||||
|
id: 'pki-test',
|
||||||
|
issuingCertificates: 'example.com',
|
||||||
|
});
|
||||||
|
this.crl = this.store.createRecord('pki/config/crl', {
|
||||||
id: 'pki-test',
|
id: 'pki-test',
|
||||||
expiry: '20h',
|
expiry: '20h',
|
||||||
disable: false,
|
disable: false,
|
||||||
|
@ -54,6 +61,17 @@ module('Integration | Component | Page::PkiConfigurationDetails', function (hook
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('shows the correct information on cluster config', async function (assert) {
|
||||||
|
await render(hbs`<Page::PkiConfigurationDetails @cluster={{this.cluster}} @hasConfig={{true}} />,`, {
|
||||||
|
owner: this.engine,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert
|
||||||
|
.dom(SELECTORS.rowValue("Mount's API path"))
|
||||||
|
.hasText('https://pr-a.vault.example.com/v1/ns1/pki-root', 'mount API path row renders');
|
||||||
|
assert.dom(SELECTORS.rowValue('AIA path')).hasText('None', "renders 'None' when no data");
|
||||||
|
});
|
||||||
|
|
||||||
test('shows the correct information on global urls section', async function (assert) {
|
test('shows the correct information on global urls section', async function (assert) {
|
||||||
await render(
|
await render(
|
||||||
hbs`<Page::PkiConfigurationDetails @urls={{this.urls}} @crl={{this.crl}} @mountConfig={{this.mountConfig}} @hasConfig={{true}} />,`,
|
hbs`<Page::PkiConfigurationDetails @urls={{this.urls}} @crl={{this.crl}} @mountConfig={{this.mountConfig}} @hasConfig={{true}} />,`,
|
||||||
|
|
|
@ -26,8 +26,12 @@ module('Integration | Component | page/pki-configuration-edit', function (hooks)
|
||||||
this.backend = 'pki-engine';
|
this.backend = 'pki-engine';
|
||||||
// both models only use findRecord. API parameters for pki/crl
|
// both models only use findRecord. API parameters for pki/crl
|
||||||
// are set by default backend values when the engine is mounted
|
// are set by default backend values when the engine is mounted
|
||||||
this.store.pushPayload('pki/crl', {
|
this.store.pushPayload('pki/config/cluster', {
|
||||||
modelName: 'pki/crl',
|
modelName: 'pki/config/cluster',
|
||||||
|
id: this.backend,
|
||||||
|
});
|
||||||
|
this.store.pushPayload('pki/config/crl', {
|
||||||
|
modelName: 'pki/config/crl',
|
||||||
id: this.backend,
|
id: this.backend,
|
||||||
auto_rebuild: false,
|
auto_rebuild: false,
|
||||||
auto_rebuild_grace_period: '12h',
|
auto_rebuild_grace_period: '12h',
|
||||||
|
@ -38,19 +42,31 @@ module('Integration | Component | page/pki-configuration-edit', function (hooks)
|
||||||
ocsp_disable: false,
|
ocsp_disable: false,
|
||||||
ocsp_expiry: '12h',
|
ocsp_expiry: '12h',
|
||||||
});
|
});
|
||||||
this.store.pushPayload('pki/urls', {
|
this.store.pushPayload('pki/config/urls', {
|
||||||
modelName: 'pki/urls',
|
modelName: 'pki/config/urls',
|
||||||
id: this.backend,
|
id: this.backend,
|
||||||
issuing_certificates: ['hashicorp.com'],
|
issuing_certificates: ['hashicorp.com'],
|
||||||
crl_distribution_points: ['some-crl-distribution.com'],
|
crl_distribution_points: ['some-crl-distribution.com'],
|
||||||
ocsp_servers: ['ocsp-stuff.com'],
|
ocsp_servers: ['ocsp-stuff.com'],
|
||||||
});
|
});
|
||||||
this.urls = this.store.peekRecord('pki/urls', this.backend);
|
this.cluster = this.store.peekRecord('pki/config/cluster', this.backend);
|
||||||
this.crl = this.store.peekRecord('pki/crl', this.backend);
|
this.crl = this.store.peekRecord('pki/config/crl', this.backend);
|
||||||
|
this.urls = this.store.peekRecord('pki/config/urls', this.backend);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it renders with config data and updates config', async function (assert) {
|
test('it renders with config data and updates config', async function (assert) {
|
||||||
assert.expect(27);
|
assert.expect(28);
|
||||||
|
this.server.post(`/${this.backend}/config/cluster`, (schema, req) => {
|
||||||
|
assert.ok(true, 'request made to save cluster config');
|
||||||
|
assert.propEqual(
|
||||||
|
JSON.parse(req.requestBody),
|
||||||
|
{
|
||||||
|
path: 'https://pr-a.vault.example.com/v1/ns1/pki-root',
|
||||||
|
aia_path: 'http://another-path.com',
|
||||||
|
},
|
||||||
|
'it updates config model attributes'
|
||||||
|
);
|
||||||
|
});
|
||||||
this.server.post(`/${this.backend}/config/crl`, (schema, req) => {
|
this.server.post(`/${this.backend}/config/crl`, (schema, req) => {
|
||||||
assert.ok(true, 'request made to save crl config');
|
assert.ok(true, 'request made to save crl config');
|
||||||
assert.propEqual(
|
assert.propEqual(
|
||||||
|
@ -83,6 +99,7 @@ module('Integration | Component | page/pki-configuration-edit', function (hooks)
|
||||||
await render(
|
await render(
|
||||||
hbs`
|
hbs`
|
||||||
<Page::PkiConfigurationEdit
|
<Page::PkiConfigurationEdit
|
||||||
|
@cluster={{this.cluster}}
|
||||||
@urls={{this.urls}}
|
@urls={{this.urls}}
|
||||||
@crl={{this.crl}}
|
@crl={{this.crl}}
|
||||||
@backend={{this.backend}}
|
@backend={{this.backend}}
|
||||||
|
@ -91,6 +108,7 @@ module('Integration | Component | page/pki-configuration-edit', function (hooks)
|
||||||
this.context
|
this.context
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert.dom(SELECTORS.configEditSection).exists('renders config section');
|
||||||
assert.dom(SELECTORS.urlsEditSection).exists('renders urls section');
|
assert.dom(SELECTORS.urlsEditSection).exists('renders urls section');
|
||||||
assert.dom(SELECTORS.crlEditSection).exists('renders crl section');
|
assert.dom(SELECTORS.crlEditSection).exists('renders crl section');
|
||||||
assert.dom(SELECTORS.cancelButton).exists();
|
assert.dom(SELECTORS.cancelButton).exists();
|
||||||
|
@ -101,6 +119,8 @@ module('Integration | Component | page/pki-configuration-edit', function (hooks)
|
||||||
assert.dom(SELECTORS.urlFieldInput('crlDistributionPoints')).hasValue('some-crl-distribution.com');
|
assert.dom(SELECTORS.urlFieldInput('crlDistributionPoints')).hasValue('some-crl-distribution.com');
|
||||||
assert.dom(SELECTORS.urlFieldInput('ocspServers')).hasValue('ocsp-stuff.com');
|
assert.dom(SELECTORS.urlFieldInput('ocspServers')).hasValue('ocsp-stuff.com');
|
||||||
|
|
||||||
|
await fillIn(SELECTORS.configInput('path'), 'https://pr-a.vault.example.com/v1/ns1/pki-root');
|
||||||
|
await fillIn(SELECTORS.configInput('aiaPath'), 'http://another-path.com');
|
||||||
await fillIn(SELECTORS.urlFieldInput('issuingCertificates'), 'update-hashicorp.com');
|
await fillIn(SELECTORS.urlFieldInput('issuingCertificates'), 'update-hashicorp.com');
|
||||||
await fillIn(SELECTORS.urlFieldInput('crlDistributionPoints'), 'test-crl.com');
|
await fillIn(SELECTORS.urlFieldInput('crlDistributionPoints'), 'test-crl.com');
|
||||||
await fillIn(SELECTORS.urlFieldInput('ocspServers'), 'ocsp.com');
|
await fillIn(SELECTORS.urlFieldInput('ocspServers'), 'ocsp.com');
|
||||||
|
|
|
@ -25,7 +25,7 @@ module('Integration | Component | page/pki-configure-create', function (hooks) {
|
||||||
{ label: 'configure' },
|
{ label: 'configure' },
|
||||||
];
|
];
|
||||||
this.config = this.store.createRecord('pki/action');
|
this.config = this.store.createRecord('pki/action');
|
||||||
this.urls = this.store.createRecord('pki/urls');
|
this.urls = this.store.createRecord('pki/config/urls');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it renders', async function (assert) {
|
test('it renders', async function (assert) {
|
||||||
|
|
|
@ -23,7 +23,7 @@ module('Integration | Component | pki-generate-root', function (hooks) {
|
||||||
this.store = this.owner.lookup('service:store');
|
this.store = this.owner.lookup('service:store');
|
||||||
this.secretMountPath = this.owner.lookup('service:secret-mount-path');
|
this.secretMountPath = this.owner.lookup('service:secret-mount-path');
|
||||||
this.secretMountPath.currentPath = 'pki-test';
|
this.secretMountPath.currentPath = 'pki-test';
|
||||||
this.urls = this.store.createRecord('pki/urls', { id: 'pki-test' });
|
this.urls = this.store.createRecord('pki/config/urls', { id: 'pki-test' });
|
||||||
this.model = this.store.createRecord('pki/action');
|
this.model = this.store.createRecord('pki/action');
|
||||||
this.onSave = Sinon.spy();
|
this.onSave = Sinon.spy();
|
||||||
this.onCancel = Sinon.spy();
|
this.onCancel = Sinon.spy();
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'vault/tests/helpers';
|
||||||
|
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||||
|
|
||||||
|
module('Unit | Adapter | pki/config', function (hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
setupMirage(hooks);
|
||||||
|
|
||||||
|
hooks.beforeEach(async function () {
|
||||||
|
this.store = this.owner.lookup('service:store');
|
||||||
|
this.backend = 'pki-engine';
|
||||||
|
});
|
||||||
|
|
||||||
|
const testHelper = (test) => {
|
||||||
|
test('it should make request to correct endpoint on update', async function (assert) {
|
||||||
|
assert.expect(1);
|
||||||
|
|
||||||
|
this.server.post(`/${this.backend}/config/${this.endpoint}`, () => {
|
||||||
|
assert.ok(true, `request made to POST config/${this.endpoint} endpoint on update`);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.store.pushPayload(`pki/config/${this.endpoint}`, {
|
||||||
|
modelName: `pki/config/${this.endpoint}`,
|
||||||
|
id: this.backend,
|
||||||
|
});
|
||||||
|
|
||||||
|
const model = this.store.peekRecord(`pki/config/${this.endpoint}`, this.backend);
|
||||||
|
await model.save();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it should make request to correct endpoint on find', async function (assert) {
|
||||||
|
assert.expect(1);
|
||||||
|
|
||||||
|
this.server.get(`/${this.backend}/config/${this.endpoint}`, () => {
|
||||||
|
assert.ok(true, `request is made to GET /config/${this.endpoint} endpoint on find`);
|
||||||
|
return { data: { id: this.backend } };
|
||||||
|
});
|
||||||
|
|
||||||
|
this.store.findRecord(`pki/config/${this.endpoint}`, this.backend);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module('cluster', function (hooks) {
|
||||||
|
hooks.beforeEach(async function () {
|
||||||
|
this.endpoint = 'cluster';
|
||||||
|
});
|
||||||
|
testHelper(test);
|
||||||
|
});
|
||||||
|
|
||||||
|
module('urls', function (hooks) {
|
||||||
|
hooks.beforeEach(async function () {
|
||||||
|
this.endpoint = 'urls';
|
||||||
|
});
|
||||||
|
testHelper(test);
|
||||||
|
});
|
||||||
|
|
||||||
|
module('crl', function (hooks) {
|
||||||
|
hooks.beforeEach(async function () {
|
||||||
|
this.endpoint = 'crl';
|
||||||
|
});
|
||||||
|
testHelper(test);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,45 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) HashiCorp, Inc.
|
|
||||||
* SPDX-License-Identifier: MPL-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { module, test } from 'qunit';
|
|
||||||
import { setupTest } from 'vault/tests/helpers';
|
|
||||||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
|
||||||
|
|
||||||
module('Unit | Adapter | pki/crl', function (hooks) {
|
|
||||||
setupTest(hooks);
|
|
||||||
setupMirage(hooks);
|
|
||||||
|
|
||||||
hooks.beforeEach(function () {
|
|
||||||
this.store = this.owner.lookup('service:store');
|
|
||||||
this.backend = 'pki-engine';
|
|
||||||
});
|
|
||||||
|
|
||||||
test('it should make request to correct endpoint on update', async function (assert) {
|
|
||||||
assert.expect(1);
|
|
||||||
|
|
||||||
this.server.post(`/${this.backend}/config/crl`, () => {
|
|
||||||
assert.ok(true, 'request made to correct endpoint on update');
|
|
||||||
});
|
|
||||||
|
|
||||||
this.store.pushPayload('pki/crl', {
|
|
||||||
modelName: 'pki/crl',
|
|
||||||
id: this.backend,
|
|
||||||
});
|
|
||||||
|
|
||||||
const model = this.store.peekRecord('pki/crl', this.backend);
|
|
||||||
await model.save();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('it should make request to correct endpoint on find', async function (assert) {
|
|
||||||
assert.expect(1);
|
|
||||||
|
|
||||||
this.server.get(`/${this.backend}/config/crl`, () => {
|
|
||||||
assert.ok(true, 'request is made to correct endpoint on find');
|
|
||||||
return { data: { id: this.backend } };
|
|
||||||
});
|
|
||||||
|
|
||||||
this.store.findRecord('pki/crl', this.backend);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,45 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) HashiCorp, Inc.
|
|
||||||
* SPDX-License-Identifier: MPL-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { module, test } from 'qunit';
|
|
||||||
import { setupTest } from 'vault/tests/helpers';
|
|
||||||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
|
||||||
|
|
||||||
module('Unit | Adapter | pki/urls', function (hooks) {
|
|
||||||
setupTest(hooks);
|
|
||||||
setupMirage(hooks);
|
|
||||||
|
|
||||||
hooks.beforeEach(function () {
|
|
||||||
this.store = this.owner.lookup('service:store');
|
|
||||||
this.backend = 'pki-engine';
|
|
||||||
});
|
|
||||||
|
|
||||||
test('it should make request to correct endpoint on update', async function (assert) {
|
|
||||||
assert.expect(1);
|
|
||||||
|
|
||||||
this.server.post(`/${this.backend}/config/urls`, () => {
|
|
||||||
assert.ok(true, 'request made to correct endpoint on update');
|
|
||||||
});
|
|
||||||
|
|
||||||
this.store.pushPayload('pki/urls', {
|
|
||||||
modelName: 'pki/urls',
|
|
||||||
id: this.backend,
|
|
||||||
});
|
|
||||||
|
|
||||||
const model = this.store.peekRecord('pki/urls', this.backend);
|
|
||||||
await model.save();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('it should make request to correct endpoint on find', async function (assert) {
|
|
||||||
assert.expect(1);
|
|
||||||
|
|
||||||
this.server.get(`/${this.backend}/config/urls`, () => {
|
|
||||||
assert.ok(true, 'request is made to correct endpoint on find');
|
|
||||||
return { data: { id: this.backend } };
|
|
||||||
});
|
|
||||||
|
|
||||||
this.store.findRecord('pki/urls', this.backend);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Model from '@ember-data/model';
|
import Model from '@ember-data/model';
|
||||||
import { FormField } from 'vault/app-types';
|
import { FormField } from 'vault/app-types';
|
||||||
|
|
||||||
export default class PkiCrlModel extends Model {
|
export default class PkiConfigCrlModel extends Model {
|
||||||
autoRebuild: boolean;
|
autoRebuild: boolean;
|
||||||
autoRebuildGracePeriod: string;
|
autoRebuildGracePeriod: string;
|
||||||
enableDelta: boolean;
|
enableDelta: boolean;
|
|
@ -1,6 +1,6 @@
|
||||||
import Model from '@ember-data/model';
|
import Model from '@ember-data/model';
|
||||||
|
|
||||||
export default class PkiUrlsModel extends Model {
|
export default class PkiConfigUrlsModel extends Model {
|
||||||
get useOpenAPI(): boolean;
|
get useOpenAPI(): boolean;
|
||||||
getHelpUrl(backendPath: string): string;
|
getHelpUrl(backendPath: string): string;
|
||||||
issuingCertificates: array;
|
issuingCertificates: array;
|
Loading…
Reference in New Issue