mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-17 17:41:50 +00:00
feat(m365): add the new provider m365 - UI part (#7591)
This commit is contained in:
@@ -186,6 +186,15 @@ export const addCredentialsProvider = async (formData: FormData) => {
|
||||
client_secret: formData.get("client_secret"),
|
||||
tenant_id: formData.get("tenant_id"),
|
||||
};
|
||||
} else if (providerType === "m365") {
|
||||
// Static credentials configuration for M365
|
||||
secret = {
|
||||
client_id: formData.get("client_id"),
|
||||
client_secret: formData.get("client_secret"),
|
||||
tenant_id: formData.get("tenant_id"),
|
||||
user: formData.get("user"),
|
||||
encrypted_password: formData.get("encrypted_password"),
|
||||
};
|
||||
} else if (providerType === "gcp") {
|
||||
// Static credentials configuration for GCP
|
||||
secret = {
|
||||
@@ -280,6 +289,15 @@ export const updateCredentialsProvider = async (
|
||||
client_secret: formData.get("client_secret"),
|
||||
tenant_id: formData.get("tenant_id"),
|
||||
};
|
||||
} else if (providerType === "m365") {
|
||||
// Static credentials configuration for M365
|
||||
secret = {
|
||||
client_id: formData.get("client_id"),
|
||||
client_secret: formData.get("client_secret"),
|
||||
tenant_id: formData.get("tenant_id"),
|
||||
user: formData.get("user"),
|
||||
encrypted_password: formData.get("encrypted_password"),
|
||||
};
|
||||
} else if (providerType === "gcp") {
|
||||
// Static credentials configuration for GCP
|
||||
secret = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from "./AWSProviderBadge";
|
||||
export * from "./AzureProviderBadge";
|
||||
export * from "./GCPProviderBadge";
|
||||
export * from "./KS8ProviderBadge";
|
||||
export * from "./aws-provider-badge";
|
||||
export * from "./azure-provider-badge";
|
||||
export * from "./gcp-provider-badge";
|
||||
export * from "./ks8-provider-badge";
|
||||
export * from "./m365-provider-badge";
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { IconSvgProps } from "@/types";
|
||||
|
||||
export const M365ProviderBadge: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height || 64}
|
||||
role="presentation"
|
||||
viewBox="0 0 256 256"
|
||||
width={size || width || 64}
|
||||
{...props}
|
||||
>
|
||||
<g>
|
||||
<rect width="256" height="256" rx="60" fill="#f4f2ed" />
|
||||
<g transform="scale(3.5) translate(2 2)">
|
||||
<g clipPath="url(#clip0)">
|
||||
<g clipPath="url(#clip1)">
|
||||
<path
|
||||
d="M53.1574 10.3146C52.1706 7.19669 49.2773 5.07764 46.007 5.07764L43.5352 5.07764C39.9228 5.07764 36.8237 7.65268 36.1621 11.2039L32.4891 30.9179L33.5912 27.2788C34.5491 24.1158 37.4644 21.9526 40.7692 21.9526H52.2499L58.8326 24.2562L62.3337 21.9644C59.0634 21.9644 56.1701 19.8336 55.1833 16.7157L53.1574 10.3146Z"
|
||||
fill="url(#paint0_radial)"
|
||||
/>
|
||||
<path
|
||||
d="M20.615 62.8082C21.5914 65.9426 24.4927 68.0777 27.7757 68.0777H32.6415C36.7421 68.0777 40.0824 64.7845 40.1408 60.6844L40.3984 42.5737L39.4114 45.86C38.459 49.0313 35.5396 51.2027 32.2284 51.2027H20.75L14.8141 48.4965L11.4807 51.2027C14.7636 51.2027 17.665 53.3378 18.6414 56.4722L20.615 62.8082Z"
|
||||
fill="url(#paint1_radial)"
|
||||
/>
|
||||
<path
|
||||
d="M45.5 5.07764H19.25C11.75 5.07764 7.25001 14.7496 4.25002 24.4216C0.695797 35.8804 -3.95498 51.2056 9.50001 51.2056H20.931C24.2656 51.2056 27.1975 49.0121 28.135 45.812C30.1073 39.0797 33.5545 27.3661 36.2631 18.446C37.6417 13.906 38.79 10.007 40.5523 7.57888C41.5404 6.21761 43.1871 5.07764 45.5 5.07764Z"
|
||||
fill="url(#paint2_linear)"
|
||||
/>
|
||||
<path
|
||||
d="M27.4946 68.0776H53.7446C61.2446 68.0776 65.7446 58.4071 68.7446 48.7365C72.2988 37.2794 76.9496 21.9565 63.4946 21.9565H52.0633C48.7288 21.9565 45.797 24.1499 44.8594 27.3499C42.8871 34.0812 39.44 45.7927 36.7314 54.7113C35.3529 59.2506 34.2046 63.149 32.4422 65.5768C31.4542 66.9378 29.8075 68.0776 27.4946 68.0776Z"
|
||||
fill="url(#paint4_radial)"
|
||||
/>
|
||||
<rect
|
||||
x="24.125"
|
||||
y="51.2031"
|
||||
width="48.375"
|
||||
height="21.375"
|
||||
rx="3.63727"
|
||||
fill="black"
|
||||
/>
|
||||
<text x="26" y="67" fill="white" fontSize="16" fontWeight="bold">
|
||||
M365
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<radialGradient
|
||||
id="paint0_radial"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(59.4363 31.0868) rotate(-130.285) scale(27.6431 26.1575)"
|
||||
>
|
||||
<stop offset="0.0955758" stopColor="#00AEFF" />
|
||||
<stop offset="0.773185" stopColor="#2253CE" />
|
||||
<stop offset="1" stopColor="#0736C4" />
|
||||
</radialGradient>
|
||||
<radialGradient
|
||||
id="paint1_radial"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(15.3608 50.9716) rotate(50.2556) scale(25.0142 24.5538)"
|
||||
>
|
||||
<stop stopColor="#FFB657" />
|
||||
<stop offset="0.633728" stopColor="#FF5F3D" />
|
||||
<stop offset="0.923392" stopColor="#C02B3C" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
id="paint2_linear"
|
||||
x1="17.6789"
|
||||
y1="10.6669"
|
||||
x2="21.2461"
|
||||
y2="52.961"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0.156162" stopColor="#0D91E1" />
|
||||
<stop offset="0.487484" stopColor="#52B471" />
|
||||
<stop offset="0.652394" stopColor="#98BD42" />
|
||||
<stop offset="0.937361" stopColor="#FFC800" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
id="paint4_radial"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(64.843 17.441) rotate(109.722) scale(61.4524 75.0539)"
|
||||
>
|
||||
<stop offset="0.0661714" stopColor="#8C48FF" />
|
||||
<stop offset="0.5" stopColor="#F2598A" />
|
||||
<stop offset="0.895833" stopColor="#FFB152" />
|
||||
</radialGradient>
|
||||
<clipPath id="clip0">
|
||||
<rect
|
||||
width="72"
|
||||
height="72"
|
||||
fill="white"
|
||||
transform="translate(0.5 0.578125)"
|
||||
/>
|
||||
</clipPath>
|
||||
<clipPath id="clip1">
|
||||
<rect
|
||||
width="72"
|
||||
height="72"
|
||||
fill="white"
|
||||
transform="translate(0.5 0.578125)"
|
||||
/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
@@ -1,11 +1,11 @@
|
||||
import React from "react";
|
||||
|
||||
import { ConnectionFalse, ConnectionPending, ConnectionTrue } from "../icons";
|
||||
import { getProviderLogo } from "../ui/entities";
|
||||
import { getProviderLogo, ProviderType } from "../ui/entities";
|
||||
|
||||
interface ProviderInfoProps {
|
||||
connected: boolean | null;
|
||||
provider: "aws" | "azure" | "gcp" | "kubernetes";
|
||||
provider: ProviderType;
|
||||
providerAlias: string;
|
||||
providerUID?: string;
|
||||
}
|
||||
|
||||
@@ -7,9 +7,13 @@ import { z } from "zod";
|
||||
|
||||
import { addProviderFormSchema } from "@/types";
|
||||
|
||||
import { AWSProviderBadge, AzureProviderBadge } from "../icons/providers-badge";
|
||||
import { GCPProviderBadge } from "../icons/providers-badge/GCPProviderBadge";
|
||||
import { KS8ProviderBadge } from "../icons/providers-badge/KS8ProviderBadge";
|
||||
import {
|
||||
AWSProviderBadge,
|
||||
AzureProviderBadge,
|
||||
GCPProviderBadge,
|
||||
KS8ProviderBadge,
|
||||
M365ProviderBadge,
|
||||
} from "../icons/providers-badge";
|
||||
import { CustomRadio } from "../ui/custom";
|
||||
import { FormMessage } from "../ui/form";
|
||||
|
||||
@@ -55,6 +59,12 @@ export const RadioGroupProvider: React.FC<RadioGroupProviderProps> = ({
|
||||
<span className="ml-2">Microsoft Azure</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
<CustomRadio description="Microsoft 365" value="m365">
|
||||
<div className="flex items-center">
|
||||
<M365ProviderBadge size={26} />
|
||||
<span className="ml-2">Microsoft 365</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
<CustomRadio description="Kubernetes" value="kubernetes">
|
||||
<div className="flex items-center">
|
||||
<KS8ProviderBadge size={26} />
|
||||
|
||||
@@ -24,22 +24,27 @@ const getProviderFieldDetails = (providerType?: string) => {
|
||||
case "aws":
|
||||
return {
|
||||
label: "Account ID",
|
||||
placeholder: "123456...",
|
||||
placeholder: "e.g. 123456789012",
|
||||
};
|
||||
case "gcp":
|
||||
return {
|
||||
label: "Project ID",
|
||||
placeholder: "project_id...",
|
||||
placeholder: "e.g. my-gcp-project",
|
||||
};
|
||||
case "azure":
|
||||
return {
|
||||
label: "Subscription ID",
|
||||
placeholder: "fc94207a-d396-4a14-a7fd-12a...",
|
||||
placeholder: "e.g. fc94207a-d396-4a14-a7fd-12ab34cd56ef",
|
||||
};
|
||||
case "kubernetes":
|
||||
return {
|
||||
label: "Kubernetes Context",
|
||||
placeholder: "context_name....",
|
||||
placeholder: "e.g. my-cluster-context",
|
||||
};
|
||||
case "m365":
|
||||
return {
|
||||
label: "Domain ID",
|
||||
placeholder: "e.g. your-domain.onmicrosoft.com",
|
||||
};
|
||||
default:
|
||||
return {
|
||||
|
||||
@@ -18,6 +18,7 @@ import { getTask } from "@/actions/task/tasks";
|
||||
import { CheckIcon, RocketIcon } from "@/components/icons";
|
||||
import { useToast } from "@/components/ui";
|
||||
import { CustomButton } from "@/components/ui/custom";
|
||||
import { ProviderType } from "@/components/ui/entities";
|
||||
import { Form } from "@/components/ui/form";
|
||||
import { checkTaskStatus } from "@/lib/helper";
|
||||
import { ApiError, testConnectionFormSchema } from "@/types";
|
||||
@@ -41,7 +42,7 @@ export const TestConnectionForm = ({
|
||||
connected: boolean | null;
|
||||
last_checked_at: string | null;
|
||||
};
|
||||
provider: "aws" | "azure" | "gcp" | "kubernetes";
|
||||
provider: ProviderType;
|
||||
alias: string;
|
||||
scanner_args: Record<string, any>;
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
AzureCredentials,
|
||||
GCPCredentials,
|
||||
KubernetesCredentials,
|
||||
M365Credentials,
|
||||
} from "@/types";
|
||||
|
||||
import { ProviderTitleDocs } from "../provider-title-docs";
|
||||
@@ -26,6 +27,7 @@ import { AWScredentialsForm } from "./via-credentials/aws-credentials-form";
|
||||
import { AzureCredentialsForm } from "./via-credentials/azure-credentials-form";
|
||||
import { GCPcredentialsForm } from "./via-credentials/gcp-credentials-form";
|
||||
import { KubernetesCredentialsForm } from "./via-credentials/k8s-credentials-form";
|
||||
import { M365CredentialsForm } from "./via-credentials/m365-credentials-form";
|
||||
|
||||
type CredentialsFormSchema = z.infer<
|
||||
ReturnType<typeof addCredentialsFormSchema>
|
||||
@@ -36,7 +38,8 @@ type FormType = CredentialsFormSchema &
|
||||
AWSCredentials &
|
||||
AzureCredentials &
|
||||
GCPCredentials &
|
||||
KubernetesCredentials;
|
||||
KubernetesCredentials &
|
||||
M365Credentials;
|
||||
|
||||
export const ViaCredentialsForm = ({
|
||||
searchParams,
|
||||
@@ -76,17 +79,25 @@ export const ViaCredentialsForm = ({
|
||||
client_secret: "",
|
||||
tenant_id: "",
|
||||
}
|
||||
: providerType === "gcp"
|
||||
: providerType === "m365"
|
||||
? {
|
||||
client_id: "",
|
||||
client_secret: "",
|
||||
refresh_token: "",
|
||||
tenant_id: "",
|
||||
user: "",
|
||||
encrypted_password: "",
|
||||
}
|
||||
: providerType === "kubernetes"
|
||||
: providerType === "gcp"
|
||||
? {
|
||||
kubeconfig_content: "",
|
||||
client_id: "",
|
||||
client_secret: "",
|
||||
refresh_token: "",
|
||||
}
|
||||
: {}),
|
||||
: providerType === "kubernetes"
|
||||
? {
|
||||
kubeconfig_content: "",
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -135,6 +146,18 @@ export const ViaCredentialsForm = ({
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data/attributes/secret/user":
|
||||
form.setError("user", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data/attributes/secret/encrypted_password":
|
||||
form.setError("encrypted_password", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data/attributes/secret/tenant_id":
|
||||
form.setError("tenant_id", {
|
||||
type: "server",
|
||||
@@ -191,6 +214,11 @@ export const ViaCredentialsForm = ({
|
||||
control={form.control as unknown as Control<AzureCredentials>}
|
||||
/>
|
||||
)}
|
||||
{providerType === "m365" && (
|
||||
<M365CredentialsForm
|
||||
control={form.control as unknown as Control<M365Credentials>}
|
||||
/>
|
||||
)}
|
||||
{providerType === "gcp" && (
|
||||
<GCPcredentialsForm
|
||||
control={form.control as unknown as Control<GCPCredentials>}
|
||||
|
||||
@@ -2,3 +2,4 @@ export * from "./aws-credentials-form";
|
||||
export * from "./azure-credentials-form";
|
||||
export * from "./gcp-credentials-form";
|
||||
export * from "./k8s-credentials-form";
|
||||
export * from "./m365-credentials-form";
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import { Control } from "react-hook-form";
|
||||
|
||||
import { CustomInput } from "@/components/ui/custom";
|
||||
import { M365Credentials } from "@/types";
|
||||
|
||||
export const M365CredentialsForm = ({
|
||||
control,
|
||||
}: {
|
||||
control: Control<M365Credentials>;
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col">
|
||||
<div className="text-md font-bold leading-9 text-default-foreground">
|
||||
Connect via Credentials
|
||||
</div>
|
||||
<div className="text-sm text-default-500">
|
||||
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}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="user"
|
||||
type="text"
|
||||
label="User"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the User"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.user}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="encrypted_password"
|
||||
type="password"
|
||||
label="Encrypted Password"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the Password"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.encrypted_password}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -5,9 +5,10 @@ import {
|
||||
AzureProviderBadge,
|
||||
GCPProviderBadge,
|
||||
KS8ProviderBadge,
|
||||
M365ProviderBadge,
|
||||
} from "@/components/icons/providers-badge";
|
||||
|
||||
export type ProviderType = "aws" | "azure" | "gcp" | "kubernetes";
|
||||
export type ProviderType = "aws" | "azure" | "gcp" | "kubernetes" | "m365";
|
||||
|
||||
export const getProviderLogo = (provider: ProviderType) => {
|
||||
switch (provider) {
|
||||
@@ -19,6 +20,8 @@ export const getProviderLogo = (provider: ProviderType) => {
|
||||
return <GCPProviderBadge width={35} height={35} />;
|
||||
case "kubernetes":
|
||||
return <KS8ProviderBadge width={35} height={35} />;
|
||||
case "m365":
|
||||
return <M365ProviderBadge width={35} height={35} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -34,6 +37,8 @@ export const getProviderName = (provider: ProviderType): string => {
|
||||
return "Google Cloud Platform";
|
||||
case "kubernetes":
|
||||
return "Kubernetes";
|
||||
case "m365":
|
||||
return "Microsoft 365";
|
||||
default:
|
||||
return "Unknown Provider";
|
||||
}
|
||||
|
||||
+12
-1
@@ -238,6 +238,16 @@ export type AzureCredentials = {
|
||||
providerId: string;
|
||||
};
|
||||
|
||||
export type M365Credentials = {
|
||||
client_id: string;
|
||||
client_secret: string;
|
||||
tenant_id: string;
|
||||
user: string;
|
||||
encrypted_password: string;
|
||||
secretName: string;
|
||||
providerId: string;
|
||||
};
|
||||
|
||||
export type GCPCredentials = {
|
||||
client_id: string;
|
||||
client_secret: string;
|
||||
@@ -256,7 +266,8 @@ export type CredentialsFormSchema =
|
||||
| AWSCredentials
|
||||
| AzureCredentials
|
||||
| GCPCredentials
|
||||
| KubernetesCredentials;
|
||||
| KubernetesCredentials
|
||||
| M365Credentials;
|
||||
|
||||
export interface SearchParamsProps {
|
||||
[key: string]: string | string[] | undefined;
|
||||
|
||||
+20
-2
@@ -63,7 +63,7 @@ export const awsCredentialsTypeSchema = z.object({
|
||||
|
||||
export const addProviderFormSchema = z
|
||||
.object({
|
||||
providerType: z.enum(["aws", "azure", "gcp", "kubernetes"], {
|
||||
providerType: z.enum(["aws", "azure", "gcp", "kubernetes", "m365"], {
|
||||
required_error: "Please select a provider type",
|
||||
}),
|
||||
})
|
||||
@@ -80,6 +80,12 @@ export const addProviderFormSchema = z
|
||||
providerUid: z.string(),
|
||||
awsCredentialsType: z.string().optional(),
|
||||
}),
|
||||
z.object({
|
||||
providerType: z.literal("m365"),
|
||||
providerAlias: z.string(),
|
||||
providerUid: z.string(),
|
||||
awsCredentialsType: z.string().optional(),
|
||||
}),
|
||||
z.object({
|
||||
providerType: z.literal("gcp"),
|
||||
providerAlias: z.string(),
|
||||
@@ -128,7 +134,19 @@ export const addCredentialsFormSchema = (providerType: string) =>
|
||||
.string()
|
||||
.nonempty("Kubeconfig Content is required"),
|
||||
}
|
||||
: {}),
|
||||
: providerType === "m365"
|
||||
? {
|
||||
client_id: z.string().nonempty("Client ID is required"),
|
||||
client_secret: z
|
||||
.string()
|
||||
.nonempty("Client Secret is required"),
|
||||
tenant_id: z.string().nonempty("Tenant ID is required"),
|
||||
user: z.string().nonempty("User is required"),
|
||||
encrypted_password: z
|
||||
.string()
|
||||
.nonempty("Encrypted Password is required"),
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
|
||||
export const addCredentialsRoleFormSchema = (providerType: string) =>
|
||||
|
||||
Reference in New Issue
Block a user