UI/Database Secrets Engine cleanup (#10949)
* Update role toolbar, serialization for special mongo values * Only show defaultShown if no value on info table row * Remove root_rotation_statements from mongo connection fields * Wrap this.router in try/catch if in then statement * Add changelog
This commit is contained in:
parent
6f3d179635
commit
889d82aca5
|
@ -0,0 +1,3 @@
|
|||
```release-note:improvement
|
||||
ui: Customize MongoDB input fields on Database Secrets Engine
|
||||
```
|
|
@ -52,7 +52,7 @@ export default class DatabaseListItem extends Component {
|
|||
adapter
|
||||
.rotateRootCredentials(backend, id)
|
||||
.then(() => {
|
||||
this.flashMessages.success(`Success: ${id} connection was reset`);
|
||||
this.flashMessages.success(`Success: ${id} connection was rotated`);
|
||||
})
|
||||
.catch(e => {
|
||||
this.flashMessages.danger(e.errors);
|
||||
|
|
|
@ -43,7 +43,11 @@ export default class DatabaseRoleEdit extends Component {
|
|||
secret
|
||||
.destroyRecord()
|
||||
.then(() => {
|
||||
this.router.transitionTo(LIST_ROOT_ROUTE, backend, { queryParams: { tab: 'role' } });
|
||||
try {
|
||||
this.router.transitionTo(LIST_ROOT_ROUTE, backend, { queryParams: { tab: 'role' } });
|
||||
} catch (e) {
|
||||
console.debug(e);
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
this.flashMessages.danger(e.errors?.join('. '));
|
||||
|
@ -59,7 +63,11 @@ export default class DatabaseRoleEdit extends Component {
|
|||
let path = roleSecret.type === 'static' ? 'static-roles' : 'roles';
|
||||
roleSecret.set('path', path);
|
||||
roleSecret.save().then(() => {
|
||||
this.router.transitionTo(SHOW_ROUTE, `role/${secretId}`);
|
||||
try {
|
||||
this.router.transitionTo(SHOW_ROUTE, `role/${secretId}`);
|
||||
} catch (e) {
|
||||
console.debug(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -75,7 +83,11 @@ export default class DatabaseRoleEdit extends Component {
|
|||
roleSecret.set('path', path);
|
||||
}
|
||||
roleSecret.save().then(() => {
|
||||
this.router.transitionTo(SHOW_ROUTE, `role/${secretId}`);
|
||||
try {
|
||||
this.router.transitionTo(SHOW_ROUTE, `role/${secretId}`);
|
||||
} catch (e) {
|
||||
console.debug(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ const STATEMENT_FIELDS = {
|
|||
},
|
||||
dynamic: {
|
||||
default: ['creation_statements', 'revocation_statements', 'rotation_statements'],
|
||||
'mongodb-database-plugin': ['creation_statement'],
|
||||
'mongodb-database-plugin': ['creation_statement', 'revocation_statement'],
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -44,25 +44,21 @@ export default class DatabaseRoleSettingForm extends Component {
|
|||
const type = this.args.roleType;
|
||||
if (!type) return null;
|
||||
const db = this.args.dbType || 'default';
|
||||
const fields = ROLE_FIELDS[type][db];
|
||||
if (!Array.isArray(fields)) return fields;
|
||||
const filtered = this.args.attrs.filter(a => {
|
||||
const includes = fields.includes(a.name);
|
||||
return includes;
|
||||
const dbValidFields = ROLE_FIELDS[type][db];
|
||||
if (!Array.isArray(dbValidFields)) return dbValidFields;
|
||||
return this.args.attrs.filter(a => {
|
||||
return dbValidFields.includes(a.name);
|
||||
});
|
||||
return filtered;
|
||||
}
|
||||
|
||||
get statementFields() {
|
||||
const type = this.args.roleType;
|
||||
if (!type) return null;
|
||||
const db = this.args.dbType || 'default';
|
||||
const fields = STATEMENT_FIELDS[type][db];
|
||||
if (!Array.isArray(fields)) return fields;
|
||||
const filtered = this.args.attrs.filter(a => {
|
||||
const includes = fields.includes(a.name);
|
||||
return includes;
|
||||
const dbValidFields = STATEMENT_FIELDS[type][db];
|
||||
if (!Array.isArray(dbValidFields)) return dbValidFields;
|
||||
return this.args.attrs.filter(a => {
|
||||
return dbValidFields.includes(a.name);
|
||||
});
|
||||
return filtered;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,10 +79,9 @@ export default Model.extend({
|
|||
subText: 'x509 CA file for validating the certificate presented by the MongoDB server.',
|
||||
editType: 'file',
|
||||
}),
|
||||
root_rotation_statements: attr('string', {
|
||||
root_rotation_statements: attr({
|
||||
subText: `The database statements to be executed to rotate the root user's credentials. If nothing is entered, Vault will use a reasonable default.`,
|
||||
editType: 'json',
|
||||
theme: 'hashi short',
|
||||
editType: 'stringArray',
|
||||
defaultShown: 'Default',
|
||||
}),
|
||||
|
||||
|
@ -115,15 +114,7 @@ export default Model.extend({
|
|||
|
||||
// for both create and edit fields
|
||||
mainFields: computed('plugin_name', function() {
|
||||
return [
|
||||
'plugin_name',
|
||||
'name',
|
||||
'connection_url',
|
||||
'verify_connection',
|
||||
'password_policy',
|
||||
'pluginConfig',
|
||||
'root_rotation_statements',
|
||||
];
|
||||
return ['plugin_name', 'name', 'connection_url', 'verify_connection', 'password_policy', 'pluginConfig'];
|
||||
}),
|
||||
|
||||
showAttrs: computed('plugin_name', function() {
|
||||
|
@ -133,13 +124,15 @@ export default Model.extend({
|
|||
'connection_url',
|
||||
'write_concern',
|
||||
'verify_connection',
|
||||
'root_rotation_statements',
|
||||
'allowed_roles',
|
||||
];
|
||||
return expandAttributeMeta(this, f);
|
||||
}),
|
||||
|
||||
pluginFieldGroups: computed('plugin_name', function() {
|
||||
if (!this.plugin_name) {
|
||||
return null;
|
||||
}
|
||||
let groups = [{ default: ['username', 'password', 'write_concern'] }];
|
||||
// TODO: Get plugin options based on plugin
|
||||
groups.push({
|
||||
|
|
|
@ -64,7 +64,7 @@ export default Model.extend({
|
|||
theme: 'hashi short',
|
||||
defaultShown: 'Default',
|
||||
}),
|
||||
rotation_statement: attr('string', {
|
||||
revocation_statement: attr('string', {
|
||||
editType: 'json',
|
||||
theme: 'hashi short',
|
||||
defaultShown: 'Default',
|
||||
|
@ -72,7 +72,18 @@ export default Model.extend({
|
|||
|
||||
/* FIELD ATTRIBUTES */
|
||||
get fieldAttrs() {
|
||||
let fields = ['database', 'name', 'type'];
|
||||
// Main fields on edit/create form
|
||||
let fields = ['name', 'database', 'type'];
|
||||
return expandAttributeMeta(this, fields);
|
||||
},
|
||||
|
||||
get showFields() {
|
||||
let fields = ['name', 'database', 'type'];
|
||||
if (this.type === 'dynamic') {
|
||||
fields = fields.concat(['ttl', 'max_ttl', 'creation_statements', 'revocation_statements']);
|
||||
} else {
|
||||
fields = fields.concat(['username', 'rotation_period']);
|
||||
}
|
||||
return expandAttributeMeta(this, fields);
|
||||
},
|
||||
|
||||
|
@ -86,8 +97,8 @@ export default Model.extend({
|
|||
'creation_statements',
|
||||
'creation_statement', // only for MongoDB (styling difference)
|
||||
'revocation_statements',
|
||||
'revocation_statement', // only for MongoDB (styling difference)
|
||||
'rotation_statements',
|
||||
'rotation_statement', // only for MongoDB (styling difference)
|
||||
];
|
||||
return expandAttributeMeta(this, allRoleSettingFields);
|
||||
}),
|
||||
|
|
|
@ -24,12 +24,17 @@ export default RESTSerializer.extend({
|
|||
if (payload.data.db_name) {
|
||||
database = [payload.data.db_name];
|
||||
}
|
||||
// Copy to singular for MongoDB
|
||||
const creation_statement = payload.data.creation_statements[0];
|
||||
const revocation_statement = payload.data.revocation_statements[0];
|
||||
return {
|
||||
id: payload.secret,
|
||||
name: payload.secret,
|
||||
backend: payload.backend,
|
||||
database,
|
||||
path,
|
||||
creation_statement,
|
||||
revocation_statement,
|
||||
...payload.data,
|
||||
};
|
||||
},
|
||||
|
@ -64,6 +69,18 @@ export default RESTSerializer.extend({
|
|||
data.db_name = db;
|
||||
delete data.database;
|
||||
}
|
||||
// This is necessary because the input for MongoDB is a json string
|
||||
// rather than an array, so we transpose that here
|
||||
if (data.creation_statement) {
|
||||
const singleStatement = data.creation_statement;
|
||||
data.creation_statements = [singleStatement];
|
||||
delete data.creation_statement;
|
||||
}
|
||||
if (data.revocation_statement) {
|
||||
const singleStatement = data.revocation_statement;
|
||||
data.revocation_statements = [singleStatement];
|
||||
delete data.revocation_statement;
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
{{!-- Plugin Config Section --}}
|
||||
<div class="form-section">
|
||||
<h3 class="title is-5">Plugin config</h3>
|
||||
{{#unless @model.plugin_name}}
|
||||
{{#unless @model.pluginFieldGroups}}
|
||||
<EmptyState
|
||||
@title="No plugin selected"
|
||||
@message="Select a plugin type to be able to configure it."
|
||||
|
@ -97,7 +97,6 @@
|
|||
{{#each-in fieldGroup as |group fields|}}
|
||||
{{#if (eq group "default")}}
|
||||
{{#each fields as |attr|}}
|
||||
{{!-- TODO: special password edit mode --}}
|
||||
{{form-field data-test-field attr=attr model=@model}}
|
||||
{{/each}}
|
||||
{{else}}
|
||||
|
|
|
@ -18,6 +18,19 @@
|
|||
{{#if (eq @mode 'show')}}
|
||||
<Toolbar>
|
||||
<ToolbarActions>
|
||||
{{#if @model.canDelete}}
|
||||
<ConfirmAction
|
||||
@buttonClasses="toolbar-link"
|
||||
@onConfirmAction={{action 'delete'}}
|
||||
@confirmTitle="Delete role?"
|
||||
@confirmMessage="This role will be permanently deleted. You will need to recreate it to use it again."
|
||||
@confirmButtonText="Delete"
|
||||
data-test-database-role-delete
|
||||
>
|
||||
Delete role
|
||||
</ConfirmAction>
|
||||
<div class="toolbar-separator" />
|
||||
{{/if}}
|
||||
{{#if @model.canGenerateCredentials}}
|
||||
<button
|
||||
type="button"
|
||||
|
@ -28,18 +41,6 @@
|
|||
Generate credentials
|
||||
</button>
|
||||
{{/if}}
|
||||
{{#if @model.canDelete}}
|
||||
<ConfirmAction
|
||||
@buttonClasses="toolbar-link"
|
||||
@onConfirmAction={{action 'delete'}}
|
||||
@confirmTitle="Delete role?"
|
||||
@confirmMessage="This role will be permanently deleted. You will need to re-create it to use it again."
|
||||
@confirmButtonText="Delete"
|
||||
data-test-database-role-delete
|
||||
>
|
||||
Delete role
|
||||
</ConfirmAction>
|
||||
{{/if}}
|
||||
{{#if @model.canEditRole}}
|
||||
<ToolbarSecretLink
|
||||
@secret={{concat 'role/' @model.id}}
|
||||
|
@ -53,7 +54,7 @@
|
|||
{{/if}}
|
||||
</ToolbarActions>
|
||||
</Toolbar>
|
||||
{{#each @model.fieldAttrs as |attr|}}
|
||||
{{#each @model.showFields as |attr|}}
|
||||
{{#let attr.options.defaultDisplay as |defaultDisplay|}}
|
||||
{{#if (eq attr.type "object")}}
|
||||
<InfoTableRow
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
@glyph="cancel-square-outline"
|
||||
/> No
|
||||
{{/if}}
|
||||
{{else if (and alwaysRender defaultShown)}}
|
||||
{{else if (and (not value) (and alwaysRender defaultShown))}}
|
||||
{{defaultShown}}
|
||||
{{else}}
|
||||
{{#if (eq type 'array')}}
|
||||
|
|
Loading…
Reference in New Issue