mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-05 08:26:29 +00:00
feat: initial setup
This commit is contained in:
Vendored
+8
@@ -92,6 +92,9 @@ import {
|
|||||||
TIdentityKubernetesAuths,
|
TIdentityKubernetesAuths,
|
||||||
TIdentityKubernetesAuthsInsert,
|
TIdentityKubernetesAuthsInsert,
|
||||||
TIdentityKubernetesAuthsUpdate,
|
TIdentityKubernetesAuthsUpdate,
|
||||||
|
TIdentityOidcAuths,
|
||||||
|
TIdentityOidcAuthsInsert,
|
||||||
|
TIdentityOidcAuthsUpdate,
|
||||||
TIdentityOrgMemberships,
|
TIdentityOrgMemberships,
|
||||||
TIdentityOrgMembershipsInsert,
|
TIdentityOrgMembershipsInsert,
|
||||||
TIdentityOrgMembershipsUpdate,
|
TIdentityOrgMembershipsUpdate,
|
||||||
@@ -475,6 +478,11 @@ declare module "knex/types/tables" {
|
|||||||
TIdentityAzureAuthsInsert,
|
TIdentityAzureAuthsInsert,
|
||||||
TIdentityAzureAuthsUpdate
|
TIdentityAzureAuthsUpdate
|
||||||
>;
|
>;
|
||||||
|
[TableName.IdentityOidcAuth]: KnexOriginal.CompositeTableType<
|
||||||
|
TIdentityOidcAuths,
|
||||||
|
TIdentityOidcAuthsInsert,
|
||||||
|
TIdentityOidcAuthsUpdate
|
||||||
|
>;
|
||||||
[TableName.IdentityUaClientSecret]: KnexOriginal.CompositeTableType<
|
[TableName.IdentityUaClientSecret]: KnexOriginal.CompositeTableType<
|
||||||
TIdentityUaClientSecrets,
|
TIdentityUaClientSecrets,
|
||||||
TIdentityUaClientSecretsInsert,
|
TIdentityUaClientSecretsInsert,
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.IdentityOidcAuth))) {
|
||||||
|
await knex.schema.createTable(TableName.IdentityOidcAuth, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
t.bigInteger("accessTokenTTL").defaultTo(7200).notNullable();
|
||||||
|
t.bigInteger("accessTokenMaxTTL").defaultTo(7200).notNullable();
|
||||||
|
t.bigInteger("accessTokenNumUsesLimit").defaultTo(0).notNullable();
|
||||||
|
t.jsonb("accessTokenTrustedIps").notNullable();
|
||||||
|
t.uuid("identityId").notNullable().unique();
|
||||||
|
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
||||||
|
t.string("oidcDiscoveryUrl").notNullable();
|
||||||
|
t.text("encryptedCaCert").notNullable();
|
||||||
|
t.string("caCertIV").notNullable();
|
||||||
|
t.string("caCertTag").notNullable();
|
||||||
|
t.string("boundIssuer").notNullable();
|
||||||
|
t.string("boundAudiences").notNullable();
|
||||||
|
t.jsonb("boundClaims").notNullable();
|
||||||
|
t.string("boundSubject");
|
||||||
|
t.timestamps(true, true, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.IdentityOidcAuth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.IdentityOidcAuth);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.IdentityOidcAuth);
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// Code generated by automation script, DO NOT EDIT.
|
||||||
|
// Automated by pulling database and generating zod schema
|
||||||
|
// To update. Just run npm run generate:schema
|
||||||
|
// Written by akhilmhdh.
|
||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
|
export const IdentityOidcAuthsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
accessTokenTTL: z.coerce.number().default(7200),
|
||||||
|
accessTokenMaxTTL: z.coerce.number().default(7200),
|
||||||
|
accessTokenNumUsesLimit: z.coerce.number().default(0),
|
||||||
|
accessTokenTrustedIps: z.unknown(),
|
||||||
|
identityId: z.string().uuid(),
|
||||||
|
oidcDiscoveryUrl: z.string(),
|
||||||
|
encryptedCaCert: z.string(),
|
||||||
|
caCertIV: z.string(),
|
||||||
|
caCertTag: z.string(),
|
||||||
|
boundIssuer: z.string(),
|
||||||
|
boundAudiences: z.string(),
|
||||||
|
boundClaims: z.unknown(),
|
||||||
|
boundSubject: z.string().nullable().optional(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TIdentityOidcAuths = z.infer<typeof IdentityOidcAuthsSchema>;
|
||||||
|
export type TIdentityOidcAuthsInsert = Omit<z.input<typeof IdentityOidcAuthsSchema>, TImmutableDBKeys>;
|
||||||
|
export type TIdentityOidcAuthsUpdate = Partial<Omit<z.input<typeof IdentityOidcAuthsSchema>, TImmutableDBKeys>>;
|
||||||
@@ -28,6 +28,7 @@ export * from "./identity-aws-auths";
|
|||||||
export * from "./identity-azure-auths";
|
export * from "./identity-azure-auths";
|
||||||
export * from "./identity-gcp-auths";
|
export * from "./identity-gcp-auths";
|
||||||
export * from "./identity-kubernetes-auths";
|
export * from "./identity-kubernetes-auths";
|
||||||
|
export * from "./identity-oidc-auths";
|
||||||
export * from "./identity-org-memberships";
|
export * from "./identity-org-memberships";
|
||||||
export * from "./identity-project-additional-privilege";
|
export * from "./identity-project-additional-privilege";
|
||||||
export * from "./identity-project-membership-role";
|
export * from "./identity-project-membership-role";
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ export enum TableName {
|
|||||||
IdentityAzureAuth = "identity_azure_auths",
|
IdentityAzureAuth = "identity_azure_auths",
|
||||||
IdentityUaClientSecret = "identity_ua_client_secrets",
|
IdentityUaClientSecret = "identity_ua_client_secrets",
|
||||||
IdentityAwsAuth = "identity_aws_auths",
|
IdentityAwsAuth = "identity_aws_auths",
|
||||||
|
IdentityOidcAuth = "identity_oidc_auths",
|
||||||
IdentityOrgMembership = "identity_org_memberships",
|
IdentityOrgMembership = "identity_org_memberships",
|
||||||
IdentityProjectMembership = "identity_project_memberships",
|
IdentityProjectMembership = "identity_project_memberships",
|
||||||
IdentityProjectMembershipRole = "identity_project_membership_role",
|
IdentityProjectMembershipRole = "identity_project_membership_role",
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { IdentityOidcAuthsSchema } from "@app/db/schemas";
|
||||||
|
import { writeLimit } from "@app/server/config/rateLimiter";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
import { validateOidcAuthAudiencesField } from "@app/services/identity-oidc-auth/identity-oidc-auth-validators";
|
||||||
|
|
||||||
|
export const registerIdentityOidcAuthRouter = async (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/oidc-auth/identities/:identityId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
schema: {
|
||||||
|
description: "Attach OIDC Auth configuration onto identity",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
params: z.object({
|
||||||
|
identityId: z.string().trim()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
accessTokenTrustedIps: z
|
||||||
|
.object({
|
||||||
|
ipAddress: z.string().trim()
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
.min(1)
|
||||||
|
.default([{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]),
|
||||||
|
accessTokenTTL: z
|
||||||
|
.number()
|
||||||
|
.int()
|
||||||
|
.min(1)
|
||||||
|
.refine((value) => value !== 0, {
|
||||||
|
message: "accessTokenTTL must have a non zero number"
|
||||||
|
})
|
||||||
|
.default(2592000),
|
||||||
|
accessTokenMaxTTL: z
|
||||||
|
.number()
|
||||||
|
.int()
|
||||||
|
.refine((value) => value !== 0, {
|
||||||
|
message: "accessTokenMaxTTL must have a non zero number"
|
||||||
|
})
|
||||||
|
.default(2592000),
|
||||||
|
accessTokenNumUsesLimit: z.number().int().min(0).default(0),
|
||||||
|
oidcDiscoveryUrl: z.string().url().min(1),
|
||||||
|
caCert: z.string().trim().default(""),
|
||||||
|
boundIssuer: z.string().min(1),
|
||||||
|
boundAudiences: validateOidcAuthAudiencesField,
|
||||||
|
boundClaims: z.record(z.string()),
|
||||||
|
boundSubject: z.string().optional()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
identityOidcAuth: IdentityOidcAuthsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async () => {}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -8,6 +8,7 @@ import { registerIdentityAwsAuthRouter } from "./identity-aws-iam-auth-router";
|
|||||||
import { registerIdentityAzureAuthRouter } from "./identity-azure-auth-router";
|
import { registerIdentityAzureAuthRouter } from "./identity-azure-auth-router";
|
||||||
import { registerIdentityGcpAuthRouter } from "./identity-gcp-auth-router";
|
import { registerIdentityGcpAuthRouter } from "./identity-gcp-auth-router";
|
||||||
import { registerIdentityKubernetesRouter } from "./identity-kubernetes-auth-router";
|
import { registerIdentityKubernetesRouter } from "./identity-kubernetes-auth-router";
|
||||||
|
import { registerIdentityOidcAuthRouter } from "./identity-oidc-auth-router";
|
||||||
import { registerIdentityRouter } from "./identity-router";
|
import { registerIdentityRouter } from "./identity-router";
|
||||||
import { registerIdentityUaRouter } from "./identity-universal-auth-router";
|
import { registerIdentityUaRouter } from "./identity-universal-auth-router";
|
||||||
import { registerIntegrationAuthRouter } from "./integration-auth-router";
|
import { registerIntegrationAuthRouter } from "./integration-auth-router";
|
||||||
@@ -39,6 +40,7 @@ export const registerV1Routes = async (server: FastifyZodProvider) => {
|
|||||||
await authRouter.register(registerIdentityAccessTokenRouter);
|
await authRouter.register(registerIdentityAccessTokenRouter);
|
||||||
await authRouter.register(registerIdentityAwsAuthRouter);
|
await authRouter.register(registerIdentityAwsAuthRouter);
|
||||||
await authRouter.register(registerIdentityAzureAuthRouter);
|
await authRouter.register(registerIdentityAzureAuthRouter);
|
||||||
|
await authRouter.register(registerIdentityOidcAuthRouter);
|
||||||
},
|
},
|
||||||
{ prefix: "/auth" }
|
{ prefix: "/auth" }
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { TDbClient } from "@app/db";
|
||||||
|
import { TableName } from "@app/db/schemas";
|
||||||
|
import { ormify } from "@app/lib/knex";
|
||||||
|
|
||||||
|
export type TIdentityOidcAuthDALFactory = ReturnType<typeof identityOidcAuthDALFactory>;
|
||||||
|
|
||||||
|
export const identityOidcAuthDALFactory = (db: TDbClient) => {
|
||||||
|
const oidcAuthOrm = ormify(db, TableName.IdentityOidcAuth);
|
||||||
|
return oidcAuthOrm;
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { TIdentityOidcAuthDALFactory } from "./identity-oidc-auth-dal";
|
||||||
|
|
||||||
|
type TIdentityOidcAuthServiceFactoryDep = {
|
||||||
|
identityOidcAuthDAL: TIdentityOidcAuthDALFactory;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TIdentityOidcAuthServiceFactory = ReturnType<typeof identityOidcAuthServiceFactory>;
|
||||||
|
|
||||||
|
export const identityOidcAuthServiceFactory = ({ identityOidcAuthDAL }: TIdentityOidcAuthServiceFactoryDep) => {
|
||||||
|
return {};
|
||||||
|
};
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const validateOidcAuthAudiencesField = z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.default("")
|
||||||
|
.transform((data) => {
|
||||||
|
if (data === "") return "";
|
||||||
|
// Trim each ID and join with ', ' to ensure formatting
|
||||||
|
return data
|
||||||
|
.split(",")
|
||||||
|
.map((id) => id.trim())
|
||||||
|
.join(", ");
|
||||||
|
});
|
||||||
@@ -3,5 +3,6 @@ export enum IdentityAuthMethod {
|
|||||||
KUBERNETES_AUTH = "kubernetes-auth",
|
KUBERNETES_AUTH = "kubernetes-auth",
|
||||||
GCP_AUTH = "gcp-auth",
|
GCP_AUTH = "gcp-auth",
|
||||||
AWS_AUTH = "aws-auth",
|
AWS_AUTH = "aws-auth",
|
||||||
AZURE_AUTH = "azure-auth"
|
AZURE_AUTH = "azure-auth",
|
||||||
|
OIDC_AUTH = "oidc-auth"
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-1
@@ -18,6 +18,7 @@ import { IdentityAwsAuthForm } from "./IdentityAwsAuthForm";
|
|||||||
import { IdentityAzureAuthForm } from "./IdentityAzureAuthForm";
|
import { IdentityAzureAuthForm } from "./IdentityAzureAuthForm";
|
||||||
import { IdentityGcpAuthForm } from "./IdentityGcpAuthForm";
|
import { IdentityGcpAuthForm } from "./IdentityGcpAuthForm";
|
||||||
import { IdentityKubernetesAuthForm } from "./IdentityKubernetesAuthForm";
|
import { IdentityKubernetesAuthForm } from "./IdentityKubernetesAuthForm";
|
||||||
|
import { IdentityOidcAuthForm } from "./IdentityOidcAuthForm";
|
||||||
import { IdentityUniversalAuthForm } from "./IdentityUniversalAuthForm";
|
import { IdentityUniversalAuthForm } from "./IdentityUniversalAuthForm";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -34,7 +35,8 @@ const identityAuthMethods = [
|
|||||||
{ label: "Kubernetes Auth", value: IdentityAuthMethod.KUBERNETES_AUTH },
|
{ label: "Kubernetes Auth", value: IdentityAuthMethod.KUBERNETES_AUTH },
|
||||||
{ label: "GCP Auth", value: IdentityAuthMethod.GCP_AUTH },
|
{ label: "GCP Auth", value: IdentityAuthMethod.GCP_AUTH },
|
||||||
{ label: "AWS Auth", value: IdentityAuthMethod.AWS_AUTH },
|
{ label: "AWS Auth", value: IdentityAuthMethod.AWS_AUTH },
|
||||||
{ label: "Azure Auth", value: IdentityAuthMethod.AZURE_AUTH }
|
{ label: "Azure Auth", value: IdentityAuthMethod.AZURE_AUTH },
|
||||||
|
{ label: "OIDC Auth", value: IdentityAuthMethod.OIDC_AUTH }
|
||||||
];
|
];
|
||||||
|
|
||||||
const schema = yup
|
const schema = yup
|
||||||
@@ -117,6 +119,15 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
case IdentityAuthMethod.OIDC_AUTH: {
|
||||||
|
return (
|
||||||
|
<IdentityOidcAuthForm
|
||||||
|
handlePopUpOpen={handlePopUpOpen}
|
||||||
|
handlePopUpToggle={handlePopUpToggle}
|
||||||
|
identityAuthMethodData={identityAuthMethodData}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
return <div />;
|
return <div />;
|
||||||
}
|
}
|
||||||
|
|||||||
+440
@@ -0,0 +1,440 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||||
|
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { createNotification } from "@app/components/notifications";
|
||||||
|
import { Button, FormControl, IconButton, Input } from "@app/components/v2";
|
||||||
|
import { useOrganization, useSubscription } from "@app/context";
|
||||||
|
import { IdentityAuthMethod } from "@app/hooks/api/identities";
|
||||||
|
import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
|
||||||
|
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
|
const schema = z.object({
|
||||||
|
accessTokenTrustedIps: z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
ipAddress: z.string().max(50)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.min(1),
|
||||||
|
accessTokenTTL: z.string(),
|
||||||
|
accessTokenMaxTTL: z.string(),
|
||||||
|
accessTokenNumUsesLimit: z.string(),
|
||||||
|
oidcDiscoveryUrl: z.string().url().min(1),
|
||||||
|
caCert: z.string().trim().default(""),
|
||||||
|
boundIssuer: z.string().min(1),
|
||||||
|
boundAudiences: z.string().optional().default(""),
|
||||||
|
boundClaims: z.array(
|
||||||
|
z.object({
|
||||||
|
key: z.string(),
|
||||||
|
value: z.string()
|
||||||
|
})
|
||||||
|
),
|
||||||
|
boundSubject: z.string().optional().default("")
|
||||||
|
});
|
||||||
|
|
||||||
|
export type FormData = z.infer<typeof schema>;
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void;
|
||||||
|
handlePopUpToggle: (
|
||||||
|
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
|
||||||
|
state?: boolean
|
||||||
|
) => void;
|
||||||
|
identityAuthMethodData: {
|
||||||
|
identityId: string;
|
||||||
|
name: string;
|
||||||
|
authMethod?: IdentityAuthMethod;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const IdentityOidcAuthForm = ({
|
||||||
|
handlePopUpOpen,
|
||||||
|
handlePopUpToggle,
|
||||||
|
identityAuthMethodData
|
||||||
|
}: Props) => {
|
||||||
|
const { currentOrg } = useOrganization();
|
||||||
|
const orgId = currentOrg?.id || "";
|
||||||
|
const { subscription } = useSubscription();
|
||||||
|
|
||||||
|
// const { mutateAsync: addMutateAsync } = useAddIdentityGcpAuth();
|
||||||
|
// const { mutateAsync: updateMutateAsync } = useUpdateIdentityGcpAuth();
|
||||||
|
|
||||||
|
// const { data } = useGetIdentityGcpAuth(identityAuthMethodData?.identityId ?? "");
|
||||||
|
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
reset,
|
||||||
|
formState: { isSubmitting }
|
||||||
|
} = useForm<FormData>({
|
||||||
|
resolver: zodResolver(schema),
|
||||||
|
defaultValues: {
|
||||||
|
accessTokenTTL: "2592000",
|
||||||
|
accessTokenMaxTTL: "2592000",
|
||||||
|
accessTokenNumUsesLimit: "0",
|
||||||
|
accessTokenTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
fields: boundClaimsFields,
|
||||||
|
append: appendBoundClaimField,
|
||||||
|
remove: removeBoundClaimField
|
||||||
|
} = useFieldArray({
|
||||||
|
control,
|
||||||
|
name: "boundClaims"
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
fields: accessTokenTrustedIpsFields,
|
||||||
|
append: appendAccessTokenTrustedIp,
|
||||||
|
remove: removeAccessTokenTrustedIp
|
||||||
|
} = useFieldArray({ control, name: "accessTokenTrustedIps" });
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// if (data) {
|
||||||
|
// reset({
|
||||||
|
// type: data.type,
|
||||||
|
// allowedServiceAccounts: data.allowedServiceAccounts,
|
||||||
|
// allowedProjects: data.allowedProjects,
|
||||||
|
// allowedZones: data.allowedZones,
|
||||||
|
// accessTokenTTL: String(data.accessTokenTTL),
|
||||||
|
// accessTokenMaxTTL: String(data.accessTokenMaxTTL),
|
||||||
|
// accessTokenNumUsesLimit: String(data.accessTokenNumUsesLimit),
|
||||||
|
// accessTokenTrustedIps: data.accessTokenTrustedIps.map(
|
||||||
|
// ({ ipAddress, prefix }: IdentityTrustedIp) => {
|
||||||
|
// return {
|
||||||
|
// ipAddress: `${ipAddress}${prefix !== undefined ? `/${prefix}` : ""}`
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// reset({
|
||||||
|
// type: "iam",
|
||||||
|
// allowedServiceAccounts: "",
|
||||||
|
// allowedProjects: "",
|
||||||
|
// allowedZones: "",
|
||||||
|
// accessTokenTTL: "2592000",
|
||||||
|
// accessTokenMaxTTL: "2592000",
|
||||||
|
// accessTokenNumUsesLimit: "0",
|
||||||
|
// accessTokenTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }, [data]);
|
||||||
|
|
||||||
|
const onFormSubmit = async ({
|
||||||
|
type,
|
||||||
|
allowedServiceAccounts,
|
||||||
|
allowedProjects,
|
||||||
|
allowedZones,
|
||||||
|
accessTokenTTL,
|
||||||
|
accessTokenMaxTTL,
|
||||||
|
accessTokenNumUsesLimit,
|
||||||
|
accessTokenTrustedIps
|
||||||
|
}: FormData) => {
|
||||||
|
try {
|
||||||
|
if (!identityAuthMethodData) return;
|
||||||
|
|
||||||
|
// if (data) {
|
||||||
|
// await updateMutateAsync({
|
||||||
|
// identityId: identityAuthMethodData.identityId,
|
||||||
|
// organizationId: orgId,
|
||||||
|
// type,
|
||||||
|
// allowedServiceAccounts,
|
||||||
|
// allowedProjects,
|
||||||
|
// allowedZones,
|
||||||
|
// accessTokenTTL: Number(accessTokenTTL),
|
||||||
|
// accessTokenMaxTTL: Number(accessTokenMaxTTL),
|
||||||
|
// accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
|
||||||
|
// accessTokenTrustedIps
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
// await addMutateAsync({
|
||||||
|
// identityId: identityAuthMethodData.identityId,
|
||||||
|
// organizationId: orgId,
|
||||||
|
// type,
|
||||||
|
// allowedServiceAccounts: allowedServiceAccounts || "",
|
||||||
|
// allowedProjects: allowedProjects || "",
|
||||||
|
// allowedZones: allowedZones || "",
|
||||||
|
// accessTokenTTL: Number(accessTokenTTL),
|
||||||
|
// accessTokenMaxTTL: Number(accessTokenMaxTTL),
|
||||||
|
// accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
|
||||||
|
// accessTokenTrustedIps
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
handlePopUpToggle("identityAuthMethod", false);
|
||||||
|
|
||||||
|
createNotification({
|
||||||
|
text: `Successfully ${
|
||||||
|
identityAuthMethodData?.authMethod ? "updated" : "configured"
|
||||||
|
} auth method`,
|
||||||
|
type: "success"
|
||||||
|
});
|
||||||
|
|
||||||
|
reset();
|
||||||
|
} catch (err) {
|
||||||
|
createNotification({
|
||||||
|
text: `Failed to ${identityAuthMethodData?.authMethod ? "update" : "configure"} identity`,
|
||||||
|
type: "error"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="oidcDiscoveryUrl"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
isRequired
|
||||||
|
label="OIDC Discovery URL"
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder="https://accounts.google.com/.well-known/openid-configuration"
|
||||||
|
type="text"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="boundIssuer"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
isRequired
|
||||||
|
label="Issuer"
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Input {...field} type="text" />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="boundSubject"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl label="Subject" isError={Boolean(error)} errorText={error?.message}>
|
||||||
|
<Input {...field} type="text" />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="boundAudiences"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl label="Audiences" isError={Boolean(error)} errorText={error?.message}>
|
||||||
|
<Input {...field} type="text" placeholder="service1, service2" />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{boundClaimsFields.map(({ id }, index) => (
|
||||||
|
<div className="mb-3 flex items-end space-x-2" key={id}>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name={`boundClaims.${index}.key`}
|
||||||
|
render={({ field, fieldState: { error } }) => {
|
||||||
|
return (
|
||||||
|
<FormControl
|
||||||
|
className="mb-0 flex-grow"
|
||||||
|
label={index === 0 ? "Claims" : undefined}
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
value={field.value}
|
||||||
|
onChange={(e) => field.onChange(e)}
|
||||||
|
placeholder="property"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name={`boundClaims.${index}.value`}
|
||||||
|
render={({ field, fieldState: { error } }) => {
|
||||||
|
return (
|
||||||
|
<FormControl
|
||||||
|
className="mb-0 flex-grow"
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
value={field.value}
|
||||||
|
onChange={(e) => field.onChange(e)}
|
||||||
|
placeholder="value1, value2"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
onClick={() => removeBoundClaimField(index)}
|
||||||
|
size="lg"
|
||||||
|
colorSchema="danger"
|
||||||
|
variant="plain"
|
||||||
|
ariaLabel="update"
|
||||||
|
className="p-3"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faXmark} />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<div className="my-4 ml-1">
|
||||||
|
<Button
|
||||||
|
variant="outline_bg"
|
||||||
|
onClick={() =>
|
||||||
|
appendBoundClaimField({
|
||||||
|
key: "",
|
||||||
|
value: ""
|
||||||
|
})
|
||||||
|
}
|
||||||
|
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||||
|
size="xs"
|
||||||
|
>
|
||||||
|
Add Claims
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
defaultValue="2592000"
|
||||||
|
name="accessTokenTTL"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label="Access Token TTL (seconds)"
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Input {...field} placeholder="2592000" type="number" min="1" step="1" />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
defaultValue="2592000"
|
||||||
|
name="accessTokenMaxTTL"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label="Access Token Max TTL (seconds)"
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Input {...field} placeholder="2592000" type="number" min="1" step="1" />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
defaultValue="0"
|
||||||
|
name="accessTokenNumUsesLimit"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label="Access Token Max Number of Uses"
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Input {...field} placeholder="0" type="number" min="0" step="1" />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{accessTokenTrustedIpsFields.map(({ id }, index) => (
|
||||||
|
<div className="mb-3 flex items-end space-x-2" key={id}>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name={`accessTokenTrustedIps.${index}.ipAddress`}
|
||||||
|
defaultValue="0.0.0.0/0"
|
||||||
|
render={({ field, fieldState: { error } }) => {
|
||||||
|
return (
|
||||||
|
<FormControl
|
||||||
|
className="mb-0 flex-grow"
|
||||||
|
label={index === 0 ? "Access Token Trusted IPs" : undefined}
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
value={field.value}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (subscription?.ipAllowlisting) {
|
||||||
|
field.onChange(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePopUpOpen("upgradePlan");
|
||||||
|
}}
|
||||||
|
placeholder="123.456.789.0"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
onClick={() => {
|
||||||
|
if (subscription?.ipAllowlisting) {
|
||||||
|
removeAccessTokenTrustedIp(index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePopUpOpen("upgradePlan");
|
||||||
|
}}
|
||||||
|
size="lg"
|
||||||
|
colorSchema="danger"
|
||||||
|
variant="plain"
|
||||||
|
ariaLabel="update"
|
||||||
|
className="p-3"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faXmark} />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<div className="my-4 ml-1">
|
||||||
|
<Button
|
||||||
|
variant="outline_bg"
|
||||||
|
onClick={() => {
|
||||||
|
if (subscription?.ipAllowlisting) {
|
||||||
|
appendAccessTokenTrustedIp({
|
||||||
|
ipAddress: "0.0.0.0/0"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePopUpOpen("upgradePlan");
|
||||||
|
}}
|
||||||
|
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||||
|
size="xs"
|
||||||
|
>
|
||||||
|
Add IP Address
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Button
|
||||||
|
className="mr-4"
|
||||||
|
size="sm"
|
||||||
|
type="submit"
|
||||||
|
isLoading={isSubmitting}
|
||||||
|
isDisabled={isSubmitting}
|
||||||
|
>
|
||||||
|
{identityAuthMethodData?.authMethod ? "Update" : "Configure"}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
colorSchema="secondary"
|
||||||
|
variant="plain"
|
||||||
|
onClick={() => handlePopUpToggle("identityAuthMethod", false)}
|
||||||
|
>
|
||||||
|
{identityAuthMethodData?.authMethod ? "Cancel" : "Skip"}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user