Skip to content
Snippets Groups Projects
Commit 56b45310 authored by Henrik tom Wörden's avatar Henrik tom Wörden
Browse files

Merge branch 'f-select-acl' into 'dev'

F select acl

See merge request !109
parents eab297f9 6710ba3e
No related branches found
No related tags found
2 merge requests!111Release 0.12.1,!109F select acl
Pipeline #44884 passed
Showing with 231 additions and 24 deletions
...@@ -26,6 +26,7 @@ package org.caosdb.server.database.backend.transaction; ...@@ -26,6 +26,7 @@ package org.caosdb.server.database.backend.transaction;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import org.apache.shiro.subject.Subject;
import org.caosdb.server.database.BackendTransaction; import org.caosdb.server.database.BackendTransaction;
import org.caosdb.server.database.exceptions.EntityDoesNotExistException; import org.caosdb.server.database.exceptions.EntityDoesNotExistException;
import org.caosdb.server.datatype.CollectionValue; import org.caosdb.server.datatype.CollectionValue;
...@@ -38,6 +39,7 @@ import org.caosdb.server.entity.RetrieveEntity; ...@@ -38,6 +39,7 @@ import org.caosdb.server.entity.RetrieveEntity;
import org.caosdb.server.entity.Role; import org.caosdb.server.entity.Role;
import org.caosdb.server.entity.container.Container; import org.caosdb.server.entity.container.Container;
import org.caosdb.server.entity.wrapper.Property; import org.caosdb.server.entity.wrapper.Property;
import org.caosdb.server.permissions.EntityPermission;
import org.caosdb.server.query.Query; import org.caosdb.server.query.Query;
import org.caosdb.server.query.Query.Selection; import org.caosdb.server.query.Query.Selection;
import org.caosdb.server.utils.EntityStatus; import org.caosdb.server.utils.EntityStatus;
...@@ -57,19 +59,22 @@ import org.caosdb.server.utils.EntityStatus; ...@@ -57,19 +59,22 @@ import org.caosdb.server.utils.EntityStatus;
public class RetrieveFullEntityTransaction extends BackendTransaction { public class RetrieveFullEntityTransaction extends BackendTransaction {
private final Container<? extends EntityInterface> container; private final Container<? extends EntityInterface> container;
private final Subject subject;
public RetrieveFullEntityTransaction(final EntityInterface entity) { @SuppressWarnings("unchecked")
final Container<EntityInterface> c = new Container<>(); public RetrieveFullEntityTransaction(final EntityInterface entity, Subject subject) {
c.add(entity); this(new Container<>(), subject);
this.container = c; ((Container<EntityInterface>) this.container).add(entity);
} }
public RetrieveFullEntityTransaction(final Container<? extends EntityInterface> container) { public RetrieveFullEntityTransaction(
final Container<? extends EntityInterface> container, final Subject subject) {
this.container = container; this.container = container;
this.subject = subject;
} }
public RetrieveFullEntityTransaction(final EntityID id) { public RetrieveFullEntityTransaction(final EntityID id, Subject subject) {
this(new RetrieveEntity(id)); this(new RetrieveEntity(id), subject);
} }
@Override @Override
...@@ -220,10 +225,18 @@ public class RetrieveFullEntityTransaction extends BackendTransaction { ...@@ -220,10 +225,18 @@ public class RetrieveFullEntityTransaction extends BackendTransaction {
private void resolveReferenceValue( private void resolveReferenceValue(
final ReferenceValue value, final List<Selection> selections, final String propertyName) { final ReferenceValue value, final List<Selection> selections, final String propertyName) {
final RetrieveEntity ref = new RetrieveEntity(value.getId()); final RetrieveEntity ref = new RetrieveEntity(value.getId());
if (this.subject != null) {
// recursion! (Only for the matching selections) // recursion! (Only for the matching selections)
retrieveFullEntity(ref, getSubSelects(selections, propertyName)); retrieveFullEntity(ref, getSubSelects(selections, propertyName));
// check whether the referenced entity is readable
if (!ref.getEntityACL().isPermitted(this.subject, EntityPermission.RETRIEVE_ENTITY)) {
return;
}
value.setEntity(ref, true); value.setEntity(ref, true);
} }
}
/** /**
* Retrieve the Entities which match the selections and are referenced by the Entity 'e'. * Retrieve the Entities which match the selections and are referenced by the Entity 'e'.
......
...@@ -24,6 +24,14 @@ ...@@ -24,6 +24,14 @@
*/ */
package org.caosdb.server.entity; package org.caosdb.server.entity;
/**
* Entity which is to be retrieved (i.e. read-only).
*
* <p>This class only exposes those constructors which are necessary for Entity which are to be
* retrieved (e.g. Entity(id)) and hide the others (e.g. Entity(XML-Represenation)).
*
* @author Timm Fitschen <t.fitschen@indiscale.com>
*/
public class RetrieveEntity extends Entity { public class RetrieveEntity extends Entity {
public RetrieveEntity() { public RetrieveEntity() {
......
...@@ -169,14 +169,16 @@ public class EntityToElementStrategy implements ToElementStrategy { ...@@ -169,14 +169,16 @@ public class EntityToElementStrategy implements ToElementStrategy {
// processing SELECT Queries. // processing SELECT Queries.
final EntityInterface ref = ((ReferenceValue) entity.getValue()).getEntity(); final EntityInterface ref = ((ReferenceValue) entity.getValue()).getEntity();
if (ref != null) { if (ref != null) {
ref.addToElement(element, serializeFieldStrategy);
} else {
entity.getValue().addToElement(element);
}
if (entity.hasDatatype()) { if (entity.hasDatatype()) {
setDatatype(entity, element); setDatatype(entity, element);
} }
ref.addToElement(element, serializeFieldStrategy);
// the referenced entity has been appended. Return here to suppress // the referenced entity has been appended. Return here to suppress
// adding the reference id as well. // adding the reference id as well.
return; return;
}
} else if (entity.isReferenceList() && serializeFieldStrategy.isToBeSet("_referenced")) { } else if (entity.isReferenceList() && serializeFieldStrategy.isToBeSet("_referenced")) {
// Append the all referenced entities. This needs to be done when we are // Append the all referenced entities. This needs to be done when we are
// processing SELECT Queries. // processing SELECT Queries.
......
...@@ -405,6 +405,12 @@ public class POV implements EntityFilterInterface { ...@@ -405,6 +405,12 @@ public class POV implements EntityFilterInterface {
} }
final long t2 = System.currentTimeMillis(); final long t2 = System.currentTimeMillis();
query.addBenchmark(measurement(".initPOVRefidsTable()"), t2 - t1); query.addBenchmark(measurement(".initPOVRefidsTable()"), t2 - t1);
if (this.refIdsTable != null) {
query.getQuery().filterIntermediateResult(this.refIdsTable);
}
final long t3 = System.currentTimeMillis();
query.addBenchmark(measurement(".filterRefidsWithoutRetrievePermission"), t3 - t2);
try (PreparedStatement stmt = try (PreparedStatement stmt =
query.getConnection().prepareCall("call initPOVPropertiesTable(?,?,?)")) { query.getConnection().prepareCall("call initPOVPropertiesTable(?,?,?)")) {
// initPOVPropertiesTable(in pid INT UNSIGNED, in pname // initPOVPropertiesTable(in pid INT UNSIGNED, in pname
...@@ -455,12 +461,12 @@ public class POV implements EntityFilterInterface { ...@@ -455,12 +461,12 @@ public class POV implements EntityFilterInterface {
} }
} }
} }
final long t3 = System.currentTimeMillis(); final long t4 = System.currentTimeMillis();
query.addBenchmark(measurement(""), t3 - t2); query.addBenchmark(measurement(""), t4 - t3);
if (this.refIdsTable != null) { if (this.refIdsTable != null) {
query.getQuery().applyQueryTemplates(query, this.refIdsTable); query.getQuery().applyQueryTemplates(query, this.refIdsTable);
query.addBenchmark(measurement(".applyQueryTemplates()"), System.currentTimeMillis() - t3); query.addBenchmark(measurement(".applyQueryTemplates()"), System.currentTimeMillis() - t4);
} }
if (hasSubProperty() && this.targetSet != null) { if (hasSubProperty() && this.targetSet != null) {
......
...@@ -72,11 +72,21 @@ import org.caosdb.server.permissions.EntityPermission; ...@@ -72,11 +72,21 @@ import org.caosdb.server.permissions.EntityPermission;
import org.caosdb.server.query.CQLParser.CqContext; import org.caosdb.server.query.CQLParser.CqContext;
import org.caosdb.server.query.CQLParsingErrorListener.ParsingError; import org.caosdb.server.query.CQLParsingErrorListener.ParsingError;
import org.caosdb.server.transaction.EntityTransactionInterface; import org.caosdb.server.transaction.EntityTransactionInterface;
import org.caosdb.server.transaction.Retrieve;
import org.caosdb.server.transaction.Transaction; import org.caosdb.server.transaction.Transaction;
import org.caosdb.server.transaction.WriteTransaction; import org.caosdb.server.transaction.WriteTransaction;
import org.jdom2.Element; import org.jdom2.Element;
import org.slf4j.Logger; import org.slf4j.Logger;
/**
* This class represents a single, complete Query execution from the parsing of the query string to
* the resulting list of entity ids.
*
* <p>This class handles caching of queries and checking retrieve permissions as well. It does not,
* however, retrieve the resulting entities; this is handled by the {@link Retrieve} class.
*
* @author Timm Fitschen <t.fitschen@indiscale.com>
*/
public class Query implements QueryInterface, ToElementable, EntityTransactionInterface { public class Query implements QueryInterface, ToElementable, EntityTransactionInterface {
/** Class which represents the selection of (sub)properties. */ /** Class which represents the selection of (sub)properties. */
......
...@@ -114,7 +114,7 @@ public class Retrieve extends Transaction<RetrieveContainer> { ...@@ -114,7 +114,7 @@ public class Retrieve extends Transaction<RetrieveContainer> {
private void retrieveFullEntities(final RetrieveContainer container, final Access access) private void retrieveFullEntities(final RetrieveContainer container, final Access access)
throws Exception { throws Exception {
execute(new RetrieveFullEntityTransaction(container), access); execute(new RetrieveFullEntityTransaction(container, getTransactor()), access);
} }
@Override @Override
......
...@@ -67,7 +67,8 @@ public class UpdateACL extends Transaction<TransactionContainer> ...@@ -67,7 +67,8 @@ public class UpdateACL extends Transaction<TransactionContainer>
oldContainer.add(new UpdateEntity(e.getId(), null)); oldContainer.add(new UpdateEntity(e.getId(), null));
} }
RetrieveFullEntityTransaction t = new RetrieveFullEntityTransaction(oldContainer); RetrieveFullEntityTransaction t =
new RetrieveFullEntityTransaction(oldContainer, getTransactor());
execute(t, getAccess()); execute(t, getAccess());
// the entities in this container only have an id and an ACL. -> Replace // the entities in this container only have an id and an ACL. -> Replace
......
...@@ -165,10 +165,10 @@ public class WriteTransaction extends Transaction<WritableContainer> ...@@ -165,10 +165,10 @@ public class WriteTransaction extends Transaction<WritableContainer>
// Retrieve a container which contains all IDs of those entities // Retrieve a container which contains all IDs of those entities
// which are to be updated. // which are to be updated.
execute(new RetrieveFullEntityTransaction(oldContainer), getAccess()); execute(new RetrieveFullEntityTransaction(oldContainer, getTransactor()), getAccess());
// Retrieve all entities which are to be deleted. // Retrieve all entities which are to be deleted.
execute(new RetrieveFullEntityTransaction(deleteContainer), getAccess()); execute(new RetrieveFullEntityTransaction(deleteContainer, getTransactor()), getAccess());
// Check if any updates are to be processed. // Check if any updates are to be processed.
for (final EntityInterface entity : getContainer()) { for (final EntityInterface entity : getContainer()) {
......
...@@ -23,8 +23,21 @@ import static org.junit.jupiter.api.Assertions.assertEquals; ...@@ -23,8 +23,21 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.ExecutionException;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.caosdb.server.CaosDBServer;
import org.caosdb.server.accessControl.Principal;
import org.caosdb.server.datatype.ReferenceValue; import org.caosdb.server.datatype.ReferenceValue;
import org.caosdb.server.entity.Entity; import org.caosdb.server.entity.Entity;
import org.caosdb.server.entity.EntityID; import org.caosdb.server.entity.EntityID;
...@@ -32,15 +45,168 @@ import org.caosdb.server.entity.EntityInterface; ...@@ -32,15 +45,168 @@ import org.caosdb.server.entity.EntityInterface;
import org.caosdb.server.entity.RetrieveEntity; import org.caosdb.server.entity.RetrieveEntity;
import org.caosdb.server.entity.wrapper.Property; import org.caosdb.server.entity.wrapper.Property;
import org.caosdb.server.entity.xml.PropertyToElementStrategyTest; import org.caosdb.server.entity.xml.PropertyToElementStrategyTest;
import org.caosdb.server.permissions.EntityACL;
import org.caosdb.server.query.Query.Selection; import org.caosdb.server.query.Query.Selection;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class RetrieveFullEntityTest { public class RetrieveFullEntityTest {
@BeforeAll
public static void setup() throws IOException {
CaosDBServer.initServerProperties();
}
@Test @Test
public void testRetrieveSubEntities() { public void testRetrieveSubEntities() {
final RetrieveFullEntityTransaction r = final RetrieveFullEntityTransaction r =
new RetrieveFullEntityTransaction(new EntityID("0")) { new RetrieveFullEntityTransaction(
new EntityID("0"),
new Subject() {
@Override
public Object getPrincipal() {
return new Principal("Bla", "Blub");
}
@Override
public PrincipalCollection getPrincipals() {
return null;
}
@Override
public boolean isPermitted(String permission) {
assertEquals(
permission, org.caosdb.server.permissions.EntityPermission.RETRIEVE_ENTITY);
return true;
}
@Override
public boolean isPermitted(Permission permission) {
return false;
}
@Override
public boolean[] isPermitted(String... permissions) {
return null;
}
@Override
public boolean[] isPermitted(List<Permission> permissions) {
return null;
}
@Override
public boolean isPermittedAll(String... permissions) {
return false;
}
@Override
public boolean isPermittedAll(Collection<Permission> permissions) {
return false;
}
@Override
public void checkPermission(String permission) throws AuthorizationException {}
@Override
public void checkPermission(Permission permission) throws AuthorizationException {}
@Override
public void checkPermissions(String... permissions) throws AuthorizationException {}
@Override
public void checkPermissions(Collection<Permission> permissions)
throws AuthorizationException {}
@Override
public boolean hasRole(String roleIdentifier) {
return false;
}
@Override
public boolean[] hasRoles(List<String> roleIdentifiers) {
return null;
}
@Override
public boolean hasAllRoles(Collection<String> roleIdentifiers) {
return false;
}
@Override
public void checkRole(String roleIdentifier) throws AuthorizationException {}
@Override
public void checkRoles(Collection<String> roleIdentifiers)
throws AuthorizationException {}
@Override
public void checkRoles(String... roleIdentifiers) throws AuthorizationException {}
@Override
public void login(AuthenticationToken token) throws AuthenticationException {}
@Override
public boolean isAuthenticated() {
return false;
}
@Override
public boolean isRemembered() {
return false;
}
@Override
public Session getSession() {
return null;
}
@Override
public Session getSession(boolean create) {
return null;
}
@Override
public void logout() {}
@Override
public <V> V execute(Callable<V> callable) throws ExecutionException {
return null;
}
@Override
public void execute(Runnable runnable) {}
@Override
public <V> Callable<V> associateWith(Callable<V> callable) {
return null;
}
@Override
public Runnable associateWith(Runnable runnable) {
return null;
}
@Override
public void runAs(PrincipalCollection principals)
throws NullPointerException, IllegalStateException {}
@Override
public boolean isRunAs() {
return false;
}
@Override
public PrincipalCollection getPreviousPrincipals() {
return null;
}
@Override
public PrincipalCollection releaseRunAs() {
return null;
}
}) {
/** Mock-up */ /** Mock-up */
@Override @Override
...@@ -53,6 +219,7 @@ public class RetrieveFullEntityTest { ...@@ -53,6 +219,7 @@ public class RetrieveFullEntityTest {
assertEquals("description", selections.get(0).getSelector()); assertEquals("description", selections.get(0).getSelector());
e.setDescription("A heart-shaped window."); e.setDescription("A heart-shaped window.");
e.setEntityACL(new EntityACL());
} }
; ;
}; };
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment