feat: updated form for oidc auth

This commit is contained in:
=
2025-03-14 22:11:23 +05:30
parent 1da5a5f417
commit 0f31fa3128
7 changed files with 139 additions and 5 deletions
+1 -1
View File
@@ -1,6 +1,7 @@
import { useInfiniteQuery, useQuery, UseQueryOptions } from "@tanstack/react-query"; import { useInfiniteQuery, useQuery, UseQueryOptions } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request"; import { apiRequest } from "@app/config/request";
import { Identity } from "@app/hooks/api/identities/types";
import { User } from "../types"; import { User } from "../types";
import { import {
@@ -10,7 +11,6 @@ import {
TGetServerRootKmsEncryptionDetails, TGetServerRootKmsEncryptionDetails,
TServerConfig TServerConfig
} from "./types"; } from "./types";
import { Identity } from "@app/hooks/api/identities/types";
export const adminStandaloneKeys = { export const adminStandaloneKeys = {
getUsers: "get-users", getUsers: "get-users",
@@ -462,6 +462,7 @@ export const useUpdateIdentityOidcAuth = () => {
boundIssuer, boundIssuer,
boundAudiences, boundAudiences,
boundClaims, boundClaims,
claimMetadataMapping,
boundSubject boundSubject
}) => { }) => {
const { const {
@@ -478,7 +479,8 @@ export const useUpdateIdentityOidcAuth = () => {
accessTokenTTL, accessTokenTTL,
accessTokenMaxTTL, accessTokenMaxTTL,
accessTokenNumUsesLimit, accessTokenNumUsesLimit,
accessTokenTrustedIps accessTokenTrustedIps,
claimMetadataMapping
} }
); );
@@ -504,6 +506,7 @@ export const useAddIdentityOidcAuth = () => {
boundIssuer, boundIssuer,
boundAudiences, boundAudiences,
boundClaims, boundClaims,
claimMetadataMapping,
boundSubject, boundSubject,
accessTokenTTL, accessTokenTTL,
accessTokenMaxTTL, accessTokenMaxTTL,
@@ -524,7 +527,8 @@ export const useAddIdentityOidcAuth = () => {
accessTokenTTL, accessTokenTTL,
accessTokenMaxTTL, accessTokenMaxTTL,
accessTokenNumUsesLimit, accessTokenNumUsesLimit,
accessTokenTrustedIps accessTokenTrustedIps,
claimMetadataMapping
} }
); );
@@ -193,6 +193,7 @@ export type IdentityOidcAuth = {
boundIssuer: string; boundIssuer: string;
boundAudiences: string; boundAudiences: string;
boundClaims: Record<string, string>; boundClaims: Record<string, string>;
claimMetadataMapping: Record<string, string>;
boundSubject: string; boundSubject: string;
accessTokenTTL: number; accessTokenTTL: number;
accessTokenMaxTTL: number; accessTokenMaxTTL: number;
@@ -208,6 +209,7 @@ export type AddIdentityOidcAuthDTO = {
boundIssuer: string; boundIssuer: string;
boundAudiences: string; boundAudiences: string;
boundClaims: Record<string, string>; boundClaims: Record<string, string>;
claimMetadataMapping: Record<string, string>;
boundSubject: string; boundSubject: string;
accessTokenTTL: number; accessTokenTTL: number;
accessTokenMaxTTL: number; accessTokenMaxTTL: number;
@@ -225,6 +227,7 @@ export type UpdateIdentityOidcAuthDTO = {
boundIssuer?: string; boundIssuer?: string;
boundAudiences?: string; boundAudiences?: string;
boundClaims?: Record<string, string>; boundClaims?: Record<string, string>;
claimMetadataMapping?: Record<string, string>;
boundSubject?: string; boundSubject?: string;
accessTokenTTL?: number; accessTokenTTL?: number;
accessTokenMaxTTL?: number; accessTokenMaxTTL?: number;
@@ -28,13 +28,13 @@ import {
useGetServerRootKmsEncryptionDetails, useGetServerRootKmsEncryptionDetails,
useUpdateServerConfig useUpdateServerConfig
} from "@app/hooks/api"; } from "@app/hooks/api";
import { IdentityPanel } from "@app/pages/admin/OverviewPage/components/IdentityPanel";
import { AuthPanel } from "./components/AuthPanel"; import { AuthPanel } from "./components/AuthPanel";
import { EncryptionPanel } from "./components/EncryptionPanel"; import { EncryptionPanel } from "./components/EncryptionPanel";
import { IntegrationPanel } from "./components/IntegrationPanel"; import { IntegrationPanel } from "./components/IntegrationPanel";
import { RateLimitPanel } from "./components/RateLimitPanel"; import { RateLimitPanel } from "./components/RateLimitPanel";
import { UserPanel } from "./components/UserPanel"; import { UserPanel } from "./components/UserPanel";
import { IdentityPanel } from "@app/pages/admin/OverviewPage/components/IdentityPanel";
enum TabSections { enum TabSections {
Settings = "settings", Settings = "settings",
@@ -52,6 +52,12 @@ const schema = z.object({
value: z.string() value: z.string()
}) })
), ),
claimMetadataMapping: z.array(
z.object({
key: z.string(),
value: z.string()
})
),
boundSubject: z.string().optional().default("") boundSubject: z.string().optional().default("")
}); });
@@ -109,6 +115,15 @@ export const IdentityOidcAuthForm = ({
name: "boundClaims" name: "boundClaims"
}); });
const {
fields: claimMetadataMappingFields,
append: appendClaimMetadataMappingField,
remove: removeClaimMetadataMappingField
} = useFieldArray({
control,
name: "claimMetadataMapping"
});
const { const {
fields: accessTokenTrustedIpsFields, fields: accessTokenTrustedIpsFields,
append: appendAccessTokenTrustedIp, append: appendAccessTokenTrustedIp,
@@ -126,6 +141,10 @@ export const IdentityOidcAuthForm = ({
key, key,
value value
})), })),
claimMetadataMapping: Object.entries(data.claimMetadataMapping).map(([key, value]) => ({
key,
value
})),
boundSubject: data.boundSubject, boundSubject: data.boundSubject,
accessTokenTTL: String(data.accessTokenTTL), accessTokenTTL: String(data.accessTokenTTL),
accessTokenMaxTTL: String(data.accessTokenMaxTTL), accessTokenMaxTTL: String(data.accessTokenMaxTTL),
@@ -164,6 +183,7 @@ export const IdentityOidcAuthForm = ({
boundIssuer, boundIssuer,
boundAudiences, boundAudiences,
boundClaims, boundClaims,
claimMetadataMapping,
boundSubject boundSubject
}: FormData) => { }: FormData) => {
try { try {
@@ -180,6 +200,9 @@ export const IdentityOidcAuthForm = ({
boundIssuer, boundIssuer,
boundAudiences, boundAudiences,
boundClaims: Object.fromEntries(boundClaims.map((entry) => [entry.key, entry.value])), boundClaims: Object.fromEntries(boundClaims.map((entry) => [entry.key, entry.value])),
claimMetadataMapping: Object.fromEntries(
claimMetadataMapping.map((entry) => [entry.key, entry.value])
),
boundSubject, boundSubject,
accessTokenTTL: Number(accessTokenTTL), accessTokenTTL: Number(accessTokenTTL),
accessTokenMaxTTL: Number(accessTokenMaxTTL), accessTokenMaxTTL: Number(accessTokenMaxTTL),
@@ -194,6 +217,9 @@ export const IdentityOidcAuthForm = ({
boundIssuer, boundIssuer,
boundAudiences, boundAudiences,
boundClaims: Object.fromEntries(boundClaims.map((entry) => [entry.key, entry.value])), boundClaims: Object.fromEntries(boundClaims.map((entry) => [entry.key, entry.value])),
claimMetadataMapping: Object.fromEntries(
claimMetadataMapping.map((entry) => [entry.key, entry.value])
),
boundSubject, boundSubject,
organizationId: orgId, organizationId: orgId,
accessTokenTTL: Number(accessTokenTTL), accessTokenTTL: Number(accessTokenTTL),
@@ -449,6 +475,84 @@ export const IdentityOidcAuthForm = ({
Add Claims Add Claims
</Button> </Button>
</div> </div>
{claimMetadataMappingFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller
control={control}
name={`claimMetadataMapping.${index}.key`}
render={({ field, fieldState: { error } }) => {
return (
<FormControl
className="mb-0 flex-grow"
label={index === 0 ? "Claim Metadata Mapping" : undefined}
icon={
index === 0 ? (
<Tooltip
className="text-center"
content="Map token claims to metadata. This can later be accessed in attribute based permission as identity.metadata.oidc.claims.<>."
>
<FontAwesomeIcon icon={faQuestionCircle} size="sm" />
</Tooltip>
) : undefined
}
isError={Boolean(error)}
errorText={error?.message}
>
<Input
value={field.value}
onChange={(e) => field.onChange(e)}
placeholder="property"
/>
</FormControl>
);
}}
/>
<Controller
control={control}
name={`claimMetadataMapping.${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="key1.nested-key2"
/>
</FormControl>
);
}}
/>
<IconButton
onClick={() => removeClaimMetadataMappingField(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={() =>
appendClaimMetadataMappingField({
key: "",
value: ""
})
}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
>
Add Mapping
</Button>
</div>
{accessTokenTrustedIpsFields.map(({ id }, index) => ( {accessTokenTrustedIpsFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}> <div className="mb-3 flex items-end space-x-2" key={id}>
<Controller <Controller
@@ -111,6 +111,26 @@ export const ViewIdentityOidcAuthContent = ({
</Tooltip> </Tooltip>
)} )}
</IdentityAuthFieldDisplay> </IdentityAuthFieldDisplay>
<IdentityAuthFieldDisplay className="col-span-2" label="Claim Metadata Mapping">
{Object.keys(data.claimMetadataMapping).length && (
<Tooltip
side="right"
className="max-w-xl p-2"
content={
<pre className="whitespace-pre-wrap rounded bg-mineshaft-600 p-2">
{JSON.stringify(data.claimMetadataMapping, null, 2)}
</pre>
}
>
<div className="w-min">
<Badge className="flex h-5 w-min items-center gap-1.5 whitespace-nowrap bg-mineshaft-400/50 text-bunker-300">
<FontAwesomeIcon icon={faEye} />
<span>Reveal</span>
</Badge>
</div>
</Tooltip>
)}
</IdentityAuthFieldDisplay>
</ViewIdentityContentWrapper> </ViewIdentityContentWrapper>
); );
}; };
@@ -306,7 +306,10 @@ export const SecretItem = memo(
)} )}
/> />
)} )}
<div key="actions" className="flex h-full flex-shrink-0 self-start transition-all group-hover:gap-x-2"> <div
key="actions"
className="flex h-full flex-shrink-0 self-start transition-all group-hover:gap-x-2"
>
<Tooltip content="Copy secret"> <Tooltip content="Copy secret">
<IconButton <IconButton
isDisabled={secret.secretValueHidden} isDisabled={secret.secretValueHidden}