PKI Keys List View (#17239)

* setup

* cleanup

* cleanup
This commit is contained in:
Angel Garbarino
2022-09-21 07:41:44 -07:00
committed by GitHub
parent cb5e7e16f1
commit 613498cbc9
18 changed files with 161 additions and 6 deletions

View File

@@ -0,0 +1,28 @@
import ApplicationAdapter from '../application';
import { encodePath } from 'vault/utils/path-encoding-helpers';
export default class PkiKeyEngineAdapter extends ApplicationAdapter {
namespace = 'v1';
optionsForQuery(id) {
let data = {};
if (!id) {
data['list'] = true;
}
return { data };
}
urlForQuery(backend, id) {
let url = `${this.buildURL()}/${encodePath(backend)}/keys`;
if (id) {
url = url + '/' + encodePath(id);
}
return url;
}
async query(store, type, query) {
const { backend, id } = query;
let response = await this.ajax(this.urlForQuery(backend, id), 'GET', this.optionsForQuery(id));
return response;
}
}

View File

@@ -13,7 +13,7 @@ const validations = {
};
@withModelValidations(validations)
export default class PkiIssuersEngineModel extends Model {
export default class PkiIssuerEngineModel extends Model {
@attr('string', { readOnly: true }) backend;
@attr('string', {
label: 'Issuer name',

View File

@@ -0,0 +1,10 @@
import Model, { attr } from '@ember-data/model';
export default class PkiKeyEngineModel extends Model {
@attr('string', { readOnly: true }) backend;
@attr('boolean') isDefault;
@attr('string') keyRef; // reference to an existing key: either, vault generate identifier, literal string 'default', or the name assigned to the key. Part of the request URL.
@attr('string') keyId;
@attr('string') keyName;
@attr('string') keyType;
}

View File

@@ -16,7 +16,7 @@ const validations = {
};
@withModelValidations(validations)
export default class PkiRolesEngineModel extends Model {
export default class PkiRoleEngineModel extends Model {
@attr('string', { readOnly: true }) backend;
@attr('string', {
label: 'Role name',

View File

@@ -0,0 +1,15 @@
import ApplicationSerializer from '../application';
export default class PkiKeyEngineSerializer extends ApplicationSerializer {
// rehydrate each keys model so all model attributes are accessible from the LIST response
normalizeItems(payload) {
if (payload.data) {
if (payload.data?.keys && Array.isArray(payload.data.keys)) {
return payload.data.keys.map((key) => ({ id: key, ...payload.data.key_info[key] }));
}
Object.assign(payload, payload.data);
delete payload.data;
}
return payload;
}
}

View File

@@ -16,13 +16,17 @@ import Component from '@glimmer/component';
* ```
*
* @param {array} params - Array to pass to LinkTo
* @param {string} type - Use "add" to change icon
* @param {string} type - Use "add" to change icon to plus sign, or pass in your own kind of icon.
* @param {boolean} disabled - pass true to disable link
* @param {string} disabledTooltip - tooltip to display on hover when disabled
*/
export default class ToolbarLinkComponent extends Component {
get glyph() {
return this.args.type == 'add' ? 'plus' : 'chevron-right';
// not ideal logic. Without refactoring, this allows us to add in our own icon type outside of chevron-right or plus.
// For a later refactor we should remove the substitution for add to plus and just return type.
const { type } = this.args;
if (!type) return 'chevron-right';
return type === 'add' ? 'plus' : type;
}
}

View File

@@ -38,7 +38,9 @@ export default buildRoutes(function () {
});
});
this.route('keys', function () {
this.route('create');
this.route('index', { path: '/' });
this.route('generate');
this.route('import');
this.route('key', { path: '/:id' }, function () {
this.route('details');
this.route('edit');

View File

@@ -0,0 +1,3 @@
import Route from '@ember/routing/route';
export default class PkiKeysGenerateRoute extends Route {}

View File

@@ -0,0 +1,3 @@
import Route from '@ember/routing/route';
export default class PkiKeysImportRoute extends Route {}

View File

@@ -0,0 +1,19 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class PkiKeysIndexRoute extends Route {
@service store;
@service secretMountPath;
model() {
return this.store
.query('pki/pki-key-engine', { backend: this.secretMountPath.currentPath })
.catch((err) => {
if (err.httpStatus === 404) {
return [];
} else {
throw err;
}
});
}
}

View File

@@ -0,0 +1,3 @@
import Route from '@ember/routing/route';
export default class PkiKeysKeyDetailsRoute extends Route {}

View File

@@ -0,0 +1,3 @@
import Route from '@ember/routing/route';
export default class PkiKeysKeyEditRoute extends Route {}

View File

@@ -8,3 +8,4 @@
}}
@isEngine={{true}}
/>
{{outlet}}

View File

@@ -0,0 +1 @@
keys.generate

View File

@@ -0,0 +1 @@
keys.import

View File

@@ -0,0 +1,60 @@
<Toolbar>
<ToolbarActions>
<ToolbarLink @params={{array "keys.import"}} @type="download">
Import
</ToolbarLink>
<ToolbarLink @params={{array "keys.generate"}} @type="add">
Generate
</ToolbarLink>
</ToolbarActions>
</Toolbar>
<p class="has-padding">Below is information about the private keys used by the issuers to sign certificates. While
certificates represent a public assertion of an identity, private keys represent the private part of that identity, a
secret used to prove who they are and who they trust.</p>
{{#if (gt this.model.length 0)}}
{{#each this.model as |pkiKey|}}
<LinkedBlock class="list-item-row" @params={{array "roles.role.details" pkiKey.id}} @linkPrefix={{this.mountPoint}}>
<div class="level is-mobile">
<div class="level-left">
<div>
<Icon @name="certificate" class="has-text-grey-light" />
<span class="has-text-weight-semibold is-underline">
{{pkiKey.id}}
</span>
<div class="is-flex-row has-left-margin-l has-top-margin-xs">
{{#if pkiKey.keyName}}
<span class="tag has-text-grey-dark">{{pkiKey.keyName}}</span>
{{/if}}
</div>
</div>
</div>
<div class="level-right is-flex is-paddingless is-marginless">
<div class="level-item">
<PopupMenu>
<nav class="menu">
<ul class="menu-list">
<li>
<LinkTo @route="keys.key.details" @model={{pkiKey.id}}>
Details
</LinkTo>
</li>
<li>
<LinkTo @route="keys.key.edit" @model={{pkiKey.id}}>
Edit
</LinkTo>
</li>
</ul>
</nav>
</PopupMenu>
</div>
</div>
</div>
</LinkedBlock>
{{/each}}
{{else}}
<EmptyState @title="PKI not configured" @message="This PKI mount hasnt yet been configured with a certificate issuer.">
<LinkTo @route="configuration.create.index" @model={{this.model}}>
ARG TODO waiting for language from design
</LinkTo>
</EmptyState>
{{/if}}

View File

@@ -0,0 +1 @@
keys.key.:id.details

View File

@@ -0,0 +1 @@
keys.key.:id.edit