Compare commits
1 Commits
dependabot
...
aut-1180
Author | SHA1 | Date | |
---|---|---|---|
![]() |
db966eae2d |
@@ -0,0 +1,12 @@
|
||||
export async function up(knex) {
|
||||
await knex('config').insert({
|
||||
key: 'userManagement.preventUsersFromUpdatingTheirProfile',
|
||||
value: {
|
||||
data: false
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export async function down(knex) {
|
||||
await knex('config').where({ key: 'userManagement.preventUsersFromUpdatingTheirProfile' }).delete();
|
||||
};
|
@@ -7,6 +7,7 @@ import DialogContentText from '@mui/material/DialogContentText';
|
||||
import DialogTitle from '@mui/material/DialogTitle';
|
||||
import * as React from 'react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { AppPropType } from 'propTypes/propTypes';
|
||||
import AppAuthClientsDialog from 'components/AppAuthClientsDialog/index.ee';
|
||||
@@ -17,7 +18,6 @@ import useFormatMessage from 'hooks/useFormatMessage';
|
||||
import { generateExternalLink } from 'helpers/translationValues';
|
||||
import { Form } from './style';
|
||||
import useAppAuth from 'hooks/useAppAuth';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
function AddAppConnection(props) {
|
||||
const { application, connectionId, onClose } = props;
|
||||
|
@@ -12,6 +12,7 @@ import TextField from 'components/TextField';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
import useCreateAccessToken from 'hooks/useCreateAccessToken';
|
||||
import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar';
|
||||
import usePreventUsersFromUpdatingTheirProfile from 'hooks/usePreventUsersFromUpdatingTheirProfile';
|
||||
|
||||
function LoginForm() {
|
||||
const isCloud = useCloud();
|
||||
@@ -19,6 +20,7 @@ function LoginForm() {
|
||||
const formatMessage = useFormatMessage();
|
||||
const enqueueSnackbar = useEnqueueSnackbar();
|
||||
const authentication = useAuthentication();
|
||||
const preventUsersFromUpdatingTheirProfile = usePreventUsersFromUpdatingTheirProfile();
|
||||
const { mutateAsync: createAccessToken, isPending: loading } =
|
||||
useCreateAccessToken();
|
||||
|
||||
@@ -84,7 +86,7 @@ function LoginForm() {
|
||||
sx={{ mb: 1 }}
|
||||
/>
|
||||
|
||||
{isCloud && (
|
||||
{isCloud && !preventUsersFromUpdatingTheirProfile && (
|
||||
<Link
|
||||
component={RouterLink}
|
||||
to={URLS.FORGOT_PASSWORD}
|
||||
|
@@ -40,6 +40,10 @@ function Switch(props) {
|
||||
<FormControlLabel
|
||||
className={className}
|
||||
{...FormControlLabelProps}
|
||||
componentsProps={{
|
||||
typography: {
|
||||
display: 'flex',
|
||||
}}}
|
||||
control={
|
||||
<MuiSwitch
|
||||
{...switchProps}
|
||||
|
@@ -0,0 +1,13 @@
|
||||
import useAutomatischConfig from 'hooks/useAutomatischConfig';
|
||||
|
||||
export default function usePreventUsersFromUpdatingTheirProfile() {
|
||||
const { data, isSuccess } =
|
||||
useAutomatischConfig();
|
||||
const automatischConfig = data?.data;
|
||||
|
||||
const preventUsersFromUpdatingTheirProfile = isSuccess ? automatischConfig['userManagement.preventUsersFromUpdatingTheirProfile'] : false;
|
||||
|
||||
console.log('preventUsersFromUpdatingTheirProfile', preventUsersFromUpdatingTheirProfile, automatischConfig)
|
||||
|
||||
return preventUsersFromUpdatingTheirProfile;
|
||||
}
|
@@ -259,20 +259,26 @@
|
||||
"userInterfacePage.primaryLightColorFieldLabel": "Primary light color",
|
||||
"userInterfacePage.svgDataFieldLabel": "Logo SVG code",
|
||||
"userInterfacePage.submit": "Update",
|
||||
"authenticationPage.title": "Single Sign-On with SAML",
|
||||
"authenticationForm.active": "Active",
|
||||
"authenticationForm.name": "Name",
|
||||
"authenticationForm.certificate": "Certificate",
|
||||
"authenticationForm.signatureAlgorithm": "Signature algorithm",
|
||||
"authenticationForm.issuer": "Issuer",
|
||||
"authenticationForm.entryPoint": "Entry point",
|
||||
"authenticationForm.firstnameAttributeName": "Firstname attribute name",
|
||||
"authenticationForm.surnameAttributeName": "Surname attribute name",
|
||||
"authenticationForm.emailAttributeName": "Email attribute name",
|
||||
"authenticationForm.roleAttributeName": "Role attribute name",
|
||||
"authenticationForm.defaultRole": "Default role",
|
||||
"authenticationForm.successfullySaved": "The provider has been saved.",
|
||||
"authenticationForm.save": "Save",
|
||||
"authenticationPage.title": "Authentication",
|
||||
"authenticationConfig.title": "User management",
|
||||
"authenticationConfig.userManagementPreventUsersFromUpdatingTheirProfile": "Prevent users from updating their profile",
|
||||
"authenticationConfig.userManagementPreventUsersFromUpdatingTheirProfileTooltip": "This will prevent users from updating their full name, email and password. This is useful when you want to manage users from your own identity provider.",
|
||||
"authenticationConfig.save": "Save",
|
||||
"authenticationConfig.successfullySaved": "The configuration has been saved.",
|
||||
"samlAuthenticationPage.title": "Single Sign-On with SAML",
|
||||
"samlAuthenticationForm.active": "Active",
|
||||
"samlAuthenticationForm.name": "Name",
|
||||
"samlAuthenticationForm.certificate": "Certificate",
|
||||
"samlAuthenticationForm.signatureAlgorithm": "Signature algorithm",
|
||||
"samlAuthenticationForm.issuer": "Issuer",
|
||||
"samlAuthenticationForm.entryPoint": "Entry point",
|
||||
"samlAuthenticationForm.firstnameAttributeName": "Firstname attribute name",
|
||||
"samlAuthenticationForm.surnameAttributeName": "Surname attribute name",
|
||||
"samlAuthenticationForm.emailAttributeName": "Email attribute name",
|
||||
"samlAuthenticationForm.roleAttributeName": "Role attribute name",
|
||||
"samlAuthenticationForm.defaultRole": "Default role",
|
||||
"samlAuthenticationForm.successfullySaved": "The provider has been saved.",
|
||||
"samlAuthenticationForm.save": "Save",
|
||||
"roleMappingsForm.title": "Role mappings",
|
||||
"roleMappingsForm.remoteRoleName": "Remote role name",
|
||||
"roleMappingsForm.role": "Role",
|
||||
|
@@ -0,0 +1,98 @@
|
||||
import { useMutation } from '@apollo/client';
|
||||
import LoadingButton from '@mui/lab/LoadingButton';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Switch from 'components/Switch';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar';
|
||||
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
|
||||
|
||||
import Form from 'components/Form';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
import useAutomatischConfig from 'hooks/useAutomatischConfig';
|
||||
import { UPDATE_CONFIG } from 'graphql/mutations/update-config.ee';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
function AuthenticationConfig() {
|
||||
const formatMessage = useFormatMessage();
|
||||
const enqueueSnackbar = useEnqueueSnackbar();
|
||||
const queryClient = useQueryClient();
|
||||
const { data, isLoading: isAutomatischConfigLoading } =
|
||||
useAutomatischConfig();
|
||||
const automatischConfig = data?.data;
|
||||
|
||||
const [
|
||||
updateConfig,
|
||||
{ loading: updateConfigLoading },
|
||||
] = useMutation(UPDATE_CONFIG);
|
||||
|
||||
const handleSubmit = async (values) => {
|
||||
try {
|
||||
await updateConfig({
|
||||
variables: {
|
||||
input: {
|
||||
'userManagement.preventUsersFromUpdatingTheirProfile': values.userManagement.preventUsersFromUpdatingTheirProfile,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ['automatisch', 'config'],
|
||||
});
|
||||
|
||||
enqueueSnackbar(formatMessage('authenticationConfig.successfullySaved'), {
|
||||
variant: 'success',
|
||||
SnackbarProps: {
|
||||
'data-test': 'snackbar-update-role-mappings-success',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error('Failed while saving!');
|
||||
}
|
||||
};
|
||||
|
||||
if (isAutomatischConfigLoading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="h4">
|
||||
{formatMessage('authenticationConfig.title')}
|
||||
</Typography>
|
||||
|
||||
<Form defaultValues={automatischConfig} onSubmit={handleSubmit}>
|
||||
<Stack direction="column" spacing={2}>
|
||||
<Switch
|
||||
name="userManagement.preventUsersFromUpdatingTheirProfile"
|
||||
label={<>
|
||||
{formatMessage('authenticationConfig.userManagementPreventUsersFromUpdatingTheirProfile')}
|
||||
|
||||
<Tooltip
|
||||
title={formatMessage('authenticationConfig.userManagementPreventUsersFromUpdatingTheirProfileTooltip')}
|
||||
sx={{ ml: 1 }}
|
||||
>
|
||||
<InfoOutlinedIcon />
|
||||
</Tooltip>
|
||||
</>}
|
||||
/>
|
||||
|
||||
<LoadingButton
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
sx={{ boxShadow: 2 }}
|
||||
loading={updateConfigLoading}
|
||||
>
|
||||
{formatMessage('authenticationConfig.save')}
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
AuthenticationConfig.propTypes = {
|
||||
};
|
||||
|
||||
export default AuthenticationConfig;
|
@@ -1,7 +1,6 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import LoadingButton from '@mui/lab/LoadingButton';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar';
|
||||
@@ -85,7 +84,6 @@ function RoleMappings({ provider, providerLoading }) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Divider sx={{ pt: 2 }} />
|
||||
<Typography variant="h3">
|
||||
{formatMessage('roleMappingsForm.title')}
|
||||
</Typography>
|
||||
|
@@ -75,7 +75,7 @@ function SamlConfiguration({ provider, providerLoading }) {
|
||||
},
|
||||
});
|
||||
|
||||
enqueueSnackbar(formatMessage('authenticationForm.successfullySaved'), {
|
||||
enqueueSnackbar(formatMessage('samlAuthenticationForm.successfullySaved'), {
|
||||
variant: 'success',
|
||||
SnackbarProps: {
|
||||
'data-test': 'snackbar-save-saml-provider-success',
|
||||
@@ -98,18 +98,18 @@ function SamlConfiguration({ provider, providerLoading }) {
|
||||
<Stack direction="column" gap={2}>
|
||||
<Switch
|
||||
name="active"
|
||||
label={formatMessage('authenticationForm.active')}
|
||||
label={formatMessage('samlAuthenticationForm.active')}
|
||||
/>
|
||||
<TextField
|
||||
required={true}
|
||||
name="name"
|
||||
label={formatMessage('authenticationForm.name')}
|
||||
label={formatMessage('samlAuthenticationForm.name')}
|
||||
fullWidth
|
||||
/>
|
||||
<TextField
|
||||
required={true}
|
||||
name="certificate"
|
||||
label={formatMessage('authenticationForm.certificate')}
|
||||
label={formatMessage('samlAuthenticationForm.certificate')}
|
||||
fullWidth
|
||||
multiline
|
||||
/>
|
||||
@@ -126,44 +126,44 @@ function SamlConfiguration({ provider, providerLoading }) {
|
||||
renderInput={(params) => (
|
||||
<MuiTextField
|
||||
{...params}
|
||||
label={formatMessage('authenticationForm.signatureAlgorithm')}
|
||||
label={formatMessage('samlAuthenticationForm.signatureAlgorithm')}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<TextField
|
||||
required={true}
|
||||
name="issuer"
|
||||
label={formatMessage('authenticationForm.issuer')}
|
||||
label={formatMessage('samlAuthenticationForm.issuer')}
|
||||
fullWidth
|
||||
/>
|
||||
<TextField
|
||||
required={true}
|
||||
name="entryPoint"
|
||||
label={formatMessage('authenticationForm.entryPoint')}
|
||||
label={formatMessage('samlAuthenticationForm.entryPoint')}
|
||||
fullWidth
|
||||
/>
|
||||
<TextField
|
||||
required={true}
|
||||
name="firstnameAttributeName"
|
||||
label={formatMessage('authenticationForm.firstnameAttributeName')}
|
||||
label={formatMessage('samlAuthenticationForm.firstnameAttributeName')}
|
||||
fullWidth
|
||||
/>
|
||||
<TextField
|
||||
required={true}
|
||||
name="surnameAttributeName"
|
||||
label={formatMessage('authenticationForm.surnameAttributeName')}
|
||||
label={formatMessage('samlAuthenticationForm.surnameAttributeName')}
|
||||
fullWidth
|
||||
/>
|
||||
<TextField
|
||||
required={true}
|
||||
name="emailAttributeName"
|
||||
label={formatMessage('authenticationForm.emailAttributeName')}
|
||||
label={formatMessage('samlAuthenticationForm.emailAttributeName')}
|
||||
fullWidth
|
||||
/>
|
||||
<TextField
|
||||
required={true}
|
||||
name="roleAttributeName"
|
||||
label={formatMessage('authenticationForm.roleAttributeName')}
|
||||
label={formatMessage('samlAuthenticationForm.roleAttributeName')}
|
||||
fullWidth
|
||||
/>
|
||||
<ControlledAutocomplete
|
||||
@@ -175,7 +175,7 @@ function SamlConfiguration({ provider, providerLoading }) {
|
||||
renderInput={(params) => (
|
||||
<MuiTextField
|
||||
{...params}
|
||||
label={formatMessage('authenticationForm.defaultRole')}
|
||||
label={formatMessage('samlAuthenticationForm.defaultRole')}
|
||||
/>
|
||||
)}
|
||||
loading={isRolesLoading}
|
||||
@@ -187,7 +187,7 @@ function SamlConfiguration({ provider, providerLoading }) {
|
||||
sx={{ boxShadow: 2 }}
|
||||
loading={loading}
|
||||
>
|
||||
{formatMessage('authenticationForm.save')}
|
||||
{formatMessage('samlAuthenticationForm.save')}
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
</Form>
|
||||
|
@@ -2,11 +2,14 @@ import Grid from '@mui/material/Grid';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import PageTitle from 'components/PageTitle';
|
||||
import Container from 'components/Container';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
import useSamlAuthProvider from 'hooks/useSamlAuthProvider';
|
||||
import AuthenticationConfig from './AuthenticationConfig';
|
||||
import SamlConfiguration from './SamlConfiguration';
|
||||
import RoleMappings from './RoleMappings';
|
||||
import useAdminSamlAuthProviders from 'hooks/useAdminSamlAuthProviders.ee';
|
||||
|
||||
function AuthenticationPage() {
|
||||
const formatMessage = useFormatMessage();
|
||||
|
||||
@@ -16,20 +19,37 @@ function AuthenticationPage() {
|
||||
const { data, isLoading: isProviderLoading } = useSamlAuthProvider({
|
||||
samlAuthProviderId,
|
||||
});
|
||||
|
||||
const provider = data?.data;
|
||||
|
||||
return (
|
||||
<Container sx={{ py: 3, display: 'flex', justifyContent: 'center' }}>
|
||||
<Grid container item xs={12} sm={10} md={9}>
|
||||
<Grid container item xs={12} sx={{ mb: [2, 5] }}>
|
||||
<Grid container item xs={12}>
|
||||
<PageTitle>{formatMessage('authenticationPage.title')}</PageTitle>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} sx={{ pt: 5, pb: 5 }}>
|
||||
<Stack spacing={5}>
|
||||
<AuthenticationConfig />
|
||||
|
||||
<Divider />
|
||||
</Stack>
|
||||
</Grid>
|
||||
|
||||
<Grid container item xs={12}>
|
||||
<PageTitle variant="h4">{formatMessage('samlAuthenticationPage.title')}</PageTitle>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} sx={{ pt: 5, pb: 5 }}>
|
||||
<Stack spacing={5}>
|
||||
<SamlConfiguration
|
||||
provider={provider}
|
||||
providerLoading={isProviderLoading}
|
||||
/>
|
||||
|
||||
<Divider />
|
||||
|
||||
<RoleMappings
|
||||
provider={provider}
|
||||
providerLoading={isProviderLoading}
|
||||
|
@@ -10,6 +10,7 @@ export default function Login() {
|
||||
<Container maxWidth="sm">
|
||||
<Stack direction="column" gap={2}>
|
||||
<LoginForm />
|
||||
|
||||
<SsoProviders />
|
||||
</Stack>
|
||||
</Container>
|
||||
|
@@ -29,12 +29,14 @@ import adminSettingsRoutes from './adminSettingsRoutes';
|
||||
import Notifications from 'pages/Notifications';
|
||||
import useAutomatischConfig from 'hooks/useAutomatischConfig';
|
||||
import useAuthentication from 'hooks/useAuthentication';
|
||||
import usePreventUsersFromUpdatingTheirProfile from 'hooks/usePreventUsersFromUpdatingTheirProfile';
|
||||
import useAutomatischInfo from 'hooks/useAutomatischInfo';
|
||||
import Installation from 'pages/Installation';
|
||||
|
||||
function Routes() {
|
||||
const { data: automatischInfo, isSuccess } = useAutomatischInfo();
|
||||
const { data: configData } = useAutomatischConfig();
|
||||
const preventUsersFromUpdatingTheirProfile = usePreventUsersFromUpdatingTheirProfile();
|
||||
const { isAuthenticated } = useAuthentication();
|
||||
const config = configData?.data;
|
||||
|
||||
@@ -134,14 +136,14 @@ function Routes() {
|
||||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
{preventUsersFromUpdatingTheirProfile === false && <Route
|
||||
path={URLS.FORGOT_PASSWORD}
|
||||
element={
|
||||
<PublicLayout>
|
||||
<ForgotPassword />
|
||||
</PublicLayout>
|
||||
}
|
||||
/>
|
||||
/>}
|
||||
|
||||
<Route
|
||||
path={URLS.RESET_PASSWORD}
|
||||
|
@@ -95,11 +95,11 @@ export const defaultTheme = createTheme({
|
||||
},
|
||||
},
|
||||
h4: {
|
||||
fontSize: referenceTheme.typography.pxToRem(32),
|
||||
fontSize: referenceTheme.typography.pxToRem(28),
|
||||
lineHeight: 1.3,
|
||||
fontWeight: 700,
|
||||
[referenceTheme.breakpoints.down('sm')]: {
|
||||
fontSize: referenceTheme.typography.pxToRem(16),
|
||||
fontSize: referenceTheme.typography.pxToRem(22),
|
||||
},
|
||||
},
|
||||
h5: {
|
||||
|
Reference in New Issue
Block a user