From 71c57dc4e2f38c213f3547289d64a95664724d97 Mon Sep 17 00:00:00 2001
From: Chelsea Shaw
Date: Tue, 15 Sep 2020 13:46:35 -0500
Subject: [PATCH] Ui/transformation edit update roles (#9955)
* Update or create new role after allowed_roles on transformation updated
* Update tests to include transformation create/edit and role create scenarios
---
ui/app/components/transform-create-form.js | 4 +-
ui/app/components/transform-edit-base.js | 18 ++-
ui/app/components/transform-edit-form.js | 4 +-
ui/app/components/transform-role-edit.js | 31 +----
ui/app/components/transformation-edit.js | 113 +++++++++++++++++-
ui/app/serializers/transform/role.js | 1 -
.../components/transform-edit-form.hbs | 2 +-
.../components/transformation-edit.hbs | 8 +-
.../acceptance/enterprise-transform-test.js | 113 +++++++++++++++---
.../pages/secrets/backend/transform/roles.js | 1 +
.../backend/transform/transformations.js | 2 +
11 files changed, 245 insertions(+), 52 deletions(-)
diff --git a/ui/app/components/transform-create-form.js b/ui/app/components/transform-create-form.js
index 548e2dd85c..12fadca2e7 100644
--- a/ui/app/components/transform-create-form.js
+++ b/ui/app/components/transform-create-form.js
@@ -1,3 +1,3 @@
-import TransformBase from './transform-edit-base';
+import TransformationEdit from './transformation-edit';
-export default TransformBase.extend({});
+export default TransformationEdit.extend({});
diff --git a/ui/app/components/transform-edit-base.js b/ui/app/components/transform-edit-base.js
index 097c6ce691..17d879da9a 100644
--- a/ui/app/components/transform-edit-base.js
+++ b/ui/app/components/transform-edit-base.js
@@ -8,7 +8,23 @@ import FocusOnInsertMixin from 'vault/mixins/focus-on-insert';
const LIST_ROOT_ROUTE = 'vault.cluster.secrets.backend.list-root';
const SHOW_ROUTE = 'vault.cluster.secrets.backend.show';
+export const addToList = (list, itemToAdd) => {
+ if (!list || !Array.isArray(list)) return list;
+ list.push(itemToAdd);
+ return list.uniq();
+};
+
+export const removeFromList = (list, itemToRemove) => {
+ if (!list) return list;
+ const index = list.indexOf(itemToRemove);
+ if (index < 0) return list;
+ const newList = list.removeAt(index, 1);
+ return newList.uniq();
+};
+
export default Component.extend(FocusOnInsertMixin, {
+ store: service(),
+ flashMessages: service(),
router: service(),
mode: null,
@@ -79,7 +95,7 @@ export default Component.extend(FocusOnInsertMixin, {
delete() {
this.persist('destroyRecord', () => {
- this.hasDataChanges();
+ this.onDataChange();
this.transitionToRoute(LIST_ROOT_ROUTE);
});
},
diff --git a/ui/app/components/transform-edit-form.js b/ui/app/components/transform-edit-form.js
index 548e2dd85c..12fadca2e7 100644
--- a/ui/app/components/transform-edit-form.js
+++ b/ui/app/components/transform-edit-form.js
@@ -1,3 +1,3 @@
-import TransformBase from './transform-edit-base';
+import TransformationEdit from './transformation-edit';
-export default TransformBase.extend({});
+export default TransformationEdit.extend({});
diff --git a/ui/app/components/transform-role-edit.js b/ui/app/components/transform-role-edit.js
index fbf537aecb..187c331196 100644
--- a/ui/app/components/transform-role-edit.js
+++ b/ui/app/components/transform-role-edit.js
@@ -1,24 +1,6 @@
-import TransformBase from './transform-edit-base';
-import { inject as service } from '@ember/service';
-
-const addToList = (list, itemToAdd) => {
- if (!list || !Array.isArray(list)) return list;
- list.push(itemToAdd);
- return list.uniq();
-};
-
-const removeFromList = (list, itemToRemove) => {
- if (!list) return list;
- const index = list.indexOf(itemToRemove);
- if (index < 0) return list;
- const newList = list.removeAt(index, 1);
- return newList.uniq();
-};
+import TransformBase, { addToList, removeFromList } from './transform-edit-base';
export default TransformBase.extend({
- store: service(),
- flashMessages: service(),
-
initialTransformations: null,
init() {
@@ -48,14 +30,9 @@ export default TransformBase.extend({
allowed_roles: roles,
});
- return transformation
- .save()
- .then(() => {
- return 'Successfully saved';
- })
- .catch(e => {
- return { errorStatus: e.httpStatus, ...transform };
- });
+ return transformation.save().catch(e => {
+ return { errorStatus: e.httpStatus, ...transform };
+ });
});
});
diff --git a/ui/app/components/transformation-edit.js b/ui/app/components/transformation-edit.js
index 548e2dd85c..2b18c4fd77 100644
--- a/ui/app/components/transformation-edit.js
+++ b/ui/app/components/transformation-edit.js
@@ -1,3 +1,112 @@
-import TransformBase from './transform-edit-base';
+import TransformBase, { addToList, removeFromList } from './transform-edit-base';
-export default TransformBase.extend({});
+export default TransformBase.extend({
+ initialRoles: null,
+
+ init() {
+ this._super(...arguments);
+ this.set('initialRoles', this.get('model.allowed_roles'));
+ },
+
+ updateOrCreateRole(role, transformationId, backend) {
+ return this.store
+ .queryRecord('transform/role', {
+ backend,
+ id: role.id,
+ })
+ .then(roleStore => {
+ let transformations = roleStore.transformations;
+ if (role.action === 'ADD') {
+ transformations = addToList(transformations, transformationId);
+ } else if (role.action === 'REMOVE') {
+ transformations = removeFromList(transformations, transformationId);
+ }
+ roleStore.setProperties({
+ backend,
+ transformations,
+ });
+ return roleStore.save().catch(e => {
+ return {
+ errorStatus: e.httpStatus,
+ ...role,
+ };
+ });
+ })
+ .catch(e => {
+ if (e.httpStatus !== 403 && role.action === 'ADD') {
+ // If role doesn't yet exist, create it with this transformation attached
+ var newRole = this.store.createRecord('transform/role', {
+ id: role.id,
+ name: role.id,
+ transformations: [transformationId],
+ backend,
+ });
+ return newRole.save().catch(e => {
+ return {
+ errorStatus: e.httpStatus,
+ ...role,
+ action: 'CREATE',
+ };
+ });
+ }
+
+ return {
+ ...role,
+ errorStatus: e.httpStatus,
+ };
+ });
+ },
+
+ handleUpdateRoles(updateRoles, transformationId) {
+ if (!updateRoles) return;
+ const backend = this.get('model.backend');
+ const promises = updateRoles.map(r => this.updateOrCreateRole(r, transformationId, backend));
+
+ Promise.all(promises).then(results => {
+ let hasError = results.find(role => !!role.errorStatus);
+
+ if (hasError) {
+ let message =
+ 'The edits to this transformation were successful, but transformations for its roles was not edited due to a lack of permissions.';
+ if (results.find(e => !!e.errorStatus && e.errorStatus !== 403)) {
+ // if the errors weren't all due to permissions show generic message
+ // eg. trying to update a role with empty array as transformations
+ message = `You've edited the allowed_roles for this transformation. However, the corresponding edits to some roles' transformations were not made`;
+ }
+ this.get('flashMessages').stickyInfo(message);
+ }
+ });
+ },
+
+ actions: {
+ createOrUpdate(type, event) {
+ event.preventDefault();
+
+ this.applyChanges('save', () => {
+ const transformationId = this.get('model.id');
+ const newModelRoles = this.get('model.allowed_roles') || [];
+ const initialRoles = this.get('initialRoles') || [];
+
+ const updateRoles = [...newModelRoles, ...initialRoles]
+ .filter(r => r.indexOf('*') < 0) // TODO: expand wildcards into included roles instead
+ .map(role => {
+ if (initialRoles.indexOf(role) < 0) {
+ return {
+ id: role,
+ action: 'ADD',
+ };
+ }
+ if (newModelRoles.indexOf(role) < 0) {
+ return {
+ id: role,
+ action: 'REMOVE',
+ };
+ }
+ return null;
+ })
+ .filter(r => !!r);
+ this.handleUpdateRoles(updateRoles, transformationId);
+ });
+ },
+ },
+});
diff --git a/ui/app/serializers/transform/role.js b/ui/app/serializers/transform/role.js
index 8a3d8f9eb3..ed04af7935 100644
--- a/ui/app/serializers/transform/role.js
+++ b/ui/app/serializers/transform/role.js
@@ -1,7 +1,6 @@
import ApplicationSerializer from '../application';
export default ApplicationSerializer.extend({
extractLazyPaginatedData(payload) {
- // TODO: do this for transform too?
let ret;
ret = payload.data.keys.map(key => {
let model = {
diff --git a/ui/app/templates/components/transform-edit-form.hbs b/ui/app/templates/components/transform-edit-form.hbs
index 3855980c7f..d2ef34999f 100644
--- a/ui/app/templates/components/transform-edit-form.hbs
+++ b/ui/app/templates/components/transform-edit-form.hbs
@@ -40,7 +40,7 @@
type="submit"
disabled={{buttonDisabled}}
class="button is-primary"
- data-test-role-ssh-create=true
+ data-test-transformation-save-button=true
>
{{#if (eq mode 'create')}}
Create transformation
diff --git a/ui/app/templates/components/transformation-edit.hbs b/ui/app/templates/components/transformation-edit.hbs
index 96f04e5c37..d177363c49 100644
--- a/ui/app/templates/components/transformation-edit.hbs
+++ b/ui/app/templates/components/transformation-edit.hbs
@@ -62,6 +62,7 @@
Edit transformation
@@ -117,7 +118,12 @@