diff --git a/ui/app/(prowler)/providers/(set-up-provider)/add-credentials/page.tsx b/ui/app/(prowler)/providers/(set-up-provider)/add-credentials/page.tsx index 1c039886b9..3490cdb792 100644 --- a/ui/app/(prowler)/providers/(set-up-provider)/add-credentials/page.tsx +++ b/ui/app/(prowler)/providers/(set-up-provider)/add-credentials/page.tsx @@ -10,6 +10,7 @@ import { SelectViaGCP, } from "@/components/providers/workflow/forms/select-credentials-type/gcp"; import { SelectViaGitHub } from "@/components/providers/workflow/forms/select-credentials-type/github"; +import { SelectViaM365 } from "@/components/providers/workflow/forms/select-credentials-type/m365"; import { getProviderFormType } from "@/lib/provider-helpers"; import { ProviderType } from "@/types/providers"; @@ -28,6 +29,7 @@ export default async function AddCredentialsPage({ searchParams }: Props) { if (providerType === "gcp") return ; if (providerType === "github") return ; + if (providerType === "m365") return ; return null; case "credentials": diff --git a/ui/components/providers/workflow/forms/via-credentials/m365-credentials-form.tsx b/ui/components/providers/workflow/forms/via-credentials/m365-credentials-form.tsx deleted file mode 100644 index 1659a503e8..0000000000 --- a/ui/components/providers/workflow/forms/via-credentials/m365-credentials-form.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { Control } from "react-hook-form"; - -import { InfoIcon } from "@/components/icons"; -import { CustomInput } from "@/components/ui/custom"; -import { CustomLink } from "@/components/ui/custom/custom-link"; -import { M365Credentials } from "@/types"; - -export const M365CredentialsForm = ({ - control, -}: { - control: Control; -}) => { - return ( - <> -
-
- Connect via Credentials -
-
- Please provide the information for your Microsoft 365 credentials. -
-
- - - -

- {" "} - User and password authentication is being deprecated due to - Microsoft's on-going MFA enforcement across all tenants (see{" "} - - Microsoft docs - - ). -

- -
- -

- By October 2025, MFA will be mandatory. -

-
-

- Due to that change, you must only{" "} - - use application authentication - {" "} - to maintain all Prowler M365 scan capabilities. -

- - - - ); -}; diff --git a/ui/hooks/use-credentials-form.ts b/ui/hooks/use-credentials-form.ts index 268d714d71..2690b9307a 100644 --- a/ui/hooks/use-credentials-form.ts +++ b/ui/hooks/use-credentials-form.ts @@ -40,8 +40,8 @@ export const useCredentialsForm = ({ if (providerType === "gcp" && via === "service-account") { return addCredentialsServiceAccountFormSchema(providerType); } - // For GitHub, we need to pass the via parameter to determine which fields are required - if (providerType === "github") { + // For GitHub and M365, we need to pass the via parameter to determine which fields are required + if (providerType === "github" || providerType === "m365") { return addCredentialsFormSchema(providerType, via); } return addCredentialsFormSchema(providerType); @@ -99,13 +99,27 @@ export const useCredentialsForm = ({ [ProviderCredentialFields.TENANT_ID]: "", }; case "m365": + // M365 credentials based on via parameter + if (via === "app_client_secret") { + return { + ...baseDefaults, + [ProviderCredentialFields.CLIENT_ID]: "", + [ProviderCredentialFields.CLIENT_SECRET]: "", + [ProviderCredentialFields.TENANT_ID]: "", + }; + } + if (via === "app_certificate") { + return { + ...baseDefaults, + [ProviderCredentialFields.CLIENT_ID]: "", + [ProviderCredentialFields.CERTIFICATE_CONTENT]: "", + [ProviderCredentialFields.TENANT_ID]: "", + }; + } return { ...baseDefaults, [ProviderCredentialFields.CLIENT_ID]: "", - [ProviderCredentialFields.CLIENT_SECRET]: "", [ProviderCredentialFields.TENANT_ID]: "", - [ProviderCredentialFields.USER]: "", - [ProviderCredentialFields.PASSWORD]: "", }; case "gcp": return { @@ -146,9 +160,14 @@ export const useCredentialsForm = ({ } }; + const defaultValues = getDefaultValues(); + const form = useForm({ resolver: zodResolver(formSchema), - defaultValues: getDefaultValues(), + defaultValues: defaultValues, + mode: "onSubmit", + reValidateMode: "onChange", + criteriaMode: "all", // Show all errors for each field }); const { handleServerResponse } = useFormServerErrors( @@ -169,6 +188,7 @@ export const useCredentialsForm = ({ // Filter out empty values first, then append all remaining values const filteredValues = filterEmptyValues(values); + Object.entries(filteredValues).forEach(([key, value]) => { formData.append(key, value); }); @@ -181,9 +201,12 @@ export const useCredentialsForm = ({ } }; + const { isSubmitting, errors } = form.formState; + return { form, - isLoading: form.formState.isSubmitting, + isLoading: isSubmitting, + errors, handleSubmit, handleBackStep, searchParamsObj, diff --git a/ui/types/components.ts b/ui/types/components.ts index 98197ea17b..c02440c2ae 100644 --- a/ui/types/components.ts +++ b/ui/types/components.ts @@ -213,15 +213,24 @@ export type AzureCredentials = { [ProviderCredentialFields.PROVIDER_ID]: string; }; -export type M365Credentials = { +export type M365ClientSecretCredentials = { [ProviderCredentialFields.CLIENT_ID]: string; [ProviderCredentialFields.CLIENT_SECRET]: string; [ProviderCredentialFields.TENANT_ID]: string; - [ProviderCredentialFields.USER]?: string; - [ProviderCredentialFields.PASSWORD]?: string; [ProviderCredentialFields.PROVIDER_ID]: string; }; +export type M365CertificateCredentials = { + [ProviderCredentialFields.CLIENT_ID]: string; + [ProviderCredentialFields.CERTIFICATE_CONTENT]: string; + [ProviderCredentialFields.TENANT_ID]: string; + [ProviderCredentialFields.PROVIDER_ID]: string; +}; + +export type M365Credentials = + | M365ClientSecretCredentials + | M365CertificateCredentials; + export type GCPDefaultCredentials = { client_id: string; client_secret: string;