feat: 🎸 initial LDAP authentication support (#1645)
* feat: 🎸 initial LDAP authentication support
This commit is contained in:
1 parent
b344c5fc18
commit
4c80f8d8ff
14 files changed
+161
-35
No files matched your search
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import PasswordAuthenticator from './password';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple login_name/password authenticator that authenticates with
|
||||||
|
* a scope/auth-method endpoint. Authentication occurs on an auth method
|
||||||
|
* endpoint, while deauthentication occurs on a scope endpoint.
|
||||||
|
*/
|
||||||
|
export default class LDAPAuthenticator extends PasswordAuthenticator {}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
{{!
|
||||||
|
Copyright (c) HashiCorp, Inc.
|
||||||
|
SPDX-License-Identifier: MPL-2.0
|
||||||
|
}}
|
||||||
|
|
||||||
|
<Rose::Form
|
||||||
|
class='full-width'
|
||||||
|
@onSubmit={{fn
|
||||||
|
this.submit
|
||||||
|
@onSubmit
|
||||||
|
(hash identification=this.identification password=this.password)
|
||||||
|
}}
|
||||||
|
@disabled={{@disabled}}
|
||||||
|
as |form|
|
||||||
|
>
|
||||||
|
<Hds::Form::TextInput::Field
|
||||||
|
name='identification'
|
||||||
|
@value={{this.identification}}
|
||||||
|
@type='text'
|
||||||
|
{{on 'input' (set-from-event this 'identification')}}
|
||||||
|
as |F|
|
||||||
|
>
|
||||||
|
<F.Label>{{t 'form.login_name.label'}}</F.Label>
|
||||||
|
</Hds::Form::TextInput::Field>
|
||||||
|
|
||||||
|
<Hds::Form::TextInput::Field
|
||||||
|
name='password'
|
||||||
|
@value={{this.password}}
|
||||||
|
@type='password'
|
||||||
|
{{on 'input' (set-from-event this 'password')}}
|
||||||
|
as |F|
|
||||||
|
>
|
||||||
|
<F.Label>{{t 'form.password.label'}}</F.Label>
|
||||||
|
</Hds::Form::TextInput::Field>
|
||||||
|
|
||||||
|
<form.actions
|
||||||
|
@submitText={{t 'actions.authenticate'}}
|
||||||
|
@showCancel={{false}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</Rose::Form>
|
||||||
+1
-1
@@ -8,7 +8,7 @@ import { tracked } from '@glimmer/tracking';
|
|||||||
import { action } from '@ember/object';
|
import { action } from '@ember/object';
|
||||||
import { run } from '@ember/runloop';
|
import { run } from '@ember/runloop';
|
||||||
|
|
||||||
export default class FormAuthenticatePasswordComponent extends Component {
|
export default class FormAuthenticateDetailsComponent extends Component {
|
||||||
// =properties
|
// =properties
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
{{component
|
{{component
|
||||||
(concat 'form/authenticate/' @model.type)
|
(concat 'form/authenticate/' @model.type)
|
||||||
submit=@submit
|
submit=@submit
|
||||||
cancel=false
|
|
||||||
disabled=@disabled
|
disabled=@disabled
|
||||||
}}
|
}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{{!
|
||||||
|
Copyright (c) HashiCorp, Inc.
|
||||||
|
SPDX-License-Identifier: MPL-2.0
|
||||||
|
}}
|
||||||
|
|
||||||
|
<Form::Authenticate::Details @onSubmit={{@submit}} @disabled={{@disabled}} />
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
<Rose::Form
|
<Rose::Form
|
||||||
class='full-width'
|
class='full-width'
|
||||||
@onSubmit={{@submit}}
|
@onSubmit={{@submit}}
|
||||||
@cancel={{false}}
|
|
||||||
@disabled={{@disabled}}
|
@disabled={{@disabled}}
|
||||||
as |form|
|
as |form|
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -3,35 +3,4 @@
|
|||||||
SPDX-License-Identifier: MPL-2.0
|
SPDX-License-Identifier: MPL-2.0
|
||||||
}}
|
}}
|
||||||
|
|
||||||
<Rose::Form
|
<Form::Authenticate::Details @onSubmit={{@submit}} @disabled={{@disabled}} />
|
||||||
class='full-width'
|
|
||||||
@onSubmit={{fn
|
|
||||||
this.submit
|
|
||||||
@submit
|
|
||||||
(hash identification=this.identification password=this.password)
|
|
||||||
}}
|
|
||||||
@cancel={{false}}
|
|
||||||
@disabled={{@disabled}}
|
|
||||||
as |form|
|
|
||||||
>
|
|
||||||
|
|
||||||
<form.input
|
|
||||||
@name='identification'
|
|
||||||
@type='text'
|
|
||||||
@value={{this.identification}}
|
|
||||||
@label={{t 'form.login_name.label'}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<form.input
|
|
||||||
@name='password'
|
|
||||||
@type='password'
|
|
||||||
@value={{this.password}}
|
|
||||||
@label={{t 'form.password.label'}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<form.actions
|
|
||||||
@submitText={{t 'actions.authenticate'}}
|
|
||||||
@showCancel={{false}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</Rose::Form>
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { default } from 'core/authenticators/ldap';
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { default } from 'core/components/form/authenticate/details';
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { default } from 'core/components/form/authenticate/ldap';
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
|
import { render, find } from '@ember/test-helpers';
|
||||||
|
import { hbs } from 'ember-cli-htmlbars';
|
||||||
|
import { setupIntl } from 'ember-intl/test-support';
|
||||||
|
|
||||||
|
module('Integration | Component | form | authenticate', function (hooks) {
|
||||||
|
setupRenderingTest(hooks);
|
||||||
|
setupIntl(hooks);
|
||||||
|
|
||||||
|
test('it shows login name and password when LDAP is selected from the list', async function (assert) {
|
||||||
|
assert.expect(3);
|
||||||
|
|
||||||
|
const store = this.owner.lookup('service:store');
|
||||||
|
|
||||||
|
this.model = store.createRecord('auth-method', { type: 'ldap' });
|
||||||
|
this.submit = () => {};
|
||||||
|
this.disabled = () => {};
|
||||||
|
|
||||||
|
await render(hbs`<Form::Authenticate
|
||||||
|
@model={{this.model}}
|
||||||
|
@submit={{this.submit}}
|
||||||
|
@disabled={{this.disabled}}/>`);
|
||||||
|
assert.ok(find('.full-width'));
|
||||||
|
assert.ok(find('.hds-form-text-input'));
|
||||||
|
assert.strictEqual(
|
||||||
|
find('button[type="submit"]').textContent.trim(),
|
||||||
|
'Sign In'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it shows login name and password when password is selected from the list', async function (assert) {
|
||||||
|
assert.expect(3);
|
||||||
|
|
||||||
|
const store = this.owner.lookup('service:store');
|
||||||
|
|
||||||
|
this.model = store.createRecord('auth-method', { type: 'password' });
|
||||||
|
this.submit = () => {};
|
||||||
|
this.disabled = () => {};
|
||||||
|
|
||||||
|
await render(hbs`<Form::Authenticate
|
||||||
|
@model={{this.model}}
|
||||||
|
@submit={{this.submit}}
|
||||||
|
@disabled={{this.disabled}}/>`);
|
||||||
|
assert.ok(find('.full-width'));
|
||||||
|
assert.ok(find('.hds-form-text-input'));
|
||||||
|
assert.strictEqual(
|
||||||
|
find('button[type="submit"]').textContent.trim(),
|
||||||
|
'Sign In'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('it should only show sign in button when OIDC is selected from the list', async function (assert) {
|
||||||
|
assert.expect(3);
|
||||||
|
|
||||||
|
const store = this.owner.lookup('service:store');
|
||||||
|
|
||||||
|
this.model = store.createRecord('auth-method', { type: 'oidc' });
|
||||||
|
this.submit = () => {};
|
||||||
|
this.disabled = () => {};
|
||||||
|
|
||||||
|
await render(hbs`<Form::Authenticate
|
||||||
|
@model={{this.model}}
|
||||||
|
@submit={{this.submit}}
|
||||||
|
@disabled={{this.disabled}}/>`);
|
||||||
|
assert.ok(find('.full-width'));
|
||||||
|
assert.notOk(find('.hds-form-text-input'));
|
||||||
|
assert.strictEqual(
|
||||||
|
find('button[type="submit"]').textContent.trim(),
|
||||||
|
'Sign In'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -47,6 +47,7 @@ auth-method:
|
|||||||
types:
|
types:
|
||||||
password: Password
|
password: Password
|
||||||
oidc: OIDC
|
oidc: OIDC
|
||||||
|
ldap: LDAP
|
||||||
actions:
|
actions:
|
||||||
create: Create Auth Method
|
create: Create Auth Method
|
||||||
delete: Delete Auth Method
|
delete: Delete Auth Method
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
|||||||
const requestCookies = false;
|
const requestCookies = false;
|
||||||
switch (authMethod.type) {
|
switch (authMethod.type) {
|
||||||
case 'password':
|
case 'password':
|
||||||
|
case 'ldap':
|
||||||
await this.session.authenticate(
|
await this.session.authenticate(
|
||||||
authenticatorName,
|
authenticatorName,
|
||||||
creds,
|
creds,
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
|||||||
const requestCookies = false;
|
const requestCookies = false;
|
||||||
switch (authMethod.type) {
|
switch (authMethod.type) {
|
||||||
case 'password':
|
case 'password':
|
||||||
|
case 'ldap':
|
||||||
await this.session.authenticate(
|
await this.session.authenticate(
|
||||||
authenticatorName,
|
authenticatorName,
|
||||||
creds,
|
creds,
|
||||||
|
|||||||
Reference in new issue
Block a user