Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions web/messages/en/openid.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@
"settings_openid_provider_delete_confirm_body": "Are you sure you want to delete this external identity provider? This action cannot be undone.",
"settings_openid_provider_delete_success": "External identity provider deleted",
"settings_openid_provider_delete_failed": "Failed to delete external identity provider",
"settings_openid_provider_validation_success_title": "External ID provider successfully added.",
"settings_openid_provider_validation_success_body": "The connection to the external identity provider has been successfully verified.",
"settings_openid_provider_validation_success_detail": "The connection to your external identity provider is now verified. Your users can now log in using this provider for a faster and more convenient authentication experience.",
"settings_openid_provider_validation_failure_title": "Connection test failed.",
"settings_openid_provider_validation_failure_body": "The provider was saved but the connection to the directory synchronization API could not be verified. Go back to fix the configuration, or finish to keep the provider without directory sync.",
"settings_openid_provider_validation_failure_error": "Error: {message}",
"openid_consent_title": "{name} would like to",
"openid_consent_scope_openid": "Use OpenID.",
"openid_consent_scope_profile": "Know basic information from your profile.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const AddExternalOpenIdDirectoryStep = () => {
const state = useAddExternalOpenIdStore.getState();
const providerState = state.providerState;
const provider = state.provider;
const submitValues = { ...cloneDeep(providerState), value, kind: provider };
const submitValues = { ...cloneDeep(providerState), ...value, kind: provider };
await mutateAsync(submitValues);
},
[mutateAsync],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,38 +37,34 @@ export const AddExternalOpenIdValidationStep = () => {
{result && (
<>
<AppText font={TextStyle.TTitleH4} color={ThemeVariable.FgSuccess}>
{'External ID provider successfully added.'}
{m.settings_openid_provider_validation_success_title()}
</AppText>
<SizedBox height={ThemeSpacing.Sm} />
<AppText font={TextStyle.TBodyPrimary400} color={ThemeVariable.FgNeutral}>
{
'The connection to the external identity provider has been successfully verified.'
}
{m.settings_openid_provider_validation_success_body()}
</AppText>
<Divider spacing={ThemeSpacing.Xl} />
<AppText font={TextStyle.TBodyPrimary400} color={ThemeVariable.FgNeutral}>
{`The connection to your external identity provider is now verified. Your users can now log in using this provider for a faster and more convenient authentication experience.`}
{m.settings_openid_provider_validation_success_detail()}
</AppText>
</>
)}
{!result && (
<>
<AppText font={TextStyle.TTitleH4} color={ThemeVariable.FgCritical}>
{'External ID provider successfully added.'}
{m.settings_openid_provider_validation_failure_title()}
</AppText>
<SizedBox height={ThemeSpacing.Sm} />
<AppText font={TextStyle.TBodyPrimary400} color={ThemeVariable.FgNeutral}>
{
'The connection to the external identity provider has been successfully verified.'
}
{m.settings_openid_provider_validation_failure_body()}
</AppText>
{isPresent(message) && (
<>
<SizedBox height={ThemeSpacing.Xl2} />
<InfoBanner
variant="warning"
icon={IconKind.WarningFilled}
text={`Error: ${message}`}
text={m.settings_openid_provider_validation_failure_error({ message })}
/>
</>
)}
Expand Down
2 changes: 2 additions & 0 deletions web/src/pages/CERulePage/CERulePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,7 @@ const Content = ({ rule: initialRule, tab }: Props) => {
<field.FormTextarea
label={m.acl_form_addresses_label()}
helper={m.acl_helper_addresses()}
notNull
/>
)}
</form.AppField>
Expand Down Expand Up @@ -856,6 +857,7 @@ const Content = ({ rule: initialRule, tab }: Props) => {
<field.FormInput
label={m.acl_form_ports_label()}
helper={m.acl_helper_ports()}
notNull
/>
)}
</form.AppField>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ export const SettingsEditOpenIdProviderPage = () => {

const { mutateAsync } = useMutation({
mutationFn: api.openIdProvider.editOpenIdProvider,
onSuccess: () => {
router.history.back();
},
meta: {
invalidate: [['settings'], ['info'], ['openid']],
},
Expand Down Expand Up @@ -68,10 +65,28 @@ export const SettingsEditOpenIdProviderPage = () => {
...formData,
directory_sync_group_match: joinCsv(formData.directory_sync_group_match),
};
await mutateAsync({ ...normalizedFormData, ...values });
const submitValues = { ...normalizedFormData, ...values };
await mutateAsync(submitValues);
if (values.directory_sync_enabled) {
try {
const { data: result } = await api.openIdProvider.testDirectorySync();
if (!result.success) {
await mutateAsync({ ...submitValues, directory_sync_enabled: false });
Snackbar.error(
result.message ?? m.settings_openid_provider_validation_failure_title(),
);
return;
}
} catch (_) {
await mutateAsync({ ...submitValues, directory_sync_enabled: false });
Snackbar.error(m.settings_openid_provider_validation_failure_title());
return;
}
}
router.history.back();
}
},
[formData, mutateAsync],
[formData, mutateAsync, router],
);

if (!formData) return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { EditPageControls } from '../../../../shared/components/EditPageControls
import { EditPageFormSection } from '../../../../shared/components/EditPageFormSection/EditPageFormSection';
import { Fold } from '../../../../shared/defguard-ui/components/Fold/Fold';
import { SizedBox } from '../../../../shared/defguard-ui/components/SizedBox/SizedBox';
import { Snackbar } from '../../../../shared/defguard-ui/providers/snackbar/snackbar';
import { ThemeSpacing } from '../../../../shared/defguard-ui/types';
import { useAppForm } from '../../../../shared/form';
import { formChangeLogic } from '../../../../shared/formLogic';
Expand Down Expand Up @@ -38,6 +39,31 @@ const discriminatedSchema = z.discriminatedUnion('directory_sync_enabled', [
syncSchema,
]);

const validationSchema = syncSchema
.omit({ admin_email: true, google_service_account_file: true })
.extend({
admin_email: z.string().trim(),
google_service_account_file: z.file(m.form_error_required()).nullable(),
})
.superRefine((val, ctx) => {
if (val.directory_sync_enabled) {
if (val.admin_email.trim().length === 0) {
ctx.addIssue({
path: ['admin_email'],
code: 'custom',
message: m.form_error_required(),
});
}
if (val.google_service_account_file === null) {
ctx.addIssue({
path: ['google_service_account_file'],
code: 'custom',
message: m.form_error_required(),
});
}
}
});

type FormFields = z.infer<typeof discriminatedSchema>;

export const EditGoogleProviderForm = ({
Expand Down Expand Up @@ -72,17 +98,21 @@ export const EditGoogleProviderForm = ({
defaultValues,
validationLogic: formChangeLogic,
validators: {
onSubmit: syncSchema,
onChange: syncSchema,
onSubmit: validationSchema,
onChange: validationSchema,
},
onSubmit: async ({ value }) => {
if (value.directory_sync_enabled) {
const inner = value as z.infer<typeof syncSchema>;
const file = await parseGoogleKeyFile(inner.google_service_account_file as File);
if (!file) {
Snackbar.error(m.form_error_file_contents());
return;
}
await onSubmit({
...omit(inner, ['google_service_account_file']),
google_service_account_email: file?.client_email,
google_service_account_key: file?.private_key,
google_service_account_email: file.client_email,
google_service_account_key: file.private_key,
});
} else {
await onSubmit(omit(value, ['google_service_account_file']));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ const discriminatedSchema = z.discriminatedUnion('directory_sync_enabled', [
syncSchema,
]);

const validationSchema = syncSchema
.omit({ jumpcloud_api_key: true })
.extend({ jumpcloud_api_key: z.string() })
.superRefine((val, ctx) => {
if (val.directory_sync_enabled && val.jumpcloud_api_key.trim().length === 0) {
ctx.addIssue({
path: ['jumpcloud_api_key'],
code: 'custom',
message: m.form_error_required(),
});
}
});

type FormFields = z.infer<typeof discriminatedSchema>;

export const EditJumpCloudProviderForm = ({
Expand Down Expand Up @@ -60,8 +73,8 @@ export const EditJumpCloudProviderForm = ({
defaultValues,
validationLogic: formChangeLogic,
validators: {
onSubmit: syncSchema,
onChange: syncSchema,
onSubmit: validationSchema,
onChange: validationSchema,
},
onSubmit: async ({ value }) => {
await onSubmit(value);
Expand Down Expand Up @@ -109,17 +122,6 @@ export const EditJumpCloudProviderForm = ({
)}
</form.AppField>
<SizedBox height={ThemeSpacing.Xl2} />
<form.AppField name="jumpcloud_api_key">
{(field) => (
<field.FormInput
type="password"
required
label={m.settings_openid_provider_label_jumpcloud_api_key()}
helper={m.settings_openid_provider_helper_jumpcloud_api_key()}
/>
)}
</form.AppField>
<SizedBox height={ThemeSpacing.Xl2} />
<form.AppField name="username_handling">
{(field) => (
<field.FormSelect
Expand Down Expand Up @@ -192,6 +194,17 @@ export const EditJumpCloudProviderForm = ({
/>
)}
</form.AppField>
<SizedBox height={ThemeSpacing.Xl2} />
<form.AppField name="jumpcloud_api_key">
{(field) => (
<field.FormInput
type="password"
required
label={m.settings_openid_provider_label_jumpcloud_api_key()}
helper={m.settings_openid_provider_helper_jumpcloud_api_key()}
/>
)}
</form.AppField>
</Fold>
)}
</form.Subscribe>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export const EditMicrosoftProviderForm = ({
/>
)}
</form.AppField>
<SizedBox height={ThemeSpacing.Xl2} />
<form.AppField name="microsoftTenantId">
{(field) => (
<field.FormInput
Expand Down
Loading