mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Auth: add the missing fields for all SSO providers (#83813)
* add the missing fields for sso providers * remove fields array * add the validate_hd field for google * submit only fields defined on the provider * fix unit tests * add unit tests for the new fields/sections from the form * add hosted_domain field for the google provider * reorder fields in user mapping * remove authStyle field from gitlab and okta --------- Co-authored-by: Mihaly Gyongyosi <mgyongyosi@users.noreply.github.com>
This commit is contained in:
parent
c1c9ccb8e8
commit
6febfdffd2
@ -77,24 +77,54 @@ describe('ProviderConfigForm', () => {
|
|||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders all fields correctly', async () => {
|
it('renders all general settings fields correctly', async () => {
|
||||||
setup(<ProviderConfigForm config={testConfig} provider={testConfig.provider} />);
|
setup(<ProviderConfigForm config={testConfig} provider={testConfig.provider} />);
|
||||||
expect(screen.getByRole('textbox', { name: /Client ID/i })).toBeInTheDocument();
|
expect(screen.getByRole('textbox', { name: /Client ID/i })).toBeInTheDocument();
|
||||||
expect(screen.getByRole('combobox', { name: /Team IDs/i })).toBeInTheDocument();
|
expect(screen.getByRole('textbox', { name: /Client secret/i })).toBeInTheDocument();
|
||||||
expect(screen.getByRole('combobox', { name: /Allowed organizations/i })).toBeInTheDocument();
|
expect(screen.getByRole('combobox', { name: /Scopes/i })).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('checkbox', { name: /Allow Sign Up/i })).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('checkbox', { name: /Auto login/i })).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('textbox', { name: /Sign out redirect URL/i })).toBeInTheDocument();
|
||||||
expect(screen.getByRole('button', { name: /Save/i })).toBeInTheDocument();
|
expect(screen.getByRole('button', { name: /Save/i })).toBeInTheDocument();
|
||||||
expect(screen.getByRole('link', { name: /Discard/i })).toBeInTheDocument();
|
expect(screen.getByRole('link', { name: /Discard/i })).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('renders all user mapping fields correctly', async () => {
|
||||||
|
const { user } = setup(<ProviderConfigForm config={testConfig} provider={testConfig.provider} />);
|
||||||
|
await user.click(screen.getByText('User mapping'));
|
||||||
|
expect(screen.getByRole('textbox', { name: /Role attribute path/i })).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('checkbox', { name: /Role attribute strict mode/i })).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('checkbox', { name: /Skip organization role sync/i })).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders all extra security fields correctly', async () => {
|
||||||
|
const { user } = setup(<ProviderConfigForm config={testConfig} provider={testConfig.provider} />);
|
||||||
|
await user.click(screen.getByText('Extra security measures'));
|
||||||
|
expect(screen.getByRole('combobox', { name: /Allowed organizations/i })).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('combobox', { name: /Allowed domains/i })).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('combobox', { name: /Team Ids/i })).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('checkbox', { name: /Use PKCE/i })).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('checkbox', { name: /Use refresh token/i })).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole('checkbox', { name: /TLS skip verify/i })).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it('should save and enable on form submit', async () => {
|
it('should save and enable on form submit', async () => {
|
||||||
const { user } = setup(<ProviderConfigForm config={emptyConfig} provider={emptyConfig.provider} />);
|
const { user } = setup(<ProviderConfigForm config={emptyConfig} provider={emptyConfig.provider} />);
|
||||||
|
|
||||||
await user.type(screen.getByRole('textbox', { name: /Client ID/i }), 'test-client-id');
|
await user.type(screen.getByRole('textbox', { name: /Client ID/i }), 'test-client-id');
|
||||||
await user.type(screen.getByLabelText(/Client secret/i), 'test-client-secret');
|
await user.type(screen.getByLabelText(/Client secret/i), 'test-client-secret');
|
||||||
// Type a team name and press enter to select it
|
// Type a scope and press enter to select it
|
||||||
await user.type(screen.getByRole('combobox', { name: /Team IDs/i }), '12324{enter}');
|
await user.type(screen.getByRole('combobox', { name: /Scopes/i }), 'user:email{enter}');
|
||||||
// Add two orgs
|
await user.click(screen.getByRole('checkbox', { name: /Auto login/i }));
|
||||||
await user.type(screen.getByRole('combobox', { name: /Allowed organizations/i }), 'test-org1{enter}');
|
|
||||||
await user.type(screen.getByRole('combobox', { name: /Allowed organizations/i }), 'test-org2{enter}');
|
await user.click(screen.getByText('User mapping'));
|
||||||
|
await user.type(screen.getByRole('textbox', { name: /Role attribute path/i }), 'new-attribute-path');
|
||||||
|
await user.click(screen.getByRole('checkbox', { name: /Role attribute strict mode/i }));
|
||||||
|
|
||||||
|
await user.click(screen.getByText('Extra security measures'));
|
||||||
|
await user.type(screen.getByRole('combobox', { name: /Allowed domains/i }), 'grafana.com{enter}');
|
||||||
|
await user.click(screen.getByRole('checkbox', { name: /Use PKCE/i }));
|
||||||
|
|
||||||
await user.click(screen.getByRole('button', { name: /Save and enable/i }));
|
await user.click(screen.getByRole('button', { name: /Save and enable/i }));
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
@ -104,12 +134,27 @@ describe('ProviderConfigForm', () => {
|
|||||||
id: '300f9b7c-0488-40db-9763-a22ce8bf6b3e',
|
id: '300f9b7c-0488-40db-9763-a22ce8bf6b3e',
|
||||||
provider: 'github',
|
provider: 'github',
|
||||||
settings: {
|
settings: {
|
||||||
name: 'GitHub',
|
allowAssignGrafanaAdmin: false,
|
||||||
allowedOrganizations: 'test-org1,test-org2',
|
allowSignUp: false,
|
||||||
|
allowedDomains: 'grafana.com',
|
||||||
|
allowedOrganizations: '',
|
||||||
|
autoLogin: true,
|
||||||
clientId: 'test-client-id',
|
clientId: 'test-client-id',
|
||||||
clientSecret: 'test-client-secret',
|
clientSecret: 'test-client-secret',
|
||||||
teamIds: '12324',
|
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
name: 'GitHub',
|
||||||
|
roleAttributePath: 'new-attribute-path',
|
||||||
|
roleAttributeStrict: true,
|
||||||
|
scopes: 'user:email',
|
||||||
|
signoutRedirectUrl: '',
|
||||||
|
skipOrgRoleSync: false,
|
||||||
|
teamIds: '',
|
||||||
|
tlsClientCa: '',
|
||||||
|
tlsClientCert: '',
|
||||||
|
tlsClientKey: '',
|
||||||
|
tlsSkipVerifyInsecure: false,
|
||||||
|
usePkce: true,
|
||||||
|
useRefreshToken: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ showErrorAlert: false }
|
{ showErrorAlert: false }
|
||||||
@ -126,11 +171,9 @@ describe('ProviderConfigForm', () => {
|
|||||||
const { user } = setup(<ProviderConfigForm config={emptyConfig} provider={emptyConfig.provider} />);
|
const { user } = setup(<ProviderConfigForm config={emptyConfig} provider={emptyConfig.provider} />);
|
||||||
await user.type(screen.getByRole('textbox', { name: /Client ID/i }), 'test-client-id');
|
await user.type(screen.getByRole('textbox', { name: /Client ID/i }), 'test-client-id');
|
||||||
await user.type(screen.getByLabelText(/Client secret/i), 'test-client-secret');
|
await user.type(screen.getByLabelText(/Client secret/i), 'test-client-secret');
|
||||||
// Type a team name and press enter to select it
|
// Type a scope and press enter to select it
|
||||||
await user.type(screen.getByRole('combobox', { name: /Team IDs/i }), '12324{enter}');
|
await user.type(screen.getByRole('combobox', { name: /Scopes/i }), 'user:email{enter}');
|
||||||
// Add two orgs
|
await user.click(screen.getByRole('checkbox', { name: /Auto login/i }));
|
||||||
await user.type(screen.getByRole('combobox', { name: /Allowed organizations/i }), 'test-org1{enter}');
|
|
||||||
await user.type(screen.getByRole('combobox', { name: /Allowed organizations/i }), 'test-org2{enter}');
|
|
||||||
await user.click(screen.getByText('Save'));
|
await user.click(screen.getByText('Save'));
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
@ -140,12 +183,26 @@ describe('ProviderConfigForm', () => {
|
|||||||
id: '300f9b7c-0488-40db-9763-a22ce8bf6b3e',
|
id: '300f9b7c-0488-40db-9763-a22ce8bf6b3e',
|
||||||
provider: 'github',
|
provider: 'github',
|
||||||
settings: {
|
settings: {
|
||||||
name: 'GitHub',
|
allowAssignGrafanaAdmin: false,
|
||||||
allowedOrganizations: 'test-org1,test-org2',
|
allowSignUp: false,
|
||||||
|
allowedDomains: '',
|
||||||
|
allowedOrganizations: '',
|
||||||
|
autoLogin: true,
|
||||||
clientId: 'test-client-id',
|
clientId: 'test-client-id',
|
||||||
clientSecret: 'test-client-secret',
|
clientSecret: 'test-client-secret',
|
||||||
teamIds: '12324',
|
|
||||||
enabled: false,
|
enabled: false,
|
||||||
|
name: 'GitHub',
|
||||||
|
roleAttributePath: '',
|
||||||
|
roleAttributeStrict: false,
|
||||||
|
scopes: 'user:email',
|
||||||
|
signoutRedirectUrl: '',
|
||||||
|
skipOrgRoleSync: false,
|
||||||
|
teamIds: '',
|
||||||
|
tlsClientCa: '',
|
||||||
|
tlsClientCert: '',
|
||||||
|
tlsClientKey: '',
|
||||||
|
usePkce: false,
|
||||||
|
useRefreshToken: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ showErrorAlert: false }
|
{ showErrorAlert: false }
|
||||||
|
@ -21,7 +21,7 @@ import { FormPrompt } from '../../core/components/FormPrompt/FormPrompt';
|
|||||||
import { Page } from '../../core/components/Page/Page';
|
import { Page } from '../../core/components/Page/Page';
|
||||||
|
|
||||||
import { FieldRenderer } from './FieldRenderer';
|
import { FieldRenderer } from './FieldRenderer';
|
||||||
import { fields, sectionFields } from './fields';
|
import { sectionFields } from './fields';
|
||||||
import { SSOProvider, SSOProviderDTO } from './types';
|
import { SSOProvider, SSOProviderDTO } from './types';
|
||||||
import { dataToDTO, dtoToData } from './utils/data';
|
import { dataToDTO, dtoToData } from './utils/data';
|
||||||
|
|
||||||
@ -45,7 +45,6 @@ export const ProviderConfigForm = ({ config, provider, isLoading }: ProviderConf
|
|||||||
formState: { errors, dirtyFields, isSubmitted },
|
formState: { errors, dirtyFields, isSubmitted },
|
||||||
} = useForm({ defaultValues: dataToDTO(config), mode: 'onSubmit', reValidateMode: 'onChange' });
|
} = useForm({ defaultValues: dataToDTO(config), mode: 'onSubmit', reValidateMode: 'onChange' });
|
||||||
const [isSaving, setIsSaving] = useState(false);
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
const providerFields = fields[provider];
|
|
||||||
const [submitError, setSubmitError] = useState(false);
|
const [submitError, setSubmitError] = useState(false);
|
||||||
const dataSubmitted = isSubmitted && !submitError;
|
const dataSubmitted = isSubmitted && !submitError;
|
||||||
const sections = sectionFields[provider];
|
const sections = sectionFields[provider];
|
||||||
@ -155,55 +154,34 @@ export const ProviderConfigForm = ({ config, provider, isLoading }: ProviderConf
|
|||||||
<Field label="Enabled" hidden={true}>
|
<Field label="Enabled" hidden={true}>
|
||||||
<Switch {...register('enabled')} id="enabled" label={'Enabled'} />
|
<Switch {...register('enabled')} id="enabled" label={'Enabled'} />
|
||||||
</Field>
|
</Field>
|
||||||
{sections ? (
|
<Stack gap={2} direction={'column'}>
|
||||||
<Stack gap={2} direction={'column'}>
|
{sections
|
||||||
{sections
|
.filter((section) => !section.hidden)
|
||||||
.filter((section) => !section.hidden)
|
.map((section, index) => {
|
||||||
.map((section, index) => {
|
|
||||||
return (
|
|
||||||
<CollapsableSection label={section.name} isOpen={index === 0} key={section.name}>
|
|
||||||
{section.fields
|
|
||||||
.filter((field) => (typeof field !== 'string' ? !field.hidden : true))
|
|
||||||
.map((field) => {
|
|
||||||
return (
|
|
||||||
<FieldRenderer
|
|
||||||
key={typeof field === 'string' ? field : field.name}
|
|
||||||
field={field}
|
|
||||||
control={control}
|
|
||||||
errors={errors}
|
|
||||||
setValue={setValue}
|
|
||||||
register={register}
|
|
||||||
watch={watch}
|
|
||||||
unregister={unregister}
|
|
||||||
provider={provider}
|
|
||||||
secretConfigured={!!config?.settings.clientSecret}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</CollapsableSection>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Stack>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{providerFields.map((field) => {
|
|
||||||
return (
|
return (
|
||||||
<FieldRenderer
|
<CollapsableSection label={section.name} isOpen={index === 0} key={section.name}>
|
||||||
key={field}
|
{section.fields
|
||||||
field={field}
|
.filter((field) => (typeof field !== 'string' ? !field.hidden : true))
|
||||||
control={control}
|
.map((field) => {
|
||||||
errors={errors}
|
return (
|
||||||
setValue={setValue}
|
<FieldRenderer
|
||||||
register={register}
|
key={typeof field === 'string' ? field : field.name}
|
||||||
watch={watch}
|
field={field}
|
||||||
unregister={unregister}
|
control={control}
|
||||||
provider={provider}
|
errors={errors}
|
||||||
secretConfigured={!!config?.settings.clientSecret}
|
setValue={setValue}
|
||||||
/>
|
register={register}
|
||||||
|
watch={watch}
|
||||||
|
unregister={unregister}
|
||||||
|
provider={provider}
|
||||||
|
secretConfigured={!!config?.settings.clientSecret}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</CollapsableSection>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</>
|
</Stack>
|
||||||
)}
|
|
||||||
<Box display={'flex'} gap={2} marginTop={5}>
|
<Box display={'flex'} gap={2} marginTop={5}>
|
||||||
<Stack alignItems={'center'} gap={2}>
|
<Stack alignItems={'center'} gap={2}>
|
||||||
<Button
|
<Button
|
||||||
|
@ -9,24 +9,6 @@ import { FieldData, SSOProvider, SSOSettingsField } from './types';
|
|||||||
import { isSelectableValue } from './utils/guards';
|
import { isSelectableValue } from './utils/guards';
|
||||||
import { isUrlValid } from './utils/url';
|
import { isUrlValid } from './utils/url';
|
||||||
|
|
||||||
/** Map providers to their settings */
|
|
||||||
export const fields: Record<SSOProvider['provider'], Array<keyof SSOProvider['settings']>> = {
|
|
||||||
github: ['name', 'clientId', 'clientSecret', 'teamIds', 'allowedOrganizations'],
|
|
||||||
google: ['name', 'clientId', 'clientSecret', 'allowedDomains'],
|
|
||||||
gitlab: ['name', 'clientId', 'clientSecret', 'allowedOrganizations', 'teamIds'],
|
|
||||||
okta: [
|
|
||||||
'name',
|
|
||||||
'clientId',
|
|
||||||
'clientSecret',
|
|
||||||
'authUrl',
|
|
||||||
'tokenUrl',
|
|
||||||
'apiUrl',
|
|
||||||
'roleAttributePath',
|
|
||||||
'allowedGroups',
|
|
||||||
'allowedDomains',
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
type Section = Record<
|
type Section = Record<
|
||||||
SSOProvider['provider'],
|
SSOProvider['provider'],
|
||||||
Array<{
|
Array<{
|
||||||
@ -131,6 +113,113 @@ export const sectionFields: Section = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
google: [
|
||||||
|
{
|
||||||
|
name: 'General settings',
|
||||||
|
id: 'general',
|
||||||
|
fields: ['name', 'clientId', 'clientSecret', 'scopes', 'allowSignUp', 'autoLogin', 'signoutRedirectUrl'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'User mapping',
|
||||||
|
id: 'user',
|
||||||
|
fields: ['roleAttributePath', 'roleAttributeStrict', 'allowAssignGrafanaAdmin', 'skipOrgRoleSync'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Extra security measures',
|
||||||
|
id: 'extra',
|
||||||
|
fields: [
|
||||||
|
'validateHd',
|
||||||
|
'hostedDomain',
|
||||||
|
'allowedDomains',
|
||||||
|
'allowedGroups',
|
||||||
|
'usePkce',
|
||||||
|
'useRefreshToken',
|
||||||
|
'tlsSkipVerifyInsecure',
|
||||||
|
'tlsClientCert',
|
||||||
|
'tlsClientKey',
|
||||||
|
'tlsClientCa',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
github: [
|
||||||
|
{
|
||||||
|
name: 'General settings',
|
||||||
|
id: 'general',
|
||||||
|
fields: ['name', 'clientId', 'clientSecret', 'scopes', 'allowSignUp', 'autoLogin', 'signoutRedirectUrl'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'User mapping',
|
||||||
|
id: 'user',
|
||||||
|
fields: ['roleAttributePath', 'roleAttributeStrict', 'allowAssignGrafanaAdmin', 'skipOrgRoleSync'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Extra security measures',
|
||||||
|
id: 'extra',
|
||||||
|
fields: [
|
||||||
|
'allowedOrganizations',
|
||||||
|
'allowedDomains',
|
||||||
|
'teamIds',
|
||||||
|
'usePkce',
|
||||||
|
'useRefreshToken',
|
||||||
|
'tlsSkipVerifyInsecure',
|
||||||
|
'tlsClientCert',
|
||||||
|
'tlsClientKey',
|
||||||
|
'tlsClientCa',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
gitlab: [
|
||||||
|
{
|
||||||
|
name: 'General settings',
|
||||||
|
id: 'general',
|
||||||
|
fields: ['name', 'clientId', 'clientSecret', 'scopes', 'allowSignUp', 'autoLogin', 'signoutRedirectUrl'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'User mapping',
|
||||||
|
id: 'user',
|
||||||
|
fields: ['roleAttributePath', 'roleAttributeStrict', 'allowAssignGrafanaAdmin', 'skipOrgRoleSync'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Extra security measures',
|
||||||
|
id: 'extra',
|
||||||
|
fields: [
|
||||||
|
'allowedDomains',
|
||||||
|
'allowedGroups',
|
||||||
|
'usePkce',
|
||||||
|
'useRefreshToken',
|
||||||
|
'tlsSkipVerifyInsecure',
|
||||||
|
'tlsClientCert',
|
||||||
|
'tlsClientKey',
|
||||||
|
'tlsClientCa',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
okta: [
|
||||||
|
{
|
||||||
|
name: 'General settings',
|
||||||
|
id: 'general',
|
||||||
|
fields: ['name', 'clientId', 'clientSecret', 'scopes', 'authUrl', 'tokenUrl', 'apiUrl', 'signoutRedirectUrl'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'User mapping',
|
||||||
|
id: 'user',
|
||||||
|
fields: ['roleAttributePath', 'roleAttributeStrict', 'allowAssignGrafanaAdmin', 'skipOrgRoleSync'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Extra security measures',
|
||||||
|
id: 'extra',
|
||||||
|
fields: [
|
||||||
|
'allowedDomains',
|
||||||
|
'allowedGroups',
|
||||||
|
'usePkce',
|
||||||
|
'useRefreshToken',
|
||||||
|
'tlsSkipVerifyInsecure',
|
||||||
|
'tlsClientCert',
|
||||||
|
'tlsClientKey',
|
||||||
|
'tlsClientCa',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -485,6 +574,17 @@ export function fieldMap(provider: string): Record<string, FieldData> {
|
|||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
|
hostedDomain: {
|
||||||
|
label: 'Hosted domain',
|
||||||
|
description: 'The domain under which Grafana is hosted and accessible.',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
validateHd: {
|
||||||
|
label: 'Validate hosted domain',
|
||||||
|
description:
|
||||||
|
'If enabled, Grafana will match the Hosted Domain retrieved from the Google ID Token against the Allowed Domains list specified by the user.',
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +55,8 @@ export type SSOProviderSettingsBase = {
|
|||||||
tlsSkipVerifyInsecure?: boolean;
|
tlsSkipVerifyInsecure?: boolean;
|
||||||
// For Azure AD
|
// For Azure AD
|
||||||
forceUseGraphApi?: boolean;
|
forceUseGraphApi?: boolean;
|
||||||
|
// For Google
|
||||||
|
validateHd?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// SSO data received from the API and sent to it
|
// SSO data received from the API and sent to it
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { SelectableValue } from '@grafana/data';
|
import { SelectableValue } from '@grafana/data';
|
||||||
|
|
||||||
import { fieldMap, fields } from '../fields';
|
import { fieldMap, sectionFields } from '../fields';
|
||||||
import { FieldData, SSOProvider, SSOProviderDTO } from '../types';
|
import { FieldData, SSOProvider, SSOProviderDTO } from '../types';
|
||||||
|
|
||||||
import { isSelectableValue } from './guards';
|
import { isSelectableValue } from './guards';
|
||||||
@ -58,7 +58,8 @@ export function dataToDTO(data?: SSOProvider): SSOProviderDTO {
|
|||||||
if (!data) {
|
if (!data) {
|
||||||
return emptySettings;
|
return emptySettings;
|
||||||
}
|
}
|
||||||
const arrayFields = getArrayFields(fieldMap(data.provider));
|
const providerFields = getFieldsForProvider(data.provider);
|
||||||
|
const arrayFields = getArrayFields(fieldMap(data.provider), providerFields);
|
||||||
const settings = { ...data.settings };
|
const settings = { ...data.settings };
|
||||||
for (const field of arrayFields) {
|
for (const field of arrayFields) {
|
||||||
//@ts-expect-error
|
//@ts-expect-error
|
||||||
@ -72,30 +73,35 @@ const valuesToString = (values: Array<SelectableValue<string>>) => {
|
|||||||
return values.map(({ value }) => value).join(',');
|
return values.map(({ value }) => value).join(',');
|
||||||
};
|
};
|
||||||
|
|
||||||
const includeRequiredKeysOnly = (
|
const getFieldsForProvider = (provider: string) => {
|
||||||
obj: SSOProviderDTO,
|
const sections = sectionFields[provider];
|
||||||
requiredKeys: Array<keyof SSOProvider['settings']>
|
|
||||||
): Partial<SSOProviderDTO> => {
|
// include the enabled field because it is not part of the fields defined for providers
|
||||||
if (!requiredKeys) {
|
const fields = ['enabled'];
|
||||||
return obj;
|
|
||||||
}
|
return Object.values(sections).reduce(
|
||||||
let result: Partial<SSOProviderDTO> = {};
|
(result, section) => [
|
||||||
for (const key of requiredKeys) {
|
...result,
|
||||||
//@ts-expect-error
|
...section.fields.map((field) => (typeof field === 'string' ? field : field.name)),
|
||||||
result[key] = obj[key];
|
],
|
||||||
}
|
fields
|
||||||
return result;
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert the DTO to the data format used by the API
|
// Convert the DTO to the data format used by the API
|
||||||
export function dtoToData(dto: SSOProviderDTO, provider: string) {
|
export function dtoToData(dto: SSOProviderDTO, provider: string) {
|
||||||
const arrayFields = getArrayFields(fieldMap(provider));
|
|
||||||
let current: Partial<SSOProviderDTO> = dto;
|
let current: Partial<SSOProviderDTO> = dto;
|
||||||
|
|
||||||
if (fields[provider]) {
|
const providerFields = getFieldsForProvider(provider);
|
||||||
current = includeRequiredKeysOnly(dto, [...fields[provider], 'enabled']);
|
const arrayFields = getArrayFields(fieldMap(provider), providerFields);
|
||||||
}
|
|
||||||
const settings = { ...current };
|
// filter out the fields that are not defined on the provider
|
||||||
|
const settings: Partial<SSOProviderDTO> = Object.keys(current)
|
||||||
|
.filter((key) => providerFields.includes(key))
|
||||||
|
.reduce((obj, key) => {
|
||||||
|
//@ts-expect-error
|
||||||
|
return { ...obj, [key]: current[key] };
|
||||||
|
}, {});
|
||||||
|
|
||||||
for (const field of arrayFields) {
|
for (const field of arrayFields) {
|
||||||
const value = current[field];
|
const value = current[field];
|
||||||
@ -112,8 +118,8 @@ export function dtoToData(dto: SSOProviderDTO, provider: string) {
|
|||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getArrayFields(obj: Record<string, FieldData>): Array<keyof SSOProviderDTO> {
|
export function getArrayFields(obj: Record<string, FieldData>, providerFields: string[]): Array<keyof SSOProviderDTO> {
|
||||||
return Object.entries(obj)
|
return Object.entries(obj)
|
||||||
.filter(([_, value]) => value.type === 'select')
|
.filter(([key, value]) => providerFields.includes(key) && value.type === 'select')
|
||||||
.map(([key]) => key as keyof SSOProviderDTO);
|
.map(([key]) => key as keyof SSOProviderDTO);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user