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<>();