Fine grained clients (#2702)
This commit is contained in:
parent
be000ff08c
commit
5b559bcdbd
29 changed files with 153 additions and 75 deletions
|
@ -56,6 +56,7 @@ export const AdvancedTab = ({
|
|||
protocol,
|
||||
authenticationFlowBindingOverrides,
|
||||
adminUrl,
|
||||
access,
|
||||
},
|
||||
}: AdvancedProps) => {
|
||||
const { t } = useTranslation("clients");
|
||||
|
@ -197,7 +198,11 @@ export const AdvancedTab = ({
|
|||
tab
|
||||
</Trans>
|
||||
</Text>
|
||||
<FormAccess role="manage-clients" isHorizontal>
|
||||
<FormAccess
|
||||
role="manage-clients"
|
||||
fineGrainedAccess={access?.configure}
|
||||
isHorizontal
|
||||
>
|
||||
<FormGroup
|
||||
label={t("notBefore")}
|
||||
fieldId="kc-not-before"
|
||||
|
@ -258,7 +263,11 @@ export const AdvancedTab = ({
|
|||
)}
|
||||
{publicClient && (
|
||||
<>
|
||||
<FormAccess role="manage-clients" isHorizontal>
|
||||
<FormAccess
|
||||
role="manage-clients"
|
||||
fineGrainedAccess={access?.configure}
|
||||
isHorizontal
|
||||
>
|
||||
<FormGroup
|
||||
label={t("nodeReRegistrationTimeout")}
|
||||
fieldId="kc-node-reregistration-timeout"
|
||||
|
@ -393,6 +402,7 @@ export const AdvancedTab = ({
|
|||
setValue(`attributes.${key}`, value)
|
||||
)
|
||||
}
|
||||
hasConfigureAccess={access?.configure}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
@ -424,6 +434,7 @@ export const AdvancedTab = ({
|
|||
reset={() =>
|
||||
resetFields(["exclude.session.state.from.auth.response"])
|
||||
}
|
||||
hasConfigureAccess={access?.configure}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
@ -434,6 +445,7 @@ export const AdvancedTab = ({
|
|||
<AdvancedSettings
|
||||
protocol={protocol}
|
||||
control={control}
|
||||
hasConfigureAccess={access?.configure}
|
||||
save={() => save()}
|
||||
reset={() => {
|
||||
resetFields([
|
||||
|
@ -463,6 +475,7 @@ export const AdvancedTab = ({
|
|||
authenticationFlowBindingOverrides?.direct_grant
|
||||
);
|
||||
}}
|
||||
hasConfigureAccess={access?.configure}
|
||||
/>
|
||||
</>
|
||||
</ScrollForm>
|
||||
|
|
|
@ -11,9 +11,13 @@ import { KeycloakTextArea } from "../components/keycloak-text-area/KeycloakTextA
|
|||
|
||||
type ClientDescriptionProps = {
|
||||
protocol?: string;
|
||||
hasConfigureAccess?: boolean;
|
||||
};
|
||||
|
||||
export const ClientDescription = ({ protocol }: ClientDescriptionProps) => {
|
||||
export const ClientDescription = ({
|
||||
protocol,
|
||||
hasConfigureAccess: configure,
|
||||
}: ClientDescriptionProps) => {
|
||||
const { t } = useTranslation("clients");
|
||||
const {
|
||||
register,
|
||||
|
@ -21,7 +25,7 @@ export const ClientDescription = ({ protocol }: ClientDescriptionProps) => {
|
|||
formState: { errors },
|
||||
} = useFormContext<ClientRepresentation>();
|
||||
return (
|
||||
<FormAccess role="manage-clients" unWrap>
|
||||
<FormAccess role="manage-clients" fineGrainedAccess={configure} unWrap>
|
||||
<FormGroup
|
||||
labelIcon={
|
||||
<HelpItem helpText="clients-help:clientId" fieldLabelId="clientId" />
|
||||
|
|
|
@ -128,7 +128,7 @@ const ClientDetailHeader = ({
|
|||
}, [client, t]);
|
||||
|
||||
const { hasAccess } = useAccess();
|
||||
const isManager = hasAccess("manage-clients");
|
||||
const isManager = hasAccess("manage-clients") || client.access?.configure;
|
||||
|
||||
const dropdownItems = [
|
||||
<DropdownItem key="download" onClick={toggleDownloadDialog}>
|
||||
|
@ -189,12 +189,11 @@ export default function ClientDetails() {
|
|||
const { profileInfo } = useServerInfo();
|
||||
|
||||
const { hasAccess } = useAccess();
|
||||
const isManager = hasAccess("manage-clients");
|
||||
const canViewPermissions = hasAccess(
|
||||
"manage-authorization",
|
||||
"manage-clients"
|
||||
);
|
||||
const canViewServiceAccountRoles = hasAccess("view-users");
|
||||
const permissionsEnabled =
|
||||
!profileInfo?.disabledFeatures?.includes("ADMIN_FINE_GRAINED_AUTHZ") &&
|
||||
hasAccess("manage-authorization");
|
||||
const hasManageClients = hasAccess("manage-clients");
|
||||
const hasViewUsers = hasAccess("view-users");
|
||||
|
||||
const history = useHistory();
|
||||
|
||||
|
@ -432,27 +431,33 @@ export default function ClientDetails() {
|
|||
{...route("keys")}
|
||||
>
|
||||
{client.protocol === "openid-connect" && (
|
||||
<Keys clientId={clientId} save={save} />
|
||||
<Keys
|
||||
clientId={clientId}
|
||||
save={save}
|
||||
hasConfigureAccess={client.access?.configure}
|
||||
/>
|
||||
)}
|
||||
{client.protocol === "saml" && (
|
||||
<SamlKeys clientId={clientId} save={save} />
|
||||
)}
|
||||
</Tab>
|
||||
)}
|
||||
{!client.publicClient && !isRealmClient(client) && (
|
||||
<Tab
|
||||
id="credentials"
|
||||
title={<TabTitleText>{t("credentials")}</TabTitleText>}
|
||||
{...route("credentials")}
|
||||
>
|
||||
<Credentials
|
||||
key={key}
|
||||
client={client}
|
||||
save={save}
|
||||
refresh={() => setKey(key + 1)}
|
||||
/>
|
||||
</Tab>
|
||||
)}
|
||||
{!client.publicClient &&
|
||||
!isRealmClient(client) &&
|
||||
(hasManageClients || client.access?.configure) && (
|
||||
<Tab
|
||||
id="credentials"
|
||||
title={<TabTitleText>{t("credentials")}</TabTitleText>}
|
||||
{...route("credentials")}
|
||||
>
|
||||
<Credentials
|
||||
key={key}
|
||||
client={client}
|
||||
save={save}
|
||||
refresh={() => setKey(key + 1)}
|
||||
/>
|
||||
</Tab>
|
||||
)}
|
||||
<Tab
|
||||
id="roles"
|
||||
data-testid="rolesTab"
|
||||
|
@ -463,7 +468,7 @@ export default function ClientDetails() {
|
|||
loader={loader}
|
||||
paginated={false}
|
||||
messageBundle="clients"
|
||||
isReadOnly={!isManager}
|
||||
isReadOnly={!(hasManageClients || client.access?.configure)}
|
||||
/>
|
||||
</Tab>
|
||||
{!isRealmClient(client) && !client.bearerOnly && (
|
||||
|
@ -496,6 +501,7 @@ export default function ClientDetails() {
|
|||
clientName={client.clientId!}
|
||||
clientId={clientId}
|
||||
protocol={client!.protocol!}
|
||||
fineGrainedAccess={client!.access?.manage}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab
|
||||
|
@ -595,7 +601,7 @@ export default function ClientDetails() {
|
|||
</RoutableTabs>
|
||||
</Tab>
|
||||
)}
|
||||
{client!.serviceAccountsEnabled && canViewServiceAccountRoles && (
|
||||
{client!.serviceAccountsEnabled && hasViewUsers && (
|
||||
<Tab
|
||||
id="serviceAccount"
|
||||
data-testid="serviceAccountTab"
|
||||
|
@ -605,19 +611,16 @@ export default function ClientDetails() {
|
|||
<ServiceAccount client={client} />
|
||||
</Tab>
|
||||
)}
|
||||
{!profileInfo?.disabledFeatures?.includes(
|
||||
"ADMIN_FINE_GRAINED_AUTHZ"
|
||||
) &&
|
||||
canViewPermissions && (
|
||||
<Tab
|
||||
id="permissions"
|
||||
data-testid="permissionsTab"
|
||||
title={<TabTitleText>{t("common:permissions")}</TabTitleText>}
|
||||
{...route("permissions")}
|
||||
>
|
||||
<PermissionsTab id={client.id!} type="clients" />
|
||||
</Tab>
|
||||
)}
|
||||
{permissionsEnabled && (hasManageClients || client.access?.manage) && (
|
||||
<Tab
|
||||
id="permissions"
|
||||
data-testid="permissionsTab"
|
||||
title={<TabTitleText>{t("common:permissions")}</TabTitleText>}
|
||||
{...route("permissions")}
|
||||
>
|
||||
<PermissionsTab id={client.id!} type="clients" />
|
||||
</Tab>
|
||||
)}
|
||||
<Tab
|
||||
id="advanced"
|
||||
data-testid="advancedTab"
|
||||
|
|
|
@ -49,7 +49,7 @@ export const ClientSettings = ({
|
|||
const { realm } = useRealm();
|
||||
|
||||
const { hasAccess } = useAccess();
|
||||
const isManager = hasAccess("manage-clients");
|
||||
const isManager = hasAccess("manage-clients") || client.access?.configure;
|
||||
|
||||
const [loginThemeOpen, setLoginThemeOpen] = useState(false);
|
||||
const loginThemes = useServerInfo().themes!["login"];
|
||||
|
@ -88,7 +88,10 @@ export const ClientSettings = ({
|
|||
sections={sections.map((section) => t(section))}
|
||||
>
|
||||
<Form isHorizontal>
|
||||
<ClientDescription protocol={client.protocol} />
|
||||
<ClientDescription
|
||||
protocol={client.protocol}
|
||||
hasConfigureAccess={client.access?.configure}
|
||||
/>
|
||||
</Form>
|
||||
{protocol === "saml" ? (
|
||||
<SamlConfig />
|
||||
|
@ -96,7 +99,11 @@ export const ClientSettings = ({
|
|||
!client.bearerOnly && <CapabilityConfig />
|
||||
)}
|
||||
{protocol === "saml" && <SamlSignature />}
|
||||
<FormAccess isHorizontal role="manage-clients">
|
||||
<FormAccess
|
||||
isHorizontal
|
||||
role="manage-clients"
|
||||
fineGrainedAccess={client.access?.configure}
|
||||
>
|
||||
{!client.bearerOnly && (
|
||||
<>
|
||||
<FormGroup
|
||||
|
@ -259,7 +266,11 @@ export const ClientSettings = ({
|
|||
/>
|
||||
)}
|
||||
</FormAccess>
|
||||
<FormAccess isHorizontal role="manage-clients">
|
||||
<FormAccess
|
||||
isHorizontal
|
||||
role="manage-clients"
|
||||
fineGrainedAccess={client.access?.configure}
|
||||
>
|
||||
<FormGroup
|
||||
label={t("loginTheme")}
|
||||
labelIcon={
|
||||
|
@ -383,7 +394,11 @@ export const ClientSettings = ({
|
|||
/>
|
||||
)}
|
||||
</FormAccess>
|
||||
<FormAccess isHorizontal role="manage-clients">
|
||||
<FormAccess
|
||||
isHorizontal
|
||||
role="manage-clients"
|
||||
fineGrainedAccess={client.access?.configure}
|
||||
>
|
||||
{protocol === "openid-connect" && (
|
||||
<>
|
||||
<FormGroup
|
||||
|
|
|
@ -161,7 +161,10 @@ export default function ClientsSection() {
|
|||
},
|
||||
];
|
||||
|
||||
if (!isRealmClient(client) && isManager) {
|
||||
if (
|
||||
!isRealmClient(client) &&
|
||||
(isManager || client.access?.configure)
|
||||
) {
|
||||
actions.push({
|
||||
title: t("common:delete"),
|
||||
onClick() {
|
||||
|
|
|
@ -68,7 +68,7 @@ export const GeneralSettings = () => {
|
|||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
<ClientDescription />
|
||||
<ClientDescription hasConfigureAccess />
|
||||
</FormAccess>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -23,6 +23,7 @@ type AdvancedSettingsProps = {
|
|||
save: () => void;
|
||||
reset: () => void;
|
||||
protocol?: string;
|
||||
hasConfigureAccess?: boolean;
|
||||
};
|
||||
|
||||
export const AdvancedSettings = ({
|
||||
|
@ -30,11 +31,16 @@ export const AdvancedSettings = ({
|
|||
save,
|
||||
reset,
|
||||
protocol,
|
||||
hasConfigureAccess,
|
||||
}: AdvancedSettingsProps) => {
|
||||
const { t } = useTranslation("clients");
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<FormAccess role="manage-realm" isHorizontal>
|
||||
<FormAccess
|
||||
role="manage-realm"
|
||||
fineGrainedAccess={hasConfigureAccess}
|
||||
isHorizontal
|
||||
>
|
||||
{protocol !== "openid-connect" && (
|
||||
<FormGroup
|
||||
label={t("assertionLifespan")}
|
||||
|
|
|
@ -20,6 +20,7 @@ type AuthenticationOverridesProps = {
|
|||
save: () => void;
|
||||
reset: () => void;
|
||||
protocol?: string;
|
||||
hasConfigureAccess?: boolean;
|
||||
};
|
||||
|
||||
export const AuthenticationOverrides = ({
|
||||
|
@ -27,6 +28,7 @@ export const AuthenticationOverrides = ({
|
|||
control,
|
||||
save,
|
||||
reset,
|
||||
hasConfigureAccess,
|
||||
}: AuthenticationOverridesProps) => {
|
||||
const adminClient = useAdminClient();
|
||||
const { t } = useTranslation("clients");
|
||||
|
@ -56,7 +58,11 @@ export const AuthenticationOverrides = ({
|
|||
);
|
||||
|
||||
return (
|
||||
<FormAccess role="manage-clients" isHorizontal>
|
||||
<FormAccess
|
||||
role="manage-clients"
|
||||
fineGrainedAccess={hasConfigureAccess}
|
||||
isHorizontal
|
||||
>
|
||||
<FormGroup
|
||||
label={t("browserFlow")}
|
||||
fieldId="browserFlow"
|
||||
|
|
|
@ -20,11 +20,13 @@ import { KeycloakTextInput } from "../../components/keycloak-text-input/Keycloak
|
|||
type FineGrainOpenIdConnectProps = {
|
||||
save: () => void;
|
||||
reset: () => void;
|
||||
hasConfigureAccess?: boolean;
|
||||
};
|
||||
|
||||
export const FineGrainOpenIdConnect = ({
|
||||
save,
|
||||
reset,
|
||||
hasConfigureAccess,
|
||||
}: FineGrainOpenIdConnectProps) => {
|
||||
const { t } = useTranslation("clients");
|
||||
const providers = useServerInfo().providers;
|
||||
|
@ -141,7 +143,11 @@ export const FineGrainOpenIdConnect = ({
|
|||
));
|
||||
|
||||
return (
|
||||
<FormAccess role="manage-clients" isHorizontal>
|
||||
<FormAccess
|
||||
role="manage-clients"
|
||||
fineGrainedAccess={hasConfigureAccess}
|
||||
isHorizontal
|
||||
>
|
||||
<FormGroup
|
||||
label={t("logoUrl")}
|
||||
fieldId="logoUrl"
|
||||
|
|
|
@ -10,16 +10,22 @@ type OpenIdConnectCompatibilityModesProps = {
|
|||
control: Control<Record<string, any>>;
|
||||
save: () => void;
|
||||
reset: () => void;
|
||||
hasConfigureAccess?: boolean;
|
||||
};
|
||||
|
||||
export const OpenIdConnectCompatibilityModes = ({
|
||||
control,
|
||||
save,
|
||||
reset,
|
||||
hasConfigureAccess,
|
||||
}: OpenIdConnectCompatibilityModesProps) => {
|
||||
const { t } = useTranslation("clients");
|
||||
return (
|
||||
<FormAccess role="manage-realm" isHorizontal>
|
||||
<FormAccess
|
||||
role="manage-realm"
|
||||
fineGrainedAccess={hasConfigureAccess}
|
||||
isHorizontal
|
||||
>
|
||||
<FormGroup
|
||||
label={t("excludeSessionStateFromAuthenticationResponse")}
|
||||
fieldId="excludeSessionStateFromAuthenticationResponse"
|
||||
|
|
|
@ -347,7 +347,7 @@ export const AuthorizationEvaluate = ({ client }: Props) => {
|
|||
>
|
||||
<FormAccess
|
||||
isHorizontal
|
||||
role="manage-clients"
|
||||
role="view-clients"
|
||||
onSubmit={form.handleSubmit(evaluate)}
|
||||
>
|
||||
<FormGroup
|
||||
|
@ -487,7 +487,7 @@ export const AuthorizationEvaluate = ({ client }: Props) => {
|
|||
</FormAccess>
|
||||
</FormPanel>
|
||||
<FormPanel className="kc-permissions" title={t("common:permissions")}>
|
||||
<FormAccess isHorizontal role="manage-clients">
|
||||
<FormAccess isHorizontal role="view-clients">
|
||||
<FormGroup
|
||||
label={t("applyToResourceType")}
|
||||
fieldId="applyToResourceType"
|
||||
|
|
|
@ -65,7 +65,7 @@ export const AuthorizationExport = () => {
|
|||
|
||||
return (
|
||||
<PageSection>
|
||||
<FormAccess isHorizontal role="manage-realm" className="pf-u-mt-lg">
|
||||
<FormAccess isHorizontal role="view-realm" className="pf-u-mt-lg">
|
||||
<FormGroup
|
||||
label={t("authDetails")}
|
||||
labelIcon={
|
||||
|
|
|
@ -194,7 +194,7 @@ export default function PermissionDetails() {
|
|||
<PageSection variant="light">
|
||||
<FormAccess
|
||||
isHorizontal
|
||||
role="manage-clients"
|
||||
role="view-clients"
|
||||
onSubmit={handleSubmit(save)}
|
||||
>
|
||||
<FormProvider {...form}>
|
||||
|
|
|
@ -179,7 +179,7 @@ export default function ResourceDetails() {
|
|||
<FormProvider {...form}>
|
||||
<FormAccess
|
||||
isHorizontal
|
||||
role="manage-clients"
|
||||
role="view-clients"
|
||||
className="keycloak__resource-details__form"
|
||||
onSubmit={handleSubmit(save)}
|
||||
>
|
||||
|
|
|
@ -128,7 +128,7 @@ export default function ScopeDetails() {
|
|||
<PageSection variant="light">
|
||||
<FormAccess
|
||||
isHorizontal
|
||||
role="manage-clients"
|
||||
role="view-clients"
|
||||
onSubmit={handleSubmit(save)}
|
||||
>
|
||||
<FormGroup
|
||||
|
|
|
@ -192,7 +192,7 @@ export default function PolicyDetails() {
|
|||
<FormAccess
|
||||
isHorizontal
|
||||
onSubmit={handleSubmit(save)}
|
||||
role="manage-clients"
|
||||
role="view-clients"
|
||||
>
|
||||
<FormProvider {...form}>
|
||||
<NameDescription prefix="policy" />
|
||||
|
|
|
@ -75,7 +75,7 @@ export default function ImportForm() {
|
|||
>
|
||||
<FormProvider {...form}>
|
||||
<JsonFileUpload id="realm-file" onChange={handleFileChange} />
|
||||
<ClientDescription />
|
||||
<ClientDescription hasConfigureAccess />
|
||||
<FormGroup label={t("common:type")} fieldId="kc-type">
|
||||
<KeycloakTextInput
|
||||
type="text"
|
||||
|
|
|
@ -33,11 +33,12 @@ import { Certificate } from "./Certificate";
|
|||
type KeysProps = {
|
||||
save: () => void;
|
||||
clientId: string;
|
||||
hasConfigureAccess?: boolean;
|
||||
};
|
||||
|
||||
const attr = "jwt.credential";
|
||||
|
||||
export const Keys = ({ clientId, save }: KeysProps) => {
|
||||
export const Keys = ({ clientId, save, hasConfigureAccess }: KeysProps) => {
|
||||
const { t } = useTranslation("clients");
|
||||
const {
|
||||
control,
|
||||
|
@ -125,7 +126,11 @@ export const Keys = ({ clientId, save }: KeysProps) => {
|
|||
</TextContent>
|
||||
</CardBody>
|
||||
<CardBody>
|
||||
<FormAccess role="manage-clients" isHorizontal>
|
||||
<FormAccess
|
||||
role="manage-clients"
|
||||
fineGrainedAccess={hasConfigureAccess}
|
||||
isHorizontal
|
||||
>
|
||||
<FormGroup
|
||||
hasNoPaddingTop
|
||||
label={t("useJwksUrl")}
|
||||
|
|
|
@ -15,7 +15,7 @@ export const DedicatedScopeDetailsRoute: RouteDef = {
|
|||
path: "/:realm/clients/:clientId/clientScopes/dedicated/:tab?",
|
||||
component: lazy(() => import("../scopes/DedicatedScopes")),
|
||||
breadcrumb: (t) => t("clients:dedicatedScopes"),
|
||||
access: "manage-clients",
|
||||
access: "view-clients",
|
||||
};
|
||||
|
||||
export const toDedicatedScope = (
|
||||
|
|
|
@ -16,7 +16,7 @@ export const NewPermissionRoute: RouteDef = {
|
|||
path: "/:realm/clients/:id/authorization/permission/new/:permissionType/:selectedId?",
|
||||
component: lazy(() => import("../authorization/PermissionDetails")),
|
||||
breadcrumb: (t) => t("clients:createPermission"),
|
||||
access: "manage-clients",
|
||||
access: "view-clients",
|
||||
};
|
||||
|
||||
export const toNewPermission = (
|
||||
|
|
|
@ -9,7 +9,7 @@ export const NewPolicyRoute: RouteDef = {
|
|||
path: "/:realm/clients/:id/authorization/policy/new/:policyType",
|
||||
component: lazy(() => import("../authorization/policy/PolicyDetails")),
|
||||
breadcrumb: (t) => t("clients:createPolicy"),
|
||||
access: "manage-clients",
|
||||
access: "view-clients",
|
||||
};
|
||||
|
||||
export const toCreatePolicy = (
|
||||
|
|
|
@ -9,7 +9,7 @@ export const NewResourceRoute: RouteDef = {
|
|||
path: "/:realm/clients/:id/authorization/resource/new",
|
||||
component: lazy(() => import("../authorization/ResourceDetails")),
|
||||
breadcrumb: (t) => t("clients:createResource"),
|
||||
access: "manage-clients",
|
||||
access: "view-clients",
|
||||
};
|
||||
|
||||
export const toCreateResource = (
|
||||
|
|
|
@ -9,7 +9,7 @@ export const NewScopeRoute: RouteDef = {
|
|||
path: "/:realm/clients/:id/authorization/scope/new",
|
||||
component: lazy(() => import("../authorization/ScopeDetails")),
|
||||
breadcrumb: (t) => t("clients:createAuthorizationScope"),
|
||||
access: "manage-clients",
|
||||
access: "view-clients",
|
||||
};
|
||||
|
||||
export const toNewScope = (
|
||||
|
|
|
@ -15,7 +15,7 @@ export const PermissionDetailsRoute: RouteDef = {
|
|||
path: "/:realm/clients/:id/authorization/permission/:permissionType/:permissionId",
|
||||
component: lazy(() => import("../authorization/PermissionDetails")),
|
||||
breadcrumb: (t) => t("clients:permissionDetails"),
|
||||
access: "manage-clients",
|
||||
access: "view-clients",
|
||||
};
|
||||
|
||||
export const toPermissionDetails = (
|
||||
|
|
|
@ -14,7 +14,7 @@ export const PolicyDetailsRoute: RouteDef = {
|
|||
path: "/:realm/clients/:id/authorization/policy/:policyId/:policyType",
|
||||
component: lazy(() => import("../authorization/policy/PolicyDetails")),
|
||||
breadcrumb: (t) => t("clients:createPolicy"),
|
||||
access: "manage-clients",
|
||||
access: "view-clients",
|
||||
};
|
||||
|
||||
export const toPolicyDetails = (
|
||||
|
|
|
@ -13,7 +13,7 @@ export const ResourceDetailsRoute: RouteDef = {
|
|||
path: "/:realm/clients/:id/authorization/resource/:resourceId?",
|
||||
component: lazy(() => import("../authorization/ResourceDetails")),
|
||||
breadcrumb: (t) => t("clients:createResource"),
|
||||
access: "manage-clients",
|
||||
access: "view-clients",
|
||||
};
|
||||
|
||||
export const toResourceDetails = (
|
||||
|
|
|
@ -46,6 +46,7 @@ export type ClientScopesProps = {
|
|||
clientId: string;
|
||||
protocol: string;
|
||||
clientName: string;
|
||||
fineGrainedAccess?: boolean;
|
||||
};
|
||||
|
||||
export type Row = ClientScopeRepresentation & {
|
||||
|
@ -59,6 +60,7 @@ export const ClientScopes = ({
|
|||
clientId,
|
||||
protocol,
|
||||
clientName,
|
||||
fineGrainedAccess,
|
||||
}: ClientScopesProps) => {
|
||||
const { t } = useTranslation("clients");
|
||||
const adminClient = useAdminClient();
|
||||
|
@ -83,7 +85,7 @@ export const ClientScopes = ({
|
|||
const isDedicatedRow = (value: Row) => value.id === DEDICATED_ROW;
|
||||
|
||||
const { hasAccess } = useAccess();
|
||||
const isManager = hasAccess("manage-clients");
|
||||
const isManager = hasAccess("manage-clients") || fineGrainedAccess;
|
||||
|
||||
const loader = async (first?: number, max?: number, search?: string) => {
|
||||
const defaultClientScopes =
|
||||
|
@ -130,7 +132,7 @@ export const ClientScopes = ({
|
|||
firstNum,
|
||||
firstNum + Number(max)
|
||||
);
|
||||
if (firstNum === 0) {
|
||||
if (firstNum === 0 && isManager) {
|
||||
return [
|
||||
{
|
||||
id: DEDICATED_ROW,
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
} from "../../components/role-mapping/RoleMapping";
|
||||
import type { RoleMappingPayload } from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
|
||||
import useToggle from "../../utils/useToggle";
|
||||
import { useAccess } from "../../context/access/Access";
|
||||
|
||||
type DedicatedScopeProps = {
|
||||
client: ClientRepresentation;
|
||||
|
@ -35,6 +36,9 @@ export const DedicatedScope = ({
|
|||
const [client, setClient] = useState<ClientRepresentation>(initialClient);
|
||||
const [hide, toggle] = useToggle();
|
||||
|
||||
const { hasAccess } = useAccess();
|
||||
const isManager = hasAccess("manage-clients") || client.access?.manage;
|
||||
|
||||
const loader = async () => {
|
||||
const [clients, assignedRoles, effectiveRoles] = await Promise.all([
|
||||
adminClient.clients.find(),
|
||||
|
@ -118,7 +122,11 @@ export const DedicatedScope = ({
|
|||
|
||||
return (
|
||||
<PageSection>
|
||||
<FormAccess role="manage-clients" isHorizontal>
|
||||
<FormAccess
|
||||
role="manage-clients"
|
||||
fineGrainedAccess={client.access?.manage}
|
||||
isHorizontal
|
||||
>
|
||||
<FormGroup
|
||||
hasNoPaddingTop
|
||||
label={t("fullScopeAllowed")}
|
||||
|
@ -149,6 +157,7 @@ export const DedicatedScope = ({
|
|||
loader={loader}
|
||||
save={assignRoles}
|
||||
onHideRolesToggle={toggle}
|
||||
isManager={isManager}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
|
|
@ -35,7 +35,7 @@ export const ServiceAccount = ({ client }: ServiceAccountProps) => {
|
|||
const [serviceAccount, setServiceAccount] = useState<UserRepresentation>();
|
||||
|
||||
const { hasAccess } = useAccess();
|
||||
const isManager = hasAccess("manage-clients");
|
||||
const hasManageClients = hasAccess("manage-clients");
|
||||
|
||||
useFetch(
|
||||
() =>
|
||||
|
@ -128,7 +128,7 @@ export const ServiceAccount = ({ client }: ServiceAccountProps) => {
|
|||
name={client.clientId!}
|
||||
id={serviceAccount.id!}
|
||||
type="users"
|
||||
isManager={isManager}
|
||||
isManager={hasManageClients || client.access?.configure}
|
||||
loader={loader}
|
||||
save={assignRoles}
|
||||
onHideRolesToggle={() => setHide(!hide)}
|
||||
|
|
Loading…
Reference in a new issue