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 LDAP Mirage Handler #28432

Merged
merged 7 commits into from
Sep 20, 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
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default class LdapLibraryDetailsAccountsPageComponent extends Component<A
@tracked checkOutTtl: string | null = null;

get cliCommand() {
return `vault lease renew ad/library/${this.args.library.name}/check-out/:lease_id`;
return `vault lease renew ${this.args.library.backend}/library/${this.args.library.name}/check-out/:lease_id`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!!

}
@action
setTtl(data: TtlEvent) {
Expand Down
71 changes: 56 additions & 15 deletions ui/mirage/handlers/ldap.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,6 @@ export default function (server) {
};
};

// mount
server.post('/sys/mounts/:path', () => new Response(204));
server.get('/sys/internal/ui/mounts/:path', () => ({
data: {
accessor: 'ldap_ade94329',
type: 'ldap',
path: 'ldap-test/',
uuid: '35e9119d-5708-4b6b-58d2-f913e27f242d',
config: {},
},
}));
// config
server.post('/:backend/config', (schema, req) => createOrUpdateRecord(schema, req, 'ldapConfigs'));
server.get('/:backend/config', (schema, req) => getRecord(schema, req, 'ldapConfigs'));
Expand All @@ -67,8 +56,60 @@ export default function (server) {
server.post('/:backend/library/:name', (schema, req) => createOrUpdateRecord(schema, req, 'ldapLibraries'));
server.get('/:backend/library/:name', (schema, req) => getRecord(schema, req, 'ldapLibraries'));
server.get('/:backend/library', (schema) => listRecords(schema, 'ldapLibraries'));
server.get('/:backend/library/:name/status', () => ({
'bob.johnson': { available: false, borrower_client_token: '8b80c305eb3a7dbd161ef98f10ea60a116ce0910' },
'mary.smith': { available: true },
}));
server.get('/:backend/library/:name/status', (schema) => {
const data = schema.db['ldapAccountStatuses'].reduce((prev, curr) => {
prev[curr.account] = {
available: curr.available,
borrower_client_token: curr.borrower_client_token,
};
return prev;
}, {});
return { data };
});
// check-out / check-in
server.post('/:backend/library/:set_name/check-in', (schema, req) => {
// Check-in makes an unavailable account available again
const { service_account_names } = JSON.parse(req.requestBody);
const dbCollection = schema.db['ldapAccountStatuses'];
const updated = dbCollection.find(service_account_names).map((f) => ({
...f,
available: true,
borrower_client_token: undefined,
}));
updated.forEach((u) => {
dbCollection.update(u.id, u);
});
return {
data: {
check_ins: service_account_names,
},
};
});
server.post('/:backend/library/:set_name/check-out', (schema, req) => {
const { set_name, backend } = req.params;
const dbCollection = schema.db['ldapAccountStatuses'];
const available = dbCollection.where({ available: true });
if (available) {
return Response(404, {}, { errors: ['no accounts available to check out'] });
}
const checkOut = {
...available[0],
available: false,
borrower_client_token: crypto.randomUUID(),
};
dbCollection.update(checkOut.id, checkOut);
return {
request_id: '364a17d4-e5ab-998b-ceee-b49929229e0c',
lease_id: `${backend}/library/${set_name}/check-out/aoBsaBEI4PK96VnukubvYDlZ`,
renewable: true,
lease_duration: 36000,
data: {
password: crypto.randomUUID(),
service_account_name: checkOut.account,
},
wrap_info: null,
warnings: null,
auth: null,
};
});
}
13 changes: 13 additions & 0 deletions ui/mirage/models/ldap-account-status.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import { Model } from 'miragejs';

export default Model.extend({
account: '', // should match ID
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for this comment!

library: '',
available: false,
borrower_client_token: undefined,
});
13 changes: 12 additions & 1 deletion ui/mirage/scenarios/ldap.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,19 @@
*/

export default function (server) {
server.create('ldap-config', { path: 'kubernetes' });
server.create('ldap-config', { path: 'kubernetes', backend: 'ldap-test' });
server.create('ldap-role', 'static', { name: 'static-role' });
server.create('ldap-role', 'dynamic', { name: 'dynamic-role' });
server.create('ldap-library', { name: 'test-library' });
server.create('ldap-account-status', {
id: 'bob.johnson',
account: 'bob.johnson',
available: false,
borrower_client_token: '8b80c305eb3a7dbd161ef98f10ea60a116ce0910',
});
server.create('ldap-account-status', {
id: 'mary.smith',
account: 'mary.smith',
available: true,
});
}
39 changes: 32 additions & 7 deletions ui/tests/acceptance/secrets/backend/ldap/libraries-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { v4 as uuidv4 } from 'uuid';
import ldapMirageScenario from 'vault/mirage/scenarios/ldap';
import ldapHandlers from 'vault/mirage/handlers/ldap';
import authPage from 'vault/tests/pages/auth';
import { click } from '@ember/test-helpers';
import { isURL, visitURL } from 'vault/tests/helpers/ldap/ldap-helpers';
import { deleteEngineCmd, mountEngineCmd, runCmd } from 'vault/tests/helpers/commands';

