mirror of
https://github.com/hashicorp/vault.git
synced 2026-02-18 18:38:08 -05:00
UI: Add password field to static role creation page (#30275)
* adding password to static roles * adding check for password rotation to disable password edit * update field type and tests * adding changelog * replacing readonly with enableinput, added disable arg, test updates * update to unless * PR comments
This commit is contained in:
parent
766f97a9d4
commit
ceb9c6d062
7 changed files with 54 additions and 15 deletions
3
changelog/30275.txt
Normal file
3
changelog/30275.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
```release-note:improvement
|
||||
ui/database: Adding password input field for creating a static role
|
||||
```
|
||||
|
|
@ -125,6 +125,8 @@ export default class RoleModel extends Model {
|
|||
})
|
||||
revocation_statement;
|
||||
|
||||
@attr('string', { readOnly: true }) last_vault_rotation;
|
||||
|
||||
// ENTERPRISE ONLY
|
||||
@attr({
|
||||
label: 'Rotate immediately',
|
||||
|
|
@ -135,6 +137,12 @@ export default class RoleModel extends Model {
|
|||
})
|
||||
skip_import_rotation;
|
||||
|
||||
@attr('string', {
|
||||
sensitive: true,
|
||||
subText: 'The database password that this Vault role corresponds to.',
|
||||
})
|
||||
password;
|
||||
|
||||
/* FIELD ATTRIBUTES */
|
||||
get fieldAttrs() {
|
||||
// Main fields on edit/create form
|
||||
|
|
@ -156,6 +164,7 @@ export default class RoleModel extends Model {
|
|||
'default_ttl',
|
||||
'max_ttl',
|
||||
'username',
|
||||
'password',
|
||||
'rotation_period',
|
||||
'skip_import_rotation',
|
||||
'creation_statements',
|
||||
|
|
@ -169,7 +178,9 @@ export default class RoleModel extends Model {
|
|||
|
||||
// remove enterprise-only attrs if on community
|
||||
if (!this.version.isEnterprise) {
|
||||
allRoleSettingFields = allRoleSettingFields.filter((role) => role !== 'skip_import_rotation');
|
||||
allRoleSettingFields = allRoleSettingFields.filter(
|
||||
(role) => !['skip_import_rotation', 'password'].includes(role)
|
||||
);
|
||||
}
|
||||
|
||||
return expandAttributeMeta(this, allRoleSettingFields);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,16 @@
|
|||
{{else}}
|
||||
<ReadonlyFormField @attr={{attr}} @value={{get @model attr.name}} />
|
||||
{{/if}}
|
||||
{{else if (and (eq @mode "edit") (eq attr.name "password"))}}
|
||||
<EnableInput
|
||||
data-test-enable-field={{attr.name}}
|
||||
class="field"
|
||||
@attr={{attr}}
|
||||
{{! password field is disabled on edit once password has been rotated }}
|
||||
@disabled={{(not (eq (get @model "last_vault_rotation") undefined))}}
|
||||
>
|
||||
<FormField @attr={{attr}} @model={{@model}} />
|
||||
</EnableInput>
|
||||
{{else}}
|
||||
<FormField data-test-field={{true}} @attr={{attr}} @model={{@model}} @modelValidations={{@modelValidations}} />
|
||||
{{#if (and (eq attr.name "skip_import_rotation") this.isOverridden)}}
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ export const AVAILABLE_PLUGIN_TYPES = [
|
|||
];
|
||||
|
||||
export const ROLE_FIELDS = {
|
||||
static: ['username', 'rotation_period', 'skip_import_rotation'],
|
||||
static: ['username', 'password', 'rotation_period', 'skip_import_rotation'],
|
||||
dynamic: ['default_ttl', 'max_ttl'],
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,14 +14,16 @@
|
|||
<Input aria-label={{@label}} readonly class="input" @type="text" @value="**********" />
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="align-self-end">
|
||||
<Hds::Button
|
||||
@text="Enable input"
|
||||
@icon="edit"
|
||||
@isIconOnly={{true}}
|
||||
@color="tertiary"
|
||||
{{on "click" (fn (mut this.enable))}}
|
||||
/>
|
||||
</div>
|
||||
{{#unless @disabled}}
|
||||
<div class="align-self-end">
|
||||
<Hds::Button
|
||||
@text="Enable input"
|
||||
@icon="edit"
|
||||
@isIconOnly={{true}}
|
||||
@color="tertiary"
|
||||
{{on "click" (fn (mut this.enable))}}
|
||||
/>
|
||||
</div>
|
||||
{{/unless}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
|
@ -9,6 +9,7 @@ import { tracked } from '@glimmer/tracking';
|
|||
interface Args {
|
||||
attr?: AttrData;
|
||||
label?: string;
|
||||
disabled?: boolean; // specifically used for disabling on edit
|
||||
}
|
||||
interface AttrData {
|
||||
name: string; // required if @attr is passed
|
||||
|
|
@ -38,6 +39,7 @@ interface AttrData {
|
|||
|
||||
* @param {object} [attr] - used to generate label for `ReadonlyFormField`, `name` key is required. Can be an attribute from a model exported with expandAttributeMeta.
|
||||
* @param {string} [label] - required if no attr passed. Used to ensure a11y conformance for the readonly input.
|
||||
* @param {boolean} [disabled=false] - to be used in specific scenarios where a user can visually see but not interact with the input field. ie. disabling a field on edit
|
||||
*/
|
||||
|
||||
export default class EnableInputComponent extends Component<Args> {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { hbs } from 'ember-cli-htmlbars';
|
|||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
import { capabilitiesStub } from 'vault/tests/helpers/stubs';
|
||||
import { click, fillIn } from '@ember/test-helpers';
|
||||
import { GENERAL } from 'vault/tests/helpers/general-selectors';
|
||||
|
||||
module('Integration | Component | database-role-edit', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
|
@ -87,6 +88,7 @@ module('Integration | Component | database-role-edit', function (hooks) {
|
|||
{
|
||||
path: 'static-roles',
|
||||
username: 'staticTestUser',
|
||||
password: 'testPassword',
|
||||
rotation_period: '172800s', // 2 days in seconds
|
||||
skip_import_rotation: true,
|
||||
},
|
||||
|
|
@ -95,13 +97,18 @@ module('Integration | Component | database-role-edit', function (hooks) {
|
|||
});
|
||||
|
||||
await render(hbs`<DatabaseRoleEdit @model={{this.modelStatic}} @mode="create"/>`);
|
||||
await fillIn('[data-test-ttl-value="Rotation period"]', '2');
|
||||
await click('[data-test-toggle-input="toggle-skip_import_rotation"]');
|
||||
await fillIn(GENERAL.ttl.input('Rotation period'), '2');
|
||||
await click(GENERAL.toggleInput('toggle-skip_import_rotation'));
|
||||
await fillIn(GENERAL.inputByAttr('password'), 'testPassword'); // fill in password field
|
||||
|
||||
await click('[data-test-secret-save]');
|
||||
|
||||
await render(hbs`<DatabaseRoleEdit @model={{this.modelStatic}} @mode="show"/>`);
|
||||
assert.dom('[data-test-value-div="Rotate immediately"]').containsText('No');
|
||||
assert.dom(GENERAL.infoRowValue('Rotate immediately')).containsText('No');
|
||||
assert.dom(GENERAL.infoRowValue('password')).doesNotExist(); // verify password field doesn't show on details view
|
||||
|
||||
await render(hbs`<DatabaseRoleEdit @model={{this.modelStatic}} @mode="edit"/>`);
|
||||
assert.dom(GENERAL.icon('edit')).exists(); // verify password field is enabled for edit & enable button is rendered bc role hasn't been rotated
|
||||
});
|
||||
|
||||
test('enterprise: it should successfully create user that does rotate immediately & verify warning modal pops up', async function (assert) {
|
||||
|
|
@ -115,7 +122,11 @@ module('Integration | Component | database-role-edit', function (hooks) {
|
|||
await click('[data-test-issuer-save]'); // click continue button on modal
|
||||
|
||||
await render(hbs`<DatabaseRoleEdit @model={{this.modelStatic}} @mode="show"/>`);
|
||||
assert.dom('[data-test-value-div="Rotate immediately"]').containsText('Yes');
|
||||
assert.dom(GENERAL.infoRowValue('Rotate immediately')).containsText('Yes');
|
||||
|
||||
this.modelStatic.last_vault_rotation = '2025-04-21T12:51:59.063124-04:00'; // Setting a sample rotation time here to simulate what returns from BE after rotation
|
||||
await render(hbs`<DatabaseRoleEdit @model={{this.modelStatic}} @mode="edit"/>`);
|
||||
assert.dom(GENERAL.icon('edit')).doesNotExist(); // verify password field is disabled for edit & enable button isn't rendered bc role has already been rotated
|
||||
});
|
||||
|
||||
test('it should show Get credentials button when a user has the correct policy', async function (assert) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue