improvements: address feedback

This commit is contained in:
Scott Wilson
2025-01-24 12:55:56 -08:00
parent 94aed485a5
commit 99c9b644df
27 changed files with 2374 additions and 1994 deletions
@@ -923,7 +923,7 @@ export const useAddIdentityTokenAuth = () => {
});
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
queryClient.invalidateQueries({
queryKey: identitiesKeys.getIdentityUniversalAuth(identityId)
queryKey: identitiesKeys.getIdentityTokenAuth(identityId)
});
}
});
@@ -959,7 +959,7 @@ export const useUpdateIdentityTokenAuth = () => {
});
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
queryClient.invalidateQueries({
queryKey: identitiesKeys.getIdentityUniversalAuth(identityId)
queryKey: identitiesKeys.getIdentityTokenAuth(identityId)
});
}
});
@@ -34,7 +34,7 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
title={
isSelectedAuthAlreadyConfigured
? `Edit ${identityAuthToNameMap[selectedAuthMethod!] ?? ""}`
: `Create new ${identityAuthToNameMap[selectedAuthMethod!] ?? ""}`
: `Add ${identityAuthToNameMap[selectedAuthMethod!] ?? ""}`
}
>
<IdentityAuthMethodModalContent
@@ -111,7 +111,7 @@ export const IdentityAuthMethodModalContent = ({
[IdentityAuthMethod.UNIVERSAL_AUTH]: {
render: () => (
<IdentityUniversalAuthForm
identityAuthMethodData={identityAuthMethodData}
identityId={identityAuthMethodData.identityId}
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
@@ -121,7 +121,7 @@ export const IdentityAuthMethodModalContent = ({
[IdentityAuthMethod.OIDC_AUTH]: {
render: () => (
<IdentityOidcAuthForm
identityAuthMethodData={identityAuthMethodData}
identityId={identityAuthMethodData.identityId}
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
@@ -131,7 +131,7 @@ export const IdentityAuthMethodModalContent = ({
[IdentityAuthMethod.TOKEN_AUTH]: {
render: () => (
<IdentityTokenAuthForm
identityAuthMethodData={identityAuthMethodData}
identityId={identityAuthMethodData.identityId}
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
@@ -141,7 +141,7 @@ export const IdentityAuthMethodModalContent = ({
[IdentityAuthMethod.AZURE_AUTH]: {
render: () => (
<IdentityAzureAuthForm
identityAuthMethodData={identityAuthMethodData}
identityId={identityAuthMethodData.identityId}
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
@@ -151,7 +151,7 @@ export const IdentityAuthMethodModalContent = ({
[IdentityAuthMethod.GCP_AUTH]: {
render: () => (
<IdentityGcpAuthForm
identityAuthMethodData={identityAuthMethodData}
identityId={identityAuthMethodData.identityId}
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
@@ -161,7 +161,7 @@ export const IdentityAuthMethodModalContent = ({
[IdentityAuthMethod.KUBERNETES_AUTH]: {
render: () => (
<IdentityKubernetesAuthForm
identityAuthMethodData={identityAuthMethodData}
identityId={identityAuthMethodData.identityId}
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
@@ -171,7 +171,7 @@ export const IdentityAuthMethodModalContent = ({
[IdentityAuthMethod.AWS_AUTH]: {
render: () => (
<IdentityAwsAuthForm
identityAuthMethodData={identityAuthMethodData}
identityId={identityAuthMethodData.identityId}
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
@@ -181,7 +181,7 @@ export const IdentityAuthMethodModalContent = ({
[IdentityAuthMethod.JWT_AUTH]: {
render: () => (
<IdentityJwtAuthForm
identityAuthMethodData={identityAuthMethodData}
identityId={identityAuthMethodData.identityId}
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useState } 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";
@@ -6,17 +6,27 @@ 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 {
Button,
FormControl,
IconButton,
Input,
Tab,
TabList,
TabPanel,
Tabs
} from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context";
import {
useAddIdentityAwsAuth,
useGetIdentityAwsAuth,
useUpdateIdentityAwsAuth
} from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
import { UsePopUpState } from "@app/hooks/usePopUp";
import { IdentityFormTab } from "./types";
const schema = z
.object({
stsEndpoint: z.string(),
@@ -52,18 +62,15 @@ type Props = {
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
) => void;
identityAuthMethodData: {
identityId: string;
name: string;
configuredAuthMethods?: IdentityAuthMethod[];
authMethod?: IdentityAuthMethod;
};
identityId?: string;
isUpdate?: boolean;
};
export const IdentityAwsAuthForm = ({
handlePopUpOpen,
handlePopUpToggle,
identityAuthMethodData
identityId,
isUpdate
}: Props) => {
const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || "";
@@ -71,11 +78,9 @@ export const IdentityAwsAuthForm = ({
const { mutateAsync: addMutateAsync } = useAddIdentityAwsAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityAwsAuth();
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
const isUpdate = identityAuthMethodData?.configuredAuthMethods?.includes(
identityAuthMethodData.authMethod! || ""
);
const { data } = useGetIdentityAwsAuth(identityAuthMethodData?.identityId ?? "", {
const { data } = useGetIdentityAwsAuth(identityId ?? "", {
enabled: isUpdate
});
@@ -143,7 +148,7 @@ export const IdentityAwsAuthForm = ({
accessTokenTrustedIps
}: FormData) => {
try {
if (!identityAuthMethodData) return;
if (!identityId) return;
if (data) {
await updateMutateAsync({
@@ -151,7 +156,7 @@ export const IdentityAwsAuthForm = ({
stsEndpoint,
allowedPrincipalArns,
allowedAccountIds,
identityId: identityAuthMethodData.identityId,
identityId,
accessTokenTTL: Number(accessTokenTTL),
accessTokenMaxTTL: Number(accessTokenMaxTTL),
accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
@@ -160,7 +165,7 @@ export const IdentityAwsAuthForm = ({
} else {
await addMutateAsync({
organizationId: orgId,
identityId: identityAuthMethodData.identityId,
identityId,
stsEndpoint: stsEndpoint || "",
allowedPrincipalArns: allowedPrincipalArns || "",
allowedAccountIds: allowedAccountIds || "",
@@ -188,7 +193,21 @@ export const IdentityAwsAuthForm = ({
};
return (
<form onSubmit={handleSubmit(onFormSubmit)}>
<form
onSubmit={handleSubmit(onFormSubmit, (fields) => {
setTabValue(
["accessTokenTrustedIps"].includes(Object.keys(fields)[0])
? IdentityFormTab.Advanced
: IdentityFormTab.Configuration
);
})}
>
<Tabs value={tabValue} onValueChange={(value) => setTabValue(value as IdentityFormTab)}>
<TabList>
<Tab value={IdentityFormTab.Configuration}>Configuration</Tab>
<Tab value={IdentityFormTab.Advanced}>Advanced</Tab>
</TabList>
<TabPanel value={IdentityFormTab.Configuration}>
<Controller
control={control}
defaultValue="2592000"
@@ -272,6 +291,8 @@ export const IdentityAwsAuthForm = ({
</FormControl>
)}
/>
</TabPanel>
<TabPanel value={IdentityFormTab.Advanced}>
{accessTokenTrustedIpsFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller
@@ -340,7 +361,8 @@ export const IdentityAwsAuthForm = ({
Add IP Address
</Button>
</div>
<div className="flex justify-between">
</TabPanel>
</Tabs>
<div className="flex items-center">
<Button
className="mr-4"
@@ -349,7 +371,7 @@ export const IdentityAwsAuthForm = ({
isLoading={isSubmitting}
isDisabled={isSubmitting}
>
{!isUpdate ? "Create" : "Edit"}
{isUpdate ? "Update" : "Add"}
</Button>
<Button
@@ -360,7 +382,6 @@ export const IdentityAwsAuthForm = ({
Cancel
</Button>
</div>
</div>
</form>
);
};
@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useState } 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";
@@ -6,17 +6,27 @@ 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 {
Button,
FormControl,
IconButton,
Input,
Tab,
TabList,
TabPanel,
Tabs
} from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context";
import {
useAddIdentityAzureAuth,
useGetIdentityAzureAuth,
useUpdateIdentityAzureAuth
} from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
import { UsePopUpState } from "@app/hooks/usePopUp";
import { IdentityFormTab } from "./types";
const schema = z
.object({
tenantId: z.string().min(1),
@@ -47,18 +57,15 @@ type Props = {
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
) => void;
identityAuthMethodData: {
identityId: string;
name: string;
configuredAuthMethods?: IdentityAuthMethod[];
authMethod?: IdentityAuthMethod;
};
identityId?: string;
isUpdate?: boolean;
};
export const IdentityAzureAuthForm = ({
handlePopUpOpen,
handlePopUpToggle,
identityAuthMethodData
identityId,
isUpdate
}: Props) => {
const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || "";
@@ -66,11 +73,9 @@ export const IdentityAzureAuthForm = ({
const { mutateAsync: addMutateAsync } = useAddIdentityAzureAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityAzureAuth();
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
const isUpdate = identityAuthMethodData?.configuredAuthMethods?.includes(
identityAuthMethodData.authMethod! || ""
);
const { data } = useGetIdentityAzureAuth(identityAuthMethodData?.identityId ?? "", {
const { data } = useGetIdentityAzureAuth(identityId ?? "", {
enabled: isUpdate
});
@@ -139,12 +144,12 @@ export const IdentityAzureAuthForm = ({
accessTokenTrustedIps
}: FormData) => {
try {
if (!identityAuthMethodData) return;
if (!identityId) return;
if (data) {
await updateMutateAsync({
organizationId: orgId,
identityId: identityAuthMethodData.identityId,
identityId,
tenantId,
resource,
allowedServicePrincipalIds,
@@ -156,7 +161,7 @@ export const IdentityAzureAuthForm = ({
} else {
await addMutateAsync({
organizationId: orgId,
identityId: identityAuthMethodData.identityId,
identityId,
tenantId: tenantId || "",
resource: resource || "",
allowedServicePrincipalIds: allowedServicePrincipalIds || "",
@@ -184,7 +189,21 @@ export const IdentityAzureAuthForm = ({
};
return (
<form onSubmit={handleSubmit(onFormSubmit)}>
<form
onSubmit={handleSubmit(onFormSubmit, (fields) => {
setTabValue(
["accessTokenTrustedIps"].includes(Object.keys(fields)[0])
? IdentityFormTab.Advanced
: IdentityFormTab.Configuration
);
})}
>
<Tabs value={tabValue} onValueChange={(value) => setTabValue(value as IdentityFormTab)}>
<TabList>
<Tab value={IdentityFormTab.Configuration}>Configuration</Tab>
<Tab value={IdentityFormTab.Advanced}>Advanced</Tab>
</TabList>
<TabPanel value={IdentityFormTab.Configuration}>
<Controller
control={control}
defaultValue="2592000"
@@ -268,6 +287,8 @@ export const IdentityAzureAuthForm = ({
</FormControl>
)}
/>
</TabPanel>
<TabPanel value={IdentityFormTab.Advanced}>
{accessTokenTrustedIpsFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller
@@ -336,7 +357,8 @@ export const IdentityAzureAuthForm = ({
Add IP Address
</Button>
</div>
<div className="flex justify-between">
</TabPanel>
</Tabs>
<div className="flex items-center">
<Button
className="mr-4"
@@ -345,7 +367,7 @@ export const IdentityAzureAuthForm = ({
isLoading={isSubmitting}
isDisabled={isSubmitting}
>
{!isUpdate ? "Create" : "Edit"}
{isUpdate ? "Update" : "Add"}
</Button>
<Button
@@ -356,7 +378,6 @@ export const IdentityAzureAuthForm = ({
Cancel
</Button>
</div>
</div>
</form>
);
};
@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useState } 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";
@@ -6,17 +6,29 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import { Button, FormControl, IconButton, Input, Select, SelectItem } from "@app/components/v2";
import {
Button,
FormControl,
IconButton,
Input,
Select,
SelectItem,
Tab,
TabList,
TabPanel,
Tabs
} from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context";
import {
useAddIdentityGcpAuth,
useGetIdentityGcpAuth,
useUpdateIdentityGcpAuth
} from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
import { UsePopUpState } from "@app/hooks/usePopUp";
import { IdentityFormTab } from "./types";
const schema = z
.object({
type: z.enum(["iam", "gce"]),
@@ -48,18 +60,15 @@ type Props = {
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
) => void;
identityAuthMethodData: {
identityId: string;
name: string;
configuredAuthMethods?: IdentityAuthMethod[];
authMethod?: IdentityAuthMethod;
};
identityId?: string;
isUpdate?: boolean;
};
export const IdentityGcpAuthForm = ({
handlePopUpOpen,
handlePopUpToggle,
identityAuthMethodData
identityId,
isUpdate
}: Props) => {
const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || "";
@@ -67,11 +76,9 @@ export const IdentityGcpAuthForm = ({
const { mutateAsync: addMutateAsync } = useAddIdentityGcpAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityGcpAuth();
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
const isUpdate = identityAuthMethodData?.configuredAuthMethods?.includes(
identityAuthMethodData.authMethod! || ""
);
const { data } = useGetIdentityGcpAuth(identityAuthMethodData?.identityId ?? "", {
const { data } = useGetIdentityGcpAuth(identityId ?? "", {
enabled: isUpdate
});
@@ -146,11 +153,11 @@ export const IdentityGcpAuthForm = ({
accessTokenTrustedIps
}: FormData) => {
try {
if (!identityAuthMethodData) return;
if (!identityId) return;
if (data) {
await updateMutateAsync({
identityId: identityAuthMethodData.identityId,
identityId,
organizationId: orgId,
type,
allowedServiceAccounts,
@@ -163,7 +170,7 @@ export const IdentityGcpAuthForm = ({
});
} else {
await addMutateAsync({
identityId: identityAuthMethodData.identityId,
identityId,
organizationId: orgId,
type,
allowedServiceAccounts: allowedServiceAccounts || "",
@@ -193,7 +200,21 @@ export const IdentityGcpAuthForm = ({
};
return (
<form onSubmit={handleSubmit(onFormSubmit)}>
<form
onSubmit={handleSubmit(onFormSubmit, (fields) => {
setTabValue(
["accessTokenTrustedIps"].includes(Object.keys(fields)[0])
? IdentityFormTab.Advanced
: IdentityFormTab.Configuration
);
})}
>
<Tabs value={tabValue} onValueChange={(value) => setTabValue(value as IdentityFormTab)}>
<TabList>
<Tab value={IdentityFormTab.Configuration}>Configuration</Tab>
<Tab value={IdentityFormTab.Advanced}>Advanced</Tab>
</TabList>
<TabPanel value={IdentityFormTab.Configuration}>
<Controller
control={control}
name="type"
@@ -253,7 +274,11 @@ export const IdentityGcpAuthForm = ({
control={control}
name="allowedZones"
render={({ field, fieldState: { error } }) => (
<FormControl label="Allowed Zones" isError={Boolean(error)} errorText={error?.message}>
<FormControl
label="Allowed Zones"
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="us-west2-a, us-central1-a, ..." />
</FormControl>
)}
@@ -301,6 +326,8 @@ export const IdentityGcpAuthForm = ({
</FormControl>
)}
/>
</TabPanel>
<TabPanel value={IdentityFormTab.Advanced}>
{accessTokenTrustedIpsFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller
@@ -369,7 +396,8 @@ export const IdentityGcpAuthForm = ({
Add IP Address
</Button>
</div>
<div className="flex justify-between">
</TabPanel>
</Tabs>
<div className="flex items-center">
<Button
className="mr-4"
@@ -378,7 +406,7 @@ export const IdentityGcpAuthForm = ({
isLoading={isSubmitting}
isDisabled={isSubmitting}
>
{!isUpdate ? "Create" : "Edit"}
{isUpdate ? "Update" : "Add"}
</Button>
<Button
@@ -389,7 +417,6 @@ export const IdentityGcpAuthForm = ({
Cancel
</Button>
</div>
</div>
</form>
);
};
@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { Controller, useFieldArray, useForm } from "react-hook-form";
import { faQuestionCircle } from "@fortawesome/free-regular-svg-icons";
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
@@ -14,17 +14,22 @@ import {
Input,
Select,
SelectItem,
Tab,
TabList,
TabPanel,
Tabs,
TextArea,
Tooltip
} from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context";
import { useAddIdentityJwtAuth, useUpdateIdentityJwtAuth } from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { IdentityJwtConfigurationType } from "@app/hooks/api/identities/enums";
import { useGetIdentityJwtAuth } from "@app/hooks/api/identities/queries";
import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
import { UsePopUpState } from "@app/hooks/usePopUp";
import { IdentityFormTab } from "./types";
const commonSchema = z.object({
accessTokenTrustedIps: z
.array(
@@ -88,18 +93,15 @@ type Props = {
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
) => void;
identityAuthMethodData: {
identityId: string;
name: string;
configuredAuthMethods?: IdentityAuthMethod[];
authMethod?: IdentityAuthMethod;
};
identityId?: string;
isUpdate?: boolean;
};
export const IdentityJwtAuthForm = ({
handlePopUpOpen,
handlePopUpToggle,
identityAuthMethodData
identityId,
isUpdate
}: Props) => {
const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || "";
@@ -107,11 +109,9 @@ export const IdentityJwtAuthForm = ({
const { mutateAsync: addMutateAsync } = useAddIdentityJwtAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityJwtAuth();
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
const isUpdate = identityAuthMethodData?.configuredAuthMethods?.includes(
identityAuthMethodData.authMethod! || ""
);
const { data } = useGetIdentityJwtAuth(identityAuthMethodData?.identityId ?? "", {
const { data } = useGetIdentityJwtAuth(identityId ?? "", {
enabled: isUpdate
});
@@ -218,13 +218,13 @@ export const IdentityJwtAuthForm = ({
boundSubject
}: FormData) => {
try {
if (!identityAuthMethodData) {
if (!identityId) {
return;
}
if (data) {
await updateMutateAsync({
identityId: identityAuthMethodData.identityId,
identityId,
organizationId: orgId,
configurationType,
jwksUrl,
@@ -241,7 +241,7 @@ export const IdentityJwtAuthForm = ({
});
} else {
await addMutateAsync({
identityId: identityAuthMethodData.identityId,
identityId,
configurationType,
jwksUrl,
jwksCaCert,
@@ -275,7 +275,27 @@ export const IdentityJwtAuthForm = ({
};
return (
<form onSubmit={handleSubmit(onFormSubmit)}>
<form
onSubmit={handleSubmit(onFormSubmit, (fields) => {
setTabValue(
[
"accessTokenTrustedIps",
"boundIssuer",
"boundAudiences",
"boundSubject",
"boundClaims"
].includes(Object.keys(fields)[0])
? IdentityFormTab.Advanced
: IdentityFormTab.Configuration
);
})}
>
<Tabs value={tabValue} onValueChange={(value) => setTabValue(value as IdentityFormTab)}>
<TabList>
<Tab value={IdentityFormTab.Configuration}>Configuration</Tab>
<Tab value={IdentityFormTab.Advanced}>Advanced</Tab>
</TabList>
<TabPanel value={IdentityFormTab.Configuration}>
<Controller
control={control}
name="configurationType"
@@ -410,7 +430,50 @@ export const IdentityJwtAuthForm = ({
</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>
)}
/>
</TabPanel>
<TabPanel value={IdentityFormTab.Advanced}>
<Controller
control={control}
name="boundIssuer"
@@ -541,48 +604,6 @@ export const IdentityJwtAuthForm = ({
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
@@ -651,7 +672,8 @@ export const IdentityJwtAuthForm = ({
Add IP Address
</Button>
</div>
<div className="flex justify-between">
</TabPanel>
</Tabs>
<div className="flex items-center">
<Button
className="mr-4"
@@ -671,7 +693,6 @@ export const IdentityJwtAuthForm = ({
Cancel
</Button>
</div>
</div>
</form>
);
};
@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useState } 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";
@@ -6,17 +6,28 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import { Button, FormControl, IconButton, Input, TextArea } from "@app/components/v2";
import {
Button,
FormControl,
IconButton,
Input,
Tab,
TabList,
TabPanel,
Tabs,
TextArea
} from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context";
import {
useAddIdentityKubernetesAuth,
useGetIdentityKubernetesAuth,
useUpdateIdentityKubernetesAuth
} from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
import { UsePopUpState } from "@app/hooks/usePopUp";
import { IdentityFormTab } from "./types";
const schema = z
.object({
kubernetesHost: z.string().min(1),
@@ -50,18 +61,15 @@ type Props = {
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
) => void;
identityAuthMethodData: {
identityId: string;
name: string;
configuredAuthMethods?: IdentityAuthMethod[];
authMethod?: IdentityAuthMethod;
};
identityId?: string;
isUpdate?: boolean;
};
export const IdentityKubernetesAuthForm = ({
handlePopUpOpen,
handlePopUpToggle,
identityAuthMethodData
identityId,
isUpdate
}: Props) => {
const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || "";
@@ -69,11 +77,9 @@ export const IdentityKubernetesAuthForm = ({
const { mutateAsync: addMutateAsync } = useAddIdentityKubernetesAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityKubernetesAuth();
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
const isUpdate = identityAuthMethodData?.configuredAuthMethods?.includes(
identityAuthMethodData.authMethod! || ""
);
const { data } = useGetIdentityKubernetesAuth(identityAuthMethodData?.identityId ?? "", {
const { data } = useGetIdentityKubernetesAuth(identityId ?? "", {
enabled: isUpdate
});
@@ -154,7 +160,7 @@ export const IdentityKubernetesAuthForm = ({
accessTokenTrustedIps
}: FormData) => {
try {
if (!identityAuthMethodData) return;
if (!identityId) return;
if (data) {
await updateMutateAsync({
@@ -165,7 +171,7 @@ export const IdentityKubernetesAuthForm = ({
allowedNamespaces,
allowedAudience,
caCert,
identityId: identityAuthMethodData.identityId,
identityId,
accessTokenTTL: Number(accessTokenTTL),
accessTokenMaxTTL: Number(accessTokenMaxTTL),
accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
@@ -174,7 +180,7 @@ export const IdentityKubernetesAuthForm = ({
} else {
await addMutateAsync({
organizationId: orgId,
identityId: identityAuthMethodData.identityId,
identityId,
kubernetesHost: kubernetesHost || "",
tokenReviewerJwt,
allowedNames: allowedNames || "",
@@ -205,7 +211,27 @@ export const IdentityKubernetesAuthForm = ({
};
return (
<form onSubmit={handleSubmit(onFormSubmit)}>
<form
onSubmit={handleSubmit(onFormSubmit, (fields) => {
setTabValue(
[
"kubernetesHost",
"tokenReviewerJwt",
"accessTokenTTL",
"accessTokenMaxTTL",
"accessTokenNumUsesLimit"
].includes(Object.keys(fields)[0])
? IdentityFormTab.Configuration
: IdentityFormTab.Advanced
);
})}
>
<Tabs value={tabValue} onValueChange={(value) => setTabValue(value as IdentityFormTab)}>
<TabList>
<Tab value={IdentityFormTab.Configuration}>Configuration</Tab>
<Tab value={IdentityFormTab.Advanced}>Advanced</Tab>
</TabList>
<TabPanel value={IdentityFormTab.Configuration}>
<Controller
control={control}
defaultValue="2592000"
@@ -237,6 +263,53 @@ export const IdentityKubernetesAuthForm = ({
</FormControl>
)}
/>
<Controller
control={control}
defaultValue="2592000"
name="accessTokenTTL"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Access Token TTL (seconds)"
tooltipText="The lifetime for an acccess token in seconds. This value will be referenced at renewal time."
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}
tooltipText="The maximum lifetime for an access token in seconds. This value will be referenced at renewal time."
>
<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}
tooltipText="The maximum number of times that an access token can be used; a value of 0 implies infinite number of uses."
>
<Input {...field} placeholder="0" type="number" min="0" step="1" />
</FormControl>
)}
/>
</TabPanel>
<TabPanel value={IdentityFormTab.Advanced}>
<Controller
control={control}
name="allowedNames"
@@ -295,51 +368,6 @@ export const IdentityKubernetesAuthForm = ({
</FormControl>
)}
/>
<Controller
control={control}
defaultValue="2592000"
name="accessTokenTTL"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Access Token TTL (seconds)"
tooltipText="The lifetime for an acccess token in seconds. This value will be referenced at renewal time."
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}
tooltipText="The maximum lifetime for an access token in seconds. This value will be referenced at renewal time."
>
<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}
tooltipText="The maximum number of times that an access token can be used; a value of 0 implies infinite number of uses."
>
<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
@@ -409,7 +437,8 @@ export const IdentityKubernetesAuthForm = ({
Add IP Address
</Button>
</div>
<div className="flex justify-between">
</TabPanel>
</Tabs>
<div className="flex items-center">
<Button
className="mr-4"
@@ -418,7 +447,7 @@ export const IdentityKubernetesAuthForm = ({
isLoading={isSubmitting}
isDisabled={isSubmitting}
>
{isUpdate ? "Update" : "Create"}
{isUpdate ? "Update" : "Add"}
</Button>
<Button
@@ -429,7 +458,6 @@ export const IdentityKubernetesAuthForm = ({
Cancel
</Button>
</div>
</div>
</form>
);
};
@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { Controller, useFieldArray, useForm } from "react-hook-form";
import { faQuestionCircle } from "@fortawesome/free-regular-svg-icons";
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
@@ -7,14 +7,26 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import { Button, FormControl, IconButton, Input, TextArea, Tooltip } from "@app/components/v2";
import {
Button,
FormControl,
IconButton,
Input,
Tab,
TabList,
TabPanel,
Tabs,
TextArea,
Tooltip
} from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context";
import { useAddIdentityOidcAuth, useUpdateIdentityOidcAuth } from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { useGetIdentityOidcAuth } from "@app/hooks/api/identities/queries";
import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
import { UsePopUpState } from "@app/hooks/usePopUp";
import { IdentityFormTab } from "./types";
const schema = z.object({
accessTokenTrustedIps: z
.array(
@@ -51,18 +63,15 @@ type Props = {
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
) => void;
identityAuthMethodData: {
identityId: string;
name: string;
configuredAuthMethods?: IdentityAuthMethod[];
authMethod?: IdentityAuthMethod;
};
identityId?: string;
isUpdate?: boolean;
};
export const IdentityOidcAuthForm = ({
handlePopUpOpen,
handlePopUpToggle,
identityAuthMethodData
identityId,
isUpdate
}: Props) => {
const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || "";
@@ -70,11 +79,9 @@ export const IdentityOidcAuthForm = ({
const { mutateAsync: addMutateAsync } = useAddIdentityOidcAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityOidcAuth();
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
const isUpdate = identityAuthMethodData?.configuredAuthMethods?.includes(
identityAuthMethodData.authMethod! || ""
);
const { data } = useGetIdentityOidcAuth(identityAuthMethodData?.identityId ?? "", {
const { data } = useGetIdentityOidcAuth(identityId ?? "", {
enabled: isUpdate
});
@@ -160,13 +167,13 @@ export const IdentityOidcAuthForm = ({
boundSubject
}: FormData) => {
try {
if (!identityAuthMethodData) {
if (!identityId) {
return;
}
if (data) {
await updateMutateAsync({
identityId: identityAuthMethodData.identityId,
identityId,
organizationId: orgId,
oidcDiscoveryUrl,
caCert,
@@ -181,7 +188,7 @@ export const IdentityOidcAuthForm = ({
});
} else {
await addMutateAsync({
identityId: identityAuthMethodData.identityId,
identityId,
oidcDiscoveryUrl,
caCert,
boundIssuer,
@@ -213,7 +220,27 @@ export const IdentityOidcAuthForm = ({
};
return (
<form onSubmit={handleSubmit(onFormSubmit)}>
<form
onSubmit={handleSubmit(onFormSubmit, (fields) => {
setTabValue(
[
"accessTokenTrustedIps",
"caCert",
"boundAudiences",
"boundSubject",
"boundClaims"
].includes(Object.keys(fields)[0])
? IdentityFormTab.Advanced
: IdentityFormTab.Configuration
);
})}
>
<Tabs value={tabValue} onValueChange={(value) => setTabValue(value as IdentityFormTab)}>
<TabList>
<Tab value={IdentityFormTab.Configuration}>Configuration</Tab>
<Tab value={IdentityFormTab.Advanced}>Advanced</Tab>
</TabList>
<TabPanel value={IdentityFormTab.Configuration}>
<Controller
control={control}
name="oidcDiscoveryUrl"
@@ -250,11 +277,59 @@ export const IdentityOidcAuthForm = ({
</FormControl>
)}
/>
<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>
)}
/>
</TabPanel>
<TabPanel value={IdentityFormTab.Advanced}>
<Controller
control={control}
name="caCert"
render={({ field, fieldState: { error } }) => (
<FormControl label="CA Certificate" errorText={error?.message} isError={Boolean(error)}>
<FormControl
label="CA Certificate"
errorText={error?.message}
isError={Boolean(error)}
>
<TextArea {...field} placeholder="-----BEGIN CERTIFICATE----- ..." />
</FormControl>
)}
@@ -380,48 +455,6 @@ export const IdentityOidcAuthForm = ({
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
@@ -490,7 +523,8 @@ export const IdentityOidcAuthForm = ({
Add IP Address
</Button>
</div>
<div className="flex justify-between">
</TabPanel>
</Tabs>
<div className="flex items-center">
<Button
className="mr-4"
@@ -499,7 +533,7 @@ export const IdentityOidcAuthForm = ({
isLoading={isSubmitting}
isDisabled={isSubmitting}
>
{isUpdate ? "Update" : "Create"}
{isUpdate ? "Update" : "Add"}
</Button>
<Button
@@ -510,7 +544,6 @@ export const IdentityOidcAuthForm = ({
Cancel
</Button>
</div>
</div>
</form>
);
};
@@ -1,3 +1,4 @@
import { useEffect, useState } 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";
@@ -5,16 +6,27 @@ 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 {
Button,
FormControl,
IconButton,
Input,
Tab,
TabList,
TabPanel,
Tabs
} from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context";
import {
useAddIdentityTokenAuth,
useGetIdentityTokenAuth,
useUpdateIdentityTokenAuth
} from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
import { UsePopUpState } from "@app/hooks/usePopUp";
import { IdentityFormTab } from "./types";
const schema = z
.object({
accessTokenTTL: z.string().refine((val) => Number(val) <= 315360000, {
@@ -42,18 +54,15 @@ type Props = {
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
) => void;
identityAuthMethodData?: {
identityId: string;
name: string;
configuredAuthMethods?: IdentityAuthMethod[];
authMethod?: IdentityAuthMethod;
};
identityId?: string;
isUpdate?: boolean;
};
export const IdentityTokenAuthForm = ({
handlePopUpOpen,
handlePopUpToggle,
identityAuthMethodData
identityId,
isUpdate
}: Props) => {
const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || "";
@@ -61,12 +70,9 @@ export const IdentityTokenAuthForm = ({
const { mutateAsync: addMutateAsync } = useAddIdentityTokenAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityTokenAuth();
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
const isUpdate = identityAuthMethodData?.configuredAuthMethods?.includes(
identityAuthMethodData.authMethod! || ""
);
const { data } = useGetIdentityTokenAuth(identityAuthMethodData?.identityId ?? "", {
const { data } = useGetIdentityTokenAuth(identityId ?? "", {
enabled: isUpdate
});
@@ -91,6 +97,30 @@ export const IdentityTokenAuthForm = ({
remove: removeAccessTokenTrustedIp
} = useFieldArray({ control, name: "accessTokenTrustedIps" });
useEffect(() => {
if (data) {
reset({
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({
accessTokenTTL: "2592000",
accessTokenMaxTTL: "2592000",
accessTokenNumUsesLimit: "0",
accessTokenTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]
});
}
}, [data]);
const onFormSubmit = async ({
accessTokenTTL,
accessTokenMaxTTL,
@@ -98,12 +128,12 @@ export const IdentityTokenAuthForm = ({
accessTokenTrustedIps
}: FormData) => {
try {
if (!identityAuthMethodData) return;
if (!identityId) return;
if (data) {
await updateMutateAsync({
organizationId: orgId,
identityId: identityAuthMethodData.identityId,
identityId,
accessTokenTTL: Number(accessTokenTTL),
accessTokenMaxTTL: Number(accessTokenMaxTTL),
accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
@@ -112,7 +142,7 @@ export const IdentityTokenAuthForm = ({
} else {
await addMutateAsync({
organizationId: orgId,
identityId: identityAuthMethodData.identityId,
identityId,
accessTokenTTL: Number(accessTokenTTL),
accessTokenMaxTTL: Number(accessTokenMaxTTL),
accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
@@ -137,7 +167,21 @@ export const IdentityTokenAuthForm = ({
};
return (
<form onSubmit={handleSubmit(onFormSubmit)}>
<form
onSubmit={handleSubmit(onFormSubmit, (fields) => {
setTabValue(
["accessTokenTrustedIps"].includes(Object.keys(fields)[0])
? IdentityFormTab.Advanced
: IdentityFormTab.Configuration
);
})}
>
<Tabs value={tabValue} onValueChange={(value) => setTabValue(value as IdentityFormTab)}>
<TabList>
<Tab value={IdentityFormTab.Configuration}>Configuration</Tab>
<Tab value={IdentityFormTab.Advanced}>Advanced</Tab>
</TabList>
<TabPanel value={IdentityFormTab.Configuration}>
<Controller
control={control}
defaultValue="2592000"
@@ -180,6 +224,8 @@ export const IdentityTokenAuthForm = ({
</FormControl>
)}
/>
</TabPanel>
<TabPanel value={IdentityFormTab.Advanced}>
{accessTokenTrustedIpsFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller
@@ -248,7 +294,8 @@ export const IdentityTokenAuthForm = ({
Add IP Address
</Button>
</div>
<div className="flex justify-between">
</TabPanel>
</Tabs>
<div className="flex items-center">
<Button
className="mr-4"
@@ -257,7 +304,7 @@ export const IdentityTokenAuthForm = ({
isLoading={isSubmitting}
isDisabled={isSubmitting}
>
{isUpdate ? "Update" : "Create"}
{isUpdate ? "Update" : "Add"}
</Button>
<Button
@@ -268,7 +315,6 @@ export const IdentityTokenAuthForm = ({
Cancel
</Button>
</div>
</div>
</form>
);
};
@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useState } 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";
@@ -6,17 +6,27 @@ 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 {
Button,
FormControl,
IconButton,
Input,
Tab,
TabList,
TabPanel,
Tabs
} from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context";
import {
useAddIdentityUniversalAuth,
useGetIdentityUniversalAuth,
useUpdateIdentityUniversalAuth
} from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
import { UsePopUpState } from "@app/hooks/usePopUp";
import { IdentityFormTab } from "./types";
const schema = z
.object({
accessTokenTTL: z
@@ -55,30 +65,24 @@ type Props = {
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
) => void;
identityAuthMethodData?: {
identityId: string;
name: string;
configuredAuthMethods?: IdentityAuthMethod[];
authMethod?: IdentityAuthMethod;
};
identityId?: string;
isUpdate?: boolean;
};
export const IdentityUniversalAuthForm = ({
handlePopUpOpen,
handlePopUpToggle,
identityAuthMethodData
identityId,
isUpdate
}: Props) => {
const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || "";
const { subscription } = useSubscription();
const { mutateAsync: addMutateAsync } = useAddIdentityUniversalAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityUniversalAuth();
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
const isUpdate = identityAuthMethodData?.configuredAuthMethods?.includes(
identityAuthMethodData.authMethod! || ""
);
const { data } = useGetIdentityUniversalAuth(identityAuthMethodData?.identityId ?? "", {
const { data } = useGetIdentityUniversalAuth(identityId ?? "", {
enabled: isUpdate
});
@@ -149,13 +153,13 @@ export const IdentityUniversalAuthForm = ({
accessTokenTrustedIps
}: FormData) => {
try {
if (!identityAuthMethodData) return;
if (!identityId) return;
if (data) {
// update universal auth configuration
await updateMutateAsync({
organizationId: orgId,
identityId: identityAuthMethodData.identityId,
identityId,
clientSecretTrustedIps,
accessTokenTTL: Number(accessTokenTTL),
accessTokenMaxTTL: Number(accessTokenMaxTTL),
@@ -167,7 +171,7 @@ export const IdentityUniversalAuthForm = ({
await addMutateAsync({
organizationId: orgId,
identityId: identityAuthMethodData.identityId,
identityId,
clientSecretTrustedIps,
accessTokenTTL: Number(accessTokenTTL),
accessTokenMaxTTL: Number(accessTokenMaxTTL),
@@ -195,7 +199,21 @@ export const IdentityUniversalAuthForm = ({
};
return (
<form onSubmit={handleSubmit(onFormSubmit)}>
<form
onSubmit={handleSubmit(onFormSubmit, (fields) => {
setTabValue(
["accessTokenTrustedIps", "clientSecretTrustedIps"].includes(Object.keys(fields)[0])
? IdentityFormTab.Advanced
: IdentityFormTab.Configuration
);
})}
>
<Tabs value={tabValue} onValueChange={(value) => setTabValue(value as IdentityFormTab)}>
<TabList>
<Tab value={IdentityFormTab.Configuration}>Configuration</Tab>
<Tab value={IdentityFormTab.Advanced}>Advanced</Tab>
</TabList>
<TabPanel value={IdentityFormTab.Configuration}>
<Controller
control={control}
defaultValue="2592000"
@@ -238,6 +256,8 @@ export const IdentityUniversalAuthForm = ({
</FormControl>
)}
/>
</TabPanel>
<TabPanel value={IdentityFormTab.Advanced}>
{clientSecretTrustedIpsFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller
@@ -374,7 +394,8 @@ export const IdentityUniversalAuthForm = ({
Add IP Address
</Button>
</div>
<div className="flex justify-between">
</TabPanel>
</Tabs>
<div className="flex items-center">
<Button
className="mr-4"
@@ -383,7 +404,7 @@ export const IdentityUniversalAuthForm = ({
isLoading={isSubmitting}
isDisabled={isSubmitting}
>
{isUpdate ? "Edit" : "Create"}
{isUpdate ? "Update" : "Add"}
</Button>
<Button
colorSchema="secondary"
@@ -393,7 +414,6 @@ export const IdentityUniversalAuthForm = ({
Cancel
</Button>
</div>
</div>
</form>
);
};
@@ -0,0 +1,4 @@
export enum IdentityFormTab {
Advanced = "advanced",
Configuration = "configuration"
}
@@ -201,14 +201,6 @@ const Page = () => {
onOpenChange={(isOpen) => handlePopUpToggle("viewAuthMethod", isOpen)}
authMethod={popUp.viewAuthMethod.data}
identityId={identityId}
onEditAuthMethod={(authMethod) =>
handlePopUpOpen("identityAuthMethod", {
identityId,
name: data?.identity.name,
allAuthMethods: data?.identity.authMethods,
authMethod
})
}
/>
</div>
);
@@ -9,11 +9,11 @@ type Props = {
export const IdentityAuthFieldDisplay = ({ label, children, className }: Props) => {
return (
<div className={className}>
<span className="text-xs font-medium text-mineshaft-400">{label}</span>
<span className="text-sm text-mineshaft-400">{label}</span>
{children ? (
<p className="break-words text-sm leading-4">{children}</p>
<p className="break-words text-base leading-4">{children}</p>
) : (
<p className="text-sm italic leading-4 text-bunker-400">Not set</p>
<p className="text-base italic leading-4 text-bunker-400">Not set</p>
)}
</div>
);
@@ -75,8 +75,8 @@ export const IdentityTokenAuthTokensTable = ({ tokens, identityId }: Props) => {
return (
<div className="col-span-2 mt-3">
<div className="flex items-baseline justify-between border-b border-mineshaft-500 pb-1">
<span className="text-sm text-bunker-300">Access Tokens</span>
<div className="flex items-end justify-between border-b border-mineshaft-500 pb-2">
<span className="text-bunker-300">Access Tokens</span>
<Button
size="xs"
onClick={() => {
@@ -64,8 +64,8 @@ export const IdentityUniversalAuthClientSecretsTable = ({ clientSecrets, identit
return (
<div className="col-span-2">
<div className="flex items-baseline justify-between border-b border-mineshaft-500 pb-1">
<span className="text-sm text-bunker-300">Client Secrets</span>
<div className="flex items-end justify-between border-b border-mineshaft-500 pb-2">
<span className="text-bunker-300">Client Secrets</span>
<Button
size="xs"
onClick={() => {
@@ -1,3 +1,4 @@
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
import { createNotification } from "@app/components/notifications";
import { DeleteActionModal, Modal, ModalContent } from "@app/components/v2";
import { useOrganization } from "@app/context";
@@ -30,7 +31,6 @@ type Props = {
authMethod?: IdentityAuthMethod;
isOpen: boolean;
onOpenChange: (isOpen: boolean) => void;
onEditAuthMethod: (authMethod: IdentityAuthMethod) => void;
onDeleteAuthMethod: () => void;
};
@@ -42,13 +42,16 @@ type TRevokeOptions = {
export const Content = ({
identityId,
authMethod,
onEditAuthMethod,
onDeleteAuthMethod
}: Pick<Props, "authMethod" | "identityId" | "onEditAuthMethod" | "onDeleteAuthMethod">) => {
}: Pick<Props, "authMethod" | "identityId" | "onDeleteAuthMethod">) => {
const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || "";
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["revokeAuthMethod"] as const);
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp([
"revokeAuthMethod",
"upgradePlan",
"identityAuthMethod"
] as const);
const { mutateAsync: revokeUniversalAuth } = useDeleteIdentityUniversalAuth();
const { mutateAsync: revokeTokenAuth } = useDeleteIdentityTokenAuth();
@@ -128,7 +131,9 @@ export const Content = ({
<Component
identityId={identityId}
onDelete={handleDelete}
onEdit={() => onEditAuthMethod(authMethod)}
popUp={popUp}
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
<DeleteActionModal
isOpen={popUp?.revokeAuthMethod?.isOpen}
@@ -138,6 +143,11 @@ export const Content = ({
buttonText="Remove"
onDeleteApproved={handleDeleteAuthMethod}
/>
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text={(popUp.upgradePlan?.data as { description: string })?.description}
/>
</>
);
};
@@ -146,8 +156,7 @@ export const ViewIdentityAuthModal = ({
isOpen,
onOpenChange,
authMethod,
identityId,
onEditAuthMethod
identityId
}: Omit<Props, "onDeleteAuthMethod">) => {
if (!identityId || !authMethod) return null;
@@ -157,7 +166,6 @@ export const ViewIdentityAuthModal = ({
<Content
identityId={identityId}
authMethod={authMethod}
onEditAuthMethod={onEditAuthMethod}
onDeleteAuthMethod={() => onOpenChange(false)}
/>
</ModalContent>
@@ -2,6 +2,7 @@ import { faBan } from "@fortawesome/free-solid-svg-icons";
import { EmptyState, Spinner } from "@app/components/v2";
import { useGetIdentityAwsAuth } from "@app/hooks/api";
import { IdentityAwsAuthForm } from "@app/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAwsAuthForm";
import { IdentityAuthFieldDisplay } from "./IdentityAuthFieldDisplay";
import { ViewAuthMethodProps } from "./types";
@@ -9,8 +10,10 @@ import { ViewIdentityContentWrapper } from "./ViewIdentityContentWrapper";
export const ViewIdentityAwsAuthContent = ({
identityId,
onEdit,
onDelete
handlePopUpToggle,
handlePopUpOpen,
onDelete,
popUp
}: ViewAuthMethodProps) => {
const { data, isPending } = useGetIdentityAwsAuth(identityId);
@@ -28,8 +31,34 @@ export const ViewIdentityAwsAuthContent = ({
);
}
if (popUp.identityAuthMethod.isOpen) {
return (
<ViewIdentityContentWrapper onEdit={onEdit} onDelete={onDelete}>
<IdentityAwsAuthForm
identityId={identityId}
isUpdate
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
);
}
return (
<ViewIdentityContentWrapper
onEdit={() => handlePopUpOpen("identityAuthMethod")}
onDelete={onDelete}
>
<IdentityAuthFieldDisplay label="Access Token TLL (seconds)">
{data.accessTokenTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max TLL (seconds)">
{data.accessTokenMaxTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max Number of Uses">
{data.accessTokenNumUsesLimit}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Trusted IPs">
{data.accessTokenTrustedIps.map((ip) => ip.ipAddress).join(", ")}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay className="col-span-2" label="Allowed Principal ARNs">
{data.allowedPrincipalArns
?.split(",")
@@ -45,18 +74,6 @@ export const ViewIdentityAwsAuthContent = ({
<IdentityAuthFieldDisplay className="col-span-2" label="STS Endpoint">
{data.stsEndpoint}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token TLL (seconds)">
{data.accessTokenTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max TLL (seconds)">
{data.accessTokenMaxTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max Number of Uses">
{data.accessTokenNumUsesLimit}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Trusted IPs">
{data.accessTokenTrustedIps.map((ip) => ip.ipAddress).join(", ")}
</IdentityAuthFieldDisplay>
</ViewIdentityContentWrapper>
);
};
@@ -2,6 +2,7 @@ import { faBan } from "@fortawesome/free-solid-svg-icons";
import { EmptyState, Spinner } from "@app/components/v2";
import { useGetIdentityAzureAuth } from "@app/hooks/api";
import { IdentityAzureAuthForm } from "@app/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAzureAuthForm";
import { IdentityAuthFieldDisplay } from "./IdentityAuthFieldDisplay";
import { ViewAuthMethodProps } from "./types";
@@ -9,8 +10,10 @@ import { ViewIdentityContentWrapper } from "./ViewIdentityContentWrapper";
export const ViewIdentityAzureAuthContent = ({
identityId,
onEdit,
onDelete
handlePopUpToggle,
handlePopUpOpen,
onDelete,
popUp
}: ViewAuthMethodProps) => {
const { data, isPending } = useGetIdentityAzureAuth(identityId);
@@ -28,20 +31,22 @@ export const ViewIdentityAzureAuthContent = ({
);
}
if (popUp.identityAuthMethod.isOpen) {
return (
<ViewIdentityContentWrapper onEdit={onEdit} onDelete={onDelete}>
<IdentityAuthFieldDisplay className="col-span-2" label="Tenant ID">
{data.tenantId}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay className="col-span-2" label="Resource / Audience">
{data.resource}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay className="col-span-2" label="Allowed Service Principal IDs">
{data.allowedServicePrincipalIds
?.split(",")
.map((id) => id.trim())
.join(", ")}
</IdentityAuthFieldDisplay>
<IdentityAzureAuthForm
identityId={identityId}
isUpdate
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
);
}
return (
<ViewIdentityContentWrapper
onEdit={() => handlePopUpOpen("identityAuthMethod")}
onDelete={onDelete}
>
<IdentityAuthFieldDisplay label="Access Token TLL (seconds)">
{data.accessTokenTTL}
</IdentityAuthFieldDisplay>
@@ -54,6 +59,18 @@ export const ViewIdentityAzureAuthContent = ({
<IdentityAuthFieldDisplay label="Access Token Trusted IPs">
{data.accessTokenTrustedIps.map((ip) => ip.ipAddress).join(", ")}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay className="col-span-2" label="Tenant ID">
{data.tenantId}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay className="col-span-2" label="Resource / Audience">
{data.resource}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay className="col-span-2" label="Allowed Service Principal IDs">
{data.allowedServicePrincipalIds
?.split(",")
.map((id) => id.trim())
.join(", ")}
</IdentityAuthFieldDisplay>
</ViewIdentityContentWrapper>
);
};
@@ -1,8 +1,14 @@
import { ReactNode } from "react";
import { faEdit, faTrash } from "@fortawesome/free-solid-svg-icons";
import { faChevronDown, faEdit, faTrash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Button } from "@app/components/v2";
import {
Button,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger
} from "@app/components/v2";
type Props = {
children: ReactNode;
@@ -14,25 +20,28 @@ export const ViewIdentityContentWrapper = ({ children, onDelete, onEdit }: Props
return (
<div className="flex flex-col gap-4">
<div>
<div className="flex items-baseline justify-between border-b border-mineshaft-500 pb-1">
<span className="text-sm text-bunker-300">Details</span>
<div className="flex items-end justify-between border-b border-mineshaft-500 pb-2">
<span className="text-bunker-300">Details</span>
<div className="flex items-center gap-2">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size="xs"
onClick={onEdit}
leftIcon={<FontAwesomeIcon icon={faEdit} />}
rightIcon={<FontAwesomeIcon className="ml-1" icon={faChevronDown} />}
colorSchema="secondary"
>
Options
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="min-w-[120px]" align="end">
<DropdownMenuItem onClick={onEdit} icon={<FontAwesomeIcon icon={faEdit} />}>
Edit
</Button>
<Button
size="xs"
onClick={onDelete}
leftIcon={<FontAwesomeIcon icon={faTrash} />}
colorSchema="danger"
>
</DropdownMenuItem>
<DropdownMenuItem onClick={onDelete} icon={<FontAwesomeIcon icon={faTrash} />}>
Delete
</Button>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
<div className="mt-3 grid grid-cols-2 gap-3">{children}</div>
@@ -2,6 +2,7 @@ import { faBan } from "@fortawesome/free-solid-svg-icons";
import { EmptyState, Spinner } from "@app/components/v2";
import { useGetIdentityGcpAuth } from "@app/hooks/api";
import { IdentityGcpAuthForm } from "@app/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityGcpAuthForm";
import { IdentityAuthFieldDisplay } from "./IdentityAuthFieldDisplay";
import { ViewAuthMethodProps } from "./types";
@@ -9,8 +10,10 @@ import { ViewIdentityContentWrapper } from "./ViewIdentityContentWrapper";
export const ViewIdentityGcpAuthContent = ({
identityId,
onEdit,
onDelete
handlePopUpToggle,
handlePopUpOpen,
onDelete,
popUp
}: ViewAuthMethodProps) => {
const { data, isPending } = useGetIdentityGcpAuth(identityId);
@@ -28,8 +31,34 @@ export const ViewIdentityGcpAuthContent = ({
);
}
if (popUp.identityAuthMethod.isOpen) {
return (
<ViewIdentityContentWrapper onEdit={onEdit} onDelete={onDelete}>
<IdentityGcpAuthForm
identityId={identityId}
isUpdate
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
);
}
return (
<ViewIdentityContentWrapper
onEdit={() => handlePopUpOpen("identityAuthMethod")}
onDelete={onDelete}
>
<IdentityAuthFieldDisplay label="Access Token TLL (seconds)">
{data.accessTokenTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max TLL (seconds)">
{data.accessTokenMaxTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max Number of Uses">
{data.accessTokenNumUsesLimit}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Trusted IPs">
{data.accessTokenTrustedIps.map((ip) => ip.ipAddress).join(", ")}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Type">
{data.type === "gce" ? "GCP ID Token Auth" : "GCP IAM Auth"}
</IdentityAuthFieldDisplay>
@@ -55,18 +84,6 @@ export const ViewIdentityGcpAuthContent = ({
</IdentityAuthFieldDisplay>
</>
)}
<IdentityAuthFieldDisplay label="Access Token TLL (seconds)">
{data.accessTokenTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max TLL (seconds)">
{data.accessTokenMaxTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max Number of Uses">
{data.accessTokenNumUsesLimit}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Trusted IPs">
{data.accessTokenTrustedIps.map((ip) => ip.ipAddress).join(", ")}
</IdentityAuthFieldDisplay>
</ViewIdentityContentWrapper>
);
};
@@ -4,6 +4,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Badge, EmptyState, Spinner, Tooltip } from "@app/components/v2";
import { useGetIdentityJwtAuth } from "@app/hooks/api";
import { IdentityJwtConfigurationType } from "@app/hooks/api/identities/enums";
import { IdentityJwtAuthForm } from "@app/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityJwtAuthForm";
import { ViewIdentityContentWrapper } from "@app/pages/organization/IdentityDetailsByIDPage/components/ViewIdentityAuthModal/ViewIdentityContentWrapper";
import { IdentityAuthFieldDisplay } from "./IdentityAuthFieldDisplay";
@@ -11,8 +12,10 @@ import { ViewAuthMethodProps } from "./types";
export const ViewIdentityJwtAuthContent = ({
identityId,
onEdit,
onDelete
handlePopUpToggle,
handlePopUpOpen,
onDelete,
popUp
}: ViewAuthMethodProps) => {
const { data, isPending } = useGetIdentityJwtAuth(identityId);
@@ -30,14 +33,44 @@ export const ViewIdentityJwtAuthContent = ({
);
}
if (popUp.identityAuthMethod.isOpen) {
return (
<ViewIdentityContentWrapper onEdit={onEdit} onDelete={onDelete}>
<IdentityJwtAuthForm
identityId={identityId}
isUpdate
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
);
}
return (
<ViewIdentityContentWrapper
onEdit={() => handlePopUpOpen("identityAuthMethod")}
onDelete={onDelete}
>
<IdentityAuthFieldDisplay label="Access Token TLL (seconds)">
{data.accessTokenTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max TLL (seconds)">
{data.accessTokenMaxTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max Number of Uses">
{data.accessTokenNumUsesLimit}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Trusted IPs">
{data.accessTokenTrustedIps.map((ip) => ip.ipAddress).join(", ")}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Configuration Type">
{data.configurationType === IdentityJwtConfigurationType.JWKS ? "JWKS" : "Static"}
</IdentityAuthFieldDisplay>
{data.configurationType === IdentityJwtConfigurationType.JWKS ? (
<>
<IdentityAuthFieldDisplay className="col-span-2" label="JWKS URL">
{data.jwksUrl}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay className="col-span-2" label="JWKS CA Certificate">
{data.jwksCaCert && (
<Tooltip
side="right"
className="max-w-xl p-2"
@@ -52,16 +85,14 @@ export const ViewIdentityJwtAuthContent = ({
</Badge>
</div>
</Tooltip>
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay className="col-span-2" label="JWKS URL">
{data.jwksUrl}
)}
</IdentityAuthFieldDisplay>
</>
) : (
<IdentityAuthFieldDisplay className="col-span-2" label="Public Keys">
{data.publicKeys.length && (
<div className="flex flex-wrap gap-1">
{data.publicKeys.length &&
data.publicKeys.map((key, index) => (
{data.publicKeys.map((key, index) => (
<Tooltip
side="right"
className="max-w-xl p-2"
@@ -81,6 +112,7 @@ export const ViewIdentityJwtAuthContent = ({
</Tooltip>
))}
</div>
)}
</IdentityAuthFieldDisplay>
)}
<IdentityAuthFieldDisplay className="col-span-2" label="Issuer">
@@ -115,18 +147,6 @@ export const ViewIdentityJwtAuthContent = ({
</Tooltip>
)}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token TLL (seconds)">
{data.accessTokenTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max TLL (seconds)">
{data.accessTokenMaxTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max Number of Uses">
{data.accessTokenNumUsesLimit}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Trusted IPs">
{data.accessTokenTrustedIps.map((ip) => ip.ipAddress).join(", ")}
</IdentityAuthFieldDisplay>
</ViewIdentityContentWrapper>
);
};
@@ -3,6 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Badge, EmptyState, Spinner, Tooltip } from "@app/components/v2";
import { useGetIdentityKubernetesAuth } from "@app/hooks/api";
import { IdentityKubernetesAuthForm } from "@app/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm";
import { IdentityAuthFieldDisplay } from "./IdentityAuthFieldDisplay";
import { ViewAuthMethodProps } from "./types";
@@ -10,8 +11,10 @@ import { ViewIdentityContentWrapper } from "./ViewIdentityContentWrapper";
export const ViewIdentityKubernetesAuthContent = ({
identityId,
onEdit,
onDelete
handlePopUpToggle,
handlePopUpOpen,
onDelete,
popUp
}: ViewAuthMethodProps) => {
const { data, isPending } = useGetIdentityKubernetesAuth(identityId);
@@ -32,8 +35,34 @@ export const ViewIdentityKubernetesAuthContent = ({
);
}
if (popUp.identityAuthMethod.isOpen) {
return (
<ViewIdentityContentWrapper onEdit={onEdit} onDelete={onDelete}>
<IdentityKubernetesAuthForm
identityId={identityId}
isUpdate
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
);
}
return (
<ViewIdentityContentWrapper
onEdit={() => handlePopUpOpen("identityAuthMethod")}
onDelete={onDelete}
>
<IdentityAuthFieldDisplay label="Access Token TLL (seconds)">
{data.accessTokenTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max TLL (seconds)">
{data.accessTokenMaxTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max Number of Uses">
{data.accessTokenNumUsesLimit}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Trusted IPs">
{data.accessTokenTrustedIps.map((ip) => ip.ipAddress).join(", ")}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay
className="col-span-2"
label="Kubernetes Host / Base Kubernetes API URL"
@@ -72,6 +101,7 @@ export const ViewIdentityKubernetesAuthContent = ({
{data.allowedAudience}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay className="col-span-2" label="CA Certificate">
{data.caCert && (
<Tooltip
side="right"
className="max-w-xl p-2"
@@ -84,18 +114,7 @@ export const ViewIdentityKubernetesAuthContent = ({
</Badge>
</div>
</Tooltip>
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token TLL (seconds)">
{data.accessTokenTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max TLL (seconds)">
{data.accessTokenMaxTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max Number of Uses">
{data.accessTokenNumUsesLimit}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Trusted IPs">
{data.accessTokenTrustedIps.map((ip) => ip.ipAddress).join(", ")}
)}
</IdentityAuthFieldDisplay>
</ViewIdentityContentWrapper>
);
@@ -3,6 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Badge, EmptyState, Spinner, Tooltip } from "@app/components/v2";
import { useGetIdentityOidcAuth } from "@app/hooks/api";
import { IdentityOidcAuthForm } from "@app/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityOidcAuthForm";
import { ViewIdentityContentWrapper } from "@app/pages/organization/IdentityDetailsByIDPage/components/ViewIdentityAuthModal/ViewIdentityContentWrapper";
import { IdentityAuthFieldDisplay } from "./IdentityAuthFieldDisplay";
@@ -10,8 +11,10 @@ import { ViewAuthMethodProps } from "./types";
export const ViewIdentityOidcAuthContent = ({
identityId,
onEdit,
onDelete
handlePopUpToggle,
handlePopUpOpen,
onDelete,
popUp
}: ViewAuthMethodProps) => {
const { data, isPending } = useGetIdentityOidcAuth(identityId);
@@ -29,8 +32,34 @@ export const ViewIdentityOidcAuthContent = ({
);
}
if (popUp.identityAuthMethod.isOpen) {
return (
<ViewIdentityContentWrapper onEdit={onEdit} onDelete={onDelete}>
<IdentityOidcAuthForm
identityId={identityId}
isUpdate
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
);
}
return (
<ViewIdentityContentWrapper
onEdit={() => handlePopUpOpen("identityAuthMethod")}
onDelete={onDelete}
>
<IdentityAuthFieldDisplay label="Access Token TLL (seconds)">
{data.accessTokenTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max TLL (seconds)">
{data.accessTokenMaxTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max Number of Uses">
{data.accessTokenNumUsesLimit}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Trusted IPs">
{data.accessTokenTrustedIps.map((ip) => ip.ipAddress).join(", ")}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay className="col-span-2" label="OIDC Discovery URL">
{data.oidcDiscoveryUrl}
</IdentityAuthFieldDisplay>
@@ -38,6 +67,7 @@ export const ViewIdentityOidcAuthContent = ({
{data.boundIssuer}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay className="col-span-2" label="CA Certificate">
{data.caCert && (
<Tooltip
side="right"
className="max-w-xl p-2"
@@ -50,6 +80,7 @@ export const ViewIdentityOidcAuthContent = ({
</Badge>
</div>
</Tooltip>
)}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay className="col-span-2" label="Subject">
{data.boundSubject}
@@ -80,18 +111,6 @@ export const ViewIdentityOidcAuthContent = ({
</Tooltip>
)}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token TLL (seconds)">
{data.accessTokenTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max TLL (seconds)">
{data.accessTokenMaxTTL}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Max Number of Uses">
{data.accessTokenNumUsesLimit}
</IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay label="Access Token Trusted IPs">
{data.accessTokenTrustedIps.map((ip) => ip.ipAddress).join(", ")}
</IdentityAuthFieldDisplay>
</ViewIdentityContentWrapper>
);
};
@@ -2,6 +2,7 @@ import { faBan } from "@fortawesome/free-solid-svg-icons";
import { EmptyState, Spinner } from "@app/components/v2";
import { useGetIdentityTokenAuth, useGetIdentityTokensTokenAuth } from "@app/hooks/api";
import { IdentityTokenAuthForm } from "@app/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityTokenAuthForm";
import { IdentityAuthFieldDisplay } from "./IdentityAuthFieldDisplay";
import { IdentityTokenAuthTokensTable } from "./IdentityTokenAuthTokensTable";
@@ -10,8 +11,10 @@ import { ViewIdentityContentWrapper } from "./ViewIdentityContentWrapper";
export const ViewIdentityTokenAuthContent = ({
identityId,
onEdit,
onDelete
handlePopUpToggle,
handlePopUpOpen,
onDelete,
popUp
}: ViewAuthMethodProps) => {
const { data, isPending } = useGetIdentityTokenAuth(identityId);
const { data: tokens = [], isPending: clientSecretsPending } =
@@ -31,8 +34,22 @@ export const ViewIdentityTokenAuthContent = ({
);
}
if (popUp.identityAuthMethod.isOpen) {
return (
<ViewIdentityContentWrapper onEdit={onEdit} onDelete={onDelete}>
<IdentityTokenAuthForm
identityId={identityId}
isUpdate
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
);
}
return (
<ViewIdentityContentWrapper
onEdit={() => handlePopUpOpen("identityAuthMethod")}
onDelete={onDelete}
>
<IdentityAuthFieldDisplay label="Access Token TLL (seconds)">
{data.accessTokenTTL}
</IdentityAuthFieldDisplay>
@@ -7,6 +7,7 @@ import {
useGetIdentityUniversalAuth,
useGetIdentityUniversalAuthClientSecrets
} from "@app/hooks/api";
import { IdentityUniversalAuthForm } from "@app/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityUniversalAuthForm";
import { IdentityAuthFieldDisplay } from "./IdentityAuthFieldDisplay";
import { IdentityUniversalAuthClientSecretsTable } from "./IdentityUniversalAuthClientSecretsTable";
@@ -15,8 +16,10 @@ import { ViewIdentityContentWrapper } from "./ViewIdentityContentWrapper";
export const ViewIdentityUniversalAuthContent = ({
identityId,
onEdit,
onDelete
handlePopUpToggle,
handlePopUpOpen,
onDelete,
popUp
}: ViewAuthMethodProps) => {
const { data, isPending } = useGetIdentityUniversalAuth(identityId);
const { data: clientSecrets = [], isPending: clientSecretsPending } =
@@ -43,8 +46,22 @@ export const ViewIdentityUniversalAuthContent = ({
);
}
if (popUp.identityAuthMethod.isOpen) {
return (
<ViewIdentityContentWrapper onEdit={onEdit} onDelete={onDelete}>
<IdentityUniversalAuthForm
identityId={identityId}
isUpdate
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
/>
);
}
return (
<ViewIdentityContentWrapper
onEdit={() => handlePopUpOpen("identityAuthMethod")}
onDelete={onDelete}
>
<IdentityAuthFieldDisplay label="Access Token TLL (seconds)">
{data.accessTokenTTL}
</IdentityAuthFieldDisplay>
@@ -61,8 +78,8 @@ export const ViewIdentityUniversalAuthContent = ({
{data.clientSecretTrustedIps.map((ip) => ip.ipAddress).join(", ")}
</IdentityAuthFieldDisplay>
<div className="col-span-2 my-3">
<div className="mb-2 border-b border-mineshaft-500">
<span className="text-sm text-bunker-300">Client ID</span>
<div className="mb-3 border-b border-mineshaft-500 pb-2">
<span className="text-bunker-300">Client ID</span>
</div>
<div className="flex items-center gap-2">
<span className="text-sm">{data.clientId}</span>
@@ -1,5 +1,12 @@
import { UsePopUpState } from "@app/hooks/usePopUp";
export type ViewAuthMethodProps = {
identityId: string;
onEdit: () => void;
onDelete: () => void;
handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan", "identityAuthMethod"]>) => void;
handlePopUpToggle: (
popUpName: keyof UsePopUpState<["identityAuthMethod"]>,
state?: boolean
) => void;
popUp: UsePopUpState<["revokeAuthMethod", "upgradePlan", "identityAuthMethod"]>;
};