module('Acceptance | ldap | libraries', function (hooks) {
setupApplicationTest(hooks);
Expand All @@ -19,21 +21,41 @@ module('Acceptance | ldap | libraries', function (hooks) {
hooks.beforeEach(async function () {
ldapHandlers(this.server);
ldapMirageScenario(this.server);
this.backend = `ldap-test-${uuidv4()}`;
await authPage.login();
return visitURL('libraries');
// mount & configure
await runCmd([
mountEngineCmd('ldap', this.backend),
`write ${this.backend}/config binddn=foo bindpass=bar url=http://localhost:8208`,
]);
return visitURL('libraries', this.backend);
});

hooks.afterEach(async function () {
await runCmd(deleteEngineCmd(this.backend));
});

test('it should show libraries on overview page', async function (assert) {
await visitURL('overview', this.backend);
assert.dom('[data-test-libraries-count]').hasText('1');
});

test('it should transition to create library route on toolbar link click', async function (assert) {
await click('[data-test-toolbar-action="library"]');
assert.true(isURL('libraries/create'), 'Transitions to library create route on toolbar link click');
assert.true(
isURL('libraries/create', this.backend),
'Transitions to library create route on toolbar link click'
);
});

test('it should transition to library details route on list item click', async function (assert) {
await click('[data-test-list-item-link] a');
assert.true(
isURL('libraries/test-library/details/accounts'),
isURL('libraries/test-library/details/accounts', this.backend),
'Transitions to library details accounts route on list item click'
);
assert.dom('[data-test-account-name]').exists({ count: 2 }, 'lists the accounts');
assert.dom('[data-test-checked-out-account]').exists({ count: 1 }, 'lists the checked out accounts');
});

test('it should transition to routes from list item action menu', async function (assert) {
Expand All @@ -44,7 +66,7 @@ module('Acceptance | ldap | libraries', function (hooks) {
await click(`[data-test-${action}]`);
const uri = action === 'details' ? 'details/accounts' : action;
assert.true(
isURL(`libraries/test-library/${uri}`),
isURL(`libraries/test-library/${uri}`, this.backend),
`Transitions to ${action} route on list item action menu click`
);
await click('[data-test-breadcrumb="libraries"] a');
Expand All @@ -55,20 +77,23 @@ module('Acceptance | ldap | libraries', function (hooks) {
await click('[data-test-list-item-link] a');
await click('[data-test-tab="config"]');
assert.true(
isURL('libraries/test-library/details/configuration'),
isURL('libraries/test-library/details/configuration', this.backend),
'Transitions to configuration route on tab click'
);

await click('[data-test-tab="accounts"]');
assert.true(
isURL('libraries/test-library/details/accounts'),
isURL('libraries/test-library/details/accounts', this.backend),
'Transitions to accounts route on tab click'
);
});

test('it should transition to routes from library details toolbar links', async function (assert) {
await click('[data-test-list-item-link] a');
await click('[data-test-edit]');
assert.true(isURL('libraries/test-library/edit'), 'Transitions to credentials route from toolbar link');
assert.true(
isURL('libraries/test-library/edit', this.backend),
'Transitions to credentials route from toolbar link'
);
});
});
62 changes: 44 additions & 18 deletions ui/tests/acceptance/secrets/backend/ldap/overview-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,90 +6,116 @@
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { v4 as uuidv4 } from 'uuid';
import ldapMirageScenario from 'vault/mirage/scenarios/ldap';
import ldapHandlers from 'vault/mirage/handlers/ldap';
import authPage from 'vault/tests/pages/auth';
import { click, fillIn, visit } from '@ember/test-helpers';
import { selectChoose } from 'ember-power-select/test-support';
import { isURL, visitURL } from 'vault/tests/helpers/ldap/ldap-helpers';
import { deleteEngineCmd, mountEngineCmd, runCmd } from 'vault/tests/helpers/commands';

module('Acceptance | ldap | overview', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);

hooks.beforeEach(async function () {
ldapHandlers(this.server);
this.backend = `ldap-test-${uuidv4()}`;
this.mountAndConfig = (backend) => {
return runCmd([
mountEngineCmd('ldap', backend),
`write ${backend}/config binddn=foo bindpass=bar url=http://localhost:8208`,
]);
};
return authPage.login();
});

test('it should transition to ldap overview on mount success', async function (assert) {
const backend = 'ldap-test-mount';
await visit('/vault/secrets');
await click('[data-test-enable-engine]');
await click('[data-test-mount-type="ldap"]');
await fillIn('[data-test-input="path"]', 'ldap-test');
await fillIn('[data-test-input="path"]', backend);
await click('[data-test-mount-submit]');
assert.true(isURL('overview'), 'Transitions to ldap overview route on mount success');
assert.true(isURL('overview', backend), 'Transitions to ldap overview route on mount success');
assert.dom('[data-test-header-title]').hasText(backend);
// cleanup mounted engine
await visit('/vault/secrets');
await runCmd(deleteEngineCmd(backend));
});

test('it should transition to routes on tab link click', async function (assert) {
assert.expect(4);
await this.mountAndConfig(this.backend);

await visitURL('overview');
await visitURL('overview', this.backend);

for (const tab of ['roles', 'libraries', 'config', 'overview']) {
await click(`[data-test-tab="${tab}"]`);
const route = tab === 'config' ? 'configuration' : tab;
assert.true(isURL(route), `Transitions to ${route} route on tab link click`);
assert.true(isURL(route, this.backend), `Transitions to ${route} route on tab link click`);
}
});

test('it should transition to configuration route when engine is not configured', async function (assert) {
await visitURL('overview');
await runCmd(mountEngineCmd('ldap', this.backend));
await visitURL('overview', this.backend);
await click('[data-test-config-cta] a');
assert.true(isURL('configure'), 'Transitions to configure route on cta link click');
assert.true(isURL('configure', this.backend), 'Transitions to configure route on cta link click');

await click('[data-test-breadcrumb="ldap-test"] a');
await click(`[data-test-breadcrumb="${this.backend}"] a`);
await click('[data-test-toolbar-action="config"]');
assert.true(isURL('configure'), 'Transitions to configure route on toolbar link click');
assert.true(isURL('configure', this.backend), 'Transitions to configure route on toolbar link click');
});
// including a test for the configuration route here since it is the only one needed
test('it should transition to configuration edit on toolbar link click', async function (assert) {
ldapMirageScenario(this.server);
await visitURL('overview');
await this.mountAndConfig(this.backend);
await visitURL('overview', this.backend);
await click('[data-test-tab="config"]');
await click('[data-test-toolbar-config-action]');
assert.true(isURL('configure'), 'Transitions to configure route on toolbar link click');
assert.true(isURL('configure', this.backend), 'Transitions to configure route on toolbar link click');
});

test('it should transition to create role route on card action link click', async function (assert) {
ldapMirageScenario(this.server);
await visitURL('overview');
await this.mountAndConfig(this.backend);
await visitURL('overview', this.backend);
await click('[data-test-overview-card="Roles"] a');
assert.true(isURL('roles/create'), 'Transitions to role create route on card action link click');
assert.true(
isURL('roles/create', this.backend),
'Transitions to role create route on card action link click'
);
});

test('it should transition to create library route on card action link click', async function (assert) {
ldapMirageScenario(this.server);
await visitURL('overview');
await this.mountAndConfig(this.backend);
await visitURL('overview', this.backend);
await click('[data-test-overview-card="Libraries"] a');
assert.true(isURL('libraries/create'), 'Transitions to library create route on card action link click');
assert.true(
isURL('libraries/create', this.backend),
'Transitions to library create route on card action link click'
);
});

test('it should transition to role credentials route on generate credentials action', async function (assert) {
ldapMirageScenario(this.server);
await visitURL('overview');
await this.mountAndConfig(this.backend);
await visitURL('overview', this.backend);
await selectChoose('.search-select', 'static-role');
await click('[data-test-generate-credential-button]');
assert.true(
isURL('roles/static/static-role/credentials'),
isURL('roles/static/static-role/credentials', this.backend),
'Transitions to role credentials route on generate credentials action'
);

await click('[data-test-breadcrumb="ldap-test"] a');
await click(`[data-test-breadcrumb="${this.backend}"] a`);
await selectChoose('.search-select', 'dynamic-role');
await click('[data-test-generate-credential-button]');
assert.true(
isURL('roles/dynamic/dynamic-role/credentials'),
isURL('roles/dynamic/dynamic-role/credentials', this.backend),
'Transitions to role credentials route on generate credentials action'
);
});
Expand Down
Loading
Loading