111 lines
4.2 KiB
Java
111 lines
4.2 KiB
Java
package org.keycloak.admin.ui.rest;
|
|
|
|
import java.util.List;
|
|
import static org.keycloak.models.utils.ModelToRepresentation.toRepresentation;
|
|
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Stream;
|
|
import javax.ws.rs.Consumes;
|
|
import javax.ws.rs.DefaultValue;
|
|
import javax.ws.rs.GET;
|
|
import javax.ws.rs.Produces;
|
|
import javax.ws.rs.QueryParam;
|
|
|
|
import org.eclipse.microprofile.openapi.annotations.Operation;
|
|
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
|
|
import org.eclipse.microprofile.openapi.annotations.media.Content;
|
|
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
|
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
|
|
import org.keycloak.models.GroupModel;
|
|
import org.keycloak.models.KeycloakSession;
|
|
import org.keycloak.models.RealmModel;
|
|
import org.keycloak.models.utils.ModelToRepresentation;
|
|
import org.keycloak.representations.idm.GroupRepresentation;
|
|
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
|
import org.keycloak.utils.StringUtil;
|
|
|
|
public class GroupsResource {
|
|
private final KeycloakSession session;
|
|
private final RealmModel realm;
|
|
private final AdminPermissionEvaluator auth;
|
|
|
|
public GroupsResource(KeycloakSession session, RealmModel realm, AdminPermissionEvaluator auth) {
|
|
super();
|
|
this.realm = realm;
|
|
this.auth = auth;
|
|
this.session = session;
|
|
}
|
|
|
|
@GET
|
|
@Consumes({"application/json"})
|
|
@Produces({"application/json"})
|
|
@Operation(
|
|
summary = "List all groups with fine grained authorisation",
|
|
description = "This endpoint returns a list of groups with fine grained authorisation"
|
|
)
|
|
@APIResponse(
|
|
responseCode = "200",
|
|
description = "",
|
|
content = {@Content(
|
|
schema = @Schema(
|
|
implementation = GroupRepresentation.class,
|
|
type = SchemaType.ARRAY
|
|
)
|
|
)}
|
|
)
|
|
public final Stream<GroupRepresentation> listGroups(@QueryParam("search") @DefaultValue("") final String search, @QueryParam("first")
|
|
@DefaultValue("0") int first, @QueryParam("max") @DefaultValue("10") int max, @QueryParam("global") @DefaultValue("true") boolean global,
|
|
@QueryParam("exact") @DefaultValue("false") boolean exact) {
|
|
this.auth.groups().requireList();
|
|
final Stream<GroupModel> stream;
|
|
if (global) {
|
|
stream = session.groups().searchForGroupByNameStream(realm, search.trim(), exact, first, max);
|
|
} else {
|
|
stream = this.realm.getTopLevelGroupsStream().filter(g -> g.getName().contains(search)).skip(first).limit(max);
|
|
}
|
|
|
|
return stream.map(g -> toGroupHierarchy(g, search, exact));
|
|
}
|
|
|
|
private GroupRepresentation toGroupHierarchy(GroupModel group, final String search, boolean exact) {
|
|
GroupRepresentation rep = toRepresentation(group, true);
|
|
rep.setSubGroups(group.getSubGroupsStream().filter(g ->
|
|
groupMatchesSearchOrIsPathElement(
|
|
g, search
|
|
)
|
|
).map(subGroup ->
|
|
ModelToRepresentation.toGroupHierarchy(
|
|
subGroup, true, search, exact
|
|
)
|
|
|
|
).collect(Collectors.toList()));
|
|
|
|
setAccess(group, rep);
|
|
|
|
return rep;
|
|
}
|
|
|
|
// set fine-grained access for each group in the tree
|
|
private void setAccess(GroupModel groupTree, GroupRepresentation rootGroup) {
|
|
if (rootGroup == null) return;
|
|
|
|
rootGroup.setAccess(auth.groups().getAccess(groupTree));
|
|
|
|
rootGroup.getSubGroups().stream().forEach(subGroup -> {
|
|
GroupModel foundGroupModel = groupTree.getSubGroupsStream().filter(g -> g.getId().equals(subGroup.getId())).findFirst().get();
|
|
setAccess(foundGroupModel, subGroup);
|
|
});
|
|
|
|
}
|
|
|
|
private static boolean groupMatchesSearchOrIsPathElement(GroupModel group, String search) {
|
|
if (StringUtil.isBlank(search)) {
|
|
return true;
|
|
}
|
|
if (group.getName().contains(search)) {
|
|
return true;
|
|
}
|
|
return group.getSubGroupsStream().findAny().isPresent();
|
|
}
|
|
}
|