mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 23:12:06 -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;
|
import java.util.Set;
|
||||||
|
|
||||||
public class ResourceType {
|
public class ResourceType {
|
||||||
|
|
||||||
private final String type;
|
private final String type;
|
||||||
private final Set<String> scopes;
|
private final Set<String> scopes;
|
||||||
private final Map<String, Set<String>> scopeAliases;
|
private final Map<String, Set<String>> scopeAliases;
|
||||||
|
private final String groupType;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public ResourceType(@JsonProperty("type") String type, @JsonProperty("scopes") Set<String> scopes) {
|
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) {
|
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.type = type;
|
||||||
this.scopes = Collections.unmodifiableSet(scopes);
|
this.scopes = Collections.unmodifiableSet(scopes);
|
||||||
this.scopeAliases = scopeAliases;
|
this.scopeAliases = scopeAliases;
|
||||||
|
this.groupType = groupType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getType() {
|
public String getType() {
|
||||||
@ -49,4 +56,8 @@ public class ResourceType {
|
|||||||
public Map<String, Set<String>> getScopeAliases() {
|
public Map<String, Set<String>> getScopeAliases() {
|
||||||
return Collections.unmodifiableMap(scopeAliases);
|
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 jakarta.persistence.criteria.Path;
|
||||||
import org.keycloak.authorization.AdminPermissionsSchema;
|
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.common.util.Time;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.credential.CredentialModel;
|
import org.keycloak.credential.CredentialModel;
|
||||||
@ -63,7 +61,6 @@ import jakarta.persistence.criteria.Join;
|
|||||||
import jakarta.persistence.criteria.JoinType;
|
import jakarta.persistence.criteria.JoinType;
|
||||||
import jakarta.persistence.criteria.Predicate;
|
import jakarta.persistence.criteria.Predicate;
|
||||||
import jakarta.persistence.criteria.Root;
|
import jakarta.persistence.criteria.Root;
|
||||||
import jakarta.persistence.criteria.Subquery;
|
|
||||||
import org.keycloak.storage.jpa.JpaHashUtils;
|
import org.keycloak.storage.jpa.JpaHashUtils;
|
||||||
import org.keycloak.utils.StringUtil;
|
import org.keycloak.utils.StringUtil;
|
||||||
|
|
||||||
@ -88,7 +85,7 @@ import static org.keycloak.utils.StreamsUtil.closing;
|
|||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("JpaQueryApiInspection")
|
@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 = "email";
|
||||||
private static final String EMAIL_VERIFIED = "emailVerified";
|
private static final String EMAIL_VERIFIED = "emailVerified";
|
||||||
@ -1098,112 +1095,12 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore, Parti
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Predicate> getFilters(EvaluationContext evaluationContext) {
|
public KeycloakSession getSession() {
|
||||||
if (!AdminPermissionsSchema.SCHEMA.isAdminPermissionsEnabled(session.getContext().getRealm())) {
|
return session;
|
||||||
// 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Predicate> getNegateFilters(EvaluationContext evaluationContext) {
|
public EntityManager getEntityManager() {
|
||||||
Predicate predicate = getFilterByGroupMembership(evaluationContext, true);
|
return em;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 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 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 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();
|
public static final AdminPermissionsSchema SCHEMA = new AdminPermissionsSchema();
|
||||||
|
|
||||||
private final PartialEvaluator partialEvaluator = new PartialEvaluator();
|
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) {
|
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) {
|
public PolicyEvaluator getPolicyEvaluator(KeycloakSession session, ResourceServer resourceServer) {
|
||||||
|
|||||||
@ -17,8 +17,6 @@
|
|||||||
|
|
||||||
package org.keycloak.authorization;
|
package org.keycloak.authorization;
|
||||||
|
|
||||||
import static java.util.function.Predicate.not;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -33,14 +31,13 @@ import org.keycloak.Config;
|
|||||||
import org.keycloak.authorization.model.Policy;
|
import org.keycloak.authorization.model.Policy;
|
||||||
import org.keycloak.authorization.model.Resource;
|
import org.keycloak.authorization.model.Resource;
|
||||||
import org.keycloak.authorization.model.Scope;
|
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.PartialEvaluationPolicyProvider;
|
||||||
import org.keycloak.authorization.policy.provider.PartialEvaluationStorageProvider;
|
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.authorization.policy.provider.PolicyProvider;
|
||||||
import org.keycloak.models.AdminRoles;
|
import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakContext;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
@ -50,99 +47,45 @@ import org.keycloak.representations.idm.authorization.ResourceType;
|
|||||||
|
|
||||||
public class PartialEvaluator {
|
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)) {
|
if (!AdminPermissionsSchema.SCHEMA.isAdminPermissionsEnabled(realm)) {
|
||||||
// feature not enabled, if a storage evaluator is provided try to resolve any filter from there
|
// 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 = session.getContext().getUser();
|
||||||
UserModel adminUser = context.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
|
// 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();
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
// collect the result from the partial evaluation so that the filters can be applied
|
// collect the result from the partial evaluation so that the filters can be applied
|
||||||
PartialResourceEvaluationResult result = evaluate(session, adminUser, resourceType);
|
PartialEvaluationContext context = runEvaluation(session, adminUser, resourceType, storage, builder, queryBuilder, path);
|
||||||
EvaluationContext evaluationContext = new EvaluationContext(resourceType, queryBuilder, path, new HashSet<>(), new HashSet<>());
|
|
||||||
|
|
||||||
if (AdminPermissionsSchema.USERS.equals(resourceType)) {
|
return buildPredicates(context);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private record PartialResourceEvaluationResult(ResourceType resourceType, Set<String> rawAllowedIds, Set<String> rawDeniedIds) {
|
private PartialEvaluationContext runEvaluation(KeycloakSession session, UserModel adminUser, ResourceType resourceType, PartialEvaluationStorageProvider storage, CriteriaBuilder builder, CriteriaQuery<?> queryBuilder, Path<?> path) {
|
||||||
Set<String> allowedIds() {
|
Set<String> allowedResources = new HashSet<>();
|
||||||
return rawAllowedIds.stream().filter(not(resourceType.getType()::equals)).collect(Collectors.toSet());
|
Set<String> deniedResources = new HashSet<>();
|
||||||
}
|
|
||||||
|
|
||||||
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<>();
|
|
||||||
List<PartialEvaluationPolicyProvider> policyProviders = getPartialEvaluationPolicyProviders(session);
|
List<PartialEvaluationPolicyProvider> policyProviders = getPartialEvaluationPolicyProviders(session);
|
||||||
|
|
||||||
for (PartialEvaluationPolicyProvider policyProvider : policyProviders) {
|
for (PartialEvaluationPolicyProvider policyProvider : policyProviders) {
|
||||||
policyProvider.getPermissions(session, resourceType, adminUser).forEach(permission -> {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> ids = permission.getResources().stream().map(Resource::getName).collect(Collectors.toSet());
|
Set<String> ids = permission.getResources().stream().map(Resource::getName).collect(Collectors.toSet());
|
||||||
Set<Policy> policies = permission.getAssociatedPolicies();
|
Set<Policy> policies = permission.getAssociatedPolicies();
|
||||||
|
|
||||||
for (Policy policy : policies) {
|
for (Policy policy : policies) {
|
||||||
PartialEvaluationPolicyProvider provider = policyProviders.stream().filter((p) -> p.supports(policy)).findAny().orElse(null);
|
PartialEvaluationPolicyProvider provider = getPartialEvaluationPolicyProvider(policy, policyProviders);
|
||||||
|
|
||||||
if (provider == null) {
|
if (provider == null) {
|
||||||
continue;
|
continue;
|
||||||
@ -155,25 +98,107 @@ public class PartialEvaluator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (granted) {
|
if (granted) {
|
||||||
allowedIds.addAll(ids);
|
allowedResources.addAll(ids);
|
||||||
} else {
|
} else {
|
||||||
deniedIds.addAll(ids);
|
deniedResources.addAll(ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
allowedIds.removeAll(deniedIds);
|
allowedResources.removeAll(deniedResources);
|
||||||
|
|
||||||
if (allowedIds.contains(resourceType.getType())) {
|
return createEvaluationContext(session, resourceType, allowedResources, deniedResources, storage, builder, queryBuilder, path, adminUser);
|
||||||
allowedIds.removeIf(not(resourceType.getType()::equals));
|
}
|
||||||
|
|
||||||
|
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())) {
|
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) {
|
private List<PartialEvaluationPolicyProvider> getPartialEvaluationPolicyProviders(KeycloakSession session) {
|
||||||
@ -183,22 +208,23 @@ public class PartialEvaluator {
|
|||||||
.toList();
|
.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) {
|
if (user == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String clientId;
|
ClientModel client = getRealmManagementClient(session);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
return true;
|
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);
|
return user.hasRole(client.getRole(AdminRoles.VIEW_USERS)) || user.hasRole(client.getRole(AdminRoles.MANAGE_USERS)) || !hasAnyQueryAdminRole(client, user);
|
||||||
} else if (resourceType.equals(AdminPermissionsSchema.CLIENTS)) {
|
} else if (resourceType.equals(AdminPermissionsSchema.CLIENTS)) {
|
||||||
return user.hasRole(client.getRole(AdminRoles.VIEW_CLIENTS)) || user.hasRole(client.getRole(AdminRoles.MANAGE_CLIENTS)) || !hasAnyQueryAdminRole(client, user);
|
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;
|
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;
|
package org.keycloak.authorization.policy.provider;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import jakarta.persistence.criteria.CriteriaQuery;
|
|
||||||
import jakarta.persistence.criteria.Path;
|
|
||||||
import jakarta.persistence.criteria.Predicate;
|
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,
|
* 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.
|
* @param evaluationContext the evaluation context.
|
||||||
* @return the list of predicates
|
* @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
|
* 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
|
* {@link Predicate} instances representing the filters that should be applied to queries
|
||||||
* when querying realm resources.
|
* when querying realm resources.
|
||||||
*
|
*
|
||||||
* @param evaluationContext the evaluation context.
|
* @param context the evaluation context.
|
||||||
* @return the list of predicates
|
* @return the list of predicates
|
||||||
*/
|
*/
|
||||||
List<Predicate> getNegateFilters(EvaluationContext evaluationContext);
|
List<Predicate> getNegateFilters(PartialEvaluationContext context);
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
import static org.keycloak.authorization.AdminPermissionsSchema.VIEW_MEMBERS;
|
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.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import jakarta.ws.rs.ForbiddenException;
|
import jakarta.ws.rs.ForbiddenException;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
@ -67,6 +73,17 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
@InjectUser(ref = "jdoe")
|
@InjectUser(ref = "jdoe")
|
||||||
ManagedUser userJdoe;
|
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")
|
@InjectAdminClient(mode = InjectAdminClient.Mode.MANAGED_REALM, client = "myclient", user = "myadmin")
|
||||||
Keycloak realmAdminClient;
|
Keycloak realmAdminClient;
|
||||||
|
|
||||||
@ -75,17 +92,36 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void onBefore() {
|
public void onBefore() {
|
||||||
for (int i = 0; i < 2; i++) {
|
Map<String, List<ManagedUser>> groupMembers = new HashMap<>();
|
||||||
GroupRepresentation group = new GroupRepresentation();
|
|
||||||
group.setName("group-" + i);
|
groupMembers.put("group-0", List.of(userAlice));
|
||||||
realm.admin().groups().add(group).close();
|
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");
|
UserRepresentation myadmin = realm.admin().users().search("myadmin").get(0);
|
||||||
joinGroup(userBob, "group-1");
|
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());
|
ALL_USERS = new ArrayList<>();
|
||||||
denyPolicy = createUserPolicy(Logic.NEGATIVE, realm, client,"Not My Admin User Policy", realm.admin().users().search("myadmin").get(0).getId());
|
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
|
@AfterEach
|
||||||
@ -101,8 +137,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_01() {
|
public void test_01() {
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter();
|
||||||
assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -113,8 +148,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
public void test_02() {
|
public void test_02() {
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
// TODO: should see only user members of groups
|
assertFilter(ALL_GROUP_MEMBERS);
|
||||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder("alice", "bob"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -125,8 +159,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
public void test_03() {
|
public void test_03() {
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter();
|
||||||
assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -137,8 +170,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
public void test_04() {
|
public void test_04() {
|
||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder("alice"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -150,9 +182,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
// TODO: should only see users that are members of groups
|
assertFilter(ALL_GROUP_MEMBERS);
|
||||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
|
||||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder("alice", "bob"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -164,9 +194,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
// TODO: should see only members of single group
|
assertFilter(userAlice);
|
||||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
|
||||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder("alice", "bob"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -177,8 +205,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
public void test_07() {
|
public void test_07() {
|
||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter();
|
||||||
assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -190,9 +217,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
// TODO: should see only members of groups except those from single group
|
assertFilter(userBob, userTom, userMary);
|
||||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
|
||||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder("bob"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -216,8 +241,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
public void test_10() {
|
public void test_10() {
|
||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(ALL_USERS);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -229,8 +253,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(ALL_USERS);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -242,9 +265,8 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
// TODO: should not see users members of a group
|
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
||||||
// List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userJdoe.getUsername(), "myadmin"));
|
||||||
// assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder("jdoe", "myadmin"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -256,9 +278,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
|
|
||||||
// TODO: should return all users
|
assertFilter(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"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -271,8 +291,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(ALL_USERS);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -285,9 +304,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
// TODO: should see user that are not a member of a group or members of the single group
|
assertFilter(userAlice, userJdoe, myadmin);
|
||||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
|
||||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -299,8 +316,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userBob, userJdoe, myadmin, userTom, userMary);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -313,8 +329,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userBob, userJdoe, myadmin, userTom, userMary);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -327,9 +342,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
// TODO: should see only users not members of groups
|
assertFilter(userJdoe, 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(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -340,8 +353,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
public void test_19() {
|
public void test_19() {
|
||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter();
|
||||||
assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -353,8 +365,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter();
|
||||||
assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -366,8 +377,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter();
|
||||||
assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -379,9 +389,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
|
|
||||||
// NOK denying all users permissions should have precedence over group permissions and not return users
|
assertFilter();
|
||||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
|
||||||
//assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -394,9 +402,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
// NOK denying all users permissions should have precedence over group permissions and not return users
|
assertFilter();
|
||||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
|
||||||
//assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -409,9 +415,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
// NOK denying all users permissions should have precedence over group permissions and not return users
|
assertFilter();
|
||||||
// List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
|
||||||
// assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -423,8 +427,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter();
|
||||||
assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -437,8 +440,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter();
|
||||||
assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -451,8 +453,7 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter();
|
||||||
assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -461,10 +462,9 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_28() {
|
public void test_28() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -473,11 +473,10 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_29() {
|
public void test_29() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice, userBob, userTom, userMary);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -486,11 +485,10 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_30() {
|
public void test_30() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -499,11 +497,10 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_31() {
|
public void test_31() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowGroup("group-1");
|
allowGroup("group-1");
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice, userBob);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -512,13 +509,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_32() {
|
public void test_32() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
//NOK all group members should be granted
|
assertFilter(userAlice, userBob, userTom, userMary);
|
||||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
|
||||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -527,12 +522,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_33() {
|
public void test_33() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -541,12 +535,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_33_a() {
|
public void test_33_a() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowGroup("group-1");
|
allowGroup("group-1");
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice, userBob);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -555,11 +548,10 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_34() {
|
public void test_34() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter();
|
||||||
assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -568,13 +560,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_35() {
|
public void test_35() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
//NOK should grant access to users from other groups
|
assertFilter(userBob, userTom, userMary);
|
||||||
//List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
|
||||||
//assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userBob.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -583,12 +573,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_35_a() {
|
public void test_35_a() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyGroup("group-1");
|
denyGroup("group-1");
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice, userTom, userMary);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -597,13 +586,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_36() {
|
public void test_36() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
//NOK should grant access to users from other groups
|
assertFilter();
|
||||||
// List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
|
||||||
// assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -612,11 +599,10 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_37() {
|
public void test_37() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(ALL_USERS);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -625,12 +611,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_38() {
|
public void test_38() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(ALL_USERS);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -639,13 +624,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_39() {
|
public void test_39() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
//NOK should not return members from groups other than the user that was granted
|
assertFilter(userAlice, userJdoe, myadmin);
|
||||||
//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"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -654,13 +637,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_40() {
|
public void test_40() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
|
|
||||||
//NOK not sure if it should restrict or grant access
|
assertFilter(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"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -669,13 +650,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_40_a() {
|
public void test_40_a() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
allowGroup("group-1");
|
allowGroup("group-1");
|
||||||
|
|
||||||
//NOK not sure if it should restrict or grant access
|
assertFilter(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"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -684,13 +663,12 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_41() {
|
public void test_41() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
allowGroup("group-1");
|
allowGroup("group-1");
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(ALL_USERS);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -699,14 +677,12 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_42() {
|
public void test_42() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
//TODO should return single resource and users not members of groups
|
assertFilter(userAlice, userJdoe, myadmin);
|
||||||
// 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"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -715,14 +691,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_42_a() {
|
public void test_42_a() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
allowGroup("group-1");
|
allowGroup("group-1");
|
||||||
denyAllGroups();
|
|
||||||
|
|
||||||
//NOK not sure if it should restrict or grant access
|
assertFilter(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"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -731,12 +704,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_43() {
|
public void test_43() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userBob, userJdoe, myadmin, userTom, userMary);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -745,13 +717,12 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_44() {
|
public void test_44() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userBob, userJdoe, myadmin, userTom, userMary);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userBob.getUsername(), userJdoe.getUsername(), "myadmin"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, true);
|
assertUpdate(userBob, true);
|
||||||
@ -760,14 +731,12 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_45() {
|
public void test_45() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
allowAllUsers();
|
allowAllUsers();
|
||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
//NOK filtering is not taking into account when group membership is denied to all groups
|
assertFilter(userJdoe, myadmin);
|
||||||
//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"));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -776,11 +745,10 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_46() {
|
public void test_46() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -789,12 +757,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_47() {
|
public void test_47() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -803,12 +770,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_48() {
|
public void test_48() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -817,12 +783,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_49() {
|
public void test_49() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -831,12 +796,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_49_a() {
|
public void test_49_a() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
allowGroup("group-1");
|
allowGroup("group-1");
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername(), userBob.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -845,13 +809,12 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_50() {
|
public void test_50() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -860,13 +823,12 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_51() {
|
public void test_51() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
allowGroup("group-0");
|
allowGroup("group-0");
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -875,12 +837,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_52() {
|
public void test_52() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter();
|
||||||
assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -889,12 +850,11 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_52_a() {
|
public void test_52_a() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
denyGroup("group-1");
|
denyGroup("group-1");
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter(userAlice);
|
||||||
assertThat(search.stream().map(UserRepresentation::getUsername).toList(), containsInAnyOrder(userAlice.getUsername()));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, true);
|
assertUpdate(userAlice, true);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -903,13 +863,12 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_53() {
|
public void test_53() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
allowAllGroups();
|
allowAllGroups();
|
||||||
|
|
||||||
List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
assertFilter();
|
||||||
assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
@ -918,26 +877,104 @@ public class UserResourceTypeEvaluationSpecTest extends AbstractPermissionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_54() {
|
public void test_54() {
|
||||||
allowUser(userAlice.getId());
|
allowUser(userAlice);
|
||||||
denyAllUsers();
|
denyAllUsers();
|
||||||
denyGroup("group-0");
|
denyGroup("group-0");
|
||||||
denyAllGroups();
|
denyAllGroups();
|
||||||
|
|
||||||
// NOK should return alice because the resource is granted
|
assertFilter();
|
||||||
// List<UserRepresentation> search = realmAdminClient.realm(realm.getName()).users().search(null, -1, -1);
|
|
||||||
// assertThat(search.isEmpty(), is(true));
|
|
||||||
|
|
||||||
assertUpdate(userAlice, false);
|
assertUpdate(userAlice, false);
|
||||||
assertUpdate(userBob, false);
|
assertUpdate(userBob, false);
|
||||||
assertUpdate(userJdoe, 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() {
|
private void allowAllUsers() {
|
||||||
createAllPermission(client, USERS_RESOURCE_TYPE, allowPolicy, Set.of(VIEW, MANAGE));
|
createAllPermission(client, USERS_RESOURCE_TYPE, allowPolicy, Set.of(VIEW, MANAGE));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void allowUser(String id) {
|
private void allowUser(ManagedUser user) {
|
||||||
createPermission(client, id , USERS_RESOURCE_TYPE, Set.of(VIEW, MANAGE), allowPolicy);
|
createPermission(client, user.getId() , USERS_RESOURCE_TYPE, Set.of(VIEW, MANAGE), allowPolicy);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void denyAllUsers() {
|
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