feat(m365): integrate M365 credentials form and update provider handling

This commit is contained in:
alejandrobailo committed 2025-10-16 17:25:17 +02:00
1 parent 40e959cd2f
commit 6ea9d006c4
4 files changed
+44 -119

No files matched your search

@@ -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 <SelectViaGCP initialVia={via} />;
if (providerType === "github")
return <SelectViaGitHub initialVia={via} />;
if (providerType === "m365") return <SelectViaM365 initialVia={via} />;
return null;
case "credentials":
@@ -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<M365Credentials>;
}) => {
return (
<>
<div className="flex flex-col">
<div className="text-md text-default-foreground leading-9 font-bold">
Connect via Credentials
</div>
<div className="text-default-500 text-sm">
Please provide the information for your Microsoft 365 credentials.
</div>
</div>
<CustomInput
control={control}
name="client_id"
type="text"
label="Client ID"
labelPlacement="inside"
placeholder="Enter the Client ID"
variant="bordered"
isRequired
isInvalid={!!control._formState.errors.client_id}
/>
<CustomInput
control={control}
name="client_secret"
type="password"
label="Client Secret"
labelPlacement="inside"
placeholder="Enter the Client Secret"
variant="bordered"
isRequired
isInvalid={!!control._formState.errors.client_secret}
/>
<CustomInput
control={control}
name="tenant_id"
type="text"
label="Tenant ID"
labelPlacement="inside"
placeholder="Enter the Tenant ID"
variant="bordered"
isRequired
isInvalid={!!control._formState.errors.tenant_id}
/>
<p className="text-default-500 text-sm">
{" "}
User and password authentication is being deprecated due to
Microsoft&apos;s on-going MFA enforcement across all tenants (see{" "}
<CustomLink
href="https://azure.microsoft.com/en-us/blog/announcing-mandatory-multi-factor-authentication-for-azure-sign-in/"
size="sm"
>
Microsoft docs
</CustomLink>
).
</p>
<div className="border-system-warning bg-system-warning-medium dark:text-default-300 flex items-center rounded-lg border p-2 text-sm">
<InfoIcon className="mr-2 inline h-4 w-4 shrink-0" />
<p className="text-xs font-extrabold">
By October 2025, MFA will be mandatory.
</p>
</div>
<p className="text-default-500 text-sm">
Due to that change, you must only{" "}
<CustomLink
href="https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/microsoft365/getting-started-m365/#step-3-configure-your-m365-account"
size="sm"
>
use application authentication
</CustomLink>{" "}
to maintain all Prowler M365 scan capabilities.
</p>
<CustomInput
control={control}
name="user"
type="text"
label="User"
labelPlacement="inside"
placeholder="Enter the User"
variant="bordered"
isRequired={false}
isInvalid={!!control._formState.errors.user}
/>
<CustomInput
control={control}
name="password"
type="password"
label="Password"
labelPlacement="inside"
placeholder="Enter the Password"
variant="bordered"
isRequired={false}
isInvalid={!!control._formState.errors.password}
/>
</>
);
};
+30 -7
View File
@@ -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,
+12 -3
View File
@@ -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;