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: Fix aws credential generation sending ttl value when off #27366

Merged
merged 7 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions changelog/27366.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
ui: Fix a bug where disabling TTL on the AWS credential form would still send TTL value
```
2 changes: 1 addition & 1 deletion ui/app/adapters/aws-credential.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default ApplicationAdapter.extend({
if (roleType === 'iam_user') {
method = 'GET';
} else {
if (ttl !== undefined) {
if (ttl) {
data.ttl = ttl;
}
if (roleType === 'assumed_role' && roleArn) {
Expand Down
3 changes: 2 additions & 1 deletion ui/app/models/aws-credential.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export default Model.extend({
editType: 'ttl',
defaultValue: '3600s',
setDefault: true,
ttlOffValue: '',
label: 'TTL',
helpText:
'Specifies the TTL for the use of the STS token. Valid only when credential_type is assumed_role, federation_token, or session_token.',
Expand All @@ -66,7 +67,7 @@ export default Model.extend({
iam_user: ['credentialType'],
assumed_role: ['credentialType', 'ttl', 'roleArn'],
federation_token: ['credentialType', 'ttl'],
session_token: ['ttl'],
session_token: ['credentialType', 'ttl'],
};
if (this.accessKey || this.securityToken) {
return expandAttributeMeta(this, DISPLAY_FIELDS.slice(0));
Expand Down
1 change: 1 addition & 0 deletions ui/app/templates/components/generate-credentials.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
<Hds::Button
@text="Cancel"
@route="vault.cluster.secrets.backend.list-root"
@color="secondary"
@model={{this.backendPath}}
data-test-secret-generate-cancel={{true}}
/>
Expand Down
8 changes: 7 additions & 1 deletion ui/lib/core/addon/components/form-field.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,13 @@ export default class FormFieldComponent extends Component {
@action
setAndBroadcastTtl(value) {
const alwaysSendValue = this.valuePath === 'expiry' || this.valuePath === 'safetyBuffer';
const valueToSet = value.enabled === true || alwaysSendValue ? `${value.seconds}s` : 0;
const attrOptions = this.args.attr.options || {};
let valueToSet = 0;
if (value.enabled || alwaysSendValue) {
valueToSet = `${value.seconds}s`;
} else if (Object.keys(attrOptions).includes('ttlOffValue')) {
valueToSet = attrOptions.ttlOffValue;
}
this.setAndBroadcast(`${valueToSet}`);
}
@action
Expand Down
50 changes: 31 additions & 19 deletions ui/tests/acceptance/aws-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,32 @@
* SPDX-License-Identifier: BUSL-1.1
*/

import { click, fillIn, findAll, currentURL, find, settled, waitUntil } from '@ember/test-helpers';
import { click, fillIn, currentURL, find, settled, waitUntil } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { v4 as uuidv4 } from 'uuid';

import authPage from 'vault/tests/pages/auth';
import enablePage from 'vault/tests/pages/settings/mount-secret-backend';
import { setupMirage } from 'ember-cli-mirage/test-support';

module('Acceptance | aws secret backend', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);

hooks.beforeEach(function () {
this.uid = uuidv4();
return authPage.login();
});

test('aws backend', async function (assert) {
assert.expect(12);
const path = `aws-${this.uid}`;
const roleName = 'awsrole';
this.server.post(`/${path}/creds/${roleName}`, (_, req) => {
const payload = JSON.parse(req.requestBody);
assert.deepEqual(payload, { role_arn: 'foobar' }, 'does not send TTL when unchecked');
return {};
});

await enablePage.enable('aws', path);
await settled();
Expand All @@ -31,39 +37,33 @@ module('Acceptance | aws secret backend', function (hooks) {
await click('[data-test-secret-backend-configure]');

assert.strictEqual(currentURL(), `/vault/settings/secrets/configure/${path}`);
assert.ok(findAll('[data-test-aws-root-creds-form]').length, 'renders the empty root creds form');
assert.ok(findAll('[data-test-aws-link="root-creds"]').length, 'renders the root creds link');
assert.ok(findAll('[data-test-aws-link="leases"]').length, 'renders the leases config link');
assert.dom('[data-test-aws-root-creds-form]').exists();
assert.dom('[data-test-aws-link="root-creds"]').exists();
assert.dom('[data-test-aws-link="leases"]').exists();

await fillIn('[data-test-aws-input="accessKey"]', 'foo');
await fillIn('[data-test-aws-input="secretKey"]', 'bar');

await click('[data-test-aws-input="root-save"]');

assert.ok(
find('[data-test-flash-message]').textContent.trim(),
`The backend configuration saved successfully!`
);
assert
.dom('[data-test-flash-message]:last-of-type [data-test-flash-message-body]')
.includesText(`The backend configuration saved successfully!`);

await click('[data-test-aws-link="leases"]');

await click('[data-test-aws-input="lease-save"]');

assert.ok(
find('[data-test-flash-message]').textContent.trim(),
`The backend configuration saved successfully!`
);
assert
.dom('[data-test-flash-message]:last-of-type [data-test-flash-message-body]')
.includesText(`The backend configuration saved successfully!`);

await click('[data-test-backend-view-link]');

assert.strictEqual(currentURL(), `/vault/secrets/${path}/list`, `navigates to the roles list`);

await click('[data-test-secret-create]');

assert.ok(
find('[data-test-secret-header]').textContent.includes('AWS Role'),
`aws: renders the create page`
);
assert.dom('[data-test-secret-header]').includesText('AWS Role');

await fillIn('[data-test-input="name"]', roleName);

Expand All @@ -78,7 +78,19 @@ module('Acceptance | aws secret backend', function (hooks) {
await click(`[data-test-secret-breadcrumb="${path}"] a`);

assert.strictEqual(currentURL(), `/vault/secrets/${path}/list`);
assert.ok(findAll(`[data-test-secret-link="${roleName}"]`).length, `aws: role shows in the list`);
assert.dom(`[data-test-secret-link="${roleName}"]`).exists();

// check that generates credentials flow is correct
await click(`[data-test-secret-link="${roleName}"]`);
assert.dom('h1').hasText('Generate AWS Credentials');
assert.dom('[data-test-input="credentialType"]').hasValue('iam_user');
await fillIn('[data-test-input="credentialType"]', 'assumed_role');
await click('[data-test-ttl-toggle="TTL"]');
assert.dom('[data-test-ttl-toggle="TTL"]').isNotChecked();
await fillIn('[data-test-input="roleArn"]', 'foobar');
await click('[data-test-secret-generate]');
assert.dom('[data-test-warning]').exists('Shows access warning after generation');
await click('[data-test-secret-generate-back]');

//and delete
await click(`[data-test-secret-link="${roleName}"] [data-test-popup-menu-trigger]`);
Expand Down
29 changes: 28 additions & 1 deletion ui/tests/integration/components/form-field-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,41 @@ module('Integration | Component | form field', function (hooks) {
});

test('it renders: editType ttl', async function (assert) {
const [model, spy] = await setup.call(this, createAttr('foo', null, { editType: 'ttl' }));
const [model, spy] = await setup.call(
this,
createAttr('foo', null, {
editType: 'ttl',
helperTextDisabled: 'TTL is disabled',
helperTextEnabled: 'TTL is enabled',
})
);
assert.ok(component.hasTTLPicker, 'renders the ttl-picker component');
assert.dom('[data-test-ttl-form-subtext]').hasText('TTL is disabled');
assert.dom('[data-test-ttl-toggle]').isNotChecked();
await component.fields.objectAt(0).toggleTtl();
await component.fields.objectAt(0).select('h').change();
await component.fields.objectAt(0).ttlTime('3');
const expectedSeconds = `${3 * 3600}s`;
assert.strictEqual(model.get('foo'), expectedSeconds);
assert.ok(spy.calledWith('foo', expectedSeconds), 'onChange called with correct args');
await component.fields.objectAt(0).toggleTtl();
assert.ok(spy.calledWith('foo', '0'), 'onChange called with 0 when toggle off');
});

test('it renders: editType ttl with special settings', async function (assert) {
const [model, spy] = await setup.call(
this,
createAttr('foo', null, {
editType: 'ttl',
setDefault: '3600s',
ttlOffValue: '',
})
);
assert.ok(component.hasTTLPicker, 'renders the ttl-picker component');
assert.dom('[data-test-ttl-toggle]').isChecked();
await component.fields.objectAt(0).toggleTtl();
assert.strictEqual(model.get('foo'), '');
assert.ok(spy.calledWith('foo', ''), 'onChange called with correct args');
});

test('it renders: editType ttl without toggle', async function (assert) {
Expand Down
5 changes: 5 additions & 0 deletions ui/tests/unit/adapters/aws-credential-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ module('Unit | Adapter | aws credential', function (hooks) {
[storeStub, type, makeSnapshot({ credentialType: 'assumed_role' })],
'POST',
],
[
'assumed_role type no arn, ttl empty',
[storeStub, type, makeSnapshot({ credentialType: 'assumed_role', ttl: '' })],
'POST',
],
[
'assumed_role type no arn',
[storeStub, type, makeSnapshot({ credentialType: 'assumed_role', ttl: '3h' })],
Expand Down
Loading