mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-25 00:07:47 +01:00
feat: Add group sync settings to front end (#2183)
* feat: Add group sync settings to front end Co-authored-by: Nuno Góis <github@nunogois.com>
This commit is contained in:
parent
62eac864f3
commit
33c084dd0f
@ -17,12 +17,16 @@ import useAuthSettings from 'hooks/api/getters/useAuthSettings/useAuthSettings';
|
|||||||
import useToast from 'hooks/useToast';
|
import useToast from 'hooks/useToast';
|
||||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||||
import { removeEmptyStringFields } from 'utils/removeEmptyStringFields';
|
import { removeEmptyStringFields } from 'utils/removeEmptyStringFields';
|
||||||
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import { SsoGroupSettings } from '../SsoGroupSettings';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
enableSingleSignOut: false,
|
enableSingleSignOut: false,
|
||||||
|
enableGroupSyncing: false,
|
||||||
autoCreate: false,
|
autoCreate: false,
|
||||||
unleashHostname: location.hostname,
|
unleashHostname: location.hostname,
|
||||||
|
groupJsonPath: '',
|
||||||
clientId: '',
|
clientId: '',
|
||||||
discoverUrl: '',
|
discoverUrl: '',
|
||||||
secret: '',
|
secret: '',
|
||||||
@ -36,6 +40,7 @@ export const OidcAuth = () => {
|
|||||||
const { hasAccess } = useContext(AccessContext);
|
const { hasAccess } = useContext(AccessContext);
|
||||||
const { config } = useAuthSettings('oidc');
|
const { config } = useAuthSettings('oidc');
|
||||||
const { updateSettings, errors, loading } = useAuthSettingsApi('oidc');
|
const { updateSettings, errors, loading } = useAuthSettingsApi('oidc');
|
||||||
|
const ssoSyncShown = Boolean(uiConfig.flags.syncSSOGroups);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (config.discoverUrl) {
|
if (config.discoverUrl) {
|
||||||
@ -235,7 +240,16 @@ export const OidcAuth = () => {
|
|||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={ssoSyncShown}
|
||||||
|
show={
|
||||||
|
<SsoGroupSettings
|
||||||
|
ssoType="OIDC"
|
||||||
|
data={data}
|
||||||
|
setValue={setValue}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<AutoCreateForm data={data} setValue={setValue} />
|
<AutoCreateForm data={data} setValue={setValue} />
|
||||||
|
|
||||||
<Grid container spacing={3}>
|
<Grid container spacing={3}>
|
||||||
|
@ -17,16 +17,20 @@ import useAuthSettings from 'hooks/api/getters/useAuthSettings/useAuthSettings';
|
|||||||
import useAuthSettingsApi from 'hooks/api/actions/useAuthSettingsApi/useAuthSettingsApi';
|
import useAuthSettingsApi from 'hooks/api/actions/useAuthSettingsApi/useAuthSettingsApi';
|
||||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||||
import { removeEmptyStringFields } from 'utils/removeEmptyStringFields';
|
import { removeEmptyStringFields } from 'utils/removeEmptyStringFields';
|
||||||
|
import { SsoGroupSettings } from '../SsoGroupSettings';
|
||||||
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
autoCreate: false,
|
autoCreate: false,
|
||||||
|
enableGroupSyncing: false,
|
||||||
unleashHostname: location.hostname,
|
unleashHostname: location.hostname,
|
||||||
entityId: '',
|
entityId: '',
|
||||||
signOnUrl: '',
|
signOnUrl: '',
|
||||||
certificate: '',
|
certificate: '',
|
||||||
signOutUrl: '',
|
signOutUrl: '',
|
||||||
spCertificate: '',
|
spCertificate: '',
|
||||||
|
groupJsonPath: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SamlAuth = () => {
|
export const SamlAuth = () => {
|
||||||
@ -36,6 +40,7 @@ export const SamlAuth = () => {
|
|||||||
const { hasAccess } = useContext(AccessContext);
|
const { hasAccess } = useContext(AccessContext);
|
||||||
const { config } = useAuthSettings('saml');
|
const { config } = useAuthSettings('saml');
|
||||||
const { updateSettings, errors, loading } = useAuthSettingsApi('saml');
|
const { updateSettings, errors, loading } = useAuthSettingsApi('saml');
|
||||||
|
const ssoSyncShown = Boolean(uiConfig.flags.syncSSOGroups);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (config.entityId) {
|
if (config.entityId) {
|
||||||
@ -246,6 +251,17 @@ export const SamlAuth = () => {
|
|||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={ssoSyncShown}
|
||||||
|
show={
|
||||||
|
<SsoGroupSettings
|
||||||
|
ssoType="SAML"
|
||||||
|
data={data}
|
||||||
|
setValue={setValue}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<AutoCreateForm data={data} setValue={setValue} />
|
<AutoCreateForm data={data} setValue={setValue} />
|
||||||
<Grid container spacing={3}>
|
<Grid container spacing={3}>
|
||||||
<Grid item md={5}>
|
<Grid item md={5}>
|
||||||
|
81
frontend/src/component/admin/auth/SsoGroupSettings.tsx
Normal file
81
frontend/src/component/admin/auth/SsoGroupSettings.tsx
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import { FormControlLabel, Grid, Switch, TextField } from '@mui/material';
|
||||||
|
|
||||||
|
interface SsoGroupSettingsProps {
|
||||||
|
ssoType: 'OIDC' | 'SAML';
|
||||||
|
data?: {
|
||||||
|
enabled: boolean;
|
||||||
|
enableGroupSyncing: boolean;
|
||||||
|
groupJsonPath: string;
|
||||||
|
};
|
||||||
|
setValue: (name: string, value: string | boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SsoGroupSettings = ({
|
||||||
|
ssoType,
|
||||||
|
data = {
|
||||||
|
enabled: false,
|
||||||
|
enableGroupSyncing: false,
|
||||||
|
groupJsonPath: '',
|
||||||
|
},
|
||||||
|
setValue,
|
||||||
|
}: SsoGroupSettingsProps) => {
|
||||||
|
const updateGroupSyncing = () => {
|
||||||
|
setValue('enableGroupSyncing', !data.enableGroupSyncing);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateField = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setValue(event.target.name, event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Grid container spacing={3} mb={2}>
|
||||||
|
<Grid item md={5}>
|
||||||
|
<strong>Enable Group Syncing</strong>
|
||||||
|
<p>
|
||||||
|
Enables automatically syncing of users from the{' '}
|
||||||
|
{ssoType}
|
||||||
|
provider when a user logs in.
|
||||||
|
</p>
|
||||||
|
</Grid>
|
||||||
|
<Grid item md={6} style={{ padding: '20px' }}>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
onChange={updateGroupSyncing}
|
||||||
|
value={data.enableGroupSyncing}
|
||||||
|
name="enableGroupSyncing"
|
||||||
|
checked={data.enableGroupSyncing}
|
||||||
|
disabled={!data.enabled}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={data.enableGroupSyncing ? 'Enabled' : 'Disabled'}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid container spacing={3} mb={2}>
|
||||||
|
<Grid item md={5}>
|
||||||
|
<strong>Group Field JSON Path</strong>
|
||||||
|
<p>
|
||||||
|
Specifies the path in the {ssoType} token response from
|
||||||
|
which to read the groups the user belongs to.
|
||||||
|
</p>
|
||||||
|
</Grid>
|
||||||
|
<Grid item md={6}>
|
||||||
|
<TextField
|
||||||
|
onChange={updateField}
|
||||||
|
label="Group JSON Path"
|
||||||
|
name="groupJsonPath"
|
||||||
|
value={data.groupJsonPath}
|
||||||
|
disabled={!data.enableGroupSyncing}
|
||||||
|
style={{ width: '400px' }}
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -42,6 +42,7 @@ export interface IFlags {
|
|||||||
embedProxyFrontend?: boolean;
|
embedProxyFrontend?: boolean;
|
||||||
publicSignup?: boolean;
|
publicSignup?: boolean;
|
||||||
personalAccessTokens?: boolean;
|
personalAccessTokens?: boolean;
|
||||||
|
syncSSOGroups?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IVersionInfo {
|
export interface IVersionInfo {
|
||||||
|
@ -74,6 +74,7 @@ exports[`should create default config 1`] = `
|
|||||||
"personalAccessTokens": false,
|
"personalAccessTokens": false,
|
||||||
"publicSignup": false,
|
"publicSignup": false,
|
||||||
"responseTimeWithAppName": false,
|
"responseTimeWithAppName": false,
|
||||||
|
"syncSSOGroups": false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"flagResolver": FlagResolver {
|
"flagResolver": FlagResolver {
|
||||||
@ -86,6 +87,7 @@ exports[`should create default config 1`] = `
|
|||||||
"personalAccessTokens": false,
|
"personalAccessTokens": false,
|
||||||
"publicSignup": false,
|
"publicSignup": false,
|
||||||
"responseTimeWithAppName": false,
|
"responseTimeWithAppName": false,
|
||||||
|
"syncSSOGroups": false,
|
||||||
},
|
},
|
||||||
"externalResolver": {
|
"externalResolver": {
|
||||||
"isEnabled": [Function],
|
"isEnabled": [Function],
|
||||||
|
@ -14,6 +14,10 @@ export const defaultExperimentalOptions = {
|
|||||||
process.env.UNLEASH_EXPERIMENTAL_PERSONAL_ACCESS_TOKENS,
|
process.env.UNLEASH_EXPERIMENTAL_PERSONAL_ACCESS_TOKENS,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
|
syncSSOGroups: parseEnvVarBoolean(
|
||||||
|
process.env.UNLEASH_EXPERIMENTAL_SYNC_SSO_GROUPS,
|
||||||
|
false,
|
||||||
|
),
|
||||||
embedProxyFrontend: parseEnvVarBoolean(
|
embedProxyFrontend: parseEnvVarBoolean(
|
||||||
process.env.UNLEASH_EXPERIMENTAL_EMBED_PROXY_FRONTEND,
|
process.env.UNLEASH_EXPERIMENTAL_EMBED_PROXY_FRONTEND,
|
||||||
false,
|
false,
|
||||||
@ -43,6 +47,7 @@ export interface IExperimentalOptions {
|
|||||||
batchMetrics?: boolean;
|
batchMetrics?: boolean;
|
||||||
anonymiseEventLog?: boolean;
|
anonymiseEventLog?: boolean;
|
||||||
personalAccessTokens?: boolean;
|
personalAccessTokens?: boolean;
|
||||||
|
syncSSOGroups?: boolean;
|
||||||
};
|
};
|
||||||
externalResolver: IExternalFlagResolver;
|
externalResolver: IExternalFlagResolver;
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ process.nextTick(async () => {
|
|||||||
anonymiseEventLog: false,
|
anonymiseEventLog: false,
|
||||||
responseTimeWithAppName: true,
|
responseTimeWithAppName: true,
|
||||||
personalAccessTokens: true,
|
personalAccessTokens: true,
|
||||||
|
syncSSOGroups: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
authentication: {
|
authentication: {
|
||||||
|
@ -28,6 +28,7 @@ export function createTestConfig(config?: IUnleashOptions): IUnleashConfig {
|
|||||||
embedProxyFrontend: true,
|
embedProxyFrontend: true,
|
||||||
batchMetrics: true,
|
batchMetrics: true,
|
||||||
personalAccessTokens: true,
|
personalAccessTokens: true,
|
||||||
|
syncSSOGroups: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user