mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 17:52:32 +00:00
UI: Add missing auth config params (#25646)
* add allowed_response_headers and plugin_version to auth method config * add user_lockout_config to auth tune * add changelog; * update test * add test
This commit is contained in:
3
changelog/25646.txt
Normal file
3
changelog/25646.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:improvement
|
||||
ui: Adds allowed_response_headers, plugin_version and user_lockout_config params to auth method configuration
|
||||
```
|
||||
@@ -30,12 +30,20 @@ export default AuthConfigComponent.extend({
|
||||
waitFor(function* () {
|
||||
const data = this.model.config.serialize();
|
||||
data.description = this.model.description;
|
||||
data.user_lockout_config = {};
|
||||
|
||||
// token_type should not be tuneable for the token auth method.
|
||||
if (this.model.methodType === 'token') {
|
||||
delete data.token_type;
|
||||
}
|
||||
|
||||
this.model.userLockoutConfig.apiParams.forEach((attr) => {
|
||||
if (Object.keys(data).includes(attr)) {
|
||||
data.user_lockout_config[attr] = data[attr];
|
||||
delete data[attr];
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
yield this.model.tune(data);
|
||||
} catch (err) {
|
||||
|
||||
@@ -68,6 +68,16 @@ export default class AuthMethodModel extends Model {
|
||||
return this.local ? 'local' : 'replicated';
|
||||
}
|
||||
|
||||
userLockoutConfig = {
|
||||
modelAttrs: [
|
||||
'config.lockoutThreshold',
|
||||
'config.lockoutDuration',
|
||||
'config.lockoutCounterReset',
|
||||
'config.lockoutDisable',
|
||||
],
|
||||
apiParams: ['lockout_threshold', 'lockout_duration', 'lockout_counter_reset', 'lockout_disable'],
|
||||
};
|
||||
|
||||
get tuneAttrs() {
|
||||
const { methodType } = this;
|
||||
let tuneAttrs;
|
||||
@@ -75,12 +85,12 @@ export default class AuthMethodModel extends Model {
|
||||
if (methodType === 'token') {
|
||||
tuneAttrs = [
|
||||
'description',
|
||||
'config.{listingVisibility,defaultLeaseTtl,maxLeaseTtl,auditNonHmacRequestKeys,auditNonHmacResponseKeys,passthroughRequestHeaders}',
|
||||
'config.{listingVisibility,defaultLeaseTtl,maxLeaseTtl,auditNonHmacRequestKeys,auditNonHmacResponseKeys,passthroughRequestHeaders,allowedResponseHeaders,pluginVersion,lockoutThreshold,lockoutDuration,lockoutCounterReset,lockoutDisable}',
|
||||
];
|
||||
} else {
|
||||
tuneAttrs = [
|
||||
'description',
|
||||
'config.{listingVisibility,defaultLeaseTtl,maxLeaseTtl,tokenType,auditNonHmacRequestKeys,auditNonHmacResponseKeys,passthroughRequestHeaders}',
|
||||
'config.{listingVisibility,defaultLeaseTtl,maxLeaseTtl,tokenType,auditNonHmacRequestKeys,auditNonHmacResponseKeys,passthroughRequestHeaders,allowedResponseHeaders,pluginVersion,lockoutThreshold,lockoutDuration,lockoutCounterReset,lockoutDisable}',
|
||||
];
|
||||
}
|
||||
return expandAttributeMeta(this, tuneAttrs);
|
||||
@@ -94,7 +104,7 @@ export default class AuthMethodModel extends Model {
|
||||
'accessor',
|
||||
'local',
|
||||
'sealWrap',
|
||||
'config.{listingVisibility,defaultLeaseTtl,maxLeaseTtl,tokenType,auditNonHmacRequestKeys,auditNonHmacResponseKeys,passthroughRequestHeaders}',
|
||||
'config.{listingVisibility,defaultLeaseTtl,maxLeaseTtl,tokenType,auditNonHmacRequestKeys,auditNonHmacResponseKeys,passthroughRequestHeaders,allowedResponseHeaders,pluginVersion}',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -107,7 +117,7 @@ export default class AuthMethodModel extends Model {
|
||||
'config.listingVisibility',
|
||||
'local',
|
||||
'sealWrap',
|
||||
'config.{defaultLeaseTtl,maxLeaseTtl,tokenType,auditNonHmacRequestKeys,auditNonHmacResponseKeys,passthroughRequestHeaders}',
|
||||
'config.{defaultLeaseTtl,maxLeaseTtl,tokenType,auditNonHmacRequestKeys,auditNonHmacResponseKeys,passthroughRequestHeaders,allowedResponseHeaders,pluginVersion}',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -54,7 +54,7 @@ export default class MountConfigModel extends Model {
|
||||
allowedResponseHeaders;
|
||||
|
||||
@attr('string', {
|
||||
label: 'Token Type',
|
||||
label: 'Token type',
|
||||
helpText:
|
||||
'The type of token that should be generated via this role. For `default-service` and `default-batch` service and batch tokens will be issued respectively, unless the auth method explicitly requests a different type.',
|
||||
possibleValues: ['default-service', 'default-batch', 'batch', 'service'],
|
||||
@@ -66,4 +66,42 @@ export default class MountConfigModel extends Model {
|
||||
editType: 'stringArray',
|
||||
})
|
||||
allowedManagedKeys;
|
||||
|
||||
@attr('string', {
|
||||
label: 'Plugin version',
|
||||
subText:
|
||||
'Specifies the semantic version of the plugin to use, e.g. "v1.0.0". If unspecified, the server will select any matching un-versioned plugin that may have been registered, the latest versioned plugin registered, or a built-in plugin in that order of precedence.',
|
||||
})
|
||||
pluginVersion;
|
||||
|
||||
// Auth mount userLockoutConfig params, added to user_lockout_config object in saveModel method
|
||||
@attr('string', {
|
||||
label: 'Lockout threshold',
|
||||
subText: 'Specifies the number of failed login attempts after which the user is locked out, e.g. 15.',
|
||||
})
|
||||
lockoutThreshold;
|
||||
|
||||
@attr({
|
||||
label: 'Lockout duration',
|
||||
helperTextEnabled: 'The duration for which a user will be locked out, e.g. "5s" or "30m".',
|
||||
editType: 'ttl',
|
||||
helperTextDisabled: 'No lockout duration configured.',
|
||||
})
|
||||
lockoutDuration;
|
||||
|
||||
@attr({
|
||||
label: 'Lockout counter reset',
|
||||
helperTextEnabled:
|
||||
'The duration after which the lockout counter is reset with no failed login attempts, e.g. "5s" or "30m".',
|
||||
editType: 'ttl',
|
||||
helperTextDisabled: 'No reset duration configured.',
|
||||
})
|
||||
lockoutCounterReset;
|
||||
|
||||
@attr('boolean', {
|
||||
label: 'Disable lockout for this mount',
|
||||
subText: 'If checked, disables the user lockout feature for this mount.',
|
||||
})
|
||||
lockoutDisable;
|
||||
// end of user_lockout_config params
|
||||
}
|
||||
|
||||
@@ -7,8 +7,22 @@
|
||||
<div class="box is-sideless is-fullwidth is-marginless">
|
||||
<MessageError @model={{this.model}} @errorMessage={{this.model.errorMessage}} />
|
||||
<NamespaceReminder @mode="save" @noun="Auth Method" />
|
||||
|
||||
{{#each this.model.tuneAttrs as |attr|}}
|
||||
<FormField data-test-field @attr={{attr}} @model={{this.model}} />
|
||||
{{#if (not (includes attr.name this.model.userLockoutConfig.modelAttrs))}}
|
||||
<FormField data-test-field @attr={{attr}} @model={{this.model}} />
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
|
||||
<hr class="has-top-margin-xl has-bottom-margin-l has-background-gray-200" />
|
||||
<Hds::Text::Display @tag="h2" @size="400" @weight="bold">User lockout configuration</Hds::Text::Display>
|
||||
<Hds::Text::Body @tag="p" @size="100" @color="faint" class="has-bottom-margin-m">
|
||||
Specifies the user lockout settings for this auth mount.
|
||||
</Hds::Text::Body>
|
||||
{{#each this.model.tuneAttrs as |attr|}}
|
||||
{{#if (includes attr.name this.model.userLockoutConfig.modelAttrs)}}
|
||||
<FormField @attr={{attr}} @model={{this.model}} />
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="field is-grouped box is-fullwidth is-bottomless">
|
||||
|
||||
@@ -44,8 +44,14 @@ export const SELECTORS = {
|
||||
infoRowLabel: (label) => `[data-test-row-label="${label}"]`,
|
||||
infoRowValue: (label) => `[data-test-value-div="${label}"]`,
|
||||
inputByAttr: (attr) => `[data-test-input="${attr}"]`,
|
||||
selectByAttr: (attr) => `[data-test-select="${attr}"]`,
|
||||
fieldByAttr: (attr) => `[data-test-field="${attr}"]`,
|
||||
enableField: (attr) => `[data-test-enable-field="${attr}"] button`,
|
||||
ttl: {
|
||||
toggle: (attr) => `[data-test-toggle-label="${attr}"]`,
|
||||
input: (attr) => `[data-test-ttl-value="${attr}"]`,
|
||||
},
|
||||
|
||||
validation: (attr) => `[data-test-field-validation=${attr}]`,
|
||||
validationWarning: (attr) => `[data-test-validation-warning=${attr}]`,
|
||||
messageError: '[data-test-message-error]',
|
||||
|
||||
@@ -3,56 +3,73 @@
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { resolve } from 'rsvp';
|
||||
import EmberObject from '@ember/object';
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { render, settled } from '@ember/test-helpers';
|
||||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
import { click, fillIn, render } from '@ember/test-helpers';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import sinon from 'sinon';
|
||||
import { create } from 'ember-cli-page-object';
|
||||
import authConfigForm from 'vault/tests/pages/components/auth-config-form/options';
|
||||
|
||||
const component = create(authConfigForm);
|
||||
import { SELECTORS } from 'vault/tests/helpers/general-selectors';
|
||||
|
||||
module('Integration | Component | auth-config-form options', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
this.owner.lookup('service:flash-messages').registerTypes(['success']);
|
||||
this.router = this.owner.lookup('service:router');
|
||||
this.store = this.owner.lookup('service:store');
|
||||
this.path = 'my-auth-method/';
|
||||
this.model = this.store.createRecord('auth-method', { path: this.path, type: 'approle' });
|
||||
this.model.set('config', this.store.createRecord('mount-config'));
|
||||
});
|
||||
|
||||
test('it submits data correctly', async function (assert) {
|
||||
assert.expect(2);
|
||||
this.router.reopen({
|
||||
transitionTo() {
|
||||
return {
|
||||
followRedirects() {
|
||||
return resolve();
|
||||
assert.ok('calls transitionTo on save');
|
||||
},
|
||||
};
|
||||
},
|
||||
replaceWith() {
|
||||
return resolve();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('it submits data correctly', async function (assert) {
|
||||
assert.expect(1);
|
||||
const model = EmberObject.create({
|
||||
tune() {
|
||||
return resolve();
|
||||
},
|
||||
config: {
|
||||
serialize() {
|
||||
return {};
|
||||
this.server.post(`sys/mounts/auth/${this.path}/tune`, (schema, req) => {
|
||||
const payload = JSON.parse(req.requestBody);
|
||||
const expected = {
|
||||
default_lease_ttl: '30s',
|
||||
listing_visibility: 'unauth',
|
||||
user_lockout_config: {
|
||||
lockout_threshold: '7',
|
||||
lockout_duration: '600s',
|
||||
lockout_counter_reset: '5s',
|
||||
lockout_disable: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
assert.propEqual(payload, expected, 'payload contains tune parameters');
|
||||
return { payload };
|
||||
});
|
||||
sinon.spy(model.config, 'serialize');
|
||||
this.set('model', model);
|
||||
await render(hbs`<AuthConfigForm::Options @model={{this.model}} />`);
|
||||
component.save();
|
||||
return settled().then(() => {
|
||||
assert.strictEqual(model.config.serialize.callCount, 1, 'config serialize was called once');
|
||||
});
|
||||
|
||||
await click(SELECTORS.inputByAttr('config.listingVisibility'));
|
||||
|
||||
await click(SELECTORS.ttl.toggle('Default Lease TTL'));
|
||||
await fillIn(SELECTORS.ttl.input('Default Lease TTL'), '30');
|
||||
|
||||
await fillIn(SELECTORS.inputByAttr('config.lockoutThreshold'), '7');
|
||||
|
||||
await click(SELECTORS.ttl.toggle('Lockout duration'));
|
||||
await fillIn(SELECTORS.ttl.input('Lockout duration'), '10');
|
||||
await fillIn(
|
||||
`${SELECTORS.inputByAttr('config.lockoutDuration')} ${SELECTORS.selectByAttr('ttl-unit')}`,
|
||||
'm'
|
||||
);
|
||||
await click(SELECTORS.ttl.toggle('Lockout counter reset'));
|
||||
await fillIn(SELECTORS.ttl.input('Lockout counter reset'), '5');
|
||||
|
||||
await click(SELECTORS.inputByAttr('config.lockoutDisable'));
|
||||
|
||||
await click('[data-test-save-config]');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { clickable, fillable } from 'ember-cli-page-object';
|
||||
|
||||
import fields from '../form-field';
|
||||
export default {
|
||||
...fields,
|
||||
ttlValue: fillable('[data-test-ttl-value]'),
|
||||
ttlUnit: fillable('[data-test-ttl-value]'),
|
||||
save: clickable('[data-test-save-config]'),
|
||||
};
|
||||
Reference in New Issue
Block a user