Icu 10104 ldap accounts update (#1785)

* chore: 🤖 Add support for ldap account creation
This commit is contained in:
Dharini Jeeva authored and GitHub committed 2023-07-27 09:18:29 -07:00
1 parent e3557e297b
commit 05d62f3da5
9 files changed
+238 -122

No files matched your search

+1 -1
View File
@@ -32,7 +32,7 @@ export default factory.extend({
case TYPE_AUTH_METHOD_PASSWORD:
return { login_name: faker.internet.userName() };
case TYPE_AUTH_METHOD_LDAP: {
const groupsAmount = faker.datatype.number({ min: 1, max: 3 });
const groupsAmount = faker.datatype.number({ min: 3, max: 5 });
let groups = [];
for (let i = 0; i < groupsAmount; i++) {
groups.push(faker.random.word());
+3
View File
@@ -173,3 +173,6 @@ secret-editor:
edit: Click to replace this secret
created:
label: Created
other_fields:
label: Other Fields
help: This information is provided by the server and cannot be edited in Boundary
@@ -14,11 +14,23 @@ account:
types:
password: Password
oidc: OIDC
ldap: LDAP
titles:
new: New Account
actions:
create: Create Account
delete: Delete Account
form:
login_name:
label: Login Name
email:
label: Email
dn:
label: Dn
member_of_groups:
label: Group Names
full_name:
label: Full Name
auth-method:
title: Auth Method
title_plural: Auth Methods
@@ -52,27 +52,64 @@
</F.Error>
{{/if}}
</Hds::Form::Textarea::Field>
{{#if @model.isNew}}
<Hds::Form::TextInput::Field
@isRequired={{true}}
name='login_name'
@value={{@model.login_name}}
@isInvalid={{@model.errors.login_name}}
disabled={{form.disabled}}
{{on 'input' (set-from-event @model 'login_name')}}
as |F|
>
<F.Label>{{t 'form.login_name.label'}}</F.Label>
<F.HelperText>{{t 'form.login_name.help'}}</F.HelperText>
{{#if @model.errors.login_name}}
<F.Error as |E|>
{{#each @model.errors.login_name as |error|}}
<E.Message>{{error.message}}</E.Message>
{{/each}}
</F.Error>
{{/if}}
</Hds::Form::TextInput::Field>
{{/if}}
<Hds::Form::TextInput::Field
@isRequired={{true}}
name='login_name'
@value={{@model.login_name}}
@isInvalid={{@model.errors.login_name}}
disabled={{form.disabled}}
{{on 'input' (set-from-event @model 'login_name')}}
as |F|
>
<F.Label>{{t 'form.login_name.label'}}</F.Label>
<F.HelperText>{{t 'form.login_name.help'}}</F.HelperText>
{{#if @model.errors.login_name}}
<F.Error as |E|>
{{#each @model.errors.login_name as |error|}}
<E.Message>{{error.message}}</E.Message>
{{#unless @model.isNew}}
<Hds::Form::Fieldset class='ldap-read-only-fields' as |F|>
<F.Control>
<div class='ldap-section'>
<p class='hds-typography-display-300 hds-font-weight-bold'>{{t
'form.other_fields.label'
}}</p>
<Hds::Form::HelperText @controlId='helper-text-for-section'>{{t
'form.other_fields.help'
}}</Hds::Form::HelperText>
</div>
<InfoField @value={{@model.login_name}} as |F|>
<F.Label>{{t 'form.login_name.label'}}</F.Label>
</InfoField>
<InfoField @value={{@model.email}} as |F|>
<F.Label>{{t 'resources.account.form.email.label'}}</F.Label>
</InfoField>
<InfoField @value={{@model.full_name}} as |F|>
<F.Label>{{t 'resources.account.form.full_name.label'}}</F.Label>
</InfoField>
<InfoField @value={{@model.dn}} as |F|>
<F.Label>{{t 'resources.account.form.dn.label'}}</F.Label>
</InfoField>
<p class='hds-font-weight-semibold'>{{t
'resources.account.form.member_of_groups.label'
}}</p>
{{#each @model.member_of_groups as |group|}}
<Hds::Form::TextInput::Field
@value={{group.value}}
disabled={{true}}
/>
{{/each}}
</F.Error>
{{/if}}
</Hds::Form::TextInput::Field>
</F.Control>
</Hds::Form::Fieldset>
{{/unless}}
{{#if (can 'save model' @model)}}
<form.actions
@enableEditText={{t 'actions.edit-form'}}
+4
View File
@@ -908,6 +908,10 @@
}
}
.ldap-read-only-fields .hds-form-field--layout-vertical {
margin-bottom: 0.5rem;
}
// Session recording - List
.session-recording-list-cell-item {
display: flex;
@@ -25,110 +25,148 @@
{{#if @model.accounts}}
{{! OIDC accounts display more fields }}
{{#if @model.accounts.firstObject.isOIDC}}
<Rose::Table as |table|>
<table.header as |header|>
<header.row as |row|>
<row.headerCell>{{t 'form.name.label'}}</row.headerCell>
<row.headerCell>{{t 'form.issuer.label'}}</row.headerCell>
<row.headerCell>{{t 'form.subject.label'}}</row.headerCell>
<row.headerCell>{{t 'form.email.label'}}</row.headerCell>
<row.headerCell>{{t 'form.full_name.label'}}</row.headerCell>
<row.headerCell>{{t 'form.type.label'}}</row.headerCell>
<row.headerCell>{{t 'form.id.label'}}</row.headerCell>
</header.row>
</table.header>
<table.body as |body|>
{{#each @model.accounts as |account|}}
<body.row as |row|>
<row.headerCell scope='row'>
{{#if (can 'read account' account)}}
<LinkTo
@route='scopes.scope.auth-methods.auth-method.accounts.account'
@model={{account.id}}
>
{{account.accountName}}
</LinkTo>
{{else}}
{{account.accountName}}
{{/if}}
<p>{{account.description}}</p>
</row.headerCell>
<row.cell>
<code>{{account.issuer}}</code>
</row.cell>
<row.cell>
<code>{{account.subject}}</code>
</row.cell>
<row.cell>
<code>{{account.email}}</code>
</row.cell>
<row.cell>
{{account.full_name}}
</row.cell>
<row.cell>
<Hds::Badge @text={{account.type}} />
</row.cell>
<row.cell>
<Copyable
@text={{account.id}}
@buttonText={{t 'actions.copy-to-clipboard'}}
@acknowledgeText={{t 'states.copied'}}
<Hds::Table
@model={{@model.accounts}}
@columns={{array
(hash label=(t 'form.name.label'))
(hash label=(t 'form.issuer.label'))
(hash label=(t 'form.subject.label'))
(hash label=(t 'form.email.label'))
(hash label=(t 'form.full_name.label'))
(hash label=(t 'form.type.label'))
(hash label=(t 'form.id.label'))
}}
@valign='middle'
>
<:body as |B|>
<B.Tr>
<B.Td>
{{#if (can 'read account' B.data)}}
<LinkTo
@route='scopes.scope.auth-methods.auth-method.accounts.account'
@model={{B.data.id}}
>
<code>{{account.id}}</code>
</Copyable>
</row.cell>
</body.row>
{{/each}}
</table.body>
</Rose::Table>
{{B.data.accountName}}
</LinkTo>
{{else}}
{{B.data.accountName}}
{{/if}}
<p>{{B.data.description}}</p>
</B.Td>
<B.Td>
{{B.data.issuer}}
</B.Td>
<B.Td>
{{B.data.subject}}
</B.Td>
<B.Td>
{{B.data.email}}
</B.Td>
<B.Td>
{{B.data.full_name}}
</B.Td>
<B.Td>
<Hds::Badge @text={{B.data.type}} />
</B.Td>
<B.Td>
<Copyable
@text={{B.data.account.id}}
@buttonText={{t 'actions.copy-to-clipboard'}}
@acknowledgeText={{t 'states.copied'}}
>
<code>{{B.data.account.id}}</code>
</Copyable>
</B.Td>
</B.Tr>
</:body>
</Hds::Table>
{{else if @model.accounts.firstObject.isLDAP}}
<Hds::Table
@model={{@model.accounts}}
@columns={{array
(hash label=(t 'resources.account.form.login_name.label'))
(hash label=(t 'resources.account.form.email.label'))
(hash label=(t 'resources.account.form.full_name.label'))
(hash label=(t 'resources.account.form.dn.label'))
(hash label=(t 'resources.account.form.member_of_groups.label'))
}}
@valign='middle'
>
<:body as |B|>
<B.Tr>
<B.Td>
{{#if (can 'read account' B.data)}}
<LinkTo
@route='scopes.scope.auth-methods.auth-method.accounts.account'
@model={{B.data.id}}
>
{{B.data.displayName}}
</LinkTo>
{{else}}
{{B.data.displayName}}
{{/if}}
<p>{{B.data.description}}</p>
</B.Td>
<B.Td>
{{B.data.email}}
</B.Td>
<B.Td>{{B.data.full_name}}</B.Td>
<B.Td>{{B.data.dn}}</B.Td>
<B.Td>
<div class='truncated-list'>
{{truncate-list 'actions.more' B.data.member_of_groups 3}}
</div>
</B.Td>
</B.Tr>
</:body>
</Hds::Table>
{{else}}
<Rose::Table as |table|>
<table.header as |header|>
<header.row as |row|>
<row.headerCell>{{t 'form.name.label'}}</row.headerCell>
<row.headerCell>{{t 'form.login_name.label'}}</row.headerCell>
<row.headerCell>{{t 'form.type.label'}}</row.headerCell>
<row.headerCell>{{t 'form.id.label'}}</row.headerCell>
</header.row>
</table.header>
<table.body as |body|>
{{#each @model.accounts as |account|}}
<body.row as |row|>
<row.headerCell>
{{#if (can 'read account' account)}}
<LinkTo
@route='scopes.scope.auth-methods.auth-method.accounts.account'
@model={{account.id}}
>
{{account.accountName}}
</LinkTo>
{{else}}
{{account.accountName}}
{{/if}}
<p>{{account.description}}</p>
</row.headerCell>
<row.cell>
{{account.login_name}}
</row.cell>
<row.cell>
<Hds::Badge @text={{account.type}} />
</row.cell>
<row.cell>
<Copyable
@text={{account.id}}
@buttonText={{t 'actions.copy-to-clipboard'}}
@acknowledgeText={{t 'states.copied'}}
<Hds::Table
@model={{@model.accounts}}
@columns={{array
(hash label=(t 'form.name.label'))
(hash label=(t 'form.login_name.label'))
(hash label=(t 'form.type.label'))
(hash label=(t 'form.id.label'))
}}
@valign='middle'
>
<:body as |B|>
<B.Tr>
<B.Td>
{{#if (can 'read account' B.data)}}
<LinkTo
@route='scopes.scope.auth-methods.auth-method.accounts.account'
@model={{B.data.id}}
>
<code>{{account.id}}</code>
</Copyable>
</row.cell>
</body.row>
{{/each}}
</table.body>
</Rose::Table>
{{B.data.accountName}}
</LinkTo>
{{else}}
{{B.data.accountName}}
{{/if}}
<p>{{B.data.description}}</p>
</B.Td>
<B.Td>
{{B.data.login_name}}
</B.Td>
<B.Td>
<Hds::Badge @text={{B.data.type}} />
</B.Td>
<B.Td>
<Copyable
@text={{B.data.account.id}}
@buttonText={{t 'actions.copy-to-clipboard'}}
@acknowledgeText={{t 'states.copied'}}
>
<code>{{B.data.account.id}}</code>
</Copyable>
</B.Td>
</B.Tr>
</:body>
</Hds::Table>
{{/if}}
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.account.messages.welcome.title'}}
@@ -93,7 +93,10 @@ module('Acceptance | accounts | create', function (hooks) {
await fillIn('[name="description"]', 'description');
await fillIn('[name="login_name"]', 'username');
await click('form [type="submit"]:not(:disabled)');
assert.strictEqual(this.server.schema.accounts.all().models.length, accountsCount + 1);
assert.strictEqual(
this.server.schema.accounts.all().models.length,
accountsCount + 1
);
});
test('Users cannot create a new account without proper authorization', async function (assert) {
@@ -18,6 +18,7 @@ import {
module('Acceptance | accounts | read', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
const ACCOUNT_SELECTOR = 'main tbody .hds-table__td:nth-child(1) a';
const instances = {
scopes: {
@@ -66,7 +67,8 @@ module('Acceptance | accounts | read', function (hooks) {
test('can navigate to an account form', async function (assert) {
assert.expect(1);
await visit(urls.accounts);
await click('main tbody .rose-table-header-cell:nth-child(1) a');
await click(ACCOUNT_SELECTOR);
await a11yAudit();
assert.strictEqual(currentURL(), urls.account);
});
@@ -76,6 +78,6 @@ module('Acceptance | accounts | read', function (hooks) {
instances.account.authorized_actions =
instances.account.authorized_actions.filter((item) => item !== 'read');
await visit(urls.accounts);
assert.notOk(find('main tbody .rose-table-header-cell:nth-child(1) a'));
assert.dom(ACCOUNT_SELECTOR).doesNotExist();
});
});
@@ -73,6 +73,23 @@ module('Acceptance | accounts | update', function (hooks) {
assert.strictEqual(this.server.db.accounts[0].name, 'update name');
});
test('can update resource and save LDAP account changes', async function (assert) {
assert.expect(2);
await visit(urls.account);
await click('form [type="button"]', 'Activate edit mode');
await fillIn('[name="name"]', 'updated name');
await fillIn('[name="description"]', 'updated desc');
await click('form [type="submit"]:not(:disabled)');
assert.strictEqual(
this.server.schema.accounts.all().models[0].name,
'updated name'
);
assert.strictEqual(
this.server.schema.accounts.all().models[0].description,
'updated desc'
);
});
test('cannot update resource without proper authorization', async function (assert) {
assert.expect(1);
instances.account.authorized_actions =