Skip to content
Snippets Groups Projects
Commit 777abc79 authored by Henrik tom Wörden's avatar Henrik tom Wörden Committed by Henrik tom Wörden
Browse files

ENH: Change the way entities without retrieve permissions are filtered

parent e70bbafc
No related branches found
No related tags found
1 merge request!65F permission checks
Pipeline #25065 failed
...@@ -33,9 +33,9 @@ import java.sql.Statement; ...@@ -33,9 +33,9 @@ import java.sql.Statement;
import java.sql.Types; import java.sql.Types;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -694,8 +694,6 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac ...@@ -694,8 +694,6 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
this.cached = true; this.cached = true;
} }
this.resultSet = filterEntitiesWithoutRetrievePermission(this.resultSet);
// Fill resulting entities into container // Fill resulting entities into container
if (this.container != null && this.type == Type.FIND) { if (this.container != null && this.type == Type.FIND) {
for (final IdVersionPair p : this.resultSet) { for (final IdVersionPair p : this.resultSet) {
...@@ -749,7 +747,10 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac ...@@ -749,7 +747,10 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
protected void executeNoCache(final Access access) { protected void executeNoCache(final Access access) {
try { try {
this.resultSet = getResultSet(executeStrategy(this.versioned), this.versioned); final String tabname = executeStrategy(this.versioned);
filterEntitiesWithoutRetrievePermission(tabname);
this.resultSet = getResultSet(tabname, this.versioned);
} finally { } finally {
cleanUp(); cleanUp();
} }
...@@ -793,67 +794,62 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac ...@@ -793,67 +794,62 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
* @throws SQLException * @throws SQLException
* @throws TransactionException * @throws TransactionException
*/ */
public void filterEntitiesWithoutRetrievePermission(final String resultSet) public void filterEntitiesWithoutRetrievePermission(final String resultSet) {
throws SQLException, TransactionException {
if (!filterEntitiesWithoutRetrievePermisions) { if (!filterEntitiesWithoutRetrievePermisions) {
return; return;
} }
cachable = false; cachable = false;
try (final Statement stmt = this.getConnection().createStatement()) {
final ResultSet rs = stmt.executeQuery("SELECT id from `" + resultSet + "`"); /*
* The following creates a table with the columns (entity ID, acl) from
* a given table with entity IDs. Here, acl is the string representation
* of the acl.
*
* TODO:In future, one might want to retrieve only a distinct set of acl
* with (acl_id, acl) and a table with (entity_id, acl_id) to reduce the
* amount of data being transfered.
*/
final Statement stmt = this.getConnection().createStatement()
final String query =
("SELECT entity_n_acl.id, entity_acl.acl from "
+ "(select entities.id, entities.acl from entities "
+ "inner join `" + resultSet + " as rs on entities.id=rs.id`) "
+ "as entity_n_acl "
+ "left join entity_acl on entity_n_acl.acl=entity_acl.id;");
final ResultSet entities_with_acl = stmt.executeQuery(query);
final HashMap<String, Boolean> acl_cache = new HashMap<String, Boolean>();
final List<Integer> toBeDeleted = new LinkedList<Integer>(); final List<Integer> toBeDeleted = new LinkedList<Integer>();
while (rs.next()) {
// @todo here, we must operate on sql site. only retrieve different permissions
while (entities_with_acl.next()) {
final long t1 = System.currentTimeMillis(); final long t1 = System.currentTimeMillis();
final Integer id = rs.getInt("id"); final Integer id = entities_with_acl.getInt("id");
if (id > 99 if (id <= 99) {
&& !execute(new RetrieveSparseEntity(id, null), this.getAccess()) continue;
.getEntity() }
.getEntityACL()
.isPermitted(this.getUser(), EntityPermission.RETRIEVE_ENTITY)) { final String acl_str = bytes2UTF8(entities_with_acl.getBytes("ACL"));
if (!acl_cache.containsKey(acl_str)) {
acl_cache.put(
acl_str,
EntityACL.deserialize(acl_str)
.isPermitted(this.getUser(), EntityPermission.RETRIEVE_ENTITY));
}
if (!acl_cache.get(acl_str)) {
toBeDeleted.add(id); toBeDeleted.add(id);
} }
final long t2 = System.currentTimeMillis(); final long t2 = System.currentTimeMillis();
this.addBenchmark("filterEntitiesWithoutRetrievePermission", t2 - t1); this.addBenchmark("filterEntitiesWithoutRetrievePermission", t2 - t1);
} }
rs.close(); entities_with_acl.close();
// TODO is there a better way than the following?
for (final Integer id : toBeDeleted) { for (final Integer id : toBeDeleted) {
stmt.execute("DELETE FROM `" + resultSet + "` WHERE id = " + id); stmt.execute("DELETE FROM `" + resultSet + "` WHERE id = " + id);
} }
} }
}
/**
* Filter out all entities which may not be retrieved by this user due to a missing RETRIEVE
* permission. This one is for the filtering of the final result set and not for the filtering of
* any intermediate results.
*
* @param entities
* @throws TransactionException
* @return the filtered list.
*/
private List<IdVersionPair> filterEntitiesWithoutRetrievePermission(
final List<IdVersionPair> entities) throws TransactionException {
if (!filterEntitiesWithoutRetrievePermisions) {
return entities;
}
final List<IdVersionPair> result = new ArrayList<>();
final Iterator<IdVersionPair> iterator = entities.iterator();
while (iterator.hasNext()) {
final long t1 = System.currentTimeMillis();
final IdVersionPair next = iterator.next();
if (next.id > 99
&& execute(new RetrieveSparseEntity(next.id, next.version), getAccess())
.getEntity()
.getEntityACL()
.isPermitted(getUser(), EntityPermission.RETRIEVE_ENTITY)) {
result.add(next);
}
final long t2 = System.currentTimeMillis();
addBenchmark("filterEntitiesWithoutRetrievePermission", t2 - t1);
}
return result;
}
@Override @Override
public String toString() { public String toString() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment