You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2018/11/17 17:20:42 UTC
[16/34] jena git commit: JENA-1623: Graph-level access control and
query FROM/FROM NAMED.
JENA-1623: Graph-level access control and query FROM/FROM NAMED.
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/68bc1104
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/68bc1104
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/68bc1104
Branch: refs/heads/master
Commit: 68bc11045f2f0fa00708909e2def94b23fa47908
Parents: 6da6a8c
Author: Andy Seaborne <an...@apache.org>
Authored: Mon Nov 5 16:15:38 2018 +0000
Committer: Andy Seaborne <an...@apache.org>
Committed: Tue Nov 13 15:39:14 2018 +0000
----------------------------------------------------------------------
.../jena/sparql/core/DatasetGraphFactory.java | 4 +-
.../jena/sparql/core/DatasetGraphMapLink.java | 3 +-
.../jena/sparql/core/DynamicDatasets.java | 27 +++++-----
.../access/Filtered_SPARQL_QueryDataset.java | 50 +++++++++--------
.../jena/fuseki/access/SecurityContext.java | 15 +++---
.../fuseki/access/TestSecurityFilterFuseki.java | 57 +++++++++++---------
6 files changed, 83 insertions(+), 73 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/68bc1104/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphFactory.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphFactory.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphFactory.java
index 140e62f..27d02a5 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphFactory.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphFactory.java
@@ -158,9 +158,9 @@ public class DatasetGraphFactory
public static GraphMaker graphMakerNull = (name) -> null ;
/** A graph maker that creates unnamed Jena default graphs */
- /*package*/ static GraphMaker graphMakerMem = (name) -> GraphFactory.createDefaultGraph() ;
+ public static GraphMaker graphMakerMem = (name) -> GraphFactory.createDefaultGraph() ;
- /** A graph maker that create {@link NamedGraph}s around a Jena default graphs */
+ /** A graph maker that creates {@link NamedGraph}s around a Jena default graphs */
public static GraphMaker graphMakerNamedGraphMem = (name) -> {
Graph g = GraphFactory.createDefaultGraph() ;
return new NamedGraphWrapper(name, g);
http://git-wip-us.apache.org/repos/asf/jena/blob/68bc1104/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphMapLink.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphMapLink.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphMapLink.java
index a0d834c..ac03abf 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphMapLink.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphMapLink.java
@@ -28,7 +28,6 @@ import org.apache.jena.query.ReadWrite ;
import org.apache.jena.query.TxnType;
import org.apache.jena.sparql.SystemARQ ;
import org.apache.jena.sparql.core.DatasetGraphFactory.GraphMaker ;
-import org.apache.jena.sparql.graph.GraphFactory;
import org.apache.jena.sparql.graph.GraphUnionRead ;
import org.apache.jena.sparql.graph.GraphZero;
@@ -51,7 +50,7 @@ public class DatasetGraphMapLink extends DatasetGraphCollection
private Graph defaultGraph ;
private final Transactional txn;
private final TxnDataset2Graph txnDsg2Graph;
- private static GraphMaker dftGraphMaker = (name) -> GraphFactory.createDefaultGraph();
+ private static GraphMaker dftGraphMaker = DatasetGraphFactory.graphMakerMem;
/**
* Create a new {@code DatasetGraph} that copies the dataset structure of default
http://git-wip-us.apache.org/repos/asf/jena/blob/68bc1104/jena-arq/src/main/java/org/apache/jena/sparql/core/DynamicDatasets.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/DynamicDatasets.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/DynamicDatasets.java
index d610bb6..6a2499a 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/core/DynamicDatasets.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/DynamicDatasets.java
@@ -34,8 +34,10 @@ import org.apache.jena.sparql.graph.GraphUnionRead ;
public class DynamicDatasets
{
- /** Given a Dataset and a query, form a Dataset that
- * is the dynamic dataset from the query.
+ /**
+ * Given a DatasetDescription, form a Dataset that is the dynamic dataset over the
+ * base dataset. Returns the original Dataset if the dataset description is null or
+ * empty.
*/
public static Dataset dynamicDataset(DatasetDescription description, Dataset ds, boolean defaultUnionGraph)
{
@@ -46,10 +48,11 @@ public class DynamicDatasets
return DatasetFactory.wrap(dsg2) ;
}
- /** Given a DatasetGraph and a query, form a DatasetGraph that
- * is the dynamic dataset from the query.
- * Returns the original DatasetGraph if the dataset description is null or empty.
- */
+ /**
+ * Given a DatasetDescription, form a Dataset that is the dynamic dataset over the
+ * base dataset. Returns the original DatasetGraph if the dataset description is null
+ * or empty.
+ */
public static DatasetGraph dynamicDataset(DatasetDescription description, DatasetGraph dsg, boolean defaultUnionGraph)
{
if ( description == null )
@@ -63,9 +66,9 @@ public class DynamicDatasets
return dynamicDataset(defaultGraphs, namedGraphs, dsg, defaultUnionGraph) ;
}
- /** Given a DatasetGraph and a query, form a DatasetGraph that
- * is the dynamic dataset from the collection of graphs from the dataset
- * that go to make up the default graph and named graphs.
+ /**
+ * Form a {@link DatasetGraph} that is the dynamic dataset from the collections of
+ * graphs from the dataset that go to make up the default graph and named graphs.
*/
public static DatasetGraph dynamicDataset(Collection<Node> defaultGraphs, Collection<Node> namedGraphs, DatasetGraph dsg, boolean defaultUnionGraph)
{
@@ -99,7 +102,6 @@ public class DynamicDatasets
if ( dsg.getContext() != null )
dsg2.getContext().putAll(dsg.getContext()) ;
- // Wrap with marker.
dsg2 = new DynamicDatasetGraph(dsg2, dsg);
// Record what we've done.
@@ -109,8 +111,7 @@ public class DynamicDatasets
return dsg2 ;
}
- // DatasetGraphWrapperView
- public static class DynamicDatasetGraph extends DatasetGraphReadOnly {
+ public static class DynamicDatasetGraph extends DatasetGraphReadOnly implements DatasetGraphWrapperView {
private final DatasetGraph projected;
public DynamicDatasetGraph(DatasetGraph viewDSG, DatasetGraph baseDSG) {
@@ -118,7 +119,7 @@ public class DynamicDatasets
this.projected = baseDSG;
}
- public DatasetGraph getProjected() {
+ private DatasetGraph getProjected() {
return projected;
}
}
http://git-wip-us.apache.org/repos/asf/jena/blob/68bc1104/jena-fuseki2/jena-fuseki-access/src/main/java/org/apache/jena/fuseki/access/Filtered_SPARQL_QueryDataset.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-access/src/main/java/org/apache/jena/fuseki/access/Filtered_SPARQL_QueryDataset.java b/jena-fuseki2/jena-fuseki-access/src/main/java/org/apache/jena/fuseki/access/Filtered_SPARQL_QueryDataset.java
index 950c503..77767db 100644
--- a/jena-fuseki2/jena-fuseki-access/src/main/java/org/apache/jena/fuseki/access/Filtered_SPARQL_QueryDataset.java
+++ b/jena-fuseki2/jena-fuseki-access/src/main/java/org/apache/jena/fuseki/access/Filtered_SPARQL_QueryDataset.java
@@ -18,11 +18,12 @@
package org.apache.jena.fuseki.access;
+import static java.util.stream.Collectors.toList;
+
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
-import static java.util.stream.Collectors.toList;
import org.apache.jena.fuseki.servlets.ActionService;
import org.apache.jena.fuseki.servlets.HttpAction;
@@ -30,10 +31,7 @@ import org.apache.jena.fuseki.servlets.SPARQL_QueryDataset;
import org.apache.jena.fuseki.servlets.ServletOps;
import org.apache.jena.query.Query;
import org.apache.jena.query.QueryExecution;
-import org.apache.jena.sparql.core.DatasetDescription;
-import org.apache.jena.sparql.core.DatasetGraph;
-import org.apache.jena.sparql.core.DatasetGraphZero;
-import org.apache.jena.sparql.core.DynamicDatasets;
+import org.apache.jena.sparql.core.*;
import org.apache.jena.sparql.core.DynamicDatasets.DynamicDatasetGraph;
/** A Query {@link ActionService} that inserts a security filter on each query. */
@@ -58,38 +56,47 @@ public class Filtered_SPARQL_QueryDataset extends SPARQL_QueryDataset {
*/
@Override
protected DatasetGraph decideDataset(HttpAction action, Query query, String queryStringLog) {
- DatasetGraph dsg = action.getActiveDSG() ;
- DatasetDescription dsDesc = getDatasetDescription(action, query) ;
- if ( dsDesc == null )
- return dsg;
+ DatasetGraph dsg = action.getActiveDSG();
+ DatasetDescription dsDesc0 = getDatasetDescription(action, query);
+ SecurityContext sCxt = DataAccessLib.getSecurityContext(action, dsg, requestUser);
+ return dynamicDataset(action, query, dsg, dsDesc0, sCxt);
+ }
+
+ private DatasetGraph dynamicDataset(HttpAction action, Query query, DatasetGraph dsg0, DatasetDescription dsDesc0, SecurityContext sCxt) {
+ if ( dsDesc0 == null )
+ return dsg0;
if ( ! ALLOW_FROM )
ServletOps.errorBadRequest("Use GRAPH. (FROM/FROM NAMED is not compatible with data access control.)");
- DatasetDescription dsDesc0 = getDatasetDescription(action, query);
- if ( dsDesc0 == null )
- return dsg;
- // Filter the DatasetDescription by the SecurityContext
- SecurityContext sCxt = DataAccessLib.getSecurityContext(action, dsg, requestUser);
DatasetDescription dsDesc1 = DatasetDescription.create(
mask(dsDesc0.getDefaultGraphURIs(), sCxt),
mask(dsDesc0.getNamedGraphURIs(), sCxt));
- // dsDesc1 != null.
if ( dsDesc1.isEmpty() )
return DatasetGraphZero.create();
+
+ // Fix up the union graph in the graphs
+ // (named graph union graph is ignored by DynamicDatasets)
+ if ( dsDesc1.getDefaultGraphURIs().contains(Quad.unionGraph.getURI())) {
+ dsDesc1.getDefaultGraphURIs().remove(Quad.unionGraph.getURI());
+ dsDesc1.getDefaultGraphURIs().addAll(sCxt.visibleGraphNames());
+ }
- dsg = DynamicDatasets.dynamicDataset(dsDesc1, dsg, false) ;
+ DatasetGraph dsg1 = DynamicDatasets.dynamicDataset(dsDesc1, dsg0, false) ;
if ( query.hasDatasetDescription() ) {
- query.getGraphURIs().clear() ;
- query.getNamedGraphURIs().clear() ;
+ query.getGraphURIs().clear() ;
+ query.getNamedGraphURIs().clear() ;
}
- return dsg ;
+ return dsg1 ;
}
// Pass only those graphURIs in the security context.
private List<String> mask(List<String> graphURIs, SecurityContext sCxt) {
Collection<String> names = sCxt.visibleGraphNames();
return graphURIs.stream()
- .filter(gn->names.contains(gn))
+ .filter(gn->names.contains(gn)
+ || ( sCxt.visableDefaultGraph() && Quad.defaultGraphIRI.getURI().equals(gn))
+ || ( Quad.unionGraph.getURI().equals(gn) )
+ )
.collect(toList()) ;
}
@@ -102,8 +109,7 @@ public class Filtered_SPARQL_QueryDataset extends SPARQL_QueryDataset {
ServletOps.errorBadRequest("FROM/FROM NAMED is not compatible with data access control.");
}
- // Database defined for this service, not the possibly dynamically built "dataset"
- DatasetGraph dsg = action.getDataset();
+ DatasetGraph dsg = action.getActiveDSG();
if ( dsg == null )
return super.createQueryExecution(action, query, target);
if ( ! DataAccessCtl.isAccessControlled(dsg) )
http://git-wip-us.apache.org/repos/asf/jena/blob/68bc1104/jena-fuseki2/jena-fuseki-access/src/main/java/org/apache/jena/fuseki/access/SecurityContext.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-access/src/main/java/org/apache/jena/fuseki/access/SecurityContext.java b/jena-fuseki2/jena-fuseki-access/src/main/java/org/apache/jena/fuseki/access/SecurityContext.java
index 4d55417..cbae326 100644
--- a/jena-fuseki2/jena-fuseki-access/src/main/java/org/apache/jena/fuseki/access/SecurityContext.java
+++ b/jena-fuseki2/jena-fuseki-access/src/main/java/org/apache/jena/fuseki/access/SecurityContext.java
@@ -84,6 +84,10 @@ public class SecurityContext {
.collect(Collectors.toList()) ;
}
+ public boolean visableDefaultGraph() {
+ return matchDefaultGraph;
+ }
+
/**
* Apply a filter suitable for the TDB-backed {@link DatasetGraph}, to the {@link Context} of the
* {@link QueryExecution}. This does not modify the {@link DatasetGraph}
@@ -98,19 +102,12 @@ public class SecurityContext {
}
public QueryExecution createQueryExecution(Query query, DatasetGraph dsg) {
- if ( ! DataAccessCtl.isAccessControlled(dsg) ) {
-// throw new InternalErrorException("SecurityContext.createQueryExecution called on an unsecured DatasetGraph");
-// // Internal error?
- // Already setup or no security context.
- return QueryExecutionFactory.create(query, dsg);
- }
if ( isAccessControlledTDB(dsg) ) {
QueryExecution qExec = QueryExecutionFactory.create(query, dsg);
filterTDB(dsg, qExec);
return qExec;
}
-
- // XXX Does not work on GRAPH ?g {}
+ // Not TDB - do by selecting graphs.
DatasetGraph dsgA = DataAccessCtl.filteredDataset(dsg, this);
return QueryExecutionFactory.create(query, dsgA);
}
@@ -150,7 +147,7 @@ public class SecurityContext {
throw new IllegalArgumentException("Not a TDB1 or TDB2 database: "+dsg.getClass().getSimpleName());
}
- public boolean isAccessControlledTDB(DatasetGraph dsg) {
+ private static boolean isAccessControlledTDB(DatasetGraph dsg) {
DatasetGraph dsgBase = DatasetGraphAccessControl.unwrapOrNull(dsg);
if ( dsgBase == null )
return false;
http://git-wip-us.apache.org/repos/asf/jena/blob/68bc1104/jena-fuseki2/jena-fuseki-access/src/test/java/org/apache/jena/fuseki/access/TestSecurityFilterFuseki.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-access/src/test/java/org/apache/jena/fuseki/access/TestSecurityFilterFuseki.java b/jena-fuseki2/jena-fuseki-access/src/test/java/org/apache/jena/fuseki/access/TestSecurityFilterFuseki.java
index 91c2afb..00febf7 100644
--- a/jena-fuseki2/jena-fuseki-access/src/test/java/org/apache/jena/fuseki/access/TestSecurityFilterFuseki.java
+++ b/jena-fuseki2/jena-fuseki-access/src/test/java/org/apache/jena/fuseki/access/TestSecurityFilterFuseki.java
@@ -18,18 +18,11 @@
package org.apache.jena.fuseki.access;
-import static org.apache.jena.fuseki.access.AccessTestLib.addTestData;
-import static org.apache.jena.fuseki.access.AccessTestLib.assertSeen;
-import static org.apache.jena.fuseki.access.AccessTestLib.s0;
-import static org.apache.jena.fuseki.access.AccessTestLib.s1;
+import static org.apache.jena.fuseki.access.AccessTestLib.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
+import java.util.*;
import org.apache.jena.atlas.iterator.Iter;
import org.apache.jena.atlas.lib.SetUtils;
@@ -92,6 +85,7 @@ public class TestSecurityFilterFuseki {
reg.put("user0", new SecurityContext(Quad.defaultGraphIRI.getURI()));
reg.put("user1", new SecurityContext("http://test/g1", Quad.defaultGraphIRI.getURI()));
reg.put("user2", new SecurityContext("http://test/g1", "http://test/g2", "http://test/g3"));
+ reg.put("user3", new SecurityContext(Quad.defaultGraphIRI.getURI(), "http://test/g2", "http://test/g3"));
testdsg1 = DataAccessCtl.controlledDataset(testdsg1, reg);
testdsg2 = DataAccessCtl.controlledDataset(testdsg2, reg);
@@ -122,6 +116,7 @@ public class TestSecurityFilterFuseki {
addUserPassword(propertyUserStore, "user0", "pw0", roles);
addUserPassword(propertyUserStore, "user1", "pw1", roles);
addUserPassword(propertyUserStore, "user2", "pw2", roles);
+ addUserPassword(propertyUserStore, "user3", "pw3", roles);
return propertyUserStore;
}
@@ -203,24 +198,36 @@ public class TestSecurityFilterFuseki {
query401("user0", "not-the-password", queryAll);
}
- // More queries. DevSecureNG.java // FROM, "GRAPH ?g" and non-graph (also TestSecurityFilterLocal)
+ // Visibility of data.
-// query(connx, "SELECT * FROM <http://host/graphname1> { GRAPH ?g {} }");
-// query(connx, "SELECT * FROM NAMED <http://host/graphname1> { { ?s ?p ?o } UNION { GRAPH ?g { ?s ?p ?o } } }");
-// query(connx, "SELECT * FROM NAMED <http://host/graphname1> { GRAPH <http://host/graphname1> { ?s ?p ?o } }");
-// query(connx, "SELECT * { GRAPH ?g {} }");
-// query(connx, "SELECT * { { ?s ?p ?o } UNION { GRAPH ?g { ?s ?p ?o } } }");
-// query(connx, "SELECT * FROM <http://host/graphname1> { ?s ?p ?o }");
-// query(connx, "SELECT * FROM <http://host/graphname1> { { ?s ?p ?o } UNION { GRAPH ?g { ?s ?p ?o } } }");
-// query(connx, "SELECT * FROM NAMED <http://host/graphname1> { { ?s ?p ?o } UNION { GRAPH ?g { ?s ?p ?o } } }");
-// query(connx, "SELECT * { GRAPH <http://host/graphname1> { ?s ?p ?o }}");
-//
-// query(connx, "SELECT * FROM <http://host/graphname4> { { ?s ?p ?o } UNION { GRAPH ?g { ?s ?p ?o } } }");
-// query(connx, "SELECT * { GRAPH <http://host/graphname4> { ?s ?p ?o }}");
-//
-// query(connx, "SELECT * { GRAPH <"+Quad.unionGraph.getURI()+"> { ?s ?p ?o } }");
-// query(connx, "SELECT * FROM <"+Quad.unionGraph.getURI()+"> { ?s ?p ?o }");
+ @Test public void query_dyn_1() {
+ Set<Node> results = query("user1", "pw1", "SELECT * FROM <http://test/g1> { ?s ?p ?o }");
+ assertSeen(results, s1);
+ }
+
+ @Test public void query_dyn_2() {
+ Set<Node> results = query("user1", "pw1", "SELECT * FROM <http://test/g2> { ?s ?p ?o }");
+ assertSeen(results);
+ }
+ @Test public void query_dyn_3() {
+ Set<Node> results = query("user1", "pw1", "SELECT * FROM <http://test/g1> FROM <http://test/g2> { ?s ?p ?o }");
+ assertSeen(results,s1);
+ }
+
+ @Test public void query_dyn_4() {
+ Set<Node> results = query("user3", "pw3", "SELECT * FROM <"+Quad.unionGraph.getURI()+"> { ?s ?p ?o }");
+ assertSeen(results, s2, s3);
+ Set<Node> results2 = query("user3", "pw3", "SELECT * { GRAPH <"+Quad.unionGraph.getURI()+"> { ?s ?p ?o } }");
+ assertEquals(results, results2);
+ }
+
+ @Test public void query_dyn_5() {
+ Set<Node> results = query("user3", "pw3", "SELECT * FROM NAMED <http://test/g1> { ?s ?p ?o }");
+ assertSeen(results);
+ Set<Node> results2 = query("user3", "pw3", "SELECT * { GRAPH <http://test/g1> { ?s ?p ?o } }");
+ assertEquals(results, results2);
+ }
private Set<Node> gsp(String user, String password, String graphName) {
Set<Node> results = new HashSet<>();