feat: updated form for oidc auth

This commit is contained in:
=
2025-03-14 22:10:23 +05:30
parent 1da5a5f417
commit 0f31fa3128
7 changed files with 139 additions and 5 deletions

View File

@@ -1,6 +1,7 @@
import { useInfiniteQuery, useQuery, UseQueryOptions } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import { Identity } from "@app/hooks/api/identities/types";
import { User } from "../types";
import {
@@ -10,7 +11,6 @@ import {
TGetServerRootKmsEncryptionDetails,
TServerConfig
} from "./types";
import { Identity } from "@app/hooks/api/identities/types";
export const adminStandaloneKeys = {
getUsers: "get-users",

View File

@@ -462,6 +462,7 @@ export const useUpdateIdentityOidcAuth = () => {
boundIssuer,
boundAudiences,
boundClaims,
claimMetadataMapping,
boundSubject
}) => {
const {
@@ -478,7 +479,8 @@ export const useUpdateIdentityOidcAuth = () => {
accessTokenTTL,
accessTokenMaxTTL,
accessTokenNumUsesLimit,
accessTokenTrustedIps
accessTokenTrustedIps,
claimMetadataMapping
}
);
@@ -504,6 +506,7 @@ export const useAddIdentityOidcAuth = () => {
boundIssuer,
boundAudiences,
boundClaims,
claimMetadataMapping,
boundSubject,
accessTokenTTL,
accessTokenMaxTTL,
@@ -524,7 +527,8 @@ export const useAddIdentityOidcAuth = () => {
accessTokenTTL,
accessTokenMaxTTL,
accessTokenNumUsesLimit,
accessTokenTrustedIps
accessTokenTrustedIps,
claimMetadataMapping
}
);

View File

@@ -193,6 +193,7 @@ export type IdentityOidcAuth = {
boundIssuer: string;
boundAudiences: string;
boundClaims: Record<string, string>;
claimMetadataMapping: Record<string, string>;
boundSubject: string;
accessTokenTTL: number;
accessTokenMaxTTL: number;
@@ -208,6 +209,7 @@ export type AddIdentityOidcAuthDTO = {
boundIssuer: string;
boundAudiences: string;
boundClaims: Record<string, string>;
claimMetadataMapping: Record<string, string>;
boundSubject: string;
accessTokenTTL: number;
accessTokenMaxTTL: number;
@@ -225,6 +227,7 @@ export type UpdateIdentityOidcAuthDTO = {
boundIssuer?: string;
boundAudiences?: string;
boundClaims?: Record<string, string>;
claimMetadataMapping?: Record<string, string>;
boundSubject?: string;
accessTokenTTL?: number;
accessTokenMaxTTL?: number;

View File

@@ -28,13 +28,13 @@ import {
useGetServerRootKmsEncryptionDetails,
useUpdateServerConfig
} from "@app/hooks/api";
import { IdentityPanel } from "@app/pages/admin/OverviewPage/components/IdentityPanel";
import { AuthPanel } from "./components/AuthPanel";
import { EncryptionPanel } from "./components/EncryptionPanel";
import { IntegrationPanel } from "./components/IntegrationPanel";
import { RateLimitPanel } from "./components/RateLimitPanel";
import { UserPanel } from "./components/UserPanel";
import { IdentityPanel } from "@app/pages/admin/OverviewPage/components/IdentityPanel";
enum TabSections {
Settings = "settings",

View File

@@ -52,6 +52,12 @@ const schema = z.object({
value: z.string()
})
),
claimMetadataMapping: z.array(
z.object({
key: z.string(),
value: z.string()
})
),
boundSubject: z.string().optional().default("")
});
@@ -109,6 +115,15 @@ export const IdentityOidcAuthForm = ({
name: "boundClaims"
});
const {
fields: claimMetadataMappingFields,
append: appendClaimMetadataMappingField,
remove: removeClaimMetadataMappingField
} = useFieldArray({
control,
name: "claimMetadataMapping"
});
const {
fields: accessTokenTrustedIpsFields,
append: appendAccessTokenTrustedIp,
@@ -126,6 +141,10 @@ export const IdentityOidcAuthForm = ({
key,
value
})),
claimMetadataMapping: Object.entries(data.claimMetadataMapping).map(([key, value]) => ({
key,
value
})),
boundSubject: data.boundSubject,
accessTokenTTL: String(data.accessTokenTTL),
accessTokenMaxTTL: String(data.accessTokenMaxTTL),
@@ -164,6 +183,7 @@ export const IdentityOidcAuthForm = ({
boundIssuer,
boundAudiences,
boundClaims,
claimMetadataMapping,
boundSubject
}: FormData) => {
try {
@@ -180,6 +200,9 @@ export const IdentityOidcAuthForm = ({
boundIssuer,
boundAudiences,
boundClaims: Object.fromEntries(boundClaims.map((entry) => [entry.key, entry.value])),
claimMetadataMapping: Object.fromEntries(
claimMetadataMapping.map((entry) => [entry.key, entry.value])
),
boundSubject,
accessTokenTTL: Number(accessTokenTTL),
accessTokenMaxTTL: Number(accessTokenMaxTTL),
@@ -194,6 +217,9 @@ export const IdentityOidcAuthForm = ({
boundIssuer,
boundAudiences,
boundClaims: Object.fromEntries(boundClaims.map((entry) => [entry.key, entry.value])),
claimMetadataMapping: Object.fromEntries(
claimMetadataMapping.map((entry) => [entry.key, entry.value])
),
boundSubject,
organizationId: orgId,
accessTokenTTL: Number(accessTokenTTL),
@@ -449,6 +475,84 @@ export const IdentityOidcAuthForm = ({
Add Claims
</Button>
</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) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller

View File

@@ -111,6 +111,26 @@ export const ViewIdentityOidcAuthContent = ({
</Tooltip>
)}
</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>
);
};

View File

@@ -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">
<IconButton
isDisabled={secret.secretValueHidden}