Skip to content

Commit 617205f

Browse files
authored
feat(connect-form): Add PLAIN and x509 auth mechanisms COMPASS-5436, COMPASS-5437 (#2729)
* add ldap auth * add x509 auth * fix display error and add improve info for x509
1 parent 1ee26df commit 617205f

File tree

5 files changed

+185
-9
lines changed

5 files changed

+185
-9
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import React from 'react';
2+
import { render, screen, fireEvent } from '@testing-library/react';
3+
import { expect } from 'chai';
4+
import sinon from 'sinon';
5+
import ConnectionStringUrl from 'mongodb-connection-string-url';
6+
7+
import AuthenticationPlain, {
8+
PLAIN_USERNAME_LABEL,
9+
PLAIN_PASSWORD_LABEL,
10+
} from './authentication-plain';
11+
import { ConnectionFormError } from '../../../utils/validation';
12+
import { UpdateConnectionFormField } from '../../../hooks/use-connect-form';
13+
14+
function renderComponent({
15+
errors = [],
16+
connectionStringUrl = new ConnectionStringUrl('mongodb://localhost:27017'),
17+
updateConnectionFormField,
18+
}: {
19+
connectionStringUrl?: ConnectionStringUrl;
20+
errors?: ConnectionFormError[];
21+
updateConnectionFormField: UpdateConnectionFormField;
22+
}) {
23+
render(
24+
<AuthenticationPlain
25+
errors={errors}
26+
connectionStringUrl={connectionStringUrl}
27+
updateConnectionFormField={updateConnectionFormField}
28+
/>
29+
);
30+
}
31+
32+
describe('AuthenticationAws Component', function () {
33+
let updateConnectionFormFieldSpy: sinon.SinonSpy;
34+
beforeEach(function () {
35+
updateConnectionFormFieldSpy = sinon.spy();
36+
});
37+
38+
describe('when the username input is changed', function () {
39+
beforeEach(function () {
40+
renderComponent({
41+
updateConnectionFormField: updateConnectionFormFieldSpy,
42+
});
43+
expect(updateConnectionFormFieldSpy.callCount).to.equal(0);
44+
45+
fireEvent.change(screen.getByLabelText(PLAIN_USERNAME_LABEL), {
46+
target: { value: 'good sandwich' },
47+
});
48+
});
49+
50+
it('calls to update the form field', function () {
51+
expect(updateConnectionFormFieldSpy.callCount).to.equal(1);
52+
expect(updateConnectionFormFieldSpy.firstCall.args[0]).to.deep.equal({
53+
type: 'update-username',
54+
username: 'good sandwich',
55+
});
56+
});
57+
});
58+
59+
describe('when the password input is changed', function () {
60+
beforeEach(function () {
61+
renderComponent({
62+
updateConnectionFormField: updateConnectionFormFieldSpy,
63+
});
64+
expect(updateConnectionFormFieldSpy.callCount).to.equal(0);
65+
66+
fireEvent.change(screen.getByLabelText(PLAIN_PASSWORD_LABEL), {
67+
target: { value: 'good sandwich' },
68+
});
69+
});
70+
71+
it('calls to update the form field', function () {
72+
expect(updateConnectionFormFieldSpy.callCount).to.equal(1);
73+
expect(updateConnectionFormFieldSpy.firstCall.args[0]).to.deep.equal({
74+
type: 'update-password',
75+
password: 'good sandwich',
76+
});
77+
});
78+
});
79+
80+
it('renders a username error when there is a username error', function () {
81+
renderComponent({
82+
errors: [
83+
{
84+
fieldName: 'username',
85+
message: 'username error',
86+
},
87+
],
88+
updateConnectionFormField: updateConnectionFormFieldSpy,
89+
});
90+
91+
expect(screen.getByText('username error')).to.be.visible;
92+
});
93+
94+
it('renders a password error when there is a password error', function () {
95+
renderComponent({
96+
errors: [
97+
{
98+
fieldName: 'password',
99+
message: 'password error',
100+
},
101+
],
102+
updateConnectionFormField: updateConnectionFormFieldSpy,
103+
});
104+
105+
expect(screen.getByText('password error')).to.be.visible;
106+
});
107+
});

packages/connect-form/src/components/advanced-options-tabs/authentication-tab/authentication-plain.tsx

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,70 @@
11
import React from 'react';
2+
import { TextInput } from '@mongodb-js/compass-components';
3+
4+
import ConnectionStringUrl from 'mongodb-connection-string-url';
5+
import { UpdateConnectionFormField } from '../../../hooks/use-connect-form';
6+
import FormFieldContainer from '../../form-field-container';
7+
import {
8+
ConnectionFormError,
9+
errorMessageByFieldName,
10+
} from '../../../utils/validation';
11+
import {
12+
getConnectionStringPassword,
13+
getConnectionStringUsername,
14+
} from '../../../utils/connection-string-helpers';
15+
16+
export const PLAIN_USERNAME_LABEL = 'Username';
17+
export const PLAIN_PASSWORD_LABEL = 'Password';
18+
19+
function AuthenticationPlain({
20+
connectionStringUrl,
21+
updateConnectionFormField,
22+
errors,
23+
}: {
24+
connectionStringUrl: ConnectionStringUrl;
25+
errors: ConnectionFormError[];
26+
updateConnectionFormField: UpdateConnectionFormField;
27+
}): React.ReactElement {
28+
const username = getConnectionStringUsername(connectionStringUrl);
29+
const password = getConnectionStringPassword(connectionStringUrl);
30+
const usernameError = errorMessageByFieldName(errors, 'username');
31+
const passwordError = errorMessageByFieldName(errors, 'password');
232

3-
function AuthenticationPlain(): React.ReactElement {
433
return (
534
<>
6-
<p>LDAP</p>
35+
<FormFieldContainer>
36+
<TextInput
37+
onChange={({
38+
target: { value },
39+
}: React.ChangeEvent<HTMLInputElement>) => {
40+
updateConnectionFormField({
41+
type: 'update-username',
42+
username: value,
43+
});
44+
}}
45+
label={PLAIN_USERNAME_LABEL}
46+
value={username || ''}
47+
errorMessage={usernameError}
48+
state={usernameError ? 'error' : undefined}
49+
/>
50+
</FormFieldContainer>
51+
<FormFieldContainer>
52+
<TextInput
53+
onChange={({
54+
target: { value },
55+
}: React.ChangeEvent<HTMLInputElement>) => {
56+
updateConnectionFormField({
57+
type: 'update-password',
58+
password: value,
59+
});
60+
}}
61+
label={PLAIN_PASSWORD_LABEL}
62+
type="password"
63+
value={password || ''}
64+
errorMessage={passwordError}
65+
state={passwordError ? 'error' : undefined}
66+
/>
67+
</FormFieldContainer>
768
</>
869
);
970
}

packages/connect-form/src/components/advanced-options-tabs/authentication-tab/authentication-x509.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1+
import { Banner, BannerVariant } from '@mongodb-js/compass-components';
12
import React from 'react';
23

34
function AuthenticationX509(): React.ReactElement {
45
return (
56
<>
6-
<p>X.509</p>
7+
<Banner variant={BannerVariant.Info}>
8+
X.509 Authentication type requires a <strong>Client Certificate</strong>{' '}
9+
to work. Make sure to enable TLS and add one in the{' '}
10+
<strong>TLS/SSL</strong> tab.
11+
</Banner>
712
</>
813
);
914
}

packages/connect-form/src/hooks/use-connect-form.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -430,10 +430,15 @@ export function handleConnectionFormFieldUpdate(
430430
authMechanismProperties.delete(action.key);
431431
}
432432

433-
updatedSearchParams.set(
434-
'authMechanismProperties',
435-
authMechanismProperties.toString()
436-
);
433+
const authMechanismPropertiesString = authMechanismProperties.toString();
434+
if (authMechanismPropertiesString) {
435+
updatedSearchParams.set(
436+
'authMechanismProperties',
437+
authMechanismPropertiesString
438+
);
439+
} else {
440+
updatedSearchParams.delete('authMechanismProperties');
441+
}
437442

438443
return {
439444
connectionOptions: {

packages/connect-form/src/utils/validation.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ export type FieldName =
99
| 'hosts'
1010
| 'isSrv'
1111
| 'kerberosPrincipal'
12-
| 'ldapPassword'
13-
| 'ldapUsername'
1412
| 'password'
1513
| 'schema'
1614
| 'proxyHostname'

0 commit comments

Comments
 (0)