Skip to content

Commit

Permalink
chore(connection-form): add show options for connection form in vscod…
Browse files Browse the repository at this point in the history
…e support VSCODE-483 (#5176)
  • Loading branch information
Anemy authored Nov 30, 2023
1 parent d51a2c0 commit 93f6efc
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { expect } from 'chai';
import sinon from 'sinon';

import AdvancedOptionsTabs from './advanced-options-tabs';
import { ConnectionFormPreferencesContext } from '../../hooks/use-connect-form-preferences';

const testUrl = 'mongodb+srv://0ranges:p!neapp1es@localhost/?ssl=true';

Expand All @@ -15,6 +16,7 @@ const tabs = [
},
{ name: 'TLS/SSL', id: 'tls' },
{ name: 'Proxy/SSH', id: 'proxy' },
{ name: 'In-Use Encryption', id: 'csfle' },
{ name: 'Advanced', id: 'advanced' },
];

Expand Down Expand Up @@ -105,4 +107,22 @@ describe('AdvancedOptionsTabs Component', function () {
screen.getAllByTestId('connection-tls-tab')[0].getAttribute('aria-label')
).to.equal('TLS/SSL (2 errors)');
});

it('should not render CSFLE when its set to false in the preferences', function () {
render(
<ConnectionFormPreferencesContext.Provider value={{ showCSFLE: false }}>
<AdvancedOptionsTabs
connectionOptions={{
connectionString: testUrl,
}}
errors={[]}
updateConnectionFormField={updateConnectionFormFieldSpy}
/>
</ConnectionFormPreferencesContext.Provider>
);

const csfleTabName = tabs.find((tab) => tab.id === 'csfle')?.name;
expect(csfleTabName).to.not.be.undefined;
expect(screen.queryByText(csfleTabName as string)).to.not.exist;
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type { UpdateConnectionFormField } from '../../hooks/use-connect-form';
import type { ConnectionFormError, TabId } from '../../utils/validation';
import { errorsByFieldTab } from '../../utils/validation';
import { defaultConnectionString } from '../../constants/default-connection';
import { useConnectionFormPreference } from '../../hooks/use-connect-form-preferences';

const tabsStyles = css({
marginTop: spacing[2],
Expand Down Expand Up @@ -60,6 +61,7 @@ function AdvancedOptionsTabs({
connectionOptions: ConnectionOptions;
}): React.ReactElement {
const [activeTab, setActiveTab] = useState(0);
const showCSFLE = useConnectionFormPreference('showCSFLE');

const tabs: TabObject[] = [
{ name: 'General', id: 'general', component: GeneralTab },
Expand All @@ -70,11 +72,15 @@ function AdvancedOptionsTabs({
},
{ name: 'TLS/SSL', id: 'tls', component: TLSTab },
{ name: 'Proxy/SSH', id: 'proxy', component: ProxyAndSshTunnelTab },
{
name: 'In-Use Encryption',
id: 'csfle',
component: CSFLETab,
},
...(showCSFLE
? [
{
name: 'In-Use Encryption',
id: 'csfle',
component: CSFLETab,
} as const,
]
: []),
{ name: 'Advanced', id: 'advanced', component: AdvancedTab },
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,86 @@ import { render, screen, fireEvent } from '@testing-library/react';
import { expect } from 'chai';
import sinon from 'sinon';
import ConnectionStringUrl from 'mongodb-connection-string-url';
import { AuthMechanism } from 'mongodb';

import AuthenticationTab from './authentication-tab';
import type { ConnectionFormError } from '../../../utils/validation';
import type { UpdateConnectionFormField } from '../../../hooks/use-connect-form';
import { ConnectionFormPreferencesContext } from '../../../hooks/use-connect-form-preferences';
import type { ConnectionFormPreferences } from '../../../hooks/use-connect-form-preferences';

function renderComponent({
errors = [],
connectionStringUrl = new ConnectionStringUrl('mongodb://localhost:27017'),
connectionFormPreferences = {
enableOidc: true,
},
updateConnectionFormField,
}: {
connectionStringUrl?: ConnectionStringUrl;
connectionFormPreferences?: Partial<ConnectionFormPreferences>;
errors?: ConnectionFormError[];
updateConnectionFormField: UpdateConnectionFormField;
}) {
render(
<AuthenticationTab
errors={errors}
connectionStringUrl={connectionStringUrl}
updateConnectionFormField={updateConnectionFormField}
connectionOptions={{
connectionString: 'mongodb://localhost:27017',
}}
/>
<ConnectionFormPreferencesContext.Provider
value={connectionFormPreferences}
>
<AuthenticationTab
errors={errors}
connectionStringUrl={connectionStringUrl}
updateConnectionFormField={updateConnectionFormField}
connectionOptions={{
connectionString: 'mongodb://localhost:27017',
}}
/>
</ConnectionFormPreferencesContext.Provider>
);
}

const authMechanisms = [
{
title: 'Username/Password',
id: AuthMechanism.MONGODB_DEFAULT,
},
{
title: 'OIDC (Preview)',
id: AuthMechanism.MONGODB_OIDC,
},
{
title: 'X.509',
id: AuthMechanism.MONGODB_X509,
},
{
title: 'Kerberos',
id: AuthMechanism.MONGODB_GSSAPI,
},
{
title: 'LDAP',
id: AuthMechanism.MONGODB_PLAIN,
},
{
title: 'AWS IAM',
id: AuthMechanism.MONGODB_AWS,
},
];

describe('AuthenticationTab Component', function () {
let updateConnectionFormFieldSpy: sinon.SinonSpy;
beforeEach(function () {
updateConnectionFormFieldSpy = sinon.spy();
});

it('renders all of the auth mechanisms', function () {
renderComponent({
updateConnectionFormField: updateConnectionFormFieldSpy,
});

authMechanisms.forEach((mechanism) => {
expect(screen.getByText(mechanism.title)).to.be.visible;
});
});

describe('when a new auth mechanism is clicked', function () {
beforeEach(function () {
renderComponent({
Expand Down Expand Up @@ -66,7 +114,6 @@ describe('AuthenticationTab Component', function () {

it('renders the username/password tab when auth is set', function () {
renderComponent({
errors: [],
connectionStringUrl: new ConnectionStringUrl(
'mongodb://a123:b123@localhost'
),
Expand All @@ -79,7 +126,6 @@ describe('AuthenticationTab Component', function () {

it('renders the username/password tab when only password is set', function () {
renderComponent({
errors: [],
connectionStringUrl: new ConnectionStringUrl(
'mongodb://:b123@localhost',
{ looseValidation: true }
Expand All @@ -90,4 +136,30 @@ describe('AuthenticationTab Component', function () {
expect(screen.getByLabelText('Username')).to.be.visible;
expect(screen.getByLabelText('Password')).to.be.visible;
});

it('should not render OIDC auth when its set to false in the preferences', function () {
renderComponent({
connectionFormPreferences: { showOIDCAuth: false },
updateConnectionFormField: updateConnectionFormFieldSpy,
});

const oidcAuthName = authMechanisms.find(
(tab) => tab.id === 'MONGODB-OIDC'
)?.title;
expect(oidcAuthName).to.not.be.undefined;
expect(screen.queryByText(oidcAuthName as string)).to.not.exist;
});

it('should not render Kerberos auth when its set to false in the preferences', function () {
renderComponent({
connectionFormPreferences: { showKerberosAuth: false },
updateConnectionFormField: updateConnectionFormFieldSpy,
});

const kerberosAuthName = authMechanisms.find(
(tab) => tab.id === 'GSSAPI'
)?.title;
expect(kerberosAuthName).to.not.be.undefined;
expect(screen.queryByText(kerberosAuthName as string)).to.not.exist;
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,22 @@ function AuthenticationTab({
updateConnectionFormField: UpdateConnectionFormField;
connectionOptions: ConnectionOptions;
}): React.ReactElement {
// enableOIDC is the feature flag, showOIDC is the connection form preference.
const enableOIDC = !!useConnectionFormPreference('enableOidc');
const enabledAuthOptions = useMemo(() => {
if (enableOIDC) {
return options;
}
return options.filter((option) => option.id !== 'MONGODB-OIDC');
}, [enableOIDC]);
const showOIDC = useConnectionFormPreference('showOIDCAuth');
const showKerberos = useConnectionFormPreference('showKerberosAuth');
const enabledAuthOptions = useMemo(
() =>
options.filter((option) => {
if (option.id === 'MONGODB-OIDC') {
return enableOIDC && showOIDC;
} else if (option.id === 'GSSAPI') {
return showKerberos;
}
return true;
}),
[enableOIDC, showKerberos, showOIDC]
);

const selectedAuthTabId =
getSelectedAuthTabForConnectionString(connectionStringUrl);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createContext, useContext } from 'react';

// Not all of these preference map to Compass preferences.
export type ConnectionFormPreferences = {
protectConnectionStrings: boolean;
forceConnectionOptions: [key: string, value: string][];
Expand All @@ -8,6 +9,9 @@ export type ConnectionFormPreferences = {
enableOidc: boolean;
enableDebugUseCsfleSchemaMap: boolean;
protectConnectionStringsForNewConnections: boolean;
showOIDCAuth: boolean;
showKerberosAuth: boolean;
showCSFLE: boolean;
};

const defaultPreferences = {
Expand All @@ -18,6 +22,9 @@ const defaultPreferences = {
enableOidc: false,
enableDebugUseCsfleSchemaMap: false,
protectConnectionStringsForNewConnections: false,
showOIDCAuth: true,
showKerberosAuth: true,
showCSFLE: true,
};

export const ConnectionFormPreferencesContext = createContext<
Expand Down

0 comments on commit 93f6efc

Please sign in to comment.