mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 15:02:05 -03:30
Aligning partial evaluation with the outcome from regular evaluations
Closes #38626 Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
parent
94673a6eb0
commit
dbb0179a93
@ -23,9 +23,11 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class ResourceType {
|
||||
|
||||
private final String type;
|
||||
private final Set<String> scopes;
|
||||
private final Map<String, Set<String>> scopeAliases;
|
||||
private final String groupType;
|
||||
|
||||
@JsonCreator
|
||||
public ResourceType(@JsonProperty("type") String type, @JsonProperty("scopes") Set<String> scopes) {
|
||||
@ -33,9 +35,14 @@ public class ResourceType {
|
||||
}
|
||||
|
||||
public ResourceType(String type, Set<String> scopes, Map<String, Set<String>> scopeAliases) {
|
||||
this(type, scopes, scopeAliases, null);
|
||||
}
|
||||
|
||||
public ResourceType(String type, Set<String> scopes, Map<String, Set<String>> scopeAliases, String groupType) {
|
||||
this.type = type;
|
||||
this.scopes = Collections.unmodifiableSet(scopes);
|
||||
this.scopeAliases = scopeAliases;
|
||||
this.groupType = groupType;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
@ -49,4 +56,8 @@ public class ResourceType {
|
||||
public Map<String, Set<String>> getScopeAliases() {
|
||||
return Collections.unmodifiableMap(scopeAliases);
|
||||
}
|
||||
|
||||
public String getGroupType() {
|
||||
return groupType;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright 2025 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.models.jpa;
|
||||
|
||||
import static org.keycloak.authorization.AdminPermissionsSchema.GROUPS_RESOURCE_TYPE;
|
||||
import static org.keycloak.authorization.AdminPermissionsSchema.USERS_RESOURCE_TYPE;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Expression;
|
||||
import jakarta.persistence.criteria.Path;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import jakarta.persistence.criteria.Subquery;
|
||||
import org.keycloak.authorization.AdminPermissionsSchema;
|
||||
import org.keycloak.authorization.jpa.entities.ResourceEntity;
|
||||
import org.keycloak.authorization.policy.provider.PartialEvaluationContext;
|
||||
import org.keycloak.authorization.policy.provider.PartialEvaluationStorageProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.jpa.entities.UserGroupMembershipEntity;
|
||||
|
||||
/**
|
||||
* A {@link PartialEvaluationStorageProvider} that provides support for partial evaluation when querying {@link UserModel}.
|
||||
*/
|
||||
public interface JpaUserPartialEvaluationProvider extends PartialEvaluationStorageProvider {
|
||||
|
||||
KeycloakSession getSession();
|
||||
EntityManager getEntityManager();
|
||||
|
||||
@Override
|
||||
default List<Predicate> getFilters(PartialEvaluationContext context) {
|
||||
KeycloakSession session = getSession();
|
||||
|
||||
if (!AdminPermissionsSchema.SCHEMA.isAdminPermissionsEnabled(session.getContext().getRealm())) {
|
||||
// support for FGAP v1, remove once v1 is removed
|
||||
Set<String> userGroups = (Set<String>) session.getAttribute(UserModel.GROUPS);
|
||||
|
||||
|
||||
if (userGroups != null) {
|
||||
return List.of(getFilterByGroupMembership(session, context, userGroups));
|
||||
}
|
||||
|
||||
return List.of();
|
||||
}
|
||||
|
||||
return Optional.ofNullable(getAllowedGroupFilters(context)).map(List::of).orElse(List.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<Predicate> getNegateFilters(PartialEvaluationContext context) {
|
||||
return Optional.ofNullable(getDeniedGroupsFilters(context)).map(List::of).orElse(List.of());
|
||||
}
|
||||
|
||||
private Predicate getAllowedGroupFilters(PartialEvaluationContext context) {
|
||||
Set<String> allowedGroups = context.getAllowedGroups();
|
||||
|
||||
if (allowedGroups.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (context.deniedResources().contains(USERS_RESOURCE_TYPE)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (context.isResourceTypeAllowed()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
EntityManager em = getEntityManager();
|
||||
CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
|
||||
if (allowedGroups.contains(GROUPS_RESOURCE_TYPE)) {
|
||||
return cb.exists(createUserMembershipSubquery(context));
|
||||
}
|
||||
|
||||
return cb.exists(createUserMembershipSubquery(context, root -> root.get("groupId").in(allowedGroups)));
|
||||
}
|
||||
|
||||
private Predicate getDeniedGroupsFilters(PartialEvaluationContext context) {
|
||||
CriteriaBuilder cb = context.getCriteriaBuilder();
|
||||
Set<String> allowedGroups = context.getAllowedGroups();
|
||||
Set<String> deniedGroups = context.getDeniedGroups();
|
||||
|
||||
if (deniedGroups.contains(GROUPS_RESOURCE_TYPE)) {
|
||||
// no access granted to group resources
|
||||
Predicate notMembers = cb.not(cb.exists(createUserMembershipSubquery(context)));
|
||||
|
||||
// access denied for the group resource type
|
||||
if (context.isResourceTypeAllowed()) {
|
||||
// access granted to all resources
|
||||
if (allowedGroups.isEmpty()) {
|
||||
if (context.getDeniedGroupIds().isEmpty()) {
|
||||
// filter group members but allow
|
||||
return cb.and(cb.or(notMembers, context.getPath().get("id").in(context.getAllowedResourceIds())));
|
||||
}
|
||||
|
||||
return notMembers;
|
||||
}
|
||||
|
||||
Predicate onlySpecificGroups = cb.exists(createUserMembershipSubquery(context, root -> root.get("groupId").in(allowedGroups)));
|
||||
return cb.and(cb.or(notMembers, onlySpecificGroups));
|
||||
}
|
||||
|
||||
return cb.not(cb.exists(createUserMembershipSubquery(context, root -> root.get("groupId").in(context.getDeniedGroupIds()))));
|
||||
}
|
||||
|
||||
if (context.getAllowedResources().isEmpty() && (allowedGroups.isEmpty() || context.deniedResources().contains(USERS_RESOURCE_TYPE))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return cb.not(cb.exists(createUserMembershipSubquery(context, root -> root.get("groupId").in(deniedGroups))));
|
||||
}
|
||||
|
||||
private Subquery<?> createUserMembershipSubquery(PartialEvaluationContext context) {
|
||||
return createUserMembershipSubquery(context, null);
|
||||
}
|
||||
|
||||
private Subquery<?> createUserMembershipSubquery(PartialEvaluationContext context, Function<Root<?>, Predicate> predicate) {
|
||||
EntityManager em = getEntityManager();
|
||||
CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
CriteriaQuery<?> query = context.criteriaQuery();
|
||||
Subquery<Integer> subquery = query.subquery(Integer.class);
|
||||
Root<?> from = subquery.from(UserGroupMembershipEntity.class);
|
||||
|
||||
subquery.select(cb.literal(1));
|
||||
|
||||
Path<?> root = context.getPath();
|
||||
List<Predicate> finalPredicates = new ArrayList<>();
|
||||
|
||||
if (predicate != null) {
|
||||
finalPredicates.add(predicate.apply(from));
|
||||
}
|
||||
|
||||
finalPredicates.add(cb.equal(from.get("user").get("id"), root.get("id")));
|
||||
|
||||
subquery.where(finalPredicates.toArray(Predicate[]::new));
|
||||
|
||||
return subquery;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated remove once FGAP v1 is removed
|
||||
*/
|
||||
@Deprecated
|
||||
private Predicate getFilterByGroupMembership(KeycloakSession session, PartialEvaluationContext context, Set<String> groupIds) {
|
||||
EntityManager em = getEntityManager();
|
||||
CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
CriteriaQuery<?> query = context.criteriaQuery();
|
||||
Subquery<Integer> subquery = query.subquery(Integer.class);
|
||||
Root<?> from = subquery.from(UserGroupMembershipEntity.class);
|
||||
|
||||
subquery.select(cb.literal(1));
|
||||
|
||||
List<Predicate> subPredicates = new ArrayList<>();
|
||||
|
||||
subPredicates.add(from.get("groupId").in(groupIds));
|
||||
|
||||
Path<?> root = context.getPath();
|
||||
|
||||
subPredicates.add(cb.equal(from.get("user").get("id"), root.get("id")));
|
||||
|
||||
Subquery<Integer> subquery1 = query.subquery(Integer.class);
|
||||
|
||||
subquery1.select(cb.literal(1));
|
||||
|
||||
Root<ResourceEntity> from1 = subquery1.from(ResourceEntity.class);
|
||||
|
||||
List<Predicate> subs = new ArrayList<>();
|
||||
|
||||
Expression<String> groupId = from.get("groupId");
|
||||
|
||||
RealmModel realm = session.getContext().getRealm();
|
||||
|
||||
if (AdminPermissionsSchema.SCHEMA.isAdminPermissionsEnabled(realm)) {
|
||||
subs.add(cb.like(from1.get("name"), groupId));
|
||||
} else {
|
||||
subs.add(cb.like(from1.get("name"), cb.concat("group.resource.", groupId)));
|
||||
}
|
||||
|
||||
subquery1.where(subs.toArray(Predicate[]::new));
|
||||
|
||||
subPredicates.add(cb.exists(subquery1));
|
||||
|
||||
subquery.where(subPredicates.toArray(Predicate[]::new));
|
||||
|
||||
return cb.exists(subquery);
|
||||
}
|
||||
}
|
||||
@ -19,8 +19,6 @@ package org.keycloak.models.jpa;
|
||||
|
||||
import jakarta.persistence.criteria.Path;
|
||||
import org.keycloak.authorization.AdminPermissionsSchema;
|
||||
import org.keycloak.authorization.jpa.entities.ResourceEntity;
|
||||
import org.keycloak.authorization.policy.provider.PartialEvaluationStorageProvider;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.credential.CredentialModel;
|
||||
@ -63,7 +61,6 @@ import jakarta.persistence.criteria.Join;
|
||||
import jakarta.persistence.criteria.JoinType;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import jakarta.persistence.criteria.Subquery;
|
||||
import org.keycloak.storage.jpa.JpaHashUtils;
|
||||
import org.keycloak.utils.StringUtil;
|
||||
|
||||
@ -88,7 +85,7 @@ import static org.keycloak.utils.StreamsUtil.closing;
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
@SuppressWarnings("JpaQueryApiInspection")
|
||||
public class JpaUserProvider implements UserProvider, UserCredentialStore, PartialEvaluationStorageProvider {
|
||||
public class JpaUserProvider implements UserProvider, UserCredentialStore, JpaUserPartialEvaluationProvider {
|
||||
|
||||
private static final String EMAIL = "email";
|
||||
private static final String EMAIL_VERIFIED = "emailVerified";
|
||||
@ -1098,112 +1095,12 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore, Parti
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Predicate> getFilters(EvaluationContext evaluationContext) {
|
||||
if (!AdminPermissionsSchema.SCHEMA.isAdminPermissionsEnabled(session.getContext().getRealm())) {
|
||||
// support for FGAP v1
|
||||
Set<String> userGroups = (Set<String>) session.getAttribute(UserModel.GROUPS);
|
||||
|
||||
|
||||
if (userGroups != null) {
|
||||
return List.of(getFilterByGroupMembership(session, evaluationContext, userGroups));
|
||||
}
|
||||
|
||||
return List.of();
|
||||
}
|
||||
|
||||
Predicate predicate = getFilterByGroupMembership(evaluationContext, false);
|
||||
|
||||
if (predicate != null) {
|
||||
return List.of(predicate);
|
||||
}
|
||||
|
||||
return List.of();
|
||||
public KeycloakSession getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Predicate> getNegateFilters(EvaluationContext evaluationContext) {
|
||||
Predicate predicate = getFilterByGroupMembership(evaluationContext, true);
|
||||
|
||||
if (predicate != null) {
|
||||
return List.of(predicate);
|
||||
}
|
||||
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private Predicate getFilterByGroupMembership(KeycloakSession session, EvaluationContext evaluationContext, Set<String> groupIds) {
|
||||
CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
CriteriaQuery<?> query = evaluationContext.criteriaQuery();
|
||||
Subquery subquery = query.subquery(String.class);
|
||||
Root<?> from = subquery.from(UserGroupMembershipEntity.class);
|
||||
|
||||
subquery.select(cb.literal(1));
|
||||
|
||||
List<Predicate> subPredicates = new ArrayList<>();
|
||||
|
||||
subPredicates.add(from.get("groupId").in(groupIds));
|
||||
|
||||
Path<?> root = evaluationContext.path();
|
||||
|
||||
subPredicates.add(cb.equal(from.get("user").get("id"), root.get("id")));
|
||||
|
||||
Subquery subquery1 = query.subquery(String.class);
|
||||
|
||||
subquery1.select(cb.literal(1));
|
||||
|
||||
Root from1 = subquery1.from(ResourceEntity.class);
|
||||
|
||||
List<Predicate> subs = new ArrayList<>();
|
||||
|
||||
Expression<String> groupId = from.get("groupId");
|
||||
|
||||
RealmModel realm = session.getContext().getRealm();
|
||||
|
||||
if (AdminPermissionsSchema.SCHEMA.isAdminPermissionsEnabled(realm)) {
|
||||
subs.add(cb.like(from1.get("name"), groupId));
|
||||
} else {
|
||||
subs.add(cb.like(from1.get("name"), cb.concat("group.resource.", groupId)));
|
||||
}
|
||||
|
||||
subquery1.where(subs.toArray(Predicate[]::new));
|
||||
|
||||
subPredicates.add(cb.exists(subquery1));
|
||||
|
||||
subquery.where(subPredicates.toArray(Predicate[]::new));
|
||||
|
||||
return cb.exists(subquery);
|
||||
}
|
||||
|
||||
private Predicate getFilterByGroupMembership(EvaluationContext evaluationContext, boolean negate) {
|
||||
if (negate && evaluationContext.deniedGroupIds().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (!negate && evaluationContext.allowedGroupIds().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
CriteriaQuery<?> query = evaluationContext.criteriaQuery();
|
||||
Subquery subquery = query.subquery(String.class);
|
||||
Root<?> from = subquery.from(UserGroupMembershipEntity.class);
|
||||
|
||||
subquery.select(cb.literal(1));
|
||||
|
||||
List<Predicate> subPredicates = new ArrayList<>();
|
||||
|
||||
subPredicates.add(from.get("groupId").in(negate ? evaluationContext.deniedGroupIds() : evaluationContext.allowedGroupIds()));
|
||||
|
||||
Path<?> root = evaluationContext.path();
|
||||
|
||||
subPredicates.add(cb.equal(from.get("user").get("id"), root.get("id")));
|
||||
|
||||
subquery.where(subPredicates.toArray(Predicate[]::new));
|
||||
|
||||
if (negate) {
|
||||
return cb.not(cb.exists(subquery));
|
||||
}
|
||||
|
||||
return cb.exists(subquery);
|
||||
public EntityManager getEntityManager() {
|
||||
return em;
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ public class AdminPermissionsSchema extends AuthorizationSchema {
|
||||
public static final ResourceType CLIENTS = new ResourceType(CLIENTS_RESOURCE_TYPE, Set.of(CONFIGURE, MANAGE, MAP_ROLES, MAP_ROLES_CLIENT_SCOPE, MAP_ROLES_COMPOSITE, VIEW));
|
||||
public static final ResourceType GROUPS = new ResourceType(GROUPS_RESOURCE_TYPE, Set.of(MANAGE, VIEW, MANAGE_MEMBERSHIP, MANAGE_MEMBERS, VIEW_MEMBERS));
|
||||
public static final ResourceType ROLES = new ResourceType(ROLES_RESOURCE_TYPE, Set.of(MAP_ROLE, MAP_ROLE_CLIENT_SCOPE, MAP_ROLE_COMPOSITE));
|
||||
public static final ResourceType USERS = new ResourceType(USERS_RESOURCE_TYPE, Set.of(MANAGE, VIEW, IMPERSONATE, MAP_ROLES, MANAGE_GROUP_MEMBERSHIP), Map.of(VIEW, Set.of(VIEW_MEMBERS), MANAGE, Set.of(MANAGE_MEMBERS)));
|
||||
public static final ResourceType USERS = new ResourceType(USERS_RESOURCE_TYPE, Set.of(MANAGE, VIEW, IMPERSONATE, MAP_ROLES, MANAGE_GROUP_MEMBERSHIP), Map.of(VIEW, Set.of(VIEW_MEMBERS), MANAGE, Set.of(MANAGE_MEMBERS)), GROUPS.getType());
|
||||
public static final AdminPermissionsSchema SCHEMA = new AdminPermissionsSchema();
|
||||
|
||||
private final PartialEvaluator partialEvaluator = new PartialEvaluator();
|
||||
@ -444,7 +444,7 @@ public class AdminPermissionsSchema extends AuthorizationSchema {
|
||||
}
|
||||
|
||||
public List<Predicate> applyAuthorizationFilters(KeycloakSession session, ResourceType resourceType, PartialEvaluationStorageProvider evaluator, RealmModel realm, CriteriaBuilder builder, CriteriaQuery<?> queryBuilder, Path<?> path) {
|
||||
return partialEvaluator.applyAuthorizationFilters(session, resourceType, evaluator, realm, builder, queryBuilder, path);
|
||||
return partialEvaluator.getPredicates(session, resourceType, evaluator, realm, builder, queryBuilder, path);
|
||||
}
|
||||
|
||||
public PolicyEvaluator getPolicyEvaluator(KeycloakSession session, ResourceServer resourceServer) {
|
||||
|
||||
@ -17,8 +17,6 @@
|
||||
|
||||
package org.keycloak.authorization;
|
||||
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -33,14 +31,13 @@ import org.keycloak.Config;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.Resource;
|
||||
import org.keycloak.authorization.model.Scope;
|
||||
import org.keycloak.authorization.policy.provider.PartialEvaluationContext;
|
||||
import org.keycloak.authorization.policy.provider.PartialEvaluationPolicyProvider;
|
||||
import org.keycloak.authorization.policy.provider.PartialEvaluationStorageProvider;
|
||||
import org.keycloak.authorization.policy.provider.PartialEvaluationStorageProvider.EvaluationContext;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
||||
import org.keycloak.models.AdminRoles;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakContext;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
@ -50,99 +47,45 @@ import org.keycloak.representations.idm.authorization.ResourceType;
|
||||
|
||||
public class PartialEvaluator {
|
||||
|
||||
public List<Predicate> applyAuthorizationFilters(KeycloakSession session, ResourceType resourceType, PartialEvaluationStorageProvider storage, RealmModel realm, CriteriaBuilder builder, CriteriaQuery<?> queryBuilder, Path<?> path) {
|
||||
private static final String NO_ID = "none";
|
||||
private static final String ID_FIELD = "id";
|
||||
|
||||
public List<Predicate> getPredicates(KeycloakSession session, ResourceType resourceType, PartialEvaluationStorageProvider storage, RealmModel realm, CriteriaBuilder builder, CriteriaQuery<?> queryBuilder, Path<?> path) {
|
||||
if (!AdminPermissionsSchema.SCHEMA.isAdminPermissionsEnabled(realm)) {
|
||||
// feature not enabled, if a storage evaluator is provided try to resolve any filter from there
|
||||
return storage == null ? List.of() : storage.getFilters(new EvaluationContext(resourceType, queryBuilder, path, Set.of(), Set.of()));
|
||||
return storage == null ? List.of() : storage.getFilters(new PartialEvaluationContext(storage, builder, queryBuilder, path));
|
||||
}
|
||||
|
||||
KeycloakContext context = session.getContext();
|
||||
UserModel adminUser = context.getUser();
|
||||
UserModel adminUser = session.getContext().getUser();
|
||||
|
||||
if (skipPartialEvaluation(session, adminUser, realm, resourceType)) {
|
||||
if (shouldSkipPartialEvaluation(session, adminUser, realm, resourceType)) {
|
||||
// only run partial evaluation if the admin user does not have view-* or manage-* role for specified resourceType or has any query-* role
|
||||
return List.of();
|
||||
}
|
||||
|
||||
// collect the result from the partial evaluation so that the filters can be applied
|
||||
PartialResourceEvaluationResult result = evaluate(session, adminUser, resourceType);
|
||||
EvaluationContext evaluationContext = new EvaluationContext(resourceType, queryBuilder, path, new HashSet<>(), new HashSet<>());
|
||||
PartialEvaluationContext context = runEvaluation(session, adminUser, resourceType, storage, builder, queryBuilder, path);
|
||||
|
||||
if (AdminPermissionsSchema.USERS.equals(resourceType)) {
|
||||
PartialResourceEvaluationResult evaluateGroups = evaluate(session, adminUser, AdminPermissionsSchema.GROUPS);
|
||||
|
||||
evaluationContext.allowedGroupIds().addAll(evaluateGroups.allowedIds());
|
||||
evaluationContext.deniedGroupIds().addAll(evaluateGroups.deniedIds());
|
||||
}
|
||||
|
||||
List<Predicate> predicates = new ArrayList<>();
|
||||
Set<String> deniedIds = result.deniedIds();
|
||||
|
||||
if (!deniedIds.isEmpty()) {
|
||||
// add filters to remove denied resources from the result set
|
||||
predicates.add(builder.not(path.get("id").in(deniedIds)));
|
||||
}
|
||||
|
||||
List<Predicate> storageFilters = storage == null ? List.of() : storage.getFilters(evaluationContext);
|
||||
List<Predicate> storageNegateFilters = storage == null ? List.of() : storage.getNegateFilters(evaluationContext);
|
||||
|
||||
predicates.addAll(storageNegateFilters);
|
||||
|
||||
if (storageFilters.isEmpty() && (result.isResourceTypedDenied() || (!deniedIds.isEmpty() && result.rawAllowedIds().isEmpty()))) {
|
||||
// do not return any result because there is no filter from the evaluator, and access is denied for the resource type
|
||||
return List.of(builder.equal(path.get("id"), "none"));
|
||||
}
|
||||
|
||||
Set<String> allowedIds = result.allowedIds();
|
||||
|
||||
if (allowedIds.isEmpty()) {
|
||||
// no resources granted, filter them based on any filter previously set
|
||||
predicates.addAll(storageFilters);
|
||||
return predicates;
|
||||
}
|
||||
|
||||
if (storageFilters.isEmpty()) {
|
||||
// no filter from the evaluator, filter based on the resources that were granted
|
||||
predicates.add(builder.and(path.get("id").in(allowedIds)));
|
||||
} else {
|
||||
// there are filters from the evaluator, the resources granted will be a returned using a or condition
|
||||
List<Predicate> orPredicates = new ArrayList<>(storageFilters);
|
||||
orPredicates.add(path.get("id").in(allowedIds));
|
||||
predicates.add(builder.or(orPredicates.toArray(new Predicate[0])));
|
||||
}
|
||||
|
||||
return predicates;
|
||||
return buildPredicates(context);
|
||||
}
|
||||
|
||||
private record PartialResourceEvaluationResult(ResourceType resourceType, Set<String> rawAllowedIds, Set<String> rawDeniedIds) {
|
||||
Set<String> allowedIds() {
|
||||
return rawAllowedIds.stream().filter(not(resourceType.getType()::equals)).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
Set<String> deniedIds() {
|
||||
return rawDeniedIds.stream().filter(not(resourceType.getType()::equals)).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
boolean isResourceTypedDenied() {
|
||||
return rawAllowedIds.isEmpty() && (rawDeniedIds.isEmpty() || (rawDeniedIds.size() == 1 && rawDeniedIds.contains(resourceType.getType())));
|
||||
}
|
||||
}
|
||||
|
||||
private PartialResourceEvaluationResult evaluate(KeycloakSession session, UserModel adminUser, ResourceType resourceType) {
|
||||
Set<String> allowedIds = new HashSet<>();
|
||||
Set<String> deniedIds = new HashSet<>();
|
||||
private PartialEvaluationContext runEvaluation(KeycloakSession session, UserModel adminUser, ResourceType resourceType, PartialEvaluationStorageProvider storage, CriteriaBuilder builder, CriteriaQuery<?> queryBuilder, Path<?> path) {
|
||||
Set<String> allowedResources = new HashSet<>();
|
||||
Set<String> deniedResources = new HashSet<>();
|
||||
List<PartialEvaluationPolicyProvider> policyProviders = getPartialEvaluationPolicyProviders(session);
|
||||
|
||||
for (PartialEvaluationPolicyProvider policyProvider : policyProviders) {
|
||||
policyProvider.getPermissions(session, resourceType, adminUser).forEach(permission -> {
|
||||
if (permission.getScopes().stream().map(Scope::getName).noneMatch(name -> name.startsWith(AdminPermissionsSchema.VIEW))) {
|
||||
if (!hasViewScope(permission)) {
|
||||
// only run partial evaluation for permissions with any view scope
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> ids = permission.getResources().stream().map(Resource::getName).collect(Collectors.toSet());
|
||||
Set<Policy> policies = permission.getAssociatedPolicies();
|
||||
|
||||
for (Policy policy : policies) {
|
||||
PartialEvaluationPolicyProvider provider = policyProviders.stream().filter((p) -> p.supports(policy)).findAny().orElse(null);
|
||||
PartialEvaluationPolicyProvider provider = getPartialEvaluationPolicyProvider(policy, policyProviders);
|
||||
|
||||
if (provider == null) {
|
||||
continue;
|
||||
@ -155,25 +98,107 @@ public class PartialEvaluator {
|
||||
}
|
||||
|
||||
if (granted) {
|
||||
allowedIds.addAll(ids);
|
||||
allowedResources.addAll(ids);
|
||||
} else {
|
||||
deniedIds.addAll(ids);
|
||||
deniedResources.addAll(ids);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
allowedIds.removeAll(deniedIds);
|
||||
allowedResources.removeAll(deniedResources);
|
||||
|
||||
if (allowedIds.contains(resourceType.getType())) {
|
||||
allowedIds.removeIf(not(resourceType.getType()::equals));
|
||||
return createEvaluationContext(session, resourceType, allowedResources, deniedResources, storage, builder, queryBuilder, path, adminUser);
|
||||
}
|
||||
|
||||
private List<Predicate> buildPredicates(PartialEvaluationContext context) {
|
||||
List<Predicate> storageFilters = getStorageFilters(context);
|
||||
CriteriaBuilder builder = context.getCriteriaBuilder();
|
||||
Path<?> path = context.getPath();
|
||||
|
||||
if (isDenied(storageFilters, context)) {
|
||||
// do not return any result because there is no filter from the evaluator, and access is denied for the resource type
|
||||
return List.of(builder.equal(path.get(ID_FIELD), NO_ID));
|
||||
}
|
||||
|
||||
Set<String> deniedIds = context.getDeniedResources();
|
||||
ResourceType resourceType = context.getResourceType();
|
||||
|
||||
if (deniedIds.contains(resourceType.getType())) {
|
||||
deniedIds.removeIf(not(resourceType.getType()::equals));
|
||||
// do not filter by id if access is granted to the resource type
|
||||
deniedIds = Set.of();
|
||||
}
|
||||
|
||||
return new PartialResourceEvaluationResult(resourceType, allowedIds, deniedIds);
|
||||
List<Predicate> predicates = new ArrayList<>();
|
||||
|
||||
if (!deniedIds.isEmpty()) {
|
||||
// add filters to remove denied resources from the result set
|
||||
predicates.add(builder.not(path.get(ID_FIELD).in(deniedIds)));
|
||||
}
|
||||
|
||||
List<Predicate> storageNegateFilters = getStorageNegateFilters(context);
|
||||
|
||||
// add filters from the storage that deny access to resources
|
||||
predicates.addAll(storageNegateFilters);
|
||||
|
||||
Set<String> allowedResourceIds = context.getAllowedResources();
|
||||
|
||||
if (allowedResourceIds.contains(resourceType.getType())) {
|
||||
// do not filter by id if access is granted to the resource type
|
||||
allowedResourceIds = Set.of();
|
||||
}
|
||||
|
||||
if (allowedResourceIds.isEmpty()) {
|
||||
// no resources granted, return any predicates created until now
|
||||
predicates.addAll(storageFilters);
|
||||
return predicates;
|
||||
}
|
||||
|
||||
if (storageFilters.isEmpty()) {
|
||||
// no filter from the evaluator, filter based on the resources that were granted
|
||||
predicates.add(builder.and(path.get(ID_FIELD).in(allowedResourceIds)));
|
||||
} else {
|
||||
// there are filters from the evaluator, the resources granted will be a returned using a or condition
|
||||
List<Predicate> orPredicates = new ArrayList<>(storageFilters);
|
||||
orPredicates.add(path.get(ID_FIELD).in(allowedResourceIds));
|
||||
predicates.add(builder.or(orPredicates.toArray(new Predicate[0])));
|
||||
}
|
||||
|
||||
return predicates;
|
||||
}
|
||||
|
||||
private PartialEvaluationContext createEvaluationContext(KeycloakSession session, ResourceType resourceType, Set<String> allowedResources, Set<String> deniedResources, PartialEvaluationStorageProvider storage, CriteriaBuilder builder, CriteriaQuery<?> queryBuilder, Path<?> path, UserModel adminUser) {
|
||||
PartialEvaluationContext context = new PartialEvaluationContext(resourceType, allowedResources, deniedResources, storage, builder, queryBuilder, path);
|
||||
String groupType = resourceType.getGroupType();
|
||||
|
||||
if (groupType != null) {
|
||||
// if the resource type has support for groups, evaluate permissions for the group
|
||||
ResourceType groupResourceType = AdminPermissionsSchema.SCHEMA.getResourceTypes().get(groupType);
|
||||
|
||||
if (groupResourceType == null) {
|
||||
return context;
|
||||
}
|
||||
|
||||
PartialEvaluationContext evaluateGroups = runEvaluation(session, adminUser, groupResourceType, storage, builder, queryBuilder, path);
|
||||
context.setAllowedGroups(evaluateGroups.getAllowedResources());
|
||||
context.setDeniedGroups(evaluateGroups.getDeniedResources());
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
private List<Predicate> getStorageFilters(PartialEvaluationContext context) {
|
||||
PartialEvaluationStorageProvider storage = context.getStorage();
|
||||
return storage == null ? List.of() : storage.getFilters(context);
|
||||
}
|
||||
|
||||
private List<Predicate> getStorageNegateFilters(PartialEvaluationContext context) {
|
||||
PartialEvaluationStorageProvider storage = context.getStorage();
|
||||
return storage == null ? List.of() : storage.getNegateFilters(context);
|
||||
}
|
||||
|
||||
private boolean isDenied(List<Predicate> storageFilters, PartialEvaluationContext context) {
|
||||
return context.getAllowedResources().isEmpty() && storageFilters.isEmpty();
|
||||
}
|
||||
|
||||
private List<PartialEvaluationPolicyProvider> getPartialEvaluationPolicyProviders(KeycloakSession session) {
|
||||
@ -183,22 +208,23 @@ public class PartialEvaluator {
|
||||
.toList();
|
||||
}
|
||||
|
||||
private boolean skipPartialEvaluation(KeycloakSession session, UserModel user, RealmModel realm, ResourceType resourceType) {
|
||||
private PartialEvaluationPolicyProvider getPartialEvaluationPolicyProvider(Policy policy, List<PartialEvaluationPolicyProvider> policyProviders) {
|
||||
return policyProviders.stream()
|
||||
.filter((p) -> p.supports(policy))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private boolean hasViewScope(Policy permission) {
|
||||
return permission.getScopes().stream().map(Scope::getName).anyMatch(name -> name.startsWith(AdminPermissionsSchema.VIEW));
|
||||
}
|
||||
|
||||
private boolean shouldSkipPartialEvaluation(KeycloakSession session, UserModel user, RealmModel realm, ResourceType resourceType) {
|
||||
if (user == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String clientId;
|
||||
|
||||
if (realm.getName().equals(Config.getAdminRealm())) {
|
||||
clientId = realm.getMasterAdminClient().getClientId();
|
||||
} else {
|
||||
ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||
clientId = client == null ? null : client.getClientId();
|
||||
}
|
||||
|
||||
// client probably removed when removing the realm
|
||||
ClientModel client = clientId == null ? null : session.clients().getClientByClientId(realm, clientId);
|
||||
ClientModel client = getRealmManagementClient(session);
|
||||
|
||||
if (client == null) {
|
||||
return true;
|
||||
@ -208,20 +234,32 @@ public class PartialEvaluator {
|
||||
return user.hasRole(client.getRole(AdminRoles.VIEW_USERS)) || user.hasRole(client.getRole(AdminRoles.MANAGE_USERS)) || !hasAnyQueryAdminRole(client, user);
|
||||
} else if (resourceType.equals(AdminPermissionsSchema.CLIENTS)) {
|
||||
return user.hasRole(client.getRole(AdminRoles.VIEW_CLIENTS)) || user.hasRole(client.getRole(AdminRoles.MANAGE_CLIENTS)) || !hasAnyQueryAdminRole(client, user);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasAnyQueryAdminRole(ClientModel client, UserModel user) {
|
||||
for (String adminRole : List.of(AdminRoles.QUERY_CLIENTS, AdminRoles.QUERY_GROUPS, AdminRoles.QUERY_USERS)) {
|
||||
RoleModel role = client.getRole(adminRole);
|
||||
|
||||
if (user.hasRole(role)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private ClientModel getRealmManagementClient(KeycloakSession session) {
|
||||
RealmModel realm = session.getContext().getRealm();
|
||||
|
||||
if (realm.getName().equals(Config.getAdminRealm())) {
|
||||
return session.clients().getClientByClientId(realm, realm.getMasterAdminClient().getClientId());
|
||||
}
|
||||
|
||||
return realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||
}
|
||||
|
||||
private boolean hasAnyQueryAdminRole(ClientModel client, UserModel user) {
|
||||
boolean result = false;
|
||||
for (String adminRole : List.of(AdminRoles.QUERY_CLIENTS, AdminRoles.QUERY_GROUPS, AdminRoles.QUERY_USERS)) {
|
||||
RoleModel role = client.getRole(adminRole);
|
||||
|
||||
if (user.hasRole(role)) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2025 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.authorization.policy.provider;
|
||||
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Path;
|
||||
import org.keycloak.representations.idm.authorization.ResourceType;
|
||||
|
||||
/**
|
||||
* An {@link PartialEvaluationContext} instance provides access to contextual information when building a query for realm
|
||||
* resources of a given {@link ResourceType}.
|
||||
*/
|
||||
public class PartialEvaluationContext {
|
||||
|
||||
private final ResourceType resourceType;
|
||||
private final CriteriaQuery<?> criteriaQuery;
|
||||
private final Path<?> path;
|
||||
private final PartialEvaluationStorageProvider storage;
|
||||
private final CriteriaBuilder criteriaBuilder;
|
||||
private final Set<String> allowedResources;
|
||||
private final Set<String> deniedResources;
|
||||
private Set<String> allowedGroups = Set.of();
|
||||
private Set<String> deniedGroups = Set.of();
|
||||
|
||||
public PartialEvaluationContext(PartialEvaluationStorageProvider storage, CriteriaBuilder criteriaBuilder, CriteriaQuery<?> criteriaQuery, Path<?> path) {
|
||||
this(null, Set.of(), Set.of(), storage, criteriaBuilder, criteriaQuery, path);
|
||||
}
|
||||
|
||||
public PartialEvaluationContext(ResourceType resourceType, Set<String> allowedResources, Set<String> deniedResources, PartialEvaluationStorageProvider storage, CriteriaBuilder criteriaBuilder, CriteriaQuery<?> criteriaQuery, Path<?> path) {
|
||||
this.allowedResources = allowedResources;
|
||||
this.deniedResources = deniedResources;
|
||||
this.storage = storage;
|
||||
this.criteriaBuilder = criteriaBuilder;
|
||||
this.criteriaQuery = criteriaQuery;
|
||||
this.path = path;
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public boolean isResourceTypeAllowed() {
|
||||
return allowedResources.contains(resourceType.getType());
|
||||
}
|
||||
|
||||
public Set<String> getAllowedResourceIds() {
|
||||
return allowedResources.stream().filter(not(resourceType.getType()::equals)).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Set<String> getDeniedGroupIds() {
|
||||
return deniedGroups.stream().filter(not(resourceType.getGroupType()::equals)).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public void setAllowedGroups(Set<String> allowedGroups) {
|
||||
this.allowedGroups = allowedGroups;
|
||||
}
|
||||
|
||||
public void setDeniedGroups(Set<String> deniedGroups) {
|
||||
this.deniedGroups = deniedGroups;
|
||||
}
|
||||
|
||||
public Set<String> getDeniedGroups() {
|
||||
return deniedGroups;
|
||||
}
|
||||
|
||||
public Set<String> getAllowedGroups() {
|
||||
return allowedGroups;
|
||||
}
|
||||
|
||||
public Set<String> getAllowedResources() {
|
||||
return allowedResources;
|
||||
}
|
||||
|
||||
public Path<?> getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public Set<String> deniedResources() {
|
||||
return deniedResources;
|
||||
}
|
||||
|
||||
public CriteriaQuery<?> criteriaQuery() {
|
||||
return criteriaQuery;
|
||||
}
|
||||
|
||||
public CriteriaBuilder getCriteriaBuilder() {
|
||||
return criteriaBuilder;
|
||||
}
|
||||
|
||||
public ResourceType getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
public PartialEvaluationStorageProvider getStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
public Set<String> getDeniedResources() {
|
||||
return deniedResources;
|
||||
}
|
||||
}
|
||||
@ -19,12 +19,8 @@
|
||||
package org.keycloak.authorization.policy.provider;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Path;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import org.keycloak.representations.idm.authorization.ResourceType;
|
||||
|
||||
/**
|
||||
* If a realm has the {@link org.keycloak.common.Profile.Feature#ADMIN_FINE_GRAINED_AUTHZ} feature enabled,
|
||||
@ -41,26 +37,15 @@ public interface PartialEvaluationStorageProvider {
|
||||
* @param evaluationContext the evaluation context.
|
||||
* @return the list of predicates
|
||||
*/
|
||||
List<Predicate> getFilters(EvaluationContext evaluationContext);
|
||||
List<Predicate> getFilters(PartialEvaluationContext evaluationContext);
|
||||
|
||||
/**
|
||||
* A callback method that will be called when building queries for realm resources to deny access to resources. It returns a list of
|
||||
* {@link Predicate} instances representing the filters that should be applied to queries
|
||||
* when querying realm resources.
|
||||
*
|
||||
* @param evaluationContext the evaluation context.
|
||||
* @param context the evaluation context.
|
||||
* @return the list of predicates
|
||||
*/
|
||||
List<Predicate> getNegateFilters(EvaluationContext evaluationContext);
|
||||
|
||||
/**
|
||||
* An {@link EvaluationContext} instance provides access to contextual information when building a query for realm
|
||||
* resources of a given {@link ResourceType}.
|
||||
*
|
||||
* @param resourceType the type of the resource to query
|
||||
* @param criteriaQuery the query to rely on when building predicates
|
||||
* @param path the path for the root entity
|
||||
*/
|
||||
record EvaluationContext(ResourceType resourceType, CriteriaQuery<?> criteriaQuery, Path<?> path, Set<String> allowedGroupIds, Set<String> deniedGroupIds) {
|
||||
}
|
||||
List<Predicate> getNegateFilters(PartialEvaluationContext context);
|
||||
}
|
||||
|
||||
@ -28,9 +28,15 @@ import static org.keycloak.authorization.AdminPermissionsSchema.USERS_RESOURCE_T
|
||||
import static org.keycloak.authorization.AdminPermissionsSchema.VIEW;
|
||||
import static org.keycloak.authorization.AdminPermissionsSchema.VIEW_MEMBERS;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jakarta.ws.rs.ForbiddenException;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
@ -67,6 +73,17 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
@InjectUser(ref = "jdoe")
|
||||
ManagedUser userJdoe;
|
||||
|
||||
@InjectUser(ref = "tom")
|
||||
ManagedUser userTom;
|
||||
|
||||
@InjectUser(ref = "mary")
|
||||
ManagedUser userMary;
|
||||
|
||||
ManagedUser myadmin;
|
||||
|
||||
private List<ManagedUser> ALL_GROUP_MEMBERS;
|
||||
private List<ManagedUser> ALL_USERS;
|
||||
|
||||
@InjectAdminClient(mode = InjectAdminClient.Mode.MANAGED_REALM, client = "myclient", user = "myadmin")
|
||||
Keycloak realmAdminClient;
|
||||
|
||||
@ -75,17 +92,36 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@BeforeEach
|
||||
public void onBefore() {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
GroupRepresentation group = new GroupRepresentation();
|
||||
group.setName("group-" + i);
|
||||
realm.admin().groups().add(group).close();
|
||||
Map<String, List<ManagedUser>> groupMembers = new HashMap<>();
|
||||
|
||||
groupMembers.put("group-0", List.of(userAlice));
|
||||
groupMembers.put("group-1", List.of(userBob));
|
||||
groupMembers.put("group-2", List.of(userMary, userTom));
|
||||
|
||||
for (Entry<String, List<ManagedUser>> group : groupMembers.entrySet()) {
|
||||
String name = group.getKey();
|
||||
|
||||
GroupRepresentation rep = new GroupRepresentation();
|
||||
rep.setName(name);
|
||||
realm.admin().groups().add(rep).close();
|
||||
|
||||
List<ManagedUser> members = group.getValue();
|
||||
|
||||
for (ManagedUser member : members) {
|
||||
joinGroup(member, name);
|
||||
}
|
||||
}
|
||||
|
||||
joinGroup(userAlice, "group-0");
|
||||
joinGroup(userBob, "group-1");
|
||||
UserRepresentation myadmin = realm.admin().users().search("myadmin").get(0);
|
||||
allowPolicy = createUserPolicy(realm, client, "Only My Admin User Policy", myadmin.getId());
|
||||
denyPolicy = createUserPolicy(Logic.NEGATIVE, realm, client,"Not My Admin User Policy", myadmin.getId());
|
||||
this.myadmin = new ManagedUser(myadmin, realm.admin().users().get(myadmin.getId()));
|
||||
|
||||
allowPolicy = createUserPolicy(realm, client, "Only My Admin User Policy", realm.admin().users().search("myadmin").get(0).getId());
|
||||
denyPolicy = createUserPolicy(Logic.NEGATIVE, realm, client,"Not My Admin User Policy", realm.admin().users().search("myadmin").get(0).getId());
|
||||
ALL_USERS = new ArrayList<>();
|
||||
groupMembers.values().forEach(ALL_USERS::addAll);
|
||||
ALL_USERS.add(this.myadmin);
|
||||
ALL_USERS.add(userJdoe);
|
||||
ALL_GROUP_MEMBERS = groupMembers.values().stream().flatMap(Collection::stream).toList();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@ -101,8 +137,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_01() {
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -113,8 +148,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
public void test_02() {
|
||||
allowAllGroups();
|
||||
|
||||
// TODO: should see only user members of groups
|
||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder("alice", "bob"));
|
||||
assertFilter(ALL_GROUP_MEMBERS);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -125,8 +159,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
public void test_03() {
|
||||
denyAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -137,8 +170,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
public void test_04() {
|
||||
allowGroup("group-0");
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder("alice"));
|
||||
assertFilter(userAlice);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -150,9 +182,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
allowGroup("group-0");
|
||||
allowAllGroups();
|
||||
|
||||
// TODO: should only see users that are members of groups
|
||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder("alice", "bob"));
|
||||
assertFilter(ALL_GROUP_MEMBERS);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -164,9 +194,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
allowGroup("group-0");
|
||||
denyAllGroups();
|
||||
|
||||
// TODO: should see only members of single group
|
||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder("alice", "bob"));
|
||||
assertFilter(userAlice);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -177,8 +205,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
public void test_07() {
|
||||
denyGroup("group-0");
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -190,9 +217,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
denyGroup("group-0");
|
||||
allowAllGroups();
|
||||
|
||||
// TODO: should see only members of groups except those from single group
|
||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder("bob"));
|
||||
assertFilter(userBob, userTom, userMary);
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, true);
|
||||
@ -216,8 +241,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
public void test_10() {
|
||||
allowAllUsers();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(ALL_USERS);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -229,8 +253,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
allowAllUsers();
|
||||
allowAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(ALL_USERS);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -242,9 +265,8 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
allowAllUsers();
|
||||
denyAllGroups();
|
||||
|
||||
// TODO: should not see users members of a group
|
||||
// List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
// assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder("jdoe", "myadmin"));
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userJdoe.getUsername(), "myadmin"));
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -256,9 +278,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
allowAllUsers();
|
||||
allowGroup("group-0");
|
||||
|
||||
// TODO: should return all users
|
||||
// List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
// assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(ALL_USERS);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -271,8 +291,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
allowGroup("group-0");
|
||||
allowAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(ALL_USERS);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -285,9 +304,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
allowGroup("group-0");
|
||||
denyAllGroups();
|
||||
|
||||
// TODO: should see user that are not a member of a group or members of the single group
|
||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
||||
assertFilter(userAlice, userJdoe, myadmin);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -299,8 +316,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
allowAllUsers();
|
||||
denyGroup("group-0");
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(userBob, userJdoe, myadmin, userTom, userMary);
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, true);
|
||||
@ -313,8 +329,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
denyGroup("group-0");
|
||||
allowAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(userBob, userJdoe, myadmin, userTom, userMary);
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, true);
|
||||
@ -327,9 +342,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
denyGroup("group-0");
|
||||
denyAllGroups();
|
||||
|
||||
// TODO: should see only users not members of groups
|
||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(userJdoe, myadmin);
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -340,8 +353,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
public void test_19() {
|
||||
denyAllUsers();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -353,8 +365,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
denyAllUsers();
|
||||
allowAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -366,8 +377,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
denyAllUsers();
|
||||
denyAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -379,9 +389,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
denyAllUsers();
|
||||
allowGroup("group-0");
|
||||
|
||||
// NOK denying all users permissions should have precedence over group permissions and not return users
|
||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
//assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -394,9 +402,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
allowGroup("group-0");
|
||||
allowAllGroups();
|
||||
|
||||
// NOK denying all users permissions should have precedence over group permissions and not return users
|
||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
//assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -409,9 +415,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
allowGroup("group-0");
|
||||
denyAllGroups();
|
||||
|
||||
// NOK denying all users permissions should have precedence over group permissions and not return users
|
||||
// List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
// assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -423,8 +427,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
denyAllUsers();
|
||||
denyGroup("group-0");
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -437,8 +440,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
denyGroup("group-0");
|
||||
allowAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -451,8 +453,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
denyGroup("group-0");
|
||||
denyAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -461,10 +462,9 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_28() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
||||
assertFilter(userAlice);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -473,11 +473,10 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_29() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
||||
assertFilter(userAlice, userBob, userTom, userMary);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -486,11 +485,10 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_30() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
||||
assertFilter(userAlice);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -499,11 +497,10 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_31() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowGroup("group-1");
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername()));
|
||||
assertFilter(userAlice, userBob);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -512,13 +509,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_32() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowGroup("group-0");
|
||||
allowAllGroups();
|
||||
|
||||
//NOK all group members should be granted
|
||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername()));
|
||||
assertFilter(userAlice, userBob, userTom, userMary);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -527,12 +522,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_33() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowGroup("group-0");
|
||||
denyAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
||||
assertFilter(userAlice);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -541,12 +535,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_33_a() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowGroup("group-1");
|
||||
denyAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername()));
|
||||
assertFilter(userAlice, userBob);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -555,11 +548,10 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_34() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyGroup("group-0");
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -568,13 +560,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_35() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyGroup("group-0");
|
||||
allowAllGroups();
|
||||
|
||||
//NOK should grant access to users from other groups
|
||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userBob.getUsername()));
|
||||
assertFilter(userBob, userTom, userMary);
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, true);
|
||||
@ -583,12 +573,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_35_a() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyGroup("group-1");
|
||||
allowAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
||||
assertFilter(userAlice, userTom, userMary);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -597,13 +586,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_36() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyGroup("group-0");
|
||||
denyAllGroups();
|
||||
|
||||
//NOK should grant access to users from other groups
|
||||
// List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
// assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -612,11 +599,10 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_37() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowAllUsers();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(ALL_USERS);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -625,12 +611,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_38() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowAllUsers();
|
||||
allowAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(ALL_USERS);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -639,13 +624,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_39() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowAllUsers();
|
||||
denyAllGroups();
|
||||
|
||||
//NOK should not return members from groups other than the user that was granted
|
||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(userAlice, userJdoe, myadmin);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -654,13 +637,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_40() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowAllUsers();
|
||||
allowGroup("group-0");
|
||||
|
||||
//NOK not sure if it should restrict or grant access
|
||||
// List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
// assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(ALL_USERS);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -669,13 +650,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_40_a() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowAllUsers();
|
||||
allowGroup("group-1");
|
||||
|
||||
//NOK not sure if it should restrict or grant access
|
||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(ALL_USERS);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -684,13 +663,12 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_41() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowAllUsers();
|
||||
allowGroup("group-1");
|
||||
allowAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(ALL_USERS);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -699,14 +677,12 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_42() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowAllUsers();
|
||||
allowGroup("group-0");
|
||||
denyAllGroups();
|
||||
|
||||
//TODO should return single resource and users not members of groups
|
||||
// List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
// assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(userAlice, userJdoe, myadmin);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -715,14 +691,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_42_a() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowAllUsers();
|
||||
allowGroup("group-1");
|
||||
denyAllGroups();
|
||||
|
||||
//NOK not sure if it should restrict or grant access
|
||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(ALL_USERS);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, true);
|
||||
@ -731,12 +704,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_43() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowAllUsers();
|
||||
denyGroup("group-0");
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(userBob, userJdoe, myadmin, userTom, userMary);
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, true);
|
||||
@ -745,13 +717,12 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_44() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowAllUsers();
|
||||
denyGroup("group-0");
|
||||
allowAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(userBob, userJdoe, myadmin, userTom, userMary);
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, true);
|
||||
@ -760,14 +731,12 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_45() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
allowAllUsers();
|
||||
denyGroup("group-0");
|
||||
denyAllGroups();
|
||||
|
||||
//NOK filtering is not taking into account when group membership is denied to all groups
|
||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
||||
assertFilter(userJdoe, myadmin);
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -776,11 +745,10 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_46() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyAllUsers();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
||||
assertFilter(userAlice);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -789,12 +757,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_47() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyAllUsers();
|
||||
allowAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
||||
assertFilter(userAlice);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -803,12 +770,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_48() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyAllUsers();
|
||||
denyAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
||||
assertFilter(userAlice);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -817,12 +783,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_49() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyAllUsers();
|
||||
allowGroup("group-0");
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
||||
assertFilter(userAlice);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -831,12 +796,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_49_a() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyAllUsers();
|
||||
allowGroup("group-1");
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername()));
|
||||
assertFilter(userAlice);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -845,13 +809,12 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_50() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyAllUsers();
|
||||
allowGroup("group-0");
|
||||
allowAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
||||
assertFilter(userAlice);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -860,13 +823,12 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_51() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyAllUsers();
|
||||
allowGroup("group-0");
|
||||
denyAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
||||
assertFilter(userAlice);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -875,12 +837,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_52() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyAllUsers();
|
||||
denyGroup("group-0");
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -889,12 +850,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_52_a() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyAllUsers();
|
||||
denyGroup("group-1");
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
||||
assertFilter(userAlice);
|
||||
|
||||
assertUpdate(userAlice, true);
|
||||
assertUpdate(userBob, false);
|
||||
@ -903,13 +863,12 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_53() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyAllUsers();
|
||||
denyGroup("group-0");
|
||||
allowAllGroups();
|
||||
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
@ -918,26 +877,104 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
|
||||
@Test
|
||||
public void test_54() {
|
||||
allowUser(userAlice.getId());
|
||||
allowUser(userAlice);
|
||||
denyAllUsers();
|
||||
denyGroup("group-0");
|
||||
denyAllGroups();
|
||||
|
||||
// NOK should return alice because the resource is granted
|
||||
// List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
// assertThat(search.isEmpty(), is(true));
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userBob, false);
|
||||
assertUpdate(userJdoe, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_55() {
|
||||
allowAllUsers();
|
||||
denyUser(userAlice);
|
||||
denyUser(userJdoe);
|
||||
|
||||
assertFilter(userBob, myadmin, userMary, userTom);
|
||||
|
||||
assertUpdate(userBob, true);
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userJdoe, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_56() {
|
||||
allowUser(userJdoe);
|
||||
denyUser(userBob);
|
||||
|
||||
assertFilter(userJdoe);
|
||||
|
||||
assertUpdate(userJdoe, true);
|
||||
assertUpdate(userBob, false);
|
||||
assertUpdate(userAlice, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_57() {
|
||||
denyUser(userAlice);
|
||||
denyUser(userJdoe);
|
||||
|
||||
assertFilter();
|
||||
|
||||
assertUpdate(userBob, false);
|
||||
assertUpdate(userAlice, false);
|
||||
assertUpdate(userJdoe, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_58() {
|
||||
denyUser(userTom);
|
||||
allowGroup("group-2");
|
||||
|
||||
assertFilter(userMary);
|
||||
|
||||
assertUpdate(userMary, true);
|
||||
assertUpdate(userTom, false);
|
||||
assertUpdate(userJdoe, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_59() {
|
||||
allowAllUsers();
|
||||
denyUser(userTom);
|
||||
allowGroup("group-1");
|
||||
|
||||
assertFilter(userAlice, userBob, userMary, userJdoe, myadmin);
|
||||
|
||||
assertUpdate(userMary, true);
|
||||
assertUpdate(userJdoe, true);
|
||||
assertUpdate(userTom, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_60() {
|
||||
allowAllUsers();
|
||||
denyUser(userTom);
|
||||
allowGroup("group-1");
|
||||
denyGroup("group-2");
|
||||
|
||||
assertFilter(userAlice, userBob, userJdoe, myadmin);
|
||||
|
||||
assertUpdate(userJdoe, true);
|
||||
assertUpdate(userMary, false);
|
||||
assertUpdate(userTom, false);
|
||||
}
|
||||
|
||||
private void denyUser(ManagedUser user) {
|
||||
createPermission(client, user.getId(), USERS_RESOURCE_TYPE, Set.of(VIEW, MANAGE), denyPolicy);
|
||||
}
|
||||
|
||||
private void allowAllUsers() {
|
||||
createAllPermission(client, USERS_RESOURCE_TYPE, allowPolicy, Set.of(VIEW, MANAGE));
|
||||
}
|
||||
|
||||
private void allowUser(String id) {
|
||||
createPermission(client, id , USERS_RESOURCE_TYPE, Set.of(VIEW, MANAGE), allowPolicy);
|
||||
private void allowUser(ManagedUser user) {
|
||||
createPermission(client, user.getId() , USERS_RESOURCE_TYPE, Set.of(VIEW, MANAGE), allowPolicy);
|
||||
}
|
||||
|
||||
private void denyAllUsers() {
|
||||
@ -1011,4 +1048,18 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void assertFilter(List<ManagedUser> expected) {
|
||||
assertFilter(expected.toArray(new ManagedUser[0]));
|
||||
}
|
||||
|
||||
private void assertFilter(ManagedUser... expected) {
|
||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||
|
||||
if (expected.length == 0) {
|
||||
assertThat(search.isEmpty(), is(true));
|
||||
} else {
|
||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(Stream.of(expected).map(ManagedUser::getUsername).toArray()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user