mirror of
https://gitee.com/jmix/cuba.git
synced 2024-12-03 03:38:33 +08:00
PL-7476 Paging does not work when using in-memory security constraints
This commit is contained in:
parent
e7e0a88060
commit
262eae7582
@ -65,6 +65,12 @@ public interface PersistenceSecurity extends Security {
|
||||
*/
|
||||
void applyConstraints(Collection<Entity> entities);
|
||||
|
||||
/**
|
||||
* Filter entities in collection by in-memory constraints
|
||||
* @param entities -
|
||||
*/
|
||||
boolean filterByConstraints(Collection<Entity> entities);
|
||||
|
||||
/**
|
||||
* Reads security token and restores filtered data
|
||||
* @param resultEntity -
|
||||
|
@ -538,36 +538,53 @@ public class DataManagerBean implements DataManager {
|
||||
return copy;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <E extends Entity> List<E> getResultList(LoadContext<E> context, Query query, boolean ensureDistinct) {
|
||||
List<E> list = executeQuery(query, false);
|
||||
if (!ensureDistinct || list.size() == 0)
|
||||
boolean filteredByConstraints = false;
|
||||
int initialSize = list.size();
|
||||
if (initialSize == 0) {
|
||||
return list;
|
||||
}
|
||||
if (needFilterByConstraints(context)) {
|
||||
filteredByConstraints = security.filterByConstraints((Collection<Entity>) list);
|
||||
}
|
||||
if (!ensureDistinct) {
|
||||
return filteredByConstraints ? getResultListIterative(context, query, list, initialSize) : list;
|
||||
}
|
||||
|
||||
int requestedFirst = context.getQuery().getFirstResult();
|
||||
LinkedHashSet<E> set = new LinkedHashSet<>(list);
|
||||
if (set.size() == list.size() && requestedFirst == 0) {
|
||||
// If this is the first chunk and it has no duplicates, just return it
|
||||
if (set.size() == list.size() && requestedFirst == 0 && !filteredByConstraints) {
|
||||
// If this is the first chunk and it has no duplicates and security constraints is not applied, just return it
|
||||
return list;
|
||||
}
|
||||
// In case of not first chunk, even if there where no duplicates, start filling the set from zero
|
||||
// to ensure correct paging
|
||||
return getResultListIterative(context, query, set, initialSize);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <E extends Entity> List<E> getResultListIterative(LoadContext<E> context, Query query,
|
||||
Collection<E> filteredCollection,
|
||||
int initialSize) {
|
||||
int requestedFirst = context.getQuery().getFirstResult();
|
||||
int requestedMax = context.getQuery().getMaxResults();
|
||||
|
||||
if (requestedMax == 0) {
|
||||
// set contains all items if query without paging
|
||||
return new ArrayList<>(set);
|
||||
return new ArrayList<>(filteredCollection);
|
||||
}
|
||||
|
||||
int setSize = list.size() + requestedFirst;
|
||||
int factor = list.size() / set.size() * 2;
|
||||
int setSize = initialSize + requestedFirst;
|
||||
int factor = initialSize / filteredCollection.size() * 2;
|
||||
|
||||
set.clear();
|
||||
filteredCollection.clear();
|
||||
|
||||
int firstResult = 0;
|
||||
int maxResults = (requestedFirst + requestedMax) * factor;
|
||||
int i = 0;
|
||||
while (set.size() < setSize) {
|
||||
while (filteredCollection.size() < setSize) {
|
||||
if (i++ > 10) {
|
||||
log.warn("In-memory distinct: endless loop detected for " + context);
|
||||
break;
|
||||
@ -575,19 +592,23 @@ public class DataManagerBean implements DataManager {
|
||||
query.setFirstResult(firstResult);
|
||||
query.setMaxResults(maxResults);
|
||||
//noinspection unchecked
|
||||
list = query.getResultList();
|
||||
if (list.size() == 0)
|
||||
List<E> list = query.getResultList();
|
||||
if (list.size() == 0) {
|
||||
break;
|
||||
set.addAll(list);
|
||||
}
|
||||
if (needFilterByConstraints(context)) {
|
||||
security.filterByConstraints((Collection<Entity>) list);
|
||||
}
|
||||
filteredCollection.addAll(list);
|
||||
|
||||
firstResult = firstResult + maxResults;
|
||||
}
|
||||
|
||||
// Copy by iteration because subList() returns non-serializable class
|
||||
int max = Math.min(requestedFirst + requestedMax, set.size());
|
||||
int max = Math.min(requestedFirst + requestedMax, filteredCollection.size());
|
||||
List<E> result = new ArrayList<>(max - requestedFirst);
|
||||
int j = 0;
|
||||
for (E item : set) {
|
||||
for (E item : filteredCollection) {
|
||||
if (j >= max)
|
||||
break;
|
||||
if (j >= requestedFirst)
|
||||
@ -764,6 +785,15 @@ public class DataManagerBean implements DataManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean needFilterByConstraints(LoadContext context) {
|
||||
if (!isAuthorizationRequired() || !userSessionSource.getUserSession().hasConstraints()) {
|
||||
return false;
|
||||
}
|
||||
MetaClass metaClass = metadata.getSession().getClassNN(context.getMetaClass());
|
||||
return security.hasConstraints(metaClass);
|
||||
}
|
||||
|
||||
|
||||
protected Set<Class> collectEntityClasses(View view, Set<View> visited) {
|
||||
if (visited.contains(view)) {
|
||||
return Collections.emptySet();
|
||||
|
@ -116,6 +116,20 @@ public class PersistenceSecurityImpl extends SecurityImpl implements Persistence
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean filterByConstraints(Collection<Entity> entities) {
|
||||
boolean filtered = false;
|
||||
for (Iterator<Entity> iterator = entities.iterator(); iterator.hasNext(); ) {
|
||||
Entity entity = iterator.next();
|
||||
if (entity instanceof HasUuid && !isPermittedInMemory(entity)) {
|
||||
//we ignore situations when the collection is immutable
|
||||
iterator.remove();
|
||||
filtered = true;
|
||||
}
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyConstraints(Collection<Entity> entities) {
|
||||
List<Entity> supportedEntities = entities.stream().filter(e -> e instanceof HasUuid).collect(Collectors.toList());
|
||||
@ -226,10 +240,7 @@ public class PersistenceSecurityImpl extends SecurityImpl implements Persistence
|
||||
protected boolean internalApplyConstraints(Entity entity, Set<UUID> handled) {
|
||||
MetaClass metaClass = entity.getMetaClass();
|
||||
|
||||
if (!isPermitted(entity, constraint ->
|
||||
constraint.getCheckType().memory()
|
||||
&& (constraint.getOperationType() == ConstraintOperationType.READ
|
||||
|| constraint.getOperationType() == ConstraintOperationType.ALL))) {
|
||||
if (!isPermittedInMemory(entity)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -266,4 +277,11 @@ public class PersistenceSecurityImpl extends SecurityImpl implements Persistence
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isPermittedInMemory(Entity entity) {
|
||||
return isPermitted(entity, constraint ->
|
||||
constraint.getCheckType().memory()
|
||||
&& (constraint.getOperationType() == ConstraintOperationType.READ
|
||||
|| constraint.getOperationType() == ConstraintOperationType.ALL));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user