diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml
index c0d78cb93..9b76dd3d2 100644
--- a/addons/core/translations/resources/en-us.yaml
+++ b/addons/core/translations/resources/en-us.yaml
@@ -970,6 +970,7 @@ credential-library:
help:
vault-generic: Authorize sessions using credentials brokered by Vault
vault-ssh-certificate: Authorize sessions using the SSH Secrets Engine in Vault
+ vault-ldap: Authorize sessions using the LDAP Secrets Engine in Vault
credential:
title: Credential
title_plural: Credentials
diff --git a/ui/admin/app/components/form/credential-library/mapping-overrides/index.hbs b/ui/admin/app/components/form/credential-library/mapping-overrides/index.hbs
new file mode 100644
index 000000000..894013d87
--- /dev/null
+++ b/ui/admin/app/components/form/credential-library/mapping-overrides/index.hbs
@@ -0,0 +1,51 @@
+{{!
+ Copyright (c) HashiCorp, Inc.
+ SPDX-License-Identifier: BUSL-1.1
+}}
+
+
+ <:fieldset as |F|>
+
+ {{t
+ 'resources.credential-library.form.credential_mapping_overrides.label'
+ }}
+
+
+ {{t
+ 'resources.credential-library.form.credential_mapping_overrides.help'
+ }}
+
+
+ {{#if @model.errors.credential_mapping_overrides}}
+
+ {{#each @model.errors.credential_mapping_overrides as |error|}}
+ {{error.message}}
+ {{/each}}
+
+ {{/if}}
+
+
+ <:field as |F|>
+
+ <:newKey as |N|>
+
+
+ <:key as |K|>
+
+
+ <:value as |V|>
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/admin/app/components/form/credential-library/mapping-overrides/index.js b/ui/admin/app/components/form/credential-library/mapping-overrides/index.js
new file mode 100644
index 000000000..9d50d724a
--- /dev/null
+++ b/ui/admin/app/components/form/credential-library/mapping-overrides/index.js
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+import Component from '@glimmer/component';
+import { options } from 'api/models/credential-library';
+import { action } from '@ember/object';
+
+export default class FormCredentialLibraryMappingOverridesComponent extends Component {
+ get mappingOverrides() {
+ return options.mapping_overrides[this.args.model.credential_type];
+ }
+
+ get allowedEntries() {
+ return this.mappingOverrides.length;
+ }
+
+ /**
+ * Prevents users from selecting duplicate keys from the select list if the arg is set to true
+ * @type {array}
+ */
+ get selectOptions() {
+ const previouslySelectedKeys =
+ this.args.model.credential_mapping_overrides || [];
+ if (previouslySelectedKeys.length) {
+ return this.mappingOverrides.filter((key) =>
+ previouslySelectedKeys.every((obj) => obj.key !== key),
+ );
+ } else {
+ return this.mappingOverrides;
+ }
+ }
+
+ /**
+ * Determines if we need to show an empty row to the users to enter more key/value pairs based on removeDuplicates arg,
+ * by default it is true
+ * @type {object}
+ */
+ @action
+ showNewRow() {
+ return (
+ this.args.model.credential_mapping_overrides?.length !==
+ this.allowedEntries
+ );
+ }
+}
diff --git a/ui/admin/app/components/form/credential-library/radio/index.hbs b/ui/admin/app/components/form/credential-library/radio/index.hbs
new file mode 100644
index 000000000..e2bc8fd96
--- /dev/null
+++ b/ui/admin/app/components/form/credential-library/radio/index.hbs
@@ -0,0 +1,28 @@
+{{!
+ Copyright (c) HashiCorp, Inc.
+ SPDX-License-Identifier: BUSL-1.1
+}}
+
+
+ {{t 'form.type.label'}}
+ {{#each this.credentialTypes as |type|}}
+
+ {{t
+ (concat 'resources.credential-library.types.' type)
+ }}
+ {{t
+ (concat 'resources.credential-library.help.' type)
+ }}
+
+ {{/each}}
+
\ No newline at end of file
diff --git a/ui/admin/app/components/form/credential-library/radio/index.js b/ui/admin/app/components/form/credential-library/radio/index.js
new file mode 100644
index 000000000..4d6d2d3ba
--- /dev/null
+++ b/ui/admin/app/components/form/credential-library/radio/index.js
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: BUSL-1.1
+ */
+
+import Component from '@glimmer/component';
+import {
+ TYPES_CREDENTIAL_LIBRARY,
+ TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
+} from 'api/models/credential-library';
+import { service } from '@ember/service';
+
+export default class FormCredentialLibraryRadioComponent extends Component {
+ // =services
+ @service features;
+
+ /**
+ * Returns credential types, filtering out SSH if the feature is disabled.
+ * @returns {Array.}
+ */
+ get credentialTypes() {
+ let types = TYPES_CREDENTIAL_LIBRARY;
+ return this.features.isEnabled('ssh-target')
+ ? types
+ : types.filter(
+ (type) => type !== TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
+ );
+ }
+}
diff --git a/ui/admin/app/components/form/credential-library/vault-generic/index.hbs b/ui/admin/app/components/form/credential-library/vault-generic/index.hbs
index 3473a1b65..f4b61eb27 100644
--- a/ui/admin/app/components/form/credential-library/vault-generic/index.hbs
+++ b/ui/admin/app/components/form/credential-library/vault-generic/index.hbs
@@ -51,30 +51,11 @@
{{/if}}
- {{#if (and @model.isNew (feature-flag 'ssh-target'))}}
-
- {{t 'form.type.label'}}
- {{#each this.types as |type|}}
-
- {{t
- (concat 'resources.credential-library.types.' type)
- }}
- {{t
- (concat 'resources.credential-library.help.' type)
- }}
-
- {{/each}}
-
+ {{#if @model.isNew}}
+
{{else}}
- <:fieldset as |F|>
-
- {{t
- 'resources.credential-library.form.credential_mapping_overrides.label'
- }}
-
-
- {{t
- 'resources.credential-library.form.credential_mapping_overrides.help'
- }}
-
-
- {{#if @model.errors.credential_mapping_overrides}}
-
- {{#each @model.errors.credential_mapping_overrides as |error|}}
- {{error.message}}
- {{/each}}
-
- {{/if}}
-
-
- <:field as |F|>
-
- <:newKey as |N|>
-
-
- <:key as |K|>
-
-
- <:value as |V|>
-
-
-
-
-
+ />
{{/if}}
}
- */
- types = TYPES_CREDENTIAL_LIBRARY;
-
/**
* Only allow HTTP request body field if http_method is set to POST.
* @type {boolean}
@@ -32,14 +23,6 @@ export default class FormCredentialLibraryVaultGenericComponent extends Componen
return this.args.model.http_method?.match(/post/i);
}
- get mappingOverrides() {
- return options.mapping_overrides[this.args.model.credential_type];
- }
-
- get allowedEntries() {
- return this.mappingOverrides.length;
- }
-
/**
* Clear the previously selected key value pair when toggling between credential types on a new form
*/
@@ -48,34 +31,4 @@ export default class FormCredentialLibraryVaultGenericComponent extends Componen
this.args.model.credential_mapping_overrides = [];
this.args.model.credential_type = value;
}
-
- /**
- * Prevents users from selecting duplicate keys from the select list if the arg is set to true
- * @type {array}
- */
-
- get selectOptions() {
- const previouslySelectedKeys =
- this.args.model.credential_mapping_overrides || [];
- if (previouslySelectedKeys.length) {
- return this.mappingOverrides.filter((key) =>
- previouslySelectedKeys.every((obj) => obj.key !== key),
- );
- } else {
- return this.mappingOverrides;
- }
- }
-
- /**
- * Determines if we need to show an empty row to the users to enter more key/value pairs based on removeDuplicates arg,
- * by default it is true
- * @type {object}
- */
- @action
- showNewRow() {
- return (
- this.args.model.credential_mapping_overrides?.length !==
- this.allowedEntries
- );
- }
}
diff --git a/ui/admin/app/components/form/credential-library/vault-ldap/index.hbs b/ui/admin/app/components/form/credential-library/vault-ldap/index.hbs
new file mode 100644
index 000000000..56b8e9f10
--- /dev/null
+++ b/ui/admin/app/components/form/credential-library/vault-ldap/index.hbs
@@ -0,0 +1,126 @@
+{{!
+ Copyright (c) HashiCorp, Inc.
+ SPDX-License-Identifier: BUSL-1.1
+}}
+
+
+
+ {{t 'form.name.label'}}
+ {{t 'form.name.help'}}
+ {{#if @model.errors.name}}
+
+ {{#each @model.errors.name as |error|}}
+
+ {{error.message}}
+
+ {{/each}}
+
+ {{/if}}
+
+
+
+ {{t 'form.description.label'}}
+ {{t 'form.description.help'}}
+ {{#if @model.errors.description}}
+
+ {{#each @model.errors.description as |error|}}
+ {{error.message}}
+ {{/each}}
+
+ {{/if}}
+
+
+ {{#if @model.isNew}}
+
+ {{else}}
+
+ {{t 'form.type.label'}}
+
+ {{t (concat 'resources.credential-library.help.' @model.type)}}
+
+
+ {{/if}}
+
+
+ {{t
+ 'resources.credential-library.form.vault_path.label'
+ }}
+ {{t
+ 'resources.credential-library.form.vault_path.help'
+ }}
+ {{#if @model.errors.path}}
+
+ {{#each @model.errors.path as |error|}}
+ {{error.message}}
+ {{/each}}
+
+ {{/if}}
+
+
+
+ {{t
+ 'resources.credential-library.form.credential_type.label'
+ }}
+
+ {{t 'resources.credential-library.form.credential_type.description'}}
+
+
+
+
+
+ {{#if (can 'save model' @model)}}
+
+ {{/if}}
+
+
\ No newline at end of file
diff --git a/ui/admin/app/components/form/credential-library/vault-ssh-certificate/index.hbs b/ui/admin/app/components/form/credential-library/vault-ssh-certificate/index.hbs
index 2008d19c0..11a8743fe 100644
--- a/ui/admin/app/components/form/credential-library/vault-ssh-certificate/index.hbs
+++ b/ui/admin/app/components/form/credential-library/vault-ssh-certificate/index.hbs
@@ -54,29 +54,10 @@
{{#if @model.isNew}}
-
- {{t 'form.type.label'}}
- {{#each this.types as |type|}}
-
- {{t
- (concat 'resources.credential-library.types.' type)
- }}
- {{t
- (concat 'resources.credential-library.help.' type)
- }}
-
- {{/each}}
-
+
{{else}}
}
- */
- types = TYPES_CREDENTIAL_LIBRARY;
-
/**
* Boolean to determine if the key bits field should be displayed on the form
* @returns {boolean}
diff --git a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js
index 07202c892..346d17ddd 100644
--- a/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js
+++ b/ui/admin/app/routes/scopes/scope/credential-stores/credential-store/credential-libraries/new.js
@@ -5,7 +5,12 @@
import Route from '@ember/routing/route';
import { service } from '@ember/service';
-import { TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC } from 'api/models/credential-library';
+import {
+ TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
+ TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
+ TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
+} from 'api/models/credential-library';
+import { TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN } from 'api/models/credential';
export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrariesNewRoute extends Route {
// =services
@@ -52,23 +57,34 @@ export default class ScopesScopeCredentialStoresCredentialStoreCredentialLibrari
'scopes.scope.credential-stores.credential-store',
);
- let name, description;
+ let name, description, credential_type;
if (this.currentModel?.isNew) {
({ name, description } = this.currentModel);
this.currentModel.rollbackAttributes();
}
- // Set the type to generic vault if feature flag isn't enabled in cases where
+ // Set the type to generic vault if feature flag isn't enabled or type is not set in cases where
// user sets the query parameter manually
- type = this.features.isEnabled('ssh-target')
- ? type
- : TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC;
+ let resolvedType = type;
+ if (
+ !this.features.isEnabled('ssh-target') &&
+ resolvedType === TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE
+ ) {
+ resolvedType = TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC;
+ }
+
+ // Set the credential type to username_password_domain if the type is vault ldap
+ if (resolvedType === TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP) {
+ credential_type = TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN;
+ }
return this.store.createRecord('credential-library', {
- type,
+ type: resolvedType,
credential_store_id,
name,
description,
+ // credential_type is only set for vault ldap type
+ credential_type,
});
}
}
diff --git a/ui/admin/tests/acceptance/credential-library/create-test.js b/ui/admin/tests/acceptance/credential-library/create-test.js
index 352943338..671e3c53c 100644
--- a/ui/admin/tests/acceptance/credential-library/create-test.js
+++ b/ui/admin/tests/acceptance/credential-library/create-test.js
@@ -10,7 +10,10 @@ import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import { setupSqlite } from 'api/test-support/helpers/sqlite';
import { authenticateSession } from 'ember-simple-auth/test-support';
import { Response } from 'miragejs';
-import { TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE } from 'api/models/credential-library';
+import {
+ TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
+ TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
+} from 'api/models/credential-library';
import * as selectors from './selectors';
import * as commonSelectors from 'admin/tests/helpers/selectors';
import { setRunOptions } from 'ember-a11y-testing/test-support';
@@ -427,4 +430,89 @@ module('Acceptance | credential-libraries | create', function (hooks) {
);
assert.strictEqual(currentURL(), urls.credentialLibraries);
});
+
+ test('can create a new credential library of type vault ldap', async function (assert) {
+ await visit(urls.newCredentialLibrary);
+
+ await click(selectors.TYPE_VAULT_LDAP);
+
+ await fillIn(selectors.FIELD_VAULT_PATH, selectors.FIELD_VAULT_PATH_VALUE);
+ await fillIn(commonSelectors.FIELD_NAME, commonSelectors.FIELD_NAME_VALUE);
+
+ await click(commonSelectors.SAVE_BTN);
+
+ assert.strictEqual(
+ this.server.schema.credentialLibraries.where({
+ type: TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
+ }).length,
+ 1,
+ );
+ const credentialLibrary = this.server.schema.credentialLibraries.findBy({
+ type: TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
+ });
+
+ assert.strictEqual(
+ credentialLibrary.name,
+ commonSelectors.FIELD_NAME_VALUE,
+ );
+ assert.strictEqual(
+ credentialLibrary.attributes.path,
+ selectors.FIELD_VAULT_PATH_VALUE,
+ );
+ assert.strictEqual(
+ credentialLibrary.credentialType,
+ selectors.FIELD_CRED_TYPE_UPD_VALUE,
+ );
+ });
+
+ test('can create a new credential library with username, password and domain type for vault ldap', async function (assert) {
+ const credentialLibraryCount = getCredentialLibraryCount();
+ const usernamePasswordDomainCredentialLibraryCount =
+ getUsernamePasswordDomainCredentialLibraryCount();
+ await visit(urls.newCredentialLibrary);
+
+ await click(selectors.TYPE_VAULT_LDAP);
+
+ await fillIn(selectors.FIELD_VAULT_PATH, selectors.FIELD_VAULT_PATH_VALUE);
+ await fillIn(commonSelectors.FIELD_NAME, commonSelectors.FIELD_NAME_VALUE);
+
+ await select(
+ selectors.FIELD_CRED_MAP_OVERRIDES_SELECT,
+ selectors.FIELD_CRED_MAP_OVERRIDES_SELECT_DOMAIN_VALUE,
+ );
+ await fillIn(selectors.FIELD_CRED_MAP_OVERRIDES_INPUT, 'domain');
+
+ await click(selectors.FIELD_CRED_MAP_OVERRIDES_BTN);
+ await click(commonSelectors.SAVE_BTN);
+
+ assert.strictEqual(getCredentialLibraryCount(), credentialLibraryCount + 1);
+ assert.strictEqual(
+ getUsernamePasswordDomainCredentialLibraryCount(),
+ usernamePasswordDomainCredentialLibraryCount + 1,
+ );
+
+ const credentialLibrary = this.server.schema.credentialLibraries.findBy({
+ type: TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
+ });
+
+ assert.strictEqual(
+ credentialLibrary.name,
+ commonSelectors.FIELD_NAME_VALUE,
+ );
+ assert.strictEqual(
+ credentialLibrary.credentialType,
+ selectors.FIELD_CRED_TYPE_UPD_VALUE,
+ );
+ assert.deepEqual(credentialLibrary.credentialMappingOverrides, {
+ domain_attribute: 'domain',
+ });
+ });
+
+ test('default `vault-generic` credential library is selected when `ssh-target` feature is not enabled and user manually sets `type` in the query params', async function (assert) {
+ await visit(`${urls.newCredentialLibrary}?type=vault-ssh-certificate`);
+
+ assert.dom(selectors.TYPE_VAULT_SSH_CERT).isNotVisible();
+ assert.dom(selectors.TYPE_VAULT_LDAP).isNotChecked();
+ assert.dom(selectors.TYPE_VAULT_GENERIC).isChecked();
+ });
});
diff --git a/ui/admin/tests/acceptance/credential-library/delete-test.js b/ui/admin/tests/acceptance/credential-library/delete-test.js
index 93e903ac7..7069074fe 100644
--- a/ui/admin/tests/acceptance/credential-library/delete-test.js
+++ b/ui/admin/tests/acceptance/credential-library/delete-test.js
@@ -15,7 +15,10 @@ import sinon from 'sinon';
import * as selectors from './selectors';
import * as commonSelectors from 'admin/tests/helpers/selectors';
import { setRunOptions } from 'ember-a11y-testing/test-support';
-import { TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC } from 'api/models/credential-library';
+import {
+ TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
+ TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
+} from 'api/models/credential-library';
import { TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN } from 'api/models/credential';
module('Acceptance | credential-libraries | delete', function (hooks) {
@@ -25,6 +28,7 @@ module('Acceptance | credential-libraries | delete', function (hooks) {
let getCredentialLibraryCount;
let getUsernamePasswordDomainCredentialLibraryCount;
+ let getVaultLDAPCredentialLibraryCount;
const instances = {
scopes: {
@@ -42,6 +46,7 @@ module('Acceptance | credential-libraries | delete', function (hooks) {
newCredentialLibrary: null,
unknownCredentialLibrary: null,
usernamePasswordDomainCredentialLibrary: null,
+ vaultLDAPCredentialLibrary: null,
};
hooks.beforeEach(async function () {
@@ -71,6 +76,14 @@ module('Acceptance | credential-libraries | delete', function (hooks) {
credential_type: TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN,
},
);
+ instances.vaultLDAPCredentialLibrary = this.server.create(
+ 'credential-library',
+ {
+ scope: instances.scopes.project,
+ credentialStore: instances.credentialStore,
+ type: TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
+ },
+ );
// Generate route URLs for resources
urls.credentialStores = `/scopes/${instances.scopes.project.id}/credential-stores`;
urls.credentialStore = `${urls.credentialStores}/${instances.credentialStore.id}`;
@@ -79,6 +92,7 @@ module('Acceptance | credential-libraries | delete', function (hooks) {
urls.newCredentialLibrary = `${urls.credentialLibraries}/new`;
urls.unknownCredentialLibrary = `${urls.credentialLibraries}/foo`;
urls.usernamePasswordDomainCredentialLibrary = `${urls.credentialLibraries}/${instances.usernamePasswordDomainCredentialLibrary.id}`;
+ urls.vaultLDAPCredentialLibrary = `${urls.credentialLibraries}/${instances.vaultLDAPCredentialLibrary.id}`;
// Generate resource counter
getCredentialLibraryCount = () =>
this.server.schema.credentialLibraries.all().models.length;
@@ -87,6 +101,11 @@ module('Acceptance | credential-libraries | delete', function (hooks) {
credential_type: TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN,
}).length;
};
+ getVaultLDAPCredentialLibraryCount = () => {
+ return this.server.schema.credentialLibraries.where({
+ type: TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
+ }).length;
+ };
await authenticateSession({});
});
@@ -208,4 +227,18 @@ module('Acceptance | credential-libraries | delete', function (hooks) {
usernamePasswordDomainCredentialLibraryCount - 1,
);
});
+
+ test('can delete vault ldap credential library type', async function (assert) {
+ const vaultLDAPCredentialLibraryCount =
+ getVaultLDAPCredentialLibraryCount();
+ await visit(urls.vaultLDAPCredentialLibrary);
+
+ await click(selectors.MANAGE_DROPDOWN_CRED_LIB);
+ await click(selectors.MANAGE_DROPDOWN_CRED_LIB_DELETE);
+
+ assert.strictEqual(
+ getVaultLDAPCredentialLibraryCount(),
+ vaultLDAPCredentialLibraryCount - 1,
+ );
+ });
});
diff --git a/ui/admin/tests/acceptance/credential-library/list-test.js b/ui/admin/tests/acceptance/credential-library/list-test.js
index 30d79275c..3f3940240 100644
--- a/ui/admin/tests/acceptance/credential-library/list-test.js
+++ b/ui/admin/tests/acceptance/credential-library/list-test.js
@@ -10,6 +10,7 @@ import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import { setupSqlite } from 'api/test-support/helpers/sqlite';
import { authenticateSession } from 'ember-simple-auth/test-support';
import * as commonSelectors from 'admin/tests/helpers/selectors';
+import { TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP } from 'api/models/credential-library';
module('Acceptance | credential-libraries | list', function (hooks) {
setupApplicationTest(hooks);
@@ -48,10 +49,19 @@ module('Acceptance | credential-libraries | list', function (hooks) {
scope: instances.scopes.project,
credentialStore: instances.credentialStore,
});
+ instances.vaultLDAPCredentialLibrary = this.server.create(
+ 'credential-library',
+ {
+ scope: instances.scopes.project,
+ credentialStore: instances.credentialStore,
+ type: TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
+ },
+ );
// Generate route URLs for resources
urls.credentialStores = `/scopes/${instances.scopes.project.id}/credential-stores`;
urls.credentialStore = `${urls.credentialStores}/${instances.credentialStore.id}`;
urls.credentialLibraries = `${urls.credentialStore}/credential-libraries`;
+ urls.vaultLDAPCredentialLibrary = `${urls.credentialLibraries}/${instances.vaultLDAPCredentialLibrary.id}`;
await authenticateSession({});
});
@@ -90,4 +100,12 @@ module('Acceptance | credential-libraries | list', function (hooks) {
assert.dom(commonSelectors.HREF(urls.credentialLibraries)).isVisible();
});
+
+ test('User can navigate to vault ldap credential library details', async function (assert) {
+ await visit(urls.credentialLibraries);
+
+ assert
+ .dom(commonSelectors.TABLE_RESOURCE_LINK(urls.vaultLDAPCredentialLibrary))
+ .isVisible();
+ });
});
diff --git a/ui/admin/tests/acceptance/credential-library/read-test.js b/ui/admin/tests/acceptance/credential-library/read-test.js
index 7966a6c0e..54b77327f 100644
--- a/ui/admin/tests/acceptance/credential-library/read-test.js
+++ b/ui/admin/tests/acceptance/credential-library/read-test.js
@@ -12,6 +12,7 @@ import { authenticateSession } from 'ember-simple-auth/test-support';
import {
TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
+ TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
} from 'api/models/credential-library';
import * as commonSelectors from 'admin/tests/helpers/selectors';
import { setRunOptions } from 'ember-a11y-testing/test-support';
@@ -190,4 +191,24 @@ module('Acceptance | credential-libraries | read', function (hooks) {
assert.strictEqual(currentURL(), url);
});
+
+ test('visiting vault ldap credential library', async function (assert) {
+ const vaultLDAPCredentialLibrary = this.server.create(
+ 'credential-library',
+ {
+ scope: instances.scopes.project,
+ credentialStore: instances.credentialStore,
+ type: TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
+ },
+ );
+
+ await visit(urls.credentialLibraries);
+
+ const url = `${urls.credentialLibraries}/${vaultLDAPCredentialLibrary.id}`;
+
+ await visit(url);
+ await a11yAudit();
+
+ assert.strictEqual(currentURL(), url);
+ });
});
diff --git a/ui/admin/tests/acceptance/credential-library/selectors.js b/ui/admin/tests/acceptance/credential-library/selectors.js
index aa4de05b7..d66b0891d 100644
--- a/ui/admin/tests/acceptance/credential-library/selectors.js
+++ b/ui/admin/tests/acceptance/credential-library/selectors.js
@@ -37,6 +37,8 @@ export const FIELD_CRED_MAP_OVERRIDES_BTN =
'[name="credential_mapping_overrides"] button';
export const TYPE_VAULT_SSH_CERT = '[value="vault-ssh-certificate"]';
+export const TYPE_VAULT_LDAP = '[value="vault-ldap"]';
+export const TYPE_VAULT_GENERIC = '[value="vault-generic"]';
export const FIELD_CRIT_OPTS_KEY =
'[name="critical_options"] tbody td:nth-of-type(1) input';
diff --git a/ui/admin/tests/acceptance/credential-library/update-test.js b/ui/admin/tests/acceptance/credential-library/update-test.js
index 1a38049fa..032712d16 100644
--- a/ui/admin/tests/acceptance/credential-library/update-test.js
+++ b/ui/admin/tests/acceptance/credential-library/update-test.js
@@ -13,6 +13,7 @@ import { Response } from 'miragejs';
import {
TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
+ TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
} from 'api/models/credential-library';
import * as selectors from './selectors';
import * as commonSelectors from 'admin/tests/helpers/selectors';
@@ -72,6 +73,14 @@ module('Acceptance | credential-libraries | update', function (hooks) {
credential_type: TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN,
},
);
+ instances.vaultLDAPCredentialLibrary = this.server.create(
+ 'credential-library',
+ {
+ scope: instances.scopes.project,
+ credentialStore: instances.credentialStore,
+ type: TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
+ },
+ );
// Generate route URLs for resources
urls.globalScope = `/scopes/global/scopes`;
urls.orgScope = `/scopes/${instances.scopes.org.id}/scopes`;
@@ -83,6 +92,7 @@ module('Acceptance | credential-libraries | update', function (hooks) {
urls.newCredentialLibrary = `${urls.credentialLibraries}/new`;
urls.unknownCredentialLibrary = `${urls.credentialLibraries}/foo`;
urls.usernamePasswordDomainCredentialLibrary = `${urls.credentialLibraries}/${instances.usernamePasswordDomainCredentialLibrary.id}`;
+ urls.vaultLDAPCredentialLibrary = `${urls.credentialLibraries}/${instances.vaultLDAPCredentialLibrary.id}`;
await authenticateSession({});
});
@@ -108,6 +118,7 @@ module('Acceptance | credential-libraries | update', function (hooks) {
});
await visit(urls.credentialLibrary);
+
await click(commonSelectors.EDIT_BTN, 'Activate edit mode');
await fillIn(commonSelectors.FIELD_NAME, commonSelectors.FIELD_NAME_VALUE);
await click(commonSelectors.CANCEL_BTN);
@@ -237,6 +248,7 @@ module('Acceptance | credential-libraries | update', function (hooks) {
);
});
await visit(urls.credentialLibrary);
+
await click(commonSelectors.EDIT_BTN, 'Activate edit mode');
await fillIn(commonSelectors.FIELD_NAME, commonSelectors.FIELD_NAME_VALUE);
await click(commonSelectors.SAVE_BTN);
@@ -269,6 +281,7 @@ module('Acceptance | credential-libraries | update', function (hooks) {
);
await visit(urls.credentialLibrary);
+
await click(commonSelectors.EDIT_BTN, 'Activate edit mode');
await fillIn(commonSelectors.FIELD_NAME, commonSelectors.FIELD_NAME_VALUE);
@@ -309,6 +322,7 @@ module('Acceptance | credential-libraries | update', function (hooks) {
);
await visit(urls.credentialLibrary);
+
await click(commonSelectors.EDIT_BTN, 'Activate edit mode');
await fillIn(commonSelectors.FIELD_NAME, commonSelectors.FIELD_NAME_VALUE);
@@ -340,6 +354,7 @@ module('Acceptance | credential-libraries | update', function (hooks) {
});
await visit(urls.credentialLibrary);
+
await click(commonSelectors.EDIT_BTN, 'Activate edit mode');
assert.dom(selectors.FIELD_CRED_TYPE).doesNotExist();
@@ -363,6 +378,7 @@ module('Acceptance | credential-libraries | update', function (hooks) {
await visit(
`${urls.credentialLibraries}/${instances.credentialLibrary.id}`,
);
+
await click(commonSelectors.EDIT_BTN, 'Activate edit mode');
await fillIn(commonSelectors.FIELD_NAME, commonSelectors.FIELD_NAME_VALUE);
await fillIn(
@@ -425,4 +441,55 @@ module('Acceptance | credential-libraries | update', function (hooks) {
ext_key: 'ext_value',
});
});
+
+ test('cannot update credential type in a vault ldap credential library', async function (assert) {
+ await visit(urls.vaultLDAPCredentialLibrary);
+
+ await click(commonSelectors.EDIT_BTN, 'Activate edit mode');
+
+ assert.dom(selectors.FIELD_CRED_TYPE).doesNotExist();
+ });
+
+ test('can update a vault ldap credential library and save changes', async function (assert) {
+ await visit(urls.vaultLDAPCredentialLibrary);
+
+ await click(commonSelectors.EDIT_BTN, 'Activate edit mode');
+ await fillIn(commonSelectors.FIELD_NAME, commonSelectors.FIELD_NAME_VALUE);
+ await fillIn(
+ commonSelectors.FIELD_DESCRIPTION,
+ commonSelectors.FIELD_DESCRIPTION_VALUE,
+ );
+
+ await fillIn(selectors.FIELD_VAULT_PATH, selectors.FIELD_VAULT_PATH_VALUE);
+
+ await select(
+ selectors.FIELD_CRED_MAP_OVERRIDES_SELECT,
+ selectors.FIELD_CRED_MAP_OVERRIDES_SELECT_DOMAIN_VALUE,
+ );
+
+ await fillIn(selectors.FIELD_CRED_MAP_OVERRIDES_INPUT, 'domain');
+ await click(selectors.FIELD_CRED_MAP_OVERRIDES_BTN);
+
+ await click(commonSelectors.SAVE_BTN);
+
+ const credentialLibrary = this.server.schema.credentialLibraries.findBy({
+ type: TYPE_CREDENTIAL_LIBRARY_VAULT_LDAP,
+ });
+
+ assert.strictEqual(
+ credentialLibrary.name,
+ commonSelectors.FIELD_NAME_VALUE,
+ );
+ assert.strictEqual(
+ credentialLibrary.description,
+ commonSelectors.FIELD_DESCRIPTION_VALUE,
+ );
+ assert.strictEqual(
+ credentialLibrary.attributes.path,
+ selectors.FIELD_VAULT_PATH_VALUE,
+ );
+ assert.deepEqual(credentialLibrary.credentialMappingOverrides, {
+ domain_attribute: 'domain',
+ });
+ });
});
diff --git a/ui/admin/tests/acceptance/targets/injected-application-credential-sources-test.js b/ui/admin/tests/acceptance/targets/injected-application-credential-sources-test.js
index 07612fdda..9237720ce 100644
--- a/ui/admin/tests/acceptance/targets/injected-application-credential-sources-test.js
+++ b/ui/admin/tests/acceptance/targets/injected-application-credential-sources-test.js
@@ -18,8 +18,11 @@ import {
TYPE_CREDENTIAL_USERNAME_PASSWORD_DOMAIN,
TYPE_CREDENTIAL_JSON,
} from 'api/models/credential';
-import { TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC } from 'api/models/credential-library';
import { setRunOptions } from 'ember-a11y-testing/test-support';
+import {
+ TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
+ TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
+} from 'api/models/credential-library';
module(
'Acceptance | targets | injected application credential sources',
@@ -96,14 +99,18 @@ module(
scope: instances.scopes.project,
credentialStore: instances.staticCredentialStore,
});
- instances.credentialLibraries = this.server.createList(
- 'credential-library',
- 6,
- {
+ instances.credentialLibraries = [
+ ...this.server.createList('credential-library', 3, {
scope: instances.scopes.project,
credentialStore: instances.vaultCredentialStore,
- },
- );
+ type: TYPE_CREDENTIAL_LIBRARY_VAULT_GENERIC,
+ }),
+ ...this.server.createList('credential-library', 3, {
+ scope: instances.scopes.project,
+ credentialStore: instances.vaultCredentialStore,
+ type: TYPE_CREDENTIAL_LIBRARY_VAULT_SSH_CERTIFICATE,
+ }),
+ ];
instances.credentialLibrary = instances.credentialLibraries[0];
instances.credential = instances.credentials[0];