Skip to content

Commit 6587f5f

Browse files
Added UI support for Clients and Groups resource types (#37379)
* removed policyId from permission search form Signed-off-by: Agnieszka Gancarczyk <[email protected]> * Adding support for Clients and Groups resource types Signed-off-by: Agnieszka Gancarczyk <[email protected]> * Adding support for Clients and Groups resource types Signed-off-by: Agnieszka Gancarczyk <[email protected]> * Added support for clients resourceType Signed-off-by: Agnieszka Gancarczyk <[email protected]> * Added support for creating permission based on Clients and Groups resource types Signed-off-by: Agnieszka Gancarczyk <[email protected]> * updated messages Signed-off-by: Agnieszka Gancarczyk <[email protected]> * updated messages Signed-off-by: Agnieszka Gancarczyk <[email protected]> * Fixing the search by resource type and resource Signed-off-by: Pedro Igor <[email protected]> * Fixing changing permissions from specific to all resources Signed-off-by: Pedro Igor <[email protected]> * made groups policy default instead of aggregate and fixed ClientSelect Signed-off-by: Agnieszka Gancarczyk <[email protected]> * Added error handling for authorization scope field Signed-off-by: Agnieszka Gancarczyk <[email protected]> * Added error handling for authorization scope field Signed-off-by: Agnieszka Gancarczyk <[email protected]> * improved policy creation from create permission Signed-off-by: Agnieszka Gancarczyk <[email protected]> * improved policy creation from create permission Signed-off-by: Agnieszka Gancarczyk <[email protected]> * improved policy creation from create permission Signed-off-by: Agnieszka Gancarczyk <[email protected]> * Improved ClientScope Signed-off-by: Agnieszka Gancarczyk <[email protected]> * updated GroupSelect Signed-off-by: Agnieszka Gancarczyk <[email protected]> --------- Signed-off-by: Agnieszka Gancarczyk <[email protected]> Signed-off-by: Pedro Igor <[email protected]> Co-authored-by: Pedro Igor <[email protected]>
1 parent a26e482 commit 6587f5f

File tree

17 files changed

+301
-194
lines changed

17 files changed

+301
-194
lines changed

js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3360,13 +3360,12 @@ resourceScope=Resource scope
33603360
resourceScopeHelpText=Specifies the scope of the resource. This is used to determine the type of resource that the permission is granted to.
33613361
allClients=All clients
33623362
specificClients=Specific clients
3363-
allUsers=All users
3364-
specificUsers=Specific users
3363+
allResourceType=All {{resourceType}}
3364+
specificResourceType=Specific {{resourceType}}
33653365
assignedPolicies=Assigned policies
33663366
assignExistingPolicies=Assign existing policies
33673367
requiredPolicies=Please add at least one policy.
33683368
createNewPolicy=Create new policy
3369-
createPermissionPolicy=Create policy
33703369
policy=Policy
33713370
policyType=Policy type
33723371
policyTypeHelpText=Specifies the type of policy. This is used to determine the type of policy that the permission is granted to.
@@ -3383,16 +3382,16 @@ authorizationScopeDetailsTitle=Authorization scope details
33833382
authorizationScopeDetailsSubtitle=Authorization scope defines the actions that can be performed on a resource.
33843383
authorizationScopeDetailsName=Name
33853384
authorizationScopeDetailsDescription=Description
3386-
authorizationScopeDetailsDescriptionText=Lorem ipsum
33873385
allResources=All resources
33883386
currentRealm=Current realm
33893387
recentlyUsed=Recently used
33903388
viewAll=View all
33913389
currentRealmExplain=This realm is selected
33923390
removeInvalidUsers=Remove invalid users during searches
33933391
removeInvalidUsersHelp=Remove users from the local database if they are not available from the user storage when executing searches. If this is true, users no longer available from their corresponding user storage will be deleted from the local database whenever trying to look up users. If false, then users previously imported from the user storage will be kept in the local database, as read-only and disabled, even if that user is no longer available from the user storage. For example, user was deleted directly from LDAP or the `Users DN` is invalid. Note that this behavior will only happen when the user is not yet cached.
3394-
applyPermissionTo=Enforce access to
3395-
applyPermissionToHelpText=Specifies the resource that the permission is applied to.
3392+
createPermissionPolicy=Create policy
3393+
enforceAccessTo=Enforce access to
3394+
enforceAccessToHelpText=Specifies the resource that the permission is applied to.
33963395
emptyPermissionPoliciesInstructions=No policies exist in this realm.
33973396
noPermissionSearchResultsInstructions=No permissions matched your filters.
33983397
deleteAdminPermissionConfirm=If you delete permission {{ permission }}, administrators cannot perform the actions on resources that were defined by the permission.
@@ -3414,4 +3413,9 @@ authorizationScope.Groups.manage-members=Manages group members
34143413
authorizationScope.Groups.manage-membership=Adds or removes group members
34153414
authorizationScope.Groups.view=Views this group
34163415
authorizationScope.Groups.view-members=Views group members
3417-
authorizationScope.IdentityProviders.token-exchange=Allows clients to exchange tokens for tokens issued by this identity provider
3416+
authorizationScope.IdentityProviders.token-exchange=Allows clients to exchange tokens for tokens issued by this identity provider
3417+
usersResources=Users
3418+
clientsResources=Clients
3419+
groupsResources=Groups
3420+
resourceTypeHelpText=Specifies which {{ resourceType }} are allowed by this permission.
3421+
evaluation=Evaluation

js/apps/admin-ui/src/clients/authorization/ScopePicker.tsx

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type ScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/scopeRepresentation";
22
import {
3+
FormErrorText,
34
HelpItem,
45
KeycloakSelect,
56
SelectVariant,
@@ -29,7 +30,10 @@ export const ScopePicker = ({
2930
}: ScopePickerProps) => {
3031
const { adminClient } = useAdminClient();
3132
const { t } = useTranslation();
32-
const { control } = useFormContext();
33+
const {
34+
control,
35+
formState: { errors },
36+
} = useFormContext();
3337
const [open, setOpen] = useState(false);
3438
const [scopes, setScopes] = useState<ScopeRepresentation[]>();
3539
const [search, setSearch] = useState("");
@@ -77,44 +81,50 @@ export const ScopePicker = ({
7781
name="scopes"
7882
defaultValue={[]}
7983
control={control}
84+
rules={isAdminPermissionsClient ? { required: t("requiredField") } : {}}
8085
render={({ field }) => {
8186
const selectedValues = field.value.map((o: Scope) => o.name);
8287
return (
83-
<KeycloakSelect
84-
toggleId="scopes"
85-
variant={SelectVariant.typeaheadMulti}
86-
chipGroupProps={{
87-
numChips: 3,
88-
expandedText: t("hide"),
89-
collapsedText: t("showRemaining"),
90-
}}
91-
onToggle={(val) => setOpen(val)}
92-
isOpen={open}
93-
selections={selectedValues}
94-
onFilter={(value) => {
95-
setSearch(value);
96-
return renderScopes(allScopes || []);
97-
}}
98-
onSelect={(selectedValue) => {
99-
const option =
100-
typeof selectedValue === "string"
101-
? selectedValue
102-
: (selectedValue as Scope).name;
103-
const changedValue = field.value.find(
104-
(o: Scope) => o.name === option,
105-
)
106-
? field.value.filter((item: Scope) => item.name !== option)
107-
: [...field.value, { name: option }];
108-
field.onChange(changedValue);
109-
}}
110-
onClear={() => {
111-
setSearch("");
112-
field.onChange([]);
113-
}}
114-
typeAheadAriaLabel={t("authorizationScopes")}
115-
>
116-
{renderScopes(allScopes || [])}
117-
</KeycloakSelect>
88+
<>
89+
<KeycloakSelect
90+
toggleId="scopes"
91+
variant={SelectVariant.typeaheadMulti}
92+
chipGroupProps={{
93+
numChips: 3,
94+
expandedText: t("hide"),
95+
collapsedText: t("showRemaining"),
96+
}}
97+
onToggle={(val) => setOpen(val)}
98+
isOpen={open}
99+
selections={selectedValues}
100+
onFilter={(value) => {
101+
setSearch(value);
102+
return renderScopes(allScopes || []);
103+
}}
104+
onSelect={(selectedValue) => {
105+
const option =
106+
typeof selectedValue === "string"
107+
? selectedValue
108+
: (selectedValue as Scope).name;
109+
const changedValue = field.value.find(
110+
(o: Scope) => o.name === option,
111+
)
112+
? field.value.filter((item: Scope) => item.name !== option)
113+
: [...field.value, { name: option }];
114+
field.onChange(changedValue);
115+
}}
116+
onClear={() => {
117+
setSearch("");
118+
field.onChange([]);
119+
}}
120+
typeAheadAriaLabel={t("authorizationScopes")}
121+
>
122+
{renderScopes(allScopes || [])}
123+
</KeycloakSelect>
124+
{isAdminPermissionsClient && errors.scopes && (
125+
<FormErrorText message={t("required")} />
126+
)}
127+
</>
118128
);
119129
}}
120130
/>

js/apps/admin-ui/src/clients/authorization/SearchDropdown.tsx

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,9 @@ export type SearchForm = {
2323
uri?: string;
2424
owner?: string;
2525
resourceType?: string;
26-
policyId?: string;
2726
};
2827

2928
type SearchDropdownProps = {
30-
policies?: PolicyRepresentation[];
3129
resources?: UserRepresentation[];
3230
types?: PolicyRepresentation[];
3331
search: SearchForm;
@@ -36,7 +34,6 @@ type SearchDropdownProps = {
3634
};
3735

3836
export const SearchDropdown = ({
39-
policies,
4037
resources,
4138
types,
4239
search,
@@ -57,9 +54,6 @@ export const SearchDropdown = ({
5754

5855
const [open, toggle] = useToggle();
5956
const [resourceScopes, setResourceScopes] = useState<string[]>([]);
60-
const [localPolicies, setLocalPolicies] = useState<PolicyRepresentation[]>(
61-
policies || [],
62-
);
6357
const selectedType = useWatch({ control: form.control, name: "type" });
6458
const [key, setKey] = useState(0);
6559

@@ -71,11 +65,7 @@ export const SearchDropdown = ({
7165
useEffect(() => {
7266
const type = types?.find((item) => item.type === selectedType);
7367
setResourceScopes(type?.scopes || []);
74-
75-
if (policies?.length) {
76-
setLocalPolicies(policies);
77-
}
78-
}, [selectedType, types, policies]);
68+
}, [selectedType, types]);
7969

8070
useEffect(() => {
8171
reset(search);
@@ -125,7 +115,7 @@ export const SearchDropdown = ({
125115
)}
126116
{type !== "resource" && (
127117
<SelectControl
128-
name={type !== "adminPermission" ? "type" : "type"}
118+
name={type !== "adminPermission" ? "type" : "resourceType"}
129119
label={type !== "adminPermission" ? t("type") : t("resourceType")}
130120
controller={{
131121
defaultValue: "",
@@ -173,21 +163,6 @@ export const SearchDropdown = ({
173163
]}
174164
/>
175165
)}
176-
{type === "adminPermission" && (
177-
<SelectControl
178-
name={"policyId"}
179-
label={t("policy")}
180-
controller={{ defaultValue: search.policyId || "" }}
181-
options={
182-
localPolicies
183-
? localPolicies.map(({ id, name }) => ({
184-
key: id!,
185-
value: name!,
186-
}))
187-
: []
188-
}
189-
/>
190-
)}
191166
<ActionGroup>
192167
<Button
193168
variant="primary"

js/apps/admin-ui/src/clients/authorization/policy/ClientScope.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,10 @@ export const ClientScope = () => {
4242

4343
useFetch(
4444
() => adminClient.clientScopes.find(),
45-
(scopes) => {
45+
(scopes = []) => {
46+
const clientScopes = getValues("clientScopes") || [];
4647
setSelectedScopes(
47-
getValues("clientScopes").map(
48-
(s) => scopes.find((c) => c.id === s.id)!,
49-
),
48+
clientScopes.map((s) => scopes.find((c) => c.id === s.id)!),
5049
);
5150
setScopes(localeSort(scopes, mapByKey("name")));
5251
},

js/apps/admin-ui/src/components/client/ClientSelect.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@ export const ClientSelect = ({
6262
onFilter={(value) => setSearch(value)}
6363
variant={variant}
6464
isDisabled={isDisabled}
65-
options={clients.map(({ clientId }) => clientId!)}
65+
options={clients.map(({ id, clientId }) => ({
66+
key: id!,
67+
value: clientId!,
68+
label: clientId,
69+
}))}
6670
/>
6771
);
6872
};

js/apps/admin-ui/src/permissions-configuration/NewPermissionConfigurationDialog.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
Alert,
1010
} from "@patternfly/react-core";
1111
import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table";
12-
import { isValidComponentType } from "./permission-configuration/PermissionConfigurationDetails";
1312

1413
type NewPermissionConfigurationDialogProps = {
1514
resourceTypes?: ResourceTypesRepresentation[];
@@ -63,8 +62,7 @@ export const NewPermissionConfigurationDialog = ({
6362
>
6463
<Td>{resourceType.type}</Td>
6564
<Td style={{ textWrap: "wrap" }}>
66-
{isValidComponentType(resourceType.type!) &&
67-
t(`resourceType.${resourceType.type}`)}
65+
{t(`resourceType.${resourceType.type}`)}
6866
</Td>
6967
</Tr>
7068
);

js/apps/admin-ui/src/permissions-configuration/PermissionsConfigurationSection.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,9 @@ export default function PermissionsConfigurationSection() {
206206
</Tab>
207207
{hasViewUsers && (
208208
<Tab
209-
id="evaluate"
210-
data-testid="permissionsEvaluate"
211-
title={<TabTitleText>{t("evaluate")}</TabTitleText>}
209+
id="evaluation"
210+
data-testid="permissionsEvaluation"
211+
title={<TabTitleText>{t("evaluation")}</TabTitleText>}
212212
{...permissionsEvaluateTab}
213213
>
214214
<AuthorizationEvaluate

js/apps/admin-ui/src/permissions-configuration/PermissionsConfigurationTab.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,6 @@ export const PermissionsConfigurationTab = ({
149149
[key, search, first, max],
150150
);
151151

152-
const policies = useMemo(() => {
153-
return permissions
154-
?.flatMap((permission) => permission?.policies!)
155-
.filter((policy) => policy?.name);
156-
}, [permissions]);
157-
158152
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
159153
titleKey: "deletePermission",
160154
messageKey: t("deleteAdminPermissionConfirm", {
@@ -217,7 +211,6 @@ export const PermissionsConfigurationTab = ({
217211
<>
218212
<ToolbarItem>
219213
<SearchDropdown
220-
policies={policies!}
221214
resources={users!}
222215
types={resourceTypes}
223216
search={search}
@@ -332,7 +325,7 @@ export const PermissionsConfigurationTab = ({
332325
(resource: ResourceRepresentation, index) => (
333326
<Td key={index}>
334327
<span style={{ marginLeft: "8px" }}>
335-
{resource.displayName}
328+
{resource.displayName || resource.name}
336329
</span>
337330
</Td>
338331
),
@@ -371,7 +364,7 @@ export const PermissionsConfigurationTab = ({
371364
<>
372365
{newDialog && (
373366
<NewPermissionConfigurationDialog
374-
resourceTypes={resourceServer?.authorizationSchema!.resourceTypes}
367+
resourceTypes={resourceTypes}
375368
onSelect={(resourceType) =>
376369
navigate(
377370
toCreatePermissionConfiguration({

0 commit comments

Comments
 (0)