Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ui/transform sidebranch #9665

Merged
merged 22 commits into from
Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ecc83ef
Ui/transform enable (#9647)
chelshaw Jul 31, 2020
60e551f
Sidebranch: Transform Secret Engine Initial setup (#9625)
Monkeychip Jul 31, 2020
3f17db4
Merge branch 'master' into ui/transform-sidebranch
chelshaw Aug 5, 2020
ad57a3c
Ui/transform language fixes (#9666)
chelshaw Aug 10, 2020
5b3282e
Ui/create edit transformation fixes (#9668)
Monkeychip Aug 11, 2020
978cdfd
Merge branch 'master' into ui/transform-sidebranch
chelshaw Aug 17, 2020
716e9a4
Sidebranch: UI transform create and edit clean up (#9778)
Monkeychip Aug 19, 2020
12f6dee
Merge branch 'master' into ui/transform-sidebranch
chelshaw Aug 19, 2020
2cc7eb9
Merge branch 'master' into ui/transform-sidebranch
chelshaw Aug 20, 2020
9939a85
Ui/fix list roles transformation (#9788)
chelshaw Aug 20, 2020
f4a93bb
Ui/transform cleanup 2 (#9789)
Monkeychip Aug 20, 2020
9dcd886
Show KMIP un-selectable if enterprise but no ADP module (#9780)
chelshaw Aug 20, 2020
9b548a3
Merge branch 'master' into ui/transform-sidebranch
chelshaw Aug 20, 2020
c6e2560
New component transform-edit-base
chelshaw Aug 24, 2020
f595ed8
Duplicate RoleEdit as TransformEditBase and swap in all transform com…
chelshaw Aug 24, 2020
711d6ab
Roll back role-edit changes
chelshaw Aug 24, 2020
93a2752
Update to transform edit base
chelshaw Aug 24, 2020
19bc619
Remove extraeneous set backend type on transform components
chelshaw Aug 24, 2020
d79c481
formatting
chelshaw Aug 24, 2020
dc0c579
Revert search-select changes
chelshaw Aug 26, 2020
216d1a5
Update template/templates data on transformation (#9838)
chelshaw Aug 26, 2020
9353d56
Merge branch 'master' into ui/transform-sidebranch
chelshaw Aug 26, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions ui/app/adapters/transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { assign } from '@ember/polyfills';
import { allSettled } from 'rsvp';
import ApplicationAdapter from './application';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default ApplicationAdapter.extend({
namespace: 'v1',

createOrUpdate(store, type, snapshot) {
const serializer = store.serializerFor(type.modelName);
const data = serializer.serialize(snapshot);
const { id } = snapshot;
let url = this.urlForTransformations(snapshot.record.get('backend'), id);

return this.ajax(url, 'POST', { data });
},

createRecord() {
return this.createOrUpdate(...arguments);
},

updateRecord() {
return this.createOrUpdate(...arguments, 'update');
},

deleteRecord(store, type, snapshot) {
const { id } = snapshot;
return this.ajax(this.urlForTransformations(snapshot.record.get('backend'), id), 'DELETE');
},

pathForType() {
return 'transform';
},

urlForTransformations(backend, id) {
let url = `${this.buildURL()}/${encodePath(backend)}/transformation`;
if (id) {
url = url + '/' + encodePath(id);
}
return url;
},

optionsForQuery(id) {
let data = {};
if (!id) {
data['list'] = true;
}
return { data };
},

fetchByQuery(store, query) {
const { id, backend } = query;
const queryAjax = this.ajax(this.urlForTransformations(backend, id), 'GET', this.optionsForQuery(id));

return allSettled([queryAjax]).then(results => {
// query result 404d, so throw the adapterError
if (!results[0].value) {
throw results[0].reason;
}
let resp = {
id,
name: id,
backend,
data: {},
};

results.forEach(result => {
if (result.value) {
if (result.value.data.roles) {
resp.data = assign({}, resp.data, { zero_address_roles: result.value.data.roles });
} else {
resp.data = assign({}, resp.data, result.value.data);
}
}
});
return resp;
});
},

query(store, type, query) {
return this.fetchByQuery(store, query);
},

queryRecord(store, type, query) {
return this.fetchByQuery(store, query);
},
});
25 changes: 25 additions & 0 deletions ui/app/adapters/transform/role.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import ApplicationAdapater from '../application';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default ApplicationAdapater.extend({
namespace: 'v1',

pathForType() {
return 'role';
},

_url(backend, id) {
let type = this.pathForType();
let base = `/v1/${encodePath(backend)}/${type}`;
if (id) {
return `${base}/${encodePath(id)}`;
}
return base + '?list=true';
},

query(store, type, query) {
return this.ajax(this._url(query.backend), 'GET').then(result => {
return result;
});
},
});
25 changes: 25 additions & 0 deletions ui/app/adapters/transform/template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import ApplicationAdapater from '../application';
import { encodePath } from 'vault/utils/path-encoding-helpers';

export default ApplicationAdapater.extend({
namespace: 'v1',

pathForType() {
return 'template';
},

_url(backend, id) {
let type = this.pathForType();
let base = `${this.buildURL()}/${encodePath(backend)}/${type}`;
if (id) {
return `${base}/${encodePath(id)}`;
}
return base + '?list=true';
},

query(store, type, query) {
return this.ajax(this._url(query.backend), 'GET').then(result => {
return result;
});
},
});
9 changes: 4 additions & 5 deletions ui/app/components/mount-backend-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { computed } from '@ember/object';
import Component from '@ember/component';
import { task } from 'ember-concurrency';
import { methods } from 'vault/helpers/mountable-auth-methods';
import { engines, KMIP } from 'vault/helpers/mountable-secret-engines';
import { engines, KMIP, TRANSFORM } from 'vault/helpers/mountable-secret-engines';

const METHODS = methods();
const ENGINES = engines();
Expand Down Expand Up @@ -56,11 +56,10 @@ export default Component.extend({
}),

engines: computed('version.features[]', function() {
if (this.version.hasFeature('KMIP')) {
return ENGINES.concat([KMIP]);
} else {
return ENGINES;
if (this.get('version.isEnterprise')) {
return ENGINES.concat([KMIP, TRANSFORM]);
}
return ENGINES;
}),

willDestroy() {
Expand Down
3 changes: 1 addition & 2 deletions ui/app/components/role-edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ export default Component.extend(FocusOnInsertMixin, {
actions: {
createOrUpdate(type, event) {
event.preventDefault();

const modelId = this.get('model.id');
const modelId = this.get('model.id') || this.get('model.name'); // transform comes in as model.name
// prevent from submitting if there's no key
// maybe do something fancier later
if (type === 'create' && isBlank(modelId)) {
Expand Down
8 changes: 8 additions & 0 deletions ui/app/components/transform-create-form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import RoleEdit from './role-edit';

export default RoleEdit.extend({
init() {
this._super(...arguments);
this.set('backendType', 'transform');
},
});
8 changes: 8 additions & 0 deletions ui/app/components/transform-edit-form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import RoleEdit from './role-edit';

export default RoleEdit.extend({
chelshaw marked this conversation as resolved.
Show resolved Hide resolved
init() {
this._super(...arguments);
this.set('backendType', 'transform');
},
});
8 changes: 8 additions & 0 deletions ui/app/components/transform-show-transformation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import RoleEdit from './role-edit';

export default RoleEdit.extend({
chelshaw marked this conversation as resolved.
Show resolved Hide resolved
init() {
this._super(...arguments);
this.set('backendType', 'transform');
},
});
8 changes: 8 additions & 0 deletions ui/app/components/transformation-edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import RoleEdit from './role-edit';

export default RoleEdit.extend({
init() {
this._super(...arguments);
this.set('backendType', 'transform');
},
});
9 changes: 9 additions & 0 deletions ui/app/helpers/mountable-secret-engines.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ export const KMIP = {
value: 'kmip',
type: 'kmip',
category: 'generic',
requiredFeature: 'KMIP',
};

export const TRANSFORM = {
displayName: 'Transform',
value: 'transform',
type: 'transform',
category: 'generic',
requiredFeature: 'Transform Secrets Engine',
};

const MOUNTABLE_SECRET_ENGINES = [
Expand Down
49 changes: 49 additions & 0 deletions ui/app/helpers/options-for-backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,55 @@ const SECRET_BACKENDS = {
editComponent: 'role-ssh-edit',
listItemPartial: 'partials/secret-list/ssh-role-item',
},
transform: {
displayName: 'Transformation',
navigateTree: false,
listItemPartial: 'partials/secret-list/transform-transformation-item',
chelshaw marked this conversation as resolved.
Show resolved Hide resolved
tabs: [
{
name: 'transformations',
label: 'Transformations',
searchPlaceholder: 'Filter transformations',
item: 'transformation',
create: 'Create transformation',
editComponent: 'transformation-edit',
},
// TODO: Add tabs as needed
// {
// name: 'roles',
// modelPrefix: 'role/',
// label: 'Roles',
// searchPlaceholder: 'Filter roles',
// item: 'roles',
// create: 'Create role',
// tab: 'role',
// listItemPartial: 'partials/secret-list/item',
// editComponent: 'transform-role-edit',
// },
// {
// name: 'templates',
// modelPrefix: 'template/',
// label: 'Templates',
// searchPlaceholder: 'Filter templates',
// item: 'templates',
// create: 'Create template',
// tab: 'template',
// listItemPartial: 'partials/secret-list/item',
// editComponent: 'transform-template-edit',
// },
// {
// name: 'alphabets',
// modelPrefix: 'alphabet/',
// label: 'Alphabets',
// searchPlaceholder: 'Filter alphabets',
// item: 'alphabets',
// create: 'Create alphabet',
// tab: 'alphabet',
// listItemPartial: 'partials/secret-list/item',
// editComponent: 'alphabet-edit',
// },
],
},
transit: {
searchPlaceholder: 'Filter keys',
item: 'key',
Expand Down
12 changes: 11 additions & 1 deletion ui/app/helpers/supported-secret-backends.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import { helper as buildHelper } from '@ember/component/helper';

const SUPPORTED_SECRET_BACKENDS = ['aws', 'cubbyhole', 'generic', 'kv', 'pki', 'ssh', 'transit', 'kmip'];
const SUPPORTED_SECRET_BACKENDS = [
'aws',
'cubbyhole',
'generic',
'kv',
'pki',
'ssh',
'transit',
'kmip',
'transform',
];

export function supportedSecretBackends() {
return SUPPORTED_SECRET_BACKENDS;
Expand Down
97 changes: 97 additions & 0 deletions ui/app/models/transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { computed } from '@ember/object';
import DS from 'ember-data';
import { apiPath } from 'vault/macros/lazy-capabilities';
import { expandAttributeMeta } from 'vault/utils/field-to-attrs';
import attachCapabilities from 'vault/lib/attach-capabilities';

const { attr } = DS;

// these arrays define the order in which the fields will be displayed
// see
//https://www.vaultproject.io/api-docs/secret/transform#create-update-transformation
const TYPES = [
{
value: 'fpe',
displayName: 'Format Preserving Encryption (FPE)',
},
{
value: 'masking',
displayName: 'Masking',
},
];

const TWEAK_SOURCE = [
{
value: 'supplied',
displayName: 'supplied',
chelshaw marked this conversation as resolved.
Show resolved Hide resolved
},
{
value: 'generated',
displayName: 'generated',
},
{
value: 'internal',
displayName: 'internal',
},
];

const Model = DS.Model.extend({
useOpenAPI: false,
name: attr('string', {
// TODO: make this required for making a transformation
label: 'Name',
fieldValue: 'id',
readOnly: true,
subText: 'The name for your transformation. This cannot be edited later.',
}),
type: attr('string', {
defaultValue: 'fpe',
label: 'Type',
possibleValues: TYPES,
subText:
'Vault provides two types of transformations: Format Preserving Encryption (FPE) is reversible, while Masking is not. This cannot be edited later.',
}),
tweak_source: attr('string', {
defaultValue: 'supplied',
label: 'Tweak source',
possibleValues: TWEAK_SOURCE,
subText: `A tweak value is used when performing FPE transformations. This can be supplied, generated, or internal.`, // TODO: I do not include the link here. Need to figure out the best way to approach this.
}),
masking_character: attr('string', {
characterLimit: 1,
defaultValue: '*',
label: 'Masking character',
subText: 'Specify which character you’d like to mask your data.',
}),
template: attr('string', {
editType: 'searchSelect',
fallbackComponent: 'string-list',
label: 'Template', // TODO: make this required for making a transformation
models: ['transform/template'],
selectLimit: 1,
subLabel: 'Template Name',
subText:
'Templates allow Vault to determine what and how to capture the value to be transformed. Type to use an existing template or create a new one.',
}),
templates: attr('array'), // TODO: remove once BE changes the returned property to a singular template on the GET request.
allowed_roles: attr('array', {
editType: 'searchSelect',
label: 'Allowed roles',
fallbackComponent: 'string-list',
models: ['transform/role'],
subText: 'Search for an existing role, type a new role to create it, or use a wildcard (*).',
}),
transformAttrs: computed('type', function() {
if (this.type === 'masking') {
return ['name', 'type', 'masking_character', 'template', 'templates', 'allowed_roles'];
}
return ['name', 'type', 'tweak_source', 'template', 'templates', 'allowed_roles'];
}),
transformFieldAttrs: computed('transformAttrs', function() {
return expandAttributeMeta(this, this.get('transformAttrs'));
chelshaw marked this conversation as resolved.
Show resolved Hide resolved
}),
});

export default attachCapabilities(Model, {
updatePath: apiPath`transform/transformation/${'id'}`,
});
Loading