mirror of
https://github.com/hashicorp/vault.git
synced 2026-05-05 12:26:34 +02:00
UI: Decode Oracle database connection_url (#29114)
* decode url in the serializer for oracle connection_url * add serializer test * add test for oracle * add test back, remove decode-url helper * update comment and test * link jiras VAULT-32830 VAULT-29785 * add changelog * add test
This commit is contained in:
parent
59489a8882
commit
5ba4fb3df6
3
changelog/29114.txt
Normal file
3
changelog/29114.txt
Normal file
@ -0,0 +1,3 @@
|
||||
```release-note:bug
|
||||
ui: Decode database url to fix editing failures for an oracle connection
|
||||
```
|
||||
@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { helper as buildHelper } from '@ember/component/helper';
|
||||
|
||||
export function decodeUri(string) {
|
||||
return decodeURI(string);
|
||||
}
|
||||
|
||||
export default buildHelper(decodeUri);
|
||||
@ -29,6 +29,16 @@ export default RESTSerializer.extend({
|
||||
...payload.data,
|
||||
...payload.data.connection_details,
|
||||
};
|
||||
|
||||
// connection_details are spread above into the main body of response so we can remove redundant data
|
||||
delete response.connection_details;
|
||||
if (response?.connection_url) {
|
||||
// this url can include interpolated data, such as: "{{username}}/{{password}}@localhost:1521/OraDoc.localhost"
|
||||
// these curly brackets are returned by the API encoded: "%7B%7Busername%7D%7D/%7B%7Bpassword%7D%7D@localhost:1521/OraDoc.localhost"
|
||||
// we decode here so the UI displays and submits the url in the correct format
|
||||
response.connection_url = decodeURI(response.connection_url);
|
||||
}
|
||||
|
||||
if (payload.data.root_credentials_rotate_statements) {
|
||||
response.root_rotation_statements = payload.data.root_credentials_rotate_statements;
|
||||
}
|
||||
|
||||
@ -353,7 +353,7 @@
|
||||
@alwaysRender={{not (is-empty-value (get @model attr.name) hasDefault=defaultDisplay)}}
|
||||
@defaultShown={{defaultDisplay}}
|
||||
@label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
|
||||
@value={{if (eq attr.name "connection_url") (decode-uri (get @model attr.name)) (get @model attr.name)}}
|
||||
@value={{get @model attr.name}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{/let}}
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import { currentURL, settled, click, visit, fillIn, typeIn, waitFor } from '@ember/test-helpers';
|
||||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
import { create } from 'ember-cli-page-object';
|
||||
import { selectChoose } from 'ember-power-select/test-support';
|
||||
import { clickTrigger } from 'ember-power-select/test-support/helpers';
|
||||
@ -226,6 +227,7 @@ const connectionTests = [
|
||||
|
||||
module('Acceptance | secrets/database/*', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(async function () {
|
||||
this.backend = `database-testing`;
|
||||
@ -337,9 +339,11 @@ module('Acceptance | secrets/database/*', function (hooks) {
|
||||
await visit('/vault/secrets');
|
||||
});
|
||||
}
|
||||
test('database connection create and edit: vault-plugin-database-oracle', async function (assert) {
|
||||
|
||||
// keep oracle as separate test because it relies on an external plugin that isn't rolled into the vault binary
|
||||
// https://github.com/hashicorp/vault-plugin-database-oracle
|
||||
test('database connection create: vault-plugin-database-oracle', async function (assert) {
|
||||
assert.expect(11);
|
||||
// keep oracle as separate test because it behaves differently than the others
|
||||
const testCase = {
|
||||
name: 'oracle-connection',
|
||||
plugin: 'vault-plugin-database-oracle',
|
||||
@ -380,7 +384,52 @@ module('Acceptance | secrets/database/*', function (hooks) {
|
||||
await connectionPage.connectionUrl(testCase.url);
|
||||
testCase.requiredFields(assert, testCase.plugin);
|
||||
// Cannot save without plugin mounted
|
||||
// TODO: add fake server response for fuller test coverage
|
||||
// Edit tested separately with mocked server response
|
||||
});
|
||||
|
||||
test('database connection edit: vault-plugin-database-oracle', async function (assert) {
|
||||
assert.expect(2);
|
||||
const connectionName = 'oracle-connection';
|
||||
// mock API so we can test edit (without mounting external oracle plugin)
|
||||
this.server.get(`/${this.backend}/config/${connectionName}`, () => {
|
||||
return {
|
||||
request_id: 'f869f23e-15c0-389b-82ac-84035a2b6079',
|
||||
lease_id: '',
|
||||
renewable: false,
|
||||
lease_duration: 0,
|
||||
data: {
|
||||
allowed_roles: ['*'],
|
||||
connection_details: {
|
||||
backend: 'database',
|
||||
connection_url: '%7B%7Busername%7D%7D/%7B%7Bpassword%7D%7D@//localhost:1521/ORCLPDB1',
|
||||
max_connection_lifetime: '0s',
|
||||
max_idle_connections: 0,
|
||||
max_open_connections: 3,
|
||||
username: 'VAULTADMIN',
|
||||
},
|
||||
password_policy: '',
|
||||
plugin_name: 'vault-plugin-database-oracle',
|
||||
plugin_version: '',
|
||||
root_credentials_rotate_statements: [],
|
||||
verify_connection: true,
|
||||
},
|
||||
wrap_info: null,
|
||||
warnings: null,
|
||||
auth: null,
|
||||
mount_type: 'database',
|
||||
};
|
||||
});
|
||||
|
||||
await visit(`/vault/secrets/${this.backend}/show/${connectionName}`);
|
||||
const decoded = '{{username}}/{{password}}@//localhost:1521/ORCLPDB1';
|
||||
assert
|
||||
.dom('[data-test-row-value="Connection URL"]')
|
||||
.hasText(decoded, 'connection_url is decoded in display');
|
||||
|
||||
await connectionPage.edit();
|
||||
assert
|
||||
.dom('[data-test-input="connection_url"]')
|
||||
.hasValue(decoded, 'connection_url is decoded when editing');
|
||||
});
|
||||
|
||||
test('Can create and delete a connection', async function (assert) {
|
||||
@ -504,17 +553,17 @@ module('Acceptance | secrets/database/*', function (hooks) {
|
||||
await visit('/vault/secrets');
|
||||
});
|
||||
|
||||
test('connection_url must be decoded', async function (assert) {
|
||||
test('connection_url is decoded', async function (assert) {
|
||||
const backend = this.backend;
|
||||
const connection = await newConnection(
|
||||
backend,
|
||||
'mongodb-database-plugin',
|
||||
'{{username}}/{{password}}@oracle-xe:1521/XEPDB1'
|
||||
'{{username}}/{{password}}@mongo:1521/XEPDB1'
|
||||
);
|
||||
await navToConnection(backend, connection);
|
||||
assert
|
||||
.dom('[data-test-row-value="Connection URL"]')
|
||||
.hasText('{{username}}/{{password}}@oracle-xe:1521/XEPDB1');
|
||||
.hasText('{{username}}/{{password}}@mongo:1521/XEPDB1');
|
||||
});
|
||||
|
||||
test('Role create form', async function (assert) {
|
||||
|
||||
@ -79,12 +79,6 @@ module('Unit | Serializer | database/connection', function (hooks) {
|
||||
const expectedResult = {
|
||||
allowed_roles: ['readonly'],
|
||||
backend: 'database',
|
||||
connection_details: {
|
||||
backend: 'database',
|
||||
insecure: false,
|
||||
url: 'https://localhost:9200',
|
||||
username: 'root',
|
||||
},
|
||||
id: 'elastic-test',
|
||||
insecure: false,
|
||||
name: 'elastic-test',
|
||||
@ -98,4 +92,111 @@ module('Unit | Serializer | database/connection', function (hooks) {
|
||||
};
|
||||
assert.deepEqual(normalized, expectedResult, `Normalizes and flattens database response`);
|
||||
});
|
||||
|
||||
test('it should normalize values for the database type (oracle)', function (assert) {
|
||||
const serializer = this.owner.lookup('serializer:database/connection');
|
||||
const normalized = serializer.normalizeSecrets({
|
||||
request_id: 'request-id',
|
||||
lease_id: '',
|
||||
renewable: false,
|
||||
lease_duration: 0,
|
||||
data: {
|
||||
allowed_roles: ['*'],
|
||||
connection_details: {
|
||||
backend: 'database',
|
||||
connection_url: '%7B%7Busername%7D%7D/%7B%7Bpassword%7D%7D@//localhost:1521/ORCLPDB1',
|
||||
max_connection_lifetime: '0s',
|
||||
max_idle_connections: 0,
|
||||
max_open_connections: 3,
|
||||
username: 'VAULTADMIN',
|
||||
},
|
||||
password_policy: '',
|
||||
plugin_name: 'vault-plugin-database-oracle',
|
||||
plugin_version: '',
|
||||
root_credentials_rotate_statements: [],
|
||||
verify_connection: true,
|
||||
},
|
||||
wrap_info: null,
|
||||
warnings: null,
|
||||
auth: null,
|
||||
mount_type: 'database',
|
||||
backend: 'database',
|
||||
id: 'oracle-test',
|
||||
});
|
||||
const expectedResult = {
|
||||
allowed_roles: ['*'],
|
||||
backend: 'database',
|
||||
connection_url: '{{username}}/{{password}}@//localhost:1521/ORCLPDB1',
|
||||
id: 'oracle-test',
|
||||
max_connection_lifetime: '0s',
|
||||
max_idle_connections: 0,
|
||||
max_open_connections: 3,
|
||||
name: 'oracle-test',
|
||||
password_policy: '',
|
||||
plugin_name: 'vault-plugin-database-oracle',
|
||||
plugin_version: '',
|
||||
root_credentials_rotate_statements: [],
|
||||
root_rotation_statements: [],
|
||||
username: 'VAULTADMIN',
|
||||
verify_connection: true,
|
||||
};
|
||||
assert.deepEqual(normalized, expectedResult, `Normalizes and flattens database response`);
|
||||
});
|
||||
|
||||
test('it should normalize values if some params do not exist', function (assert) {
|
||||
const serializer = this.owner.lookup('serializer:database/connection');
|
||||
const normalized = serializer.normalizeSecrets({
|
||||
request_id: 'request-id',
|
||||
lease_id: '',
|
||||
renewable: false,
|
||||
lease_duration: 0,
|
||||
data: {
|
||||
allowed_roles: ['*'],
|
||||
connection_details: { backend: 'database' }, // no connection_url param intentionally
|
||||
plugin_name: 'vault-postgres-db',
|
||||
},
|
||||
wrap_info: null,
|
||||
warnings: null,
|
||||
auth: null,
|
||||
mount_type: 'database',
|
||||
backend: 'database',
|
||||
id: 'db-test',
|
||||
});
|
||||
const expectedResult = {
|
||||
allowed_roles: ['*'],
|
||||
backend: 'database',
|
||||
id: 'db-test',
|
||||
name: 'db-test',
|
||||
plugin_name: 'vault-postgres-db',
|
||||
};
|
||||
assert.deepEqual(normalized, expectedResult, `Normalizes and flattens database response`);
|
||||
});
|
||||
|
||||
test('it should fail gracefully if no connection_details', function (assert) {
|
||||
const serializer = this.owner.lookup('serializer:database/connection');
|
||||
const normalized = serializer.normalizeSecrets({
|
||||
request_id: 'request-id',
|
||||
lease_id: '',
|
||||
renewable: false,
|
||||
lease_duration: 0,
|
||||
data: {
|
||||
allowed_roles: ['*'],
|
||||
plugin_name: 'vault-postgres-db',
|
||||
},
|
||||
wrap_info: null,
|
||||
warnings: null,
|
||||
auth: null,
|
||||
mount_type: 'database',
|
||||
backend: 'database',
|
||||
id: 'db-test',
|
||||
});
|
||||
const expectedResult = {
|
||||
allowed_roles: ['*'],
|
||||
backend: 'database',
|
||||
id: 'db-test',
|
||||
name: 'db-test',
|
||||
plugin_name: 'vault-postgres-db',
|
||||
};
|
||||
assert.deepEqual(normalized, expectedResult, `Normalizes and flattens database response`);
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user