mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat: finished oidc form functions
This commit is contained in:
4
backend/src/@types/knex.d.ts
vendored
4
backend/src/@types/knex.d.ts
vendored
@@ -113,6 +113,9 @@ import {
|
||||
TLdapGroupMaps,
|
||||
TLdapGroupMapsInsert,
|
||||
TLdapGroupMapsUpdate,
|
||||
TOidcConfigs,
|
||||
TOidcConfigsInsert,
|
||||
TOidcConfigsUpdate,
|
||||
TOrganizations,
|
||||
TOrganizationsInsert,
|
||||
TOrganizationsUpdate,
|
||||
@@ -255,7 +258,6 @@ import {
|
||||
TWebhooksInsert,
|
||||
TWebhooksUpdate
|
||||
} from "@app/db/schemas";
|
||||
import { TOidcConfigs, TOidcConfigsInsert, TOidcConfigsUpdate } from "@app/db/schemas/oidc-configs";
|
||||
|
||||
declare module "knex/types/tables" {
|
||||
interface Tables {
|
||||
|
||||
@@ -6,17 +6,17 @@ export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.OidcConfig))) {
|
||||
await knex.schema.createTable(TableName.OidcConfig, (tb) => {
|
||||
tb.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
tb.string("issuer");
|
||||
tb.string("authorizationEndpoint");
|
||||
tb.string("jwksUri");
|
||||
tb.string("tokenEndpoint");
|
||||
tb.string("userinfoEndpoint");
|
||||
tb.text("encryptedClientId");
|
||||
tb.string("clientIdIV");
|
||||
tb.string("clientIdTag");
|
||||
tb.text("encryptedClientSecret");
|
||||
tb.string("clientSecretIV");
|
||||
tb.string("clientSecretTag");
|
||||
tb.string("issuer").notNullable();
|
||||
tb.string("authorizationEndpoint").notNullable();
|
||||
tb.string("jwksUri").notNullable();
|
||||
tb.string("tokenEndpoint").notNullable();
|
||||
tb.string("userinfoEndpoint").notNullable();
|
||||
tb.text("encryptedClientId").notNullable();
|
||||
tb.string("clientIdIV").notNullable();
|
||||
tb.string("clientIdTag").notNullable();
|
||||
tb.text("encryptedClientSecret").notNullable();
|
||||
tb.string("clientSecretIV").notNullable();
|
||||
tb.string("clientSecretTag").notNullable();
|
||||
tb.boolean("isActive").notNullable();
|
||||
tb.timestamps(true, true, true);
|
||||
tb.uuid("orgId").notNullable().unique();
|
||||
|
||||
@@ -36,6 +36,7 @@ export * from "./kms-root-config";
|
||||
export * from "./ldap-configs";
|
||||
export * from "./ldap-group-maps";
|
||||
export * from "./models";
|
||||
export * from "./oidc-configs";
|
||||
export * from "./org-bots";
|
||||
export * from "./org-memberships";
|
||||
export * from "./org-roles";
|
||||
|
||||
@@ -9,17 +9,17 @@ import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const OidcConfigsSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
issuer: z.string().nullable().optional(),
|
||||
authorizationEndpoint: z.string().nullable().optional(),
|
||||
jwksUri: z.string().nullable().optional(),
|
||||
tokenEndpoint: z.string().nullable().optional(),
|
||||
userinfoEndpoint: z.string().nullable().optional(),
|
||||
encryptedClientId: z.string().nullable().optional(),
|
||||
clientIdIV: z.string().nullable().optional(),
|
||||
clientIdTag: z.string().nullable().optional(),
|
||||
encryptedClientSecret: z.string().nullable().optional(),
|
||||
clientSecretIV: z.string().nullable().optional(),
|
||||
clientSecretTag: z.string().nullable().optional(),
|
||||
issuer: z.string(),
|
||||
authorizationEndpoint: z.string(),
|
||||
jwksUri: z.string(),
|
||||
tokenEndpoint: z.string(),
|
||||
userinfoEndpoint: z.string(),
|
||||
encryptedClientId: z.string(),
|
||||
clientIdIV: z.string(),
|
||||
clientIdTag: z.string(),
|
||||
encryptedClientSecret: z.string(),
|
||||
clientSecretIV: z.string(),
|
||||
clientSecretTag: z.string(),
|
||||
isActive: z.boolean(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date(),
|
||||
|
||||
@@ -101,6 +101,7 @@ import { integrationAuthServiceFactory } from "@app/services/integration-auth/in
|
||||
import { kmsDALFactory } from "@app/services/kms/kms-dal";
|
||||
import { kmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal";
|
||||
import { kmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import { oidcConfigDALFactory } from "@app/services/oidc/oidc-config-dal";
|
||||
import { oidcConfigServiceFactory } from "@app/services/oidc/oidc-config-service";
|
||||
import { incidentContactDALFactory } from "@app/services/org/incident-contacts-dal";
|
||||
import { orgBotDALFactory } from "@app/services/org/org-bot-dal";
|
||||
@@ -241,6 +242,7 @@ export const registerRoutes = async (
|
||||
const ldapConfigDAL = ldapConfigDALFactory(db);
|
||||
const ldapGroupMapDAL = ldapGroupMapDALFactory(db);
|
||||
|
||||
const oidcConfigDAL = oidcConfigDALFactory(db);
|
||||
const accessApprovalPolicyDAL = accessApprovalPolicyDALFactory(db);
|
||||
const accessApprovalRequestDAL = accessApprovalRequestDALFactory(db);
|
||||
const accessApprovalPolicyApproverDAL = accessApprovalPolicyApproverDALFactory(db);
|
||||
@@ -846,7 +848,10 @@ export const registerRoutes = async (
|
||||
userAliasDAL,
|
||||
licenseService,
|
||||
tokenService,
|
||||
smtpService
|
||||
smtpService,
|
||||
orgBotDAL,
|
||||
permissionService,
|
||||
oidcConfigDAL
|
||||
});
|
||||
|
||||
await superAdminService.initServerCfg();
|
||||
|
||||
@@ -12,6 +12,9 @@ import { z } from "zod";
|
||||
|
||||
import { OidcConfigsSchema } from "@app/db/schemas/oidc-configs";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { writeLimit } from "@app/server/config/rateLimiter";
|
||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||
import { AuthMode } from "@app/services/auth/auth-type";
|
||||
|
||||
export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
||||
const appCfg = getConfig();
|
||||
@@ -101,6 +104,7 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
||||
jwksUri: true,
|
||||
tokenEndpoint: true,
|
||||
userinfoEndpoint: true,
|
||||
isActive: true,
|
||||
orgId: true
|
||||
}).extend({
|
||||
clientId: z.string(),
|
||||
@@ -122,4 +126,95 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
||||
return oidc;
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "PATCH",
|
||||
url: "/config",
|
||||
config: {
|
||||
rateLimit: writeLimit
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
schema: {
|
||||
body: z
|
||||
.object({
|
||||
issuer: z.string(),
|
||||
authorizationEndpoint: z.string(),
|
||||
jwksUri: z.string(),
|
||||
tokenEndpoint: z.string(),
|
||||
userinfoEndpoint: z.string(),
|
||||
clientId: z.string(),
|
||||
clientSecret: z.string(),
|
||||
isActive: z.boolean()
|
||||
})
|
||||
.partial()
|
||||
.merge(z.object({ orgSlug: z.string() })),
|
||||
response: {
|
||||
200: OidcConfigsSchema.pick({
|
||||
id: true,
|
||||
issuer: true,
|
||||
authorizationEndpoint: true,
|
||||
jwksUri: true,
|
||||
tokenEndpoint: true,
|
||||
userinfoEndpoint: true,
|
||||
orgId: true,
|
||||
isActive: true
|
||||
})
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const oidc = await server.services.oidc.updateOidcCfg({
|
||||
actor: req.permission.type,
|
||||
actorId: req.permission.id,
|
||||
actorAuthMethod: req.permission.authMethod,
|
||||
actorOrgId: req.permission.orgId,
|
||||
...req.body
|
||||
});
|
||||
return oidc;
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "POST",
|
||||
url: "/config",
|
||||
config: {
|
||||
rateLimit: writeLimit
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
schema: {
|
||||
body: z.object({
|
||||
issuer: z.string(),
|
||||
authorizationEndpoint: z.string(),
|
||||
jwksUri: z.string(),
|
||||
tokenEndpoint: z.string(),
|
||||
userinfoEndpoint: z.string(),
|
||||
clientId: z.string(),
|
||||
clientSecret: z.string(),
|
||||
isActive: z.boolean(),
|
||||
orgSlug: z.string()
|
||||
}),
|
||||
response: {
|
||||
200: OidcConfigsSchema.pick({
|
||||
id: true,
|
||||
issuer: true,
|
||||
authorizationEndpoint: true,
|
||||
jwksUri: true,
|
||||
tokenEndpoint: true,
|
||||
userinfoEndpoint: true,
|
||||
orgId: true,
|
||||
isActive: true
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
handler: async (req) => {
|
||||
const oidc = await server.services.oidc.createOidcCfg({
|
||||
actor: req.permission.type,
|
||||
actorId: req.permission.id,
|
||||
actorAuthMethod: req.permission.authMethod,
|
||||
actorOrgId: req.permission.orgId,
|
||||
...req.body
|
||||
});
|
||||
return oidc;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -13,6 +13,18 @@ export type TGetOidcCfgDTO = {
|
||||
orgSlug: string;
|
||||
} & TGenericPermission;
|
||||
|
||||
export type TCreateOidcCfgDTO = {
|
||||
issuer: string;
|
||||
authorizationEndpoint: string;
|
||||
jwksUri: string;
|
||||
tokenEndpoint: string;
|
||||
userinfoEndpoint: string;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
isActive: boolean;
|
||||
orgSlug: string;
|
||||
} & TGenericPermission;
|
||||
|
||||
export type TUpdateOidcCfgDTO = Partial<{
|
||||
issuer: string;
|
||||
authorizationEndpoint: string;
|
||||
|
||||
93
frontend/src/hooks/api/oidcConfig/mutations.tsx
Normal file
93
frontend/src/hooks/api/oidcConfig/mutations.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { oidcConfigKeys } from "./queries";
|
||||
|
||||
export const useUpdateOIDCConfig = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
issuer,
|
||||
authorizationEndpoint,
|
||||
jwksUri,
|
||||
tokenEndpoint,
|
||||
userinfoEndpoint,
|
||||
clientId,
|
||||
clientSecret,
|
||||
isActive,
|
||||
orgSlug
|
||||
}: {
|
||||
issuer?: string;
|
||||
authorizationEndpoint?: string;
|
||||
jwksUri?: string;
|
||||
tokenEndpoint?: string;
|
||||
userinfoEndpoint?: string;
|
||||
clientId?: string;
|
||||
clientSecret?: string;
|
||||
isActive?: boolean;
|
||||
orgSlug: string;
|
||||
}) => {
|
||||
const { data } = await apiRequest.patch("/api/v1/oidc/config", {
|
||||
issuer,
|
||||
authorizationEndpoint,
|
||||
jwksUri,
|
||||
tokenEndpoint,
|
||||
userinfoEndpoint,
|
||||
clientId,
|
||||
orgSlug,
|
||||
clientSecret,
|
||||
isActive
|
||||
});
|
||||
|
||||
return data;
|
||||
},
|
||||
onSuccess(_, dto) {
|
||||
queryClient.invalidateQueries(oidcConfigKeys.getOIDCConfig(dto.orgSlug));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useCreateOIDCConfig = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
issuer,
|
||||
authorizationEndpoint,
|
||||
jwksUri,
|
||||
tokenEndpoint,
|
||||
userinfoEndpoint,
|
||||
clientId,
|
||||
clientSecret,
|
||||
isActive,
|
||||
orgSlug
|
||||
}: {
|
||||
issuer: string;
|
||||
authorizationEndpoint: string;
|
||||
jwksUri: string;
|
||||
tokenEndpoint: string;
|
||||
userinfoEndpoint: string;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
isActive: boolean;
|
||||
orgSlug: string;
|
||||
}) => {
|
||||
const { data } = await apiRequest.post("/api/v1/oidc/config", {
|
||||
issuer,
|
||||
authorizationEndpoint,
|
||||
jwksUri,
|
||||
tokenEndpoint,
|
||||
userinfoEndpoint,
|
||||
clientId,
|
||||
clientSecret,
|
||||
isActive,
|
||||
orgSlug
|
||||
});
|
||||
|
||||
return data;
|
||||
},
|
||||
onSuccess(_, dto) {
|
||||
queryClient.invalidateQueries(oidcConfigKeys.getOIDCConfig(dto.orgSlug));
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,245 @@
|
||||
import { useEffect } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { Button, FormControl, Input, Modal, ModalContent } from "@app/components/v2";
|
||||
import { useOrganization } from "@app/context";
|
||||
import { useGetOIDCConfig } from "@app/hooks/api";
|
||||
import { useCreateOIDCConfig, useUpdateOIDCConfig } from "@app/hooks/api/oidcConfig/mutations";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
type Props = {
|
||||
popUp: UsePopUpState<["addOIDC"]>;
|
||||
handlePopUpClose: (popUpName: keyof UsePopUpState<["addOIDC"]>) => void;
|
||||
handlePopUpToggle: (popUpName: keyof UsePopUpState<["addOIDC"]>, state?: boolean) => void;
|
||||
};
|
||||
|
||||
const schema = z.object({
|
||||
issuer: z.string().min(1),
|
||||
authorizationEndpoint: z.string().min(1),
|
||||
jwksUri: z.string().min(1),
|
||||
tokenEndpoint: z.string().min(1),
|
||||
userinfoEndpoint: z.string().min(1),
|
||||
clientId: z.string().min(1),
|
||||
clientSecret: z.string().min(1)
|
||||
});
|
||||
|
||||
export type OIDCFormData = z.infer<typeof schema>;
|
||||
|
||||
export const OIDCModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: Props) => {
|
||||
const { currentOrg } = useOrganization();
|
||||
|
||||
const { mutateAsync: createMutateAsync, isLoading: createIsLoading } = useCreateOIDCConfig();
|
||||
const { mutateAsync: updateMutateAsync, isLoading: updateIsLoading } = useUpdateOIDCConfig();
|
||||
const { data } = useGetOIDCConfig(currentOrg?.slug ?? "");
|
||||
|
||||
const { control, handleSubmit, reset, setValue } = useForm<OIDCFormData>({
|
||||
resolver: zodResolver(schema)
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
setValue("issuer", data.issuer);
|
||||
setValue("authorizationEndpoint", data.authorizationEndpoint);
|
||||
setValue("jwksUri", data.jwksUri);
|
||||
setValue("tokenEndpoint", data.tokenEndpoint);
|
||||
setValue("userinfoEndpoint", data.userinfoEndpoint);
|
||||
setValue("clientId", data.clientId);
|
||||
setValue("clientSecret", data.clientSecret);
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
const onOIDCModalSubmit = async ({
|
||||
issuer,
|
||||
authorizationEndpoint,
|
||||
jwksUri,
|
||||
tokenEndpoint,
|
||||
userinfoEndpoint,
|
||||
clientId,
|
||||
clientSecret
|
||||
}: OIDCFormData) => {
|
||||
try {
|
||||
if (!currentOrg) return;
|
||||
|
||||
if (!data) {
|
||||
await createMutateAsync({
|
||||
issuer,
|
||||
authorizationEndpoint,
|
||||
jwksUri,
|
||||
tokenEndpoint,
|
||||
userinfoEndpoint,
|
||||
clientId,
|
||||
clientSecret,
|
||||
isActive: true,
|
||||
orgSlug: currentOrg.slug
|
||||
});
|
||||
} else {
|
||||
await updateMutateAsync({
|
||||
issuer,
|
||||
authorizationEndpoint,
|
||||
jwksUri,
|
||||
tokenEndpoint,
|
||||
userinfoEndpoint,
|
||||
clientId,
|
||||
clientSecret,
|
||||
isActive: true,
|
||||
orgSlug: currentOrg.slug
|
||||
});
|
||||
}
|
||||
|
||||
handlePopUpClose("addOIDC");
|
||||
|
||||
createNotification({
|
||||
text: `Successfully ${!data ? "added" : "updated"} OIDC SSO configuration`,
|
||||
type: "success"
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: `Failed to ${!data ? "add" : "update"} OIDC SSO configuration`,
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={popUp?.addOIDC?.isOpen}
|
||||
onOpenChange={(isOpen) => {
|
||||
handlePopUpToggle("addOIDC", isOpen);
|
||||
reset();
|
||||
}}
|
||||
>
|
||||
<ModalContent title="Manage OIDC configuration">
|
||||
<form onSubmit={handleSubmit(onOIDCModalSubmit)}>
|
||||
<Controller
|
||||
control={control}
|
||||
name="issuer"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl label="Issuer" errorText={error?.message} isError={Boolean(error)}>
|
||||
<Input {...field} placeholder="https://accounts.google.com" autoComplete="off" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="authorizationEndpoint"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Authorization Endpoint"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder="https://accounts.google.com/o/oauth2/v2/auth"
|
||||
autoComplete="off"
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="tokenEndpoint"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Token Endpoint"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder="https://oauth2.googleapis.com/token"
|
||||
autoComplete="off"
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="userinfoEndpoint"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="User info endpoint"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder="https://openidconnect.googleapis.com/v1/userinfo"
|
||||
autoComplete="off"
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="jwksUri"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl label="JWKS URI" errorText={error?.message} isError={Boolean(error)}>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder="https://www.googleapis.com/oauth2/v3/certs"
|
||||
autoComplete="off"
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="clientId"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl label="Client ID" errorText={error?.message} isError={Boolean(error)}>
|
||||
<Input
|
||||
placeholder="Client ID"
|
||||
type="password"
|
||||
autoComplete="off"
|
||||
{...field}
|
||||
className="bg-mineshaft-800"
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
name="clientSecret"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Client Secret"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<Input
|
||||
placeholder="Client Secret"
|
||||
type="password"
|
||||
autoComplete="off"
|
||||
{...field}
|
||||
className="bg-mineshaft-800"
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<div className="mt-8 flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isLoading={createIsLoading || updateIsLoading}
|
||||
>
|
||||
{!data ? "Add" : "Update"}
|
||||
</Button>
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
variant="plain"
|
||||
onClick={() => handlePopUpClose("addOIDC")}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -3,6 +3,7 @@ import { withPermission } from "@app/hoc";
|
||||
|
||||
import { OrgGeneralAuthSection } from "./OrgGeneralAuthSection";
|
||||
import { OrgLDAPSection } from "./OrgLDAPSection";
|
||||
import { OrgOIDCSection } from "./OrgOIDCSection";
|
||||
import { OrgScimSection } from "./OrgSCIMSection";
|
||||
import { OrgSSOSection } from "./OrgSSOSection";
|
||||
|
||||
@@ -12,6 +13,7 @@ export const OrgAuthTab = withPermission(
|
||||
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-6">
|
||||
<OrgGeneralAuthSection />
|
||||
<OrgSSOSection />
|
||||
<OrgOIDCSection />
|
||||
<OrgLDAPSection />
|
||||
<OrgScimSection />
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { Button, Switch } from "@app/components/v2";
|
||||
import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context";
|
||||
import { useGetOIDCConfig } from "@app/hooks/api";
|
||||
import { useUpdateOIDCConfig } from "@app/hooks/api/oidcConfig/mutations";
|
||||
import { usePopUp } from "@app/hooks/usePopUp";
|
||||
|
||||
import { OIDCModal } from "./OIDCModal";
|
||||
|
||||
export const OrgOIDCSection = (): JSX.Element => {
|
||||
const { currentOrg } = useOrganization();
|
||||
|
||||
const { data, isLoading } = useGetOIDCConfig(currentOrg?.slug ?? "");
|
||||
const { mutateAsync } = useUpdateOIDCConfig();
|
||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||
"addOIDC"
|
||||
] as const);
|
||||
|
||||
const handleOIDCToggle = async (value: boolean) => {
|
||||
try {
|
||||
if (!currentOrg?.id) return;
|
||||
|
||||
await mutateAsync({
|
||||
orgSlug: currentOrg?.slug,
|
||||
isActive: value
|
||||
});
|
||||
|
||||
createNotification({
|
||||
text: `Successfully ${value ? "enabled" : "disabled"} OIDC SSO`,
|
||||
type: "success"
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: `Failed to ${value ? "enable" : "disable"} OIDC SSO`,
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const addOidcButtonClick = async () => {
|
||||
try {
|
||||
handlePopUpOpen("addOIDC");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<hr className="border-mineshaft-600" />
|
||||
<div className="py-4">
|
||||
<div className="mb-2 flex items-center justify-between">
|
||||
<h2 className="text-md text-mineshaft-100">OIDC</h2>
|
||||
{!isLoading && (
|
||||
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Sso}>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
onClick={addOidcButtonClick}
|
||||
colorSchema="secondary"
|
||||
isDisabled={!isAllowed}
|
||||
>
|
||||
Manage
|
||||
</Button>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm text-mineshaft-300">Manage OIDC authentication configuration</p>
|
||||
</div>
|
||||
{data && (
|
||||
<div className="py-4">
|
||||
<div className="mb-2 flex items-center justify-between">
|
||||
<h2 className="text-md text-mineshaft-100">Enable OIDC</h2>
|
||||
{!isLoading && (
|
||||
<OrgPermissionCan I={OrgPermissionActions.Edit} a={OrgPermissionSubjects.Sso}>
|
||||
{(isAllowed) => (
|
||||
<Switch
|
||||
id="enable-oidc-sso"
|
||||
onCheckedChange={(value) => handleOIDCToggle(value)}
|
||||
isChecked={data ? data.isActive : false}
|
||||
isDisabled={!isAllowed}
|
||||
/>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm text-mineshaft-300">
|
||||
Allow members to authenticate into Infisical with OIDC
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<OIDCModal
|
||||
popUp={popUp}
|
||||
handlePopUpClose={handlePopUpClose}
|
||||
handlePopUpToggle={handlePopUpToggle}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user