modifications to rename jena security as jena permissions modifications to adapt to removed deprecated classes in org.apache.jena.
Project: http://git-wip-us.apache.org/repos/asf/jena/repo Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/c4b0113d Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/c4b0113d Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/c4b0113d Branch: refs/heads/jena3 Commit: c4b0113d7b05ef2ddafcfd206df019fe56bca9be Parents: 8263b59 Author: claude <[email protected]> Authored: Fri Apr 24 23:47:52 2015 +0100 Committer: claude <[email protected]> Committed: Fri Apr 24 23:47:52 2015 +0100 ---------------------------------------------------------------------- jena-permissions/readme.md | 10 +- .../jena/permissions/AccessDeniedException.java | 66 + .../jena/permissions/AssemblerConstants.java | 62 + .../org/apache/jena/permissions/Factory.java | 69 + .../jena/permissions/SecuredAssembler.java | 264 ++ .../jena/permissions/SecurityEvaluator.java | 616 ++++ .../permissions/SecurityEvaluatorAssembler.java | 183 ++ .../permissions/graph/SecuredCapabilities.java | 151 + .../jena/permissions/graph/SecuredGraph.java | 162 ++ .../graph/SecuredGraphEventManager.java | 608 ++++ .../permissions/graph/SecuredPrefixMapping.java | 133 + .../jena/permissions/graph/impl/Factory.java | 95 + .../graph/impl/SecuredGraphImpl.java | 285 ++ .../graph/impl/SecuredPrefixMappingImpl.java | 167 ++ .../jena/permissions/graph/package-info.java | 50 + .../impl/CachedSecurityEvaluator.java | 90 + .../jena/permissions/impl/ItemHolder.java | 117 + .../jena/permissions/impl/SecuredItem.java | 185 ++ .../jena/permissions/impl/SecuredItemImpl.java | 842 ++++++ .../permissions/impl/SecuredItemInvoker.java | 146 + .../jena/permissions/model/SecuredAlt.java | 264 ++ .../jena/permissions/model/SecuredBag.java | 29 + .../permissions/model/SecuredContainer.java | 218 ++ .../jena/permissions/model/SecuredLiteral.java | 165 ++ .../jena/permissions/model/SecuredModel.java | 1566 ++++++++++ .../jena/permissions/model/SecuredProperty.java | 38 + .../jena/permissions/model/SecuredRDFList.java | 414 +++ .../jena/permissions/model/SecuredRDFNode.java | 59 + .../model/SecuredReifiedStatement.java | 38 + .../jena/permissions/model/SecuredResource.java | 333 +++ .../jena/permissions/model/SecuredSeq.java | 385 +++ .../permissions/model/SecuredStatement.java | 295 ++ ...SecuredUnsupportedPolymorphismException.java | 36 + .../permissions/model/impl/SecuredAltImpl.java | 339 +++ .../permissions/model/impl/SecuredBagImpl.java | 81 + .../model/impl/SecuredContainerImpl.java | 576 ++++ .../model/impl/SecuredLiteralImpl.java | 277 ++ .../model/impl/SecuredModelImpl.java | 2739 ++++++++++++++++++ .../model/impl/SecuredNodeIterator.java | 143 + .../model/impl/SecuredPropertyImpl.java | 129 + .../model/impl/SecuredRDFListImpl.java | 1058 +++++++ .../model/impl/SecuredRDFNodeImpl.java | 253 ++ .../model/impl/SecuredRSIterator.java | 174 ++ .../model/impl/SecuredReifiedStatementImpl.java | 99 + .../model/impl/SecuredResIterator.java | 133 + .../model/impl/SecuredResourceImpl.java | 893 ++++++ .../permissions/model/impl/SecuredSelector.java | 94 + .../permissions/model/impl/SecuredSeqImpl.java | 511 ++++ .../model/impl/SecuredStatementImpl.java | 560 ++++ .../model/impl/SecuredStatementIterator.java | 148 + .../apache/jena/permissions/package-info.java | 48 + .../permissions/query/SecuredQueryEngine.java | 152 + .../query/SecuredQueryEngineConfig.java | 29 + .../query/SecuredQueryEngineFactory.java | 115 + .../permissions/query/rewriter/OpRewriter.java | 592 ++++ .../query/rewriter/SecuredFunction.java | 138 + .../jena/permissions/utils/ContainerFilter.java | 48 + .../permissions/utils/PermStatementFilter.java | 164 ++ .../permissions/utils/PermTripleFilter.java | 163 ++ .../jena/permissions/utils/RDFListIterator.java | 79 + .../permissions/utils/RDFListSecFilter.java | 58 + .../jena/security/AccessDeniedException.java | 66 - .../jena/security/AssemblerConstants.java | 62 - .../java/org/apache/jena/security/Factory.java | 69 - .../apache/jena/security/SecuredAssembler.java | 264 -- .../apache/jena/security/SecurityEvaluator.java | 616 ---- .../security/SecurityEvaluatorAssembler.java | 183 -- .../graph/SecuredBulkUpdateHandler.java | 148 - .../security/graph/SecuredCapabilities.java | 151 - .../jena/security/graph/SecuredGraph.java | 176 -- .../graph/SecuredGraphEventManager.java | 608 ---- .../security/graph/SecuredPrefixMapping.java | 133 - .../jena/security/graph/impl/Factory.java | 129 - .../impl/SecuredBulkUpdateHandlerImpl.java | 242 -- .../security/graph/impl/SecuredGraphImpl.java | 303 -- .../graph/impl/SecuredPrefixMappingImpl.java | 167 -- .../jena/security/graph/package-info.java | 50 - .../security/impl/CachedSecurityEvaluator.java | 90 - .../apache/jena/security/impl/ItemHolder.java | 117 - .../apache/jena/security/impl/SecuredItem.java | 185 -- .../jena/security/impl/SecuredItemImpl.java | 842 ------ .../jena/security/impl/SecuredItemInvoker.java | 146 - .../apache/jena/security/model/SecuredAlt.java | 264 -- .../apache/jena/security/model/SecuredBag.java | 29 - .../jena/security/model/SecuredContainer.java | 218 -- .../jena/security/model/SecuredLiteral.java | 165 -- .../jena/security/model/SecuredModel.java | 1566 ---------- .../jena/security/model/SecuredProperty.java | 38 - .../jena/security/model/SecuredRDFList.java | 414 --- .../jena/security/model/SecuredRDFNode.java | 59 - .../security/model/SecuredReifiedStatement.java | 38 - .../jena/security/model/SecuredResource.java | 333 --- .../apache/jena/security/model/SecuredSeq.java | 385 --- .../jena/security/model/SecuredStatement.java | 295 -- ...SecuredUnsupportedPolymorphismException.java | 36 - .../security/model/impl/SecuredAltImpl.java | 339 --- .../security/model/impl/SecuredBagImpl.java | 81 - .../model/impl/SecuredContainerImpl.java | 576 ---- .../security/model/impl/SecuredLiteralImpl.java | 277 -- .../security/model/impl/SecuredModelImpl.java | 2739 ------------------ .../model/impl/SecuredNodeIterator.java | 143 - .../model/impl/SecuredPropertyImpl.java | 129 - .../security/model/impl/SecuredRDFListImpl.java | 1058 ------- .../security/model/impl/SecuredRDFNodeImpl.java | 253 -- .../security/model/impl/SecuredRSIterator.java | 174 -- .../model/impl/SecuredReifiedStatementImpl.java | 99 - .../security/model/impl/SecuredResIterator.java | 133 - .../model/impl/SecuredResourceImpl.java | 893 ------ .../security/model/impl/SecuredSelector.java | 94 - .../security/model/impl/SecuredSeqImpl.java | 511 ---- .../model/impl/SecuredStatementImpl.java | 560 ---- .../model/impl/SecuredStatementIterator.java | 148 - .../org/apache/jena/security/package-info.java | 48 - .../jena/security/query/SecuredQueryEngine.java | 152 - .../query/SecuredQueryEngineConfig.java | 29 - .../query/SecuredQueryEngineFactory.java | 115 - .../security/query/rewriter/OpRewriter.java | 592 ---- .../query/rewriter/SecuredFunction.java | 138 - .../jena/security/utils/ContainerFilter.java | 48 - .../security/utils/PermStatementFilter.java | 164 -- .../jena/security/utils/PermTripleFilter.java | 163 -- .../jena/security/utils/RDFListIterator.java | 79 - .../jena/security/utils/RDFListSecFilter.java | 58 - .../apache/jena/permissions/EqualityTester.java | 49 + .../jena/permissions/MockPrefixMapping.java | 105 + .../jena/permissions/MockSecurityEvaluator.java | 228 ++ .../ModelBasedSecurityEvaluator.java | 77 + .../jena/permissions/SecuredAssemblerTest.java | 85 + .../SecurityEvaluatorParameters.java | 135 + .../permissions/StaticSecurityEvaluator.java | 80 + .../graph/CachedSecurityEvaluatorTest.java | 46 + .../graph/SecuredGraphContractTests.java | 51 + .../graph/SecuredGraphListenerTest.java | 51 + .../graph/SecuredTDBGraphContractTests.java | 51 + .../contract/model/ModelTestSuite.java | 132 + .../contract/model/SecTestLiterals.java | 29 + .../contract/model/SecTestPackage.java | 121 + .../contract/model/SecTestReaderEvents.java | 28 + .../contract/model/SecTestReaders.java | 28 + .../graph/CrossIDGraphEventManagerTest.java | 78 + .../graph/GraphEventManagerTest.java | 144 + .../jena/permissions/graph/MemGraphTest.java | 313 ++ .../graph/RecordingGraphListener.java | 124 + .../graph/SecuredPrefixMappingTest.java | 440 +++ .../jena/permissions/graph/TDBGraphTest.java | 58 + .../jena/permissions/model/SecuredAltTest.java | 657 +++++ .../jena/permissions/model/SecuredBagTest.java | 46 + .../permissions/model/SecuredContainerTest.java | 480 +++ .../permissions/model/SecuredLiteralTest.java | 469 +++ .../model/SecuredModelDetailTest.java | 335 +++ .../permissions/model/SecuredModelTest.java | 2035 +++++++++++++ .../permissions/model/SecuredPropertyTest.java | 79 + .../permissions/model/SecuredRDFListTest.java | 970 +++++++ .../permissions/model/SecuredRDFNodeTest.java | 209 ++ .../model/SecuredReifiedStatementTest.java | 84 + .../permissions/model/SecuredResourceTest.java | 827 ++++++ .../jena/permissions/model/SecuredSeqTest.java | 1013 +++++++ .../permissions/model/SecuredStatementTest.java | 707 +++++ .../jena/permissions/query/DataSetTest.java | 245 ++ .../jena/permissions/query/QueryEngineTest.java | 260 ++ .../query/rewriter/OpRewriterTest.java | 112 + .../apache/jena/security/EqualityTester.java | 49 - .../apache/jena/security/MockPrefixMapping.java | 105 - .../jena/security/MockSecurityEvaluator.java | 228 -- .../security/ModelBasedSecurityEvaluator.java | 76 - .../jena/security/SecuredAssemblerTest.java | 84 - .../security/SecurityEvaluatorParameters.java | 135 - .../jena/security/StaticSecurityEvaluator.java | 78 - .../graph/CachedSecurityEvaluatorTest.java | 45 - .../graph/SecuredGraphContractTests.java | 51 - .../graph/SecuredGraphListenerTest.java | 51 - .../graph/SecuredTDBGraphContractTests.java | 51 - .../security/contract/model/ModelTestSuite.java | 132 - .../contract/model/SecTestLiterals.java | 29 - .../security/contract/model/SecTestPackage.java | 120 - .../contract/model/SecTestReaderEvents.java | 28 - .../security/contract/model/SecTestReaders.java | 28 - .../security/graph/BulkUpdateHandlerTest.java | 372 --- .../graph/CrossIDGraphEventManagerTest.java | 77 - .../security/graph/GraphEventManagerTest.java | 239 -- .../jena/security/graph/MemGraphTest.java | 387 --- .../security/graph/RecordingGraphListener.java | 124 - .../graph/SecuredPrefixMappingTest.java | 440 --- .../jena/security/graph/TDBGraphTest.java | 58 - .../jena/security/model/SecuredAltTest.java | 657 ----- .../jena/security/model/SecuredBagTest.java | 46 - .../security/model/SecuredContainerTest.java | 480 --- .../jena/security/model/SecuredLiteralTest.java | 468 --- .../security/model/SecuredModelDetailTest.java | 335 --- .../jena/security/model/SecuredModelTest.java | 2034 ------------- .../security/model/SecuredPropertyTest.java | 79 - .../jena/security/model/SecuredRDFListTest.java | 970 ------- .../jena/security/model/SecuredRDFNodeTest.java | 209 -- .../model/SecuredReifiedStatementTest.java | 84 - .../security/model/SecuredResourceTest.java | 827 ------ .../jena/security/model/SecuredSeqTest.java | 1013 ------- .../security/model/SecuredStatementTest.java | 707 ----- .../apache/jena/security/query/DataSetTest.java | 244 -- .../jena/security/query/QueryEngineTest.java | 259 -- .../security/query/rewriter/OpRewriterTest.java | 111 - .../jena/permissions/SecuredAssemblerTest.ttl | 56 + .../apache/jena/permissions/model/detail.ttl | 33 + .../org/apache/jena/permissions/model/test.ttl | 2 + .../org/apache/jena/permissions/model/test.xml | 7 + .../jena/security/SecuredAssemblerTest.ttl | 56 - .../org/apache/jena/security/model/detail.ttl | 33 - .../org/apache/jena/security/model/test.ttl | 2 - .../org/apache/jena/security/model/test.xml | 7 - 208 files changed, 29007 insertions(+), 29994 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jena/blob/c4b0113d/jena-permissions/readme.md ---------------------------------------------------------------------- diff --git a/jena-permissions/readme.md b/jena-permissions/readme.md index 5feaa42..23599c8 100644 --- a/jena-permissions/readme.md +++ b/jena-permissions/readme.md @@ -1,6 +1,4 @@ -REQUIRES Jena 2.10.0 - -JenaSecurity is a SecurityEvaluator interface and a set of dynamic proxies that apply that interface to Jena Graphs, Models, and associated methods and classes. +JenaPermissions is a SecurityEvaluator interface and a set of dynamic proxies that apply that interface to Jena Graphs, Models, and associated methods and classes. The SecurityEvaluator class must be implemented. This class provides the interface to the authentication results (e.g. getPrincipal())) and the authorization system. @@ -8,15 +6,15 @@ Create a SecuredGraph by calling Factory.getInstance( SecurityEvaluator, String, Create a SecuredModel by calling Factory.getInstance( SecurityEvaluator, String, Model ) or ModelFactory.createModelForGraph( SecuredGraph ); NOTE: when creating a model by wrapping a secured graph (e.g. ModelFactory.createModelForGraph( SecuredGraph );) the resulting Model does not -have the same security requirements that the standard secured model does. +have the same permission requirements that the standard secured model does. For instance when creating a list on a secured model calling model.createList( RDFNode[] ); The standard secured model verifies that the user has the right to update the triples and allows or denies the entire operation accordingly. The wrapped secured graph does not have visibility to the createList() command and can only operate on the instructions issued by the model.createList() implementation. In the standard implementation the model requests the graph to delete one triple and then insert another. Thus the user must have delete and add permissions, not the update permission. -There are several other cases where the difference in the layer can trip up the security system. In all known cases the result is a tighter -security definition than was requested. For simplicity sake we recommend that the wrapped secured graph only be used in cases where access to the +There are several other cases where the difference in the layer can trip up the permission system. In all known cases the result is a tighter +permission definition than was requested. For simplicity sake we recommend that the wrapped secured graph only be used in cases where access to the graph as a whole is granted/denied. In these cases the user either has all CRUD capabilities or none. [] a ja:Model ; http://git-wip-us.apache.org/repos/asf/jena/blob/c4b0113d/jena-permissions/src/main/java/org/apache/jena/permissions/AccessDeniedException.java ---------------------------------------------------------------------- diff --git a/jena-permissions/src/main/java/org/apache/jena/permissions/AccessDeniedException.java b/jena-permissions/src/main/java/org/apache/jena/permissions/AccessDeniedException.java new file mode 100644 index 0000000..84a263b --- /dev/null +++ b/jena-permissions/src/main/java/org/apache/jena/permissions/AccessDeniedException.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.permissions; + +import org.apache.jena.permissions.SecurityEvaluator.Action; +import org.apache.jena.permissions.SecurityEvaluator.SecNode; + +/** + * Exception thrown by the security system when an action is not allowed. + * + * Contains the graphIRI and the action that was not allowed. + */ +public class AccessDeniedException extends RuntimeException +{ + private static final long serialVersionUID = 2789332975364811725L; + + private String triple; + + /** + * Constructor. + * @param uri The SecNode that identifies graph with the security. + * @param action The action that was prohibited. + */ + public AccessDeniedException( final SecNode uri, final Action action ) + { + super(String.format("securedModel sec. %s: %s", uri, action)); + } + + /** + * Constructor. + * @param uri The SecNode that identifies graph with the security. + * @param triple The triple The triple on which the action was prohibited. + * @param action The action that was prohibited. + */ + public AccessDeniedException( final SecNode uri, final String triple, + final Action action ) + { + super(String.format("triple sec. %s: %s", uri, action)); + this.triple = triple; + } + + /** + * @return The triple on which the action was prohibited. May be null. + */ + public String getTriple() + { + return triple; + } + +} http://git-wip-us.apache.org/repos/asf/jena/blob/c4b0113d/jena-permissions/src/main/java/org/apache/jena/permissions/AssemblerConstants.java ---------------------------------------------------------------------- diff --git a/jena-permissions/src/main/java/org/apache/jena/permissions/AssemblerConstants.java b/jena-permissions/src/main/java/org/apache/jena/permissions/AssemblerConstants.java new file mode 100644 index 0000000..4a57986 --- /dev/null +++ b/jena-permissions/src/main/java/org/apache/jena/permissions/AssemblerConstants.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.permissions; + +import org.apache.jena.rdf.model.Property ; +import org.apache.jena.rdf.model.ResourceFactory ; + +public interface AssemblerConstants { + public static final String URI = "http://apache.org/jena/permissions/Assembler#"; + /** + * Property named URI+"evaluatorFactory" + */ + public static final Property EVALUATOR_FACTORY = + ResourceFactory.createProperty( URI + "evaluatorFactory" ); + /** + * Property named URI+"Model" + */ + public static final Property SECURED_MODEL = ResourceFactory.createProperty( URI + "Model" ); + /** + * Property named URI+"baseModel" + */ + public static final Property BASE_MODEL = ResourceFactory.createProperty( URI + "baseModel" ); + /** + * Property named URI+"Evaluator" + */ + public static final Property EVALUATOR_ASSEMBLER = ResourceFactory.createProperty( URI+"Evaluator" ); + /** + * Property named URI+"evaluatorImpl" + */ + public static final Property EVALUATOR_IMPL = + ResourceFactory.createProperty( URI + "evaluatorImpl" ); + + /** + * Property named URI+"evaluatorClass" + */ + public static final Property EVALUATOR_CLASS = + ResourceFactory.createProperty( URI + "evaluatorClass" ); + /** + * Property named URI+"evaluatorImpl" + */ + public static final Property ARGUMENT_LIST = + ResourceFactory.createProperty( URI + "args" ); + + // message formats + public static final String NO_X_PROVIDED = "No %s provided for %s"; +} http://git-wip-us.apache.org/repos/asf/jena/blob/c4b0113d/jena-permissions/src/main/java/org/apache/jena/permissions/Factory.java ---------------------------------------------------------------------- diff --git a/jena-permissions/src/main/java/org/apache/jena/permissions/Factory.java b/jena-permissions/src/main/java/org/apache/jena/permissions/Factory.java new file mode 100644 index 0000000..80a37f9 --- /dev/null +++ b/jena-permissions/src/main/java/org/apache/jena/permissions/Factory.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jena.permissions; + +import org.apache.jena.graph.Graph ; +import org.apache.jena.permissions.graph.SecuredGraph; +import org.apache.jena.permissions.model.SecuredModel; +import org.apache.jena.rdf.model.Model ; + +/** + * The factory that can be used to create an instance of a SecuredGraph or a SecuredModel. + */ +public class Factory +{ + + /** + * Create an instance of the SecuredGraph + * + * @param securityEvaluator + * The security evaluator to use + * @param graphIRI + * The IRI for the graph. + * @param graph + * The graph that we are wrapping. + * @return the graph secured under the name graphIRI + */ + public static SecuredGraph getInstance( + final SecurityEvaluator securityEvaluator, final String graphIRI, + final Graph graph ) + { + + return org.apache.jena.permissions.graph.impl.Factory.getInstance( + securityEvaluator, graphIRI, graph); + } + + /** + * Get an instance of SecuredModel + * + * @param securityEvaluator + * The security evaluator to use + * @param modelIRI + * The securedModel IRI (graph IRI) to evaluate against. + * @param model + * The model to secure. + * @return the model secured under the name modelIRI + */ + public static SecuredModel getInstance( + final SecurityEvaluator securityEvaluator, final String modelIRI, + final Model model ) + { + return org.apache.jena.permissions.model.impl.SecuredModelImpl.getInstance( + securityEvaluator, modelIRI, model); + } +} http://git-wip-us.apache.org/repos/asf/jena/blob/c4b0113d/jena-permissions/src/main/java/org/apache/jena/permissions/SecuredAssembler.java ---------------------------------------------------------------------- diff --git a/jena-permissions/src/main/java/org/apache/jena/permissions/SecuredAssembler.java b/jena-permissions/src/main/java/org/apache/jena/permissions/SecuredAssembler.java new file mode 100644 index 0000000..0b61717 --- /dev/null +++ b/jena-permissions/src/main/java/org/apache/jena/permissions/SecuredAssembler.java @@ -0,0 +1,264 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jena.permissions; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.apache.jena.assembler.Assembler ; +import org.apache.jena.assembler.JA ; +import org.apache.jena.assembler.Mode ; +import org.apache.jena.assembler.assemblers.AssemblerGroup ; +import org.apache.jena.assembler.assemblers.ModelAssembler ; +import org.apache.jena.assembler.exceptions.AssemblerException ; +import org.apache.jena.rdf.model.Literal ; +import org.apache.jena.rdf.model.Model ; +import org.apache.jena.rdf.model.Resource ; +import org.apache.jena.sparql.util.MappingRegistry ; + +/** + * Assembler for a secured model. + * + * <p> + * The assembler file should include the following + * <code><pre> + * <>; ja:loadClass "org.apache.jena.permission.SecuredAssembler" . + * + * sec:Model rdfs:subClassOf ja:NamedModel . + * + * sec:evaluator rdfs:domain sec:Model ; + * rdfs:range sec:Evaluator . + * </pre></code> + * + * The model definition should include something like. + * + * <code><pre> + * my:secModel a sec:Model ; + * sec:baseModel my:baseModel ; + * ja:modelName "http://example.com/securedModel" ; + * sec:evaluatorFactory "org.apache.jena.permission.MockSecurityEvaluator" ; + * . + * </pre></code> + * + * Terms used in above example: + * + * <dl> + * <dt>my:secModel</dt> + * <dd>The secured model as referenced in the assembler file.</dd> + * + * <dt>sec:Model</dt> + * <dd>Identifes my:secModel as a secured model</dd> + * + * <dt>sec:baseModel</dt> + * <dd>Identifies my:baseModel as the base model we are applying permissions to</dd> + * + * <dt>my:baseModel</dt> + * <dd>a ja:Model (or subclass) defined elsewhere in the assembler file</dd> + * + * <dt>ja:modelName</dt> + * <dd>The name of the graph as it will be addressed in the permission environment + * (see ja:NamedModel examples from Jena)</dd> + * + * <dt>sec:evaluatorFactory</dt> + * <dd>Identifies "org.apache.jena.permission.MockSecurityEvaluator" as the java class + * that implements an Evaluator Factory. The Factory must have + * static method <code>getInstance()</code> that returns a SecurityEvaluator.</dd> + * </dl> + * + * or if using an evaluator assembler + * + * <code><pre> + * my:secModel a sec:Model ; + * sec:baseModel my:baseModel ; + * ja:modelName "http://example.com/securedModel" ; + * sec:evaluatorImpl ex:myEvaluator; + * . + * + * ex:myEvaluator a sec:Evaluator ; + * ex:arg1 "argument 1 for my evaluator constructor" ; + * ex:arg2 "argument 2 for my evaluator constructor" ; + * . + * + * </pre></code> + * + * Terms used in above example: + * + * <dl> + * <dt>my:secModel</dt> + * <dd>The secured model as referenced in the assembler file.</dd> + * + * <dt>sec:Model</dt> + * <dd>Identifes my:secModel as a secured model</dd> + * + * <dt>sec:baseModel</dt> + * <dd>Identifies my:baseModel as the base model we are applying permissions to</dd> + * + * <dt>my:baseModel</dt> + * <dd>a ja:Model (or subclass) defined elsewhere in the assembler file</dd> + * + * <dt>ja:modelName</dt> + * <dd>The name of the graph as it will be addressed in the permission environment + * (see ja:NamedModel examples from Jena)</dd> + * + * <dt>sec:evaluatorImpl</dt> + * <dd>Identifies ex:myEvaluator as a SecurityEvaluator defined elsewhere in the assembler file. + * It must subclass as a sec:Evaluator.</dd> + * </dd> + * + * <dt>ex:arg1 and ex:arg2</dt> + * <dd>Arguments as defined by the user defined security evaluator assembler.</dd> + * </dl> + + * </p> + * + */ +public class SecuredAssembler extends ModelAssembler implements AssemblerConstants { + private static boolean initialized; + + // message formats + private static final String ERROR_FINDING_FACTORY = "Error finding factory class %s: %s"; + + static { init() ; } + + /** + * Initialize the assembler. + * Registers the prefix "sec" with the uri http://apache.org/jena/permission/Assembler# + * and registers this assembler with the uri http://apache.org/jena/permission/Assembler#Model + */ + static synchronized public void init() + { + if ( initialized ) + return ; + MappingRegistry.addPrefixMapping("sec", URI) ; + registerWith(Assembler.general) ; + initialized = true ; + } + + /** + * Register this assembler in the assembler group. + * @param group The assembler group to register with. + */ + static void registerWith(AssemblerGroup group) + { + if ( group == null ) + group = Assembler.general ; + group.implementWith( SECURED_MODEL, new SecuredAssembler()) ; + group.implementWith( EVALUATOR_ASSEMBLER, new SecurityEvaluatorAssembler()); + } + + @Override + public Model open(Assembler a, Resource root, Mode mode) { + + Resource rootModel = getUniqueResource( root, BASE_MODEL ); + if (rootModel == null) + { + throw new AssemblerException( root, String.format( NO_X_PROVIDED, BASE_MODEL, root )); + } + Model baseModel = a.openModel(rootModel, Mode.ANY); + + Literal modelName = getUniqueLiteral( root, JA.modelName ); + if (modelName == null) + { + throw new AssemblerException( root, String.format( NO_X_PROVIDED, JA.modelName, root )); + } + + Literal factoryName = getUniqueLiteral( root, EVALUATOR_FACTORY ); + Resource evaluatorImpl = getUniqueResource( root, EVALUATOR_IMPL ); + if (factoryName == null && evaluatorImpl == null) + { + throw new AssemblerException( root, + String.format( "Either a %s or a %s must be provided for %s" , + EVALUATOR_FACTORY, EVALUATOR_IMPL, root )); + } + if (factoryName != null && evaluatorImpl != null) + { + throw new AssemblerException( root, + String.format( "May not specify both a %s and a %s for %s" , + EVALUATOR_FACTORY, EVALUATOR_IMPL, root )); + } + SecurityEvaluator securityEvaluator = null; + if (factoryName != null) + { + securityEvaluator = executeEvaluatorFactory( root, factoryName ); + } + if (evaluatorImpl != null) + { + securityEvaluator = getEvaluatorImpl( a, evaluatorImpl ); + } + return Factory.getInstance(securityEvaluator, modelName.asLiteral().getString(), baseModel); + + } + + @Override + protected Model openEmptyModel(Assembler a, Resource root, Mode mode) { + return open(a, root, mode); + } + + private SecurityEvaluator executeEvaluatorFactory(Resource root, Literal factoryName ) { + try + { + Class<?> factoryClass = Class.forName( factoryName.getString() ); + Method method = factoryClass.getMethod("getInstance" ); + if ( ! SecurityEvaluator.class.isAssignableFrom(method.getReturnType())) + { + throw new AssemblerException( root, String.format( "%s (found at %s for %s) getInstance() must return an instance of SecurityEvaluator", factoryName, EVALUATOR_FACTORY, root )); + } + if ( ! Modifier.isStatic( method.getModifiers())) + { + throw new AssemblerException( root, String.format( "%s (found at %s for %s) getInstance() must be a static method", factoryName, EVALUATOR_FACTORY, root )); + } + return (SecurityEvaluator) method.invoke( null ); + } + catch (SecurityException e) + { + throw new AssemblerException( root, String.format( ERROR_FINDING_FACTORY, factoryName, e.getMessage() ), e); + } + catch (IllegalArgumentException e) + { + throw new AssemblerException( root, String.format( ERROR_FINDING_FACTORY, factoryName, e.getMessage() ), e); + } + catch (ClassNotFoundException e) + { + throw new AssemblerException( root, String.format( "Class %s (found at %s for %s) could not be loaded", factoryName, EVALUATOR_FACTORY, root )); + } + catch (NoSuchMethodException e) + { + throw new AssemblerException( root, String.format( "%s (found at %s for %s) must implement a static getInstance() that returns an instance of SecurityEvaluator", factoryName, EVALUATOR_FACTORY, root )); + } + catch (IllegalAccessException e) + { + throw new AssemblerException( root, String.format( ERROR_FINDING_FACTORY, factoryName, e.getMessage() ), e); + } + catch (InvocationTargetException e) + { + throw new AssemblerException( root, String.format( ERROR_FINDING_FACTORY, factoryName, e.getMessage() ), e); + } + } + + private SecurityEvaluator getEvaluatorImpl(Assembler a, Resource evaluatorImpl ) { + Object obj = a.open(a, evaluatorImpl, Mode.ANY); + if (obj instanceof SecurityEvaluator) + { + return (SecurityEvaluator) obj; + } + throw new AssemblerException( evaluatorImpl, String.format( + "%s does not specify a SecurityEvaluator instance", evaluatorImpl)); + } + +} http://git-wip-us.apache.org/repos/asf/jena/blob/c4b0113d/jena-permissions/src/main/java/org/apache/jena/permissions/SecurityEvaluator.java ---------------------------------------------------------------------- diff --git a/jena-permissions/src/main/java/org/apache/jena/permissions/SecurityEvaluator.java b/jena-permissions/src/main/java/org/apache/jena/permissions/SecurityEvaluator.java new file mode 100644 index 0000000..1e28084 --- /dev/null +++ b/jena-permissions/src/main/java/org/apache/jena/permissions/SecurityEvaluator.java @@ -0,0 +1,616 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jena.permissions; + +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.apache.commons.lang3.builder.HashCodeBuilder; + +/** + * SecurityEvaluator. + * <p> + * The security evaluator is the link between the graph security system and an + * external security system. This interface specifies the methods that are + * required by the graph security system. It is assumed that the implementation + * will handle tracking the current user and will query some underlying data + * source to determine what actions the user can and can not take. + * </p> + * <p> + * All questions of white listing or black listing will be handled in the + * concrete implementation. + * </p> + * <p> + * Implementations of this class should probably cache any evaluate calculations + * as the evaluate methods are called frequently. However, the underlying + * classes do cache results within a single method check. + * </p> + * <p> + * <dl> + * <dt>Secured operations</dt> + * <dd>The security system recognizes and secures each of the CRUD (Create, + * Read, Update and Delete) operations as represented by the Action enumeration. + * </dd> + * </dl> + * <dl> + * <dt>Levels of security</dt> + * <dd>The security interfaces operates at two (2) levels: graph (or Model) and + * triple. + * <p> + * At the the graph level the security evaluator may restrict CRUD access to the + * graph or model as a whole. When evaluating the restriction, if the user it + * not permitted to perform the operation on the graph or model access is + * denied. If the user is permitted any triple restrictions are evaluated. + * </p> + * <p> + * At the triple level the security evaluator may restrict CRUD access to + * specific triples. In order to skip potentially expensive triple security + * checks the system will generally ask if the user is permitted the CRUD action + * on any triple. This is represented by the SecTriple + * <code>(ANY, ANY, ANY)</code>. + * <ul> + * <li> + * If the system does not support triple level security the system should always + * return <code>true</code>.</li> + * If the system does support triple level security and is unable to verify that + * the user can execute the CRUD action against any arbitrary triple the system + * should return <code>false</code>. </li> + * <li>See <code>SecNode.ANY</code>, <code>SecNode.FUTURE</code>, and + * <code>SecNode.VARIABLE</code> for discussion of specifics of their respective + * usages.</li> + * </ul> + * </p> + * </dd> + * </dl> + * <dl> + * <dt> + * + * </p> + */ +public interface SecurityEvaluator { + /** + * Identifies a sepcific CRUD actions. + */ + static enum Action { + /** + * Allow creation of the object in question. + */ + Create, + /** + * Allow the user to read the object in question. + */ + Read, + /** + * Allow the user to update the object in question + */ + Update, + /** + * Allow the user to delete the object in question. + */ + Delete + + } + + /** + * A node in the evaluation. + * <p> + * A node with no value represents a node of that type but unknown + * exactitude. (e.g. <code>SecNode(URI,"")</code> is a URI but of unknown + * value. Useful for systems that restrict type creation. + * </p> + * <p> + * <code>SecNode(Anonymous,"")</code> represents an anonymous node that will + * be created. Otherwise anonymous node values are the values within the + * secured graph. + * </p> + * <p> + * An "Any" node type matches any node. + * </p> + */ + public static class SecNode implements Comparable<SecNode> { + + /** + * The types of nodes. + */ + public static enum Type { + /** + * A URI type node + */ + URI, + /** + * A Literal node. + */ + Literal, + /** + * An anonymous node. Also called a "blank" node. + */ + Anonymous, + /** + * Any node. + */ + Any + } + + /** + * Matches any node in the security system. + * <p> + * Used in triple checks as follows: + * <dl> + * <dt><code>(ANY, ANY, ANY)</code></dt> + * <dd>Asks if the user may perform the action on any triple.</dd> + * <dt><code>(X, ANY, ANY)</code></dt> + * <dd>Asks if the user may perform the action against any triple where + * X is the subject.</dd> + * <dt><code>(ANY, X, ANY)</code></dt> + * <dd>Asks if the user may perform the action against any triple where + * X is the predicate.</dd> + * <dt><code>(SecNode.ANY, SecNode.ANY, SecNode.X)</code></dt> + * <dd>Asks if if the user may perform the action against any triple + * where X is the object.</dd> + * </dl> + * The <code>ANY</code> may occur multiple times and may occur with the + * <code>VARIABLE</code> and/or <code>FUTURE</code> nodes. + * </p> + */ + public static final SecNode ANY = new SecNode(Type.Any, "any"); + + /** + * Indicates a variable in the triple. + * <p> + * </p> + * This differs from <code>ANY</code> in that the system is asking if + * there are any prohibitions not if the user may perform. Thus queries + * with the VARIABLE type node should return <code>true</code> where + * <code>ANY</code> returns <code>false</code>. In general this type is + * used in the query to determine if triple level filtering of results + * must be performed. + * <p> + * </p> + * <p> + * <dl> + * <dt><code>(VARIABLE, X, Y )</code></dt> + * <dd> + * Asks if there are any prohibitions against the user seeing all + * subjects that have property X and object Y.</dd> + * <dt> + * <code>(X, VARIABLE, Y )</code></dt> + * <dd> + * Asks if there are any prohibitions against the user seeing all + * predicates that have subject X and object Y.</dd> + * <dt> + * <code>(X, Y, VARIABLE)</code></dt> + * <dd> + * Asks if there are any prohibitions against the user seeing all + * objects that have subject X and predicate Y.</dd> + * </dl> + * The <code>VARIABLE</code> may occur multiple times and may occur with + * the <code>ANY</code> node. + * </p> + * + */ + public static final SecNode VARIABLE = new SecNode(Type.Any, "variable"); + + /** + * This is an anonymous node that will be created in the future. + * <p> + * FUTURE is used to check that an anonymous node may be created in as + * specific position in a triple. + * </p> + * <p> + * <dl> + * <dt><code>(FUTURE, X, Y )</code></dt> + * <dd> + * Asks if there the user may create an anonymous node that has property + * X and object Y.</dd> + * <dt> + * <code>(X, Y, FUTURE)</code></dt> + * <dd> + * Asks if there the user may create an anonymous node that has subject + * X and property Y.</dd> + * </dl> + * The <code>FUTURE</code> may occur multiple times and may occur with + * the <code>ANY</code> node. + * </p> + */ + public static final SecNode FUTURE = new SecNode(Type.Anonymous, ""); + + private final Type type; + private final String value; + private Integer hashCode; + + /** + * Create a SecNode of the type and value. + * + * @param type + * The type of the node + * @param value + * The value of the node. A null is interpreted as an empty + * string. + */ + public SecNode(final Type type, final String value) { + this.type = type; + this.value = value == null ? "" : value; + } + + @Override + public int compareTo(final SecNode node) { + final int retval = type.compareTo(node.type); + return retval == 0 ? value.compareTo(node.value) : retval; + } + + @Override + public boolean equals(final Object o) { + if (o instanceof SecNode) { + return this.compareTo((SecNode) o) == 0; + } + return false; + } + + /** + * Get the type of the node. + * + * @return The type of the node. + */ + public Type getType() { + return type; + } + + /** + * Get the value of the node. + * + * @return the value of the node + */ + public String getValue() { + return value; + } + + @Override + public int hashCode() { + if (hashCode == null) { + hashCode = new HashCodeBuilder().append(type).append(value) + .toHashCode(); + } + return hashCode; + } + + @Override + public String toString() { + return String.format("[%s:%s]", getType(), getValue()); + } + } + + /** + * An immutable triple of SecNodes. + */ + public static class SecTriple implements Comparable<SecTriple> { + private final SecNode subject; + private final SecNode predicate; + private final SecNode object; + private transient Integer hashCode; + + /** + * The triple of <code>(ANY, ANY, ANY)</code>. + */ + public static final SecTriple ANY = new SecTriple(SecNode.ANY, + SecNode.ANY, SecNode.ANY); + + /** + * Create the sec triple + * + * @param subject + * The subject node. + * @param predicate + * The predicate node. + * @param object + * The object node. + * @throws IllegalArgumentException + * is any value is null. + */ + public SecTriple(final SecNode subject, final SecNode predicate, + final SecNode object) { + if (subject == null) { + throw new IllegalArgumentException("Subject may not be null"); + } + if (predicate == null) { + throw new IllegalArgumentException("Predicate may not be null"); + } + if (object == null) { + throw new IllegalArgumentException("Object may not be null"); + } + this.subject = subject; + this.predicate = predicate; + this.object = object; + } + + @Override + public int compareTo(final SecTriple o) { + if (o == null) { + return 1; + } + int retval = subject.compareTo(o.subject); + if (retval == 0) { + retval = predicate.compareTo(o.predicate); + } + return retval == 0 ? object.compareTo(o.object) : retval; + } + + @Override + public boolean equals(final Object o) { + if (o instanceof SecTriple) { + return this.compareTo((SecTriple) o) == 0; + } + return false; + } + + /** + * @return the object node. + */ + public SecNode getObject() { + return object; + } + + /** + * @return the predicate node. + */ + public SecNode getPredicate() { + return predicate; + } + + /** + * @return the subject node. + */ + public SecNode getSubject() { + return subject; + } + + @Override + public int hashCode() { + if (hashCode == null) { + hashCode = new HashCodeBuilder().append(object) + .append(predicate).append(subject).toHashCode(); + } + return hashCode; + } + + @Override + public String toString() { + return String.format("( %s, %s, %s )", getSubject(), + getPredicate(), getObject()); + } + } + + /** + * A collection of utility functions for the SecurityEvaluator + * implementations. + */ + public static class Util { + /** + * Return an array of actions as a set. + * <p> + * The order of the collection is preserved + * </p> + * + * @param actions + * The actions. + * @return The set of actions. + */ + public static Set<Action> asSet(final Action[] actions) { + return Util.asSet(Arrays.asList(actions)); + } + + /** + * Return a collection of actions as a set. + * <p> + * The order of the collection is preserved + * </p> + * + * @param actions + * The collection of actions. + * @return The set of actions. + */ + public static Set<Action> asSet(final Collection<Action> actions) { + if (actions instanceof Set) { + return (Set<Action>) actions; + } + else { + return new LinkedHashSet<Action>(actions); + } + } + } + + /** + * Determine if the action is allowed on the graph. + * + * @param principal + * The principal that is attempting the action. + * + * @param action + * The action to perform + * @param graphIRI + * The IRI of the graph to check + * @return true if the action is allowed, false otherwise. + */ + public boolean evaluate(Object principal, Action action, SecNode graphIRI); + + /** + * Determine if the action is allowed on the triple within the graph. + * <p> + * The evaluation should be performed in the following order: + * <ol> + * <li> + * If the triple contains a <code>VARIABLE</code> then this method must + * return <code>true</code> if there are any restrictions where the + * remaining nodes are either constants or <code>ANY</code> nodes. This will + * force the system to use subsequent checks to verify access by + * substituting the value of the <code>VARIABLE</code>s. + * <em>If the system can not quickly verify the solution + * it is always acceptable to return <code>true</code>.</em> + * <li> + * Except as specified in the above check, if the triple contains an + * <code>ANY</code> then this method must return <code>false</code> if there + * are any restrictions where the remaining nodes are held constant and the + * ANY node is allowed to vary. This checks is used to avoid subsequent + * explicit triple checks. + * <em>If the system can not quickly verify the solution it is always + * acceptable to return <code>false</code>.</em></li> + * <li>All other triples are explict triples and the system must determine + * if the user is permitted to perform the action on the triple. If the + * triple contains a <code>FUTURE</code> node that node should be considered + * as an anonymous or blank node that is not yet created. It should only be + * used with <code>Create</code> actions and is asking if the user may + * create a blank node in that position in the triple.</li> + * </ol> + * </p> + * + * @param principal + * The principal that is attempting the action. + * + * @param action + * The action to perform + * @param graphIRI + * The IRI of the graph to the action is being taken upon. May be + * <code>ANY</code>. + * @param triple + * The triple to check + * @return true if the action is allowed, false otherwise. + * @throws IllegalArgumentException + * if any argument is null. + */ + public boolean evaluate(Object principal, Action action, SecNode graphIRI, + SecTriple triple); + + /** + * Determine if all actions are allowed on the graph. + * + * @param principal + * The principal that is attempting the action. + * + * @param actions + * The set of actions to perform + * @param graphIRI + * The IRI of the graph to the action is being taken upon. May be + * <code>ANY</code>. + * @return true if all the actions are allowed, false otherwise. + * @throws IllegalArgumentException + * if any argument is null. + */ + public boolean evaluate(Object principal, Set<Action> actions, + SecNode graphIRI); + + /** + * Determine if all the actions are allowed on the triple within the graph. + * <p> + * See evaluate( Action, SecNode, SecTriple ) for discussion of evaluation + * strategy. + * </p> + * + * @param actions + * The actions to perform. + * @param graphIRI + * The IRI of the graph to the action is being taken upon. May be + * <code>ANY</code>. + * @param triple + * The triple to check + * @return true if all the actions are allowed, false otherwise. + * @throws IllegalArgumentException + * if any argument is null. + */ + public boolean evaluate(Object principal, Set<Action> actions, + SecNode graphIRI, SecTriple triple); + + /** + * Determine if any of the actions are allowed on the graph. + * + * @param principal + * The principal that is attempting the action. + * + * @param actions + * The actions to perform + * @param graphIRI + * The IRI of the graph to the action is being taken upon. May be + * <code>ANY</code>. + * @return true true if any the actions are allowed, false otherwise. + * @throws IllegalArgumentException + * if any argument is null. + */ + public boolean evaluateAny(Object principal, Set<Action> actions, + SecNode graphIRI); + + /** + * Determine if any of the actions are allowed on the triple within the + * graph. + * <p> + * See evaluate( Action, SecNode, SecTriple ) for discussion of evaluation + * strategy. + * </p> + * + * @param principal + * The principal that is attempting the action. + * + * @param actions + * The actions to check. + * @param graphIRI + * The IRI of the graph to the action is being taken upon. May be + * <code>ANY</code>. + * @param triple + * The triple to check + * @return true if any the actions are allowed, false otherwise. + * @throws IllegalArgumentException + * if any argument is null. + */ + public boolean evaluateAny(Object principal, Set<Action> actions, + SecNode graphIRI, SecTriple triple); + + /** + * Determine if the user is allowed to update the "from" triple to the "to" + * triple. + * <p> + * Update is a special case since it modifies one triple to be another. So + * the user must have permissions to change the "from" triple into the "to" + * triple. + * + * @param principal + * The principal that is attempting the action. + * @param graphIRI + * The IRI of the graph to the action is being taken upon. May be + * <code>ANY</code>. + * @param from + * The triple to be changed + * @param to + * The value to change it to. + * @return true if the user may make the change, false otherwise. + * @throws IllegalArgumentException + * if any argument is null. + */ + public boolean evaluateUpdate(Object principal, SecNode graphIRI, + SecTriple from, SecTriple to); + + /** + * returns the current principal or null if there is no current principal. + * + * All security evaluation methods use this method to determine who the call + * is being executed as. This allows subsystems (like the listener system) + * to capture the current user and evaluate later calls in terms of that + * user. + * + * @return The current principal + */ + public Object getPrincipal(); +} http://git-wip-us.apache.org/repos/asf/jena/blob/c4b0113d/jena-permissions/src/main/java/org/apache/jena/permissions/SecurityEvaluatorAssembler.java ---------------------------------------------------------------------- diff --git a/jena-permissions/src/main/java/org/apache/jena/permissions/SecurityEvaluatorAssembler.java b/jena-permissions/src/main/java/org/apache/jena/permissions/SecurityEvaluatorAssembler.java new file mode 100644 index 0000000..bb4814f --- /dev/null +++ b/jena-permissions/src/main/java/org/apache/jena/permissions/SecurityEvaluatorAssembler.java @@ -0,0 +1,183 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jena.permissions; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.jena.assembler.Assembler ; +import org.apache.jena.assembler.Mode ; +import org.apache.jena.assembler.assemblers.AssemblerBase ; +import org.apache.jena.assembler.exceptions.AssemblerException ; +import org.apache.jena.rdf.model.* ; + +/** + * A simple assembler for a SecurityEvaluator + * <p> + * This assembler load the specified class, locates the first constructor that accepts + * the number of arguments in the assembler file, and calls it passing the arguments. + * Generally the result of this assembler is passed to a sec:Model construction. + * @see SecuredAssembler + * </p> + * <ul> + * <li>The evaluator must have one and only one public constructor + * that takes the number of arguments specified in the assembler file. + * </li> + * + * <li> + * The evaluator may have more constructors but they may not have the same + * number of arguments as specified in the assembler file. + * </li> + * + * <li> + * The arguments must be specified in the assembler file in the order that they + * should be passed to the constructor. + * </li> + * </ul> + * + * <p> + * Literal arguments are converted to their data type before calling the constructor. For example + * "13"^^xsd:int will be converted to an Integer with the value of 13. + * </p> + * The assembler file should include the following + * <code><pre> + * @prefix xsd: <http://www.w3.org/2001/XMLSchema#> + * + * <>; ja:loadClass "org.apache.jena.security.SecuredAssembler" . + * + * sec:Model rdfs:subClassOf ja:NamedModel . + * + * </pre></code> + * + * The model definition should include something like. + * + * <code><pre> + * ex:myEvaluator a sec:Evaluator ; + * sec:args [ rdf:_1 "argument 1 for my evaluator constructor" ; + * rdf:_2 "13"^^xsd:int ; ]; + * sec:evaluatorClass "evaluatorClassname"; + * . + * </pre></code> + * + * Terms used in above example: + * + * <dl> + * <dt>my:secEvaluator</dt> + * <dd>The security evaluator as referenced in the assembler file.</dd> + * + * <dt>sec:Evaluator</dt> + * <dd>Identifies my:secEvaluator as a SecurityEvaluator</dd> + * + * <dt>sec:args</dt> + * <dd>Identifies the argument list</dd> + * + * <dt>rdf:_1</dt> + * <dd>The first argument</dd> + * + * <dt>rdf:_2</dt> + * <dd>The second argument (an integer in this case</dd> + * + * <dt>sec:evaluatorClass</dt> + * <dd>The fully qualified name of the SecurityEvaluator class to call. This class must extend + * SecurityEvaluator, and must have one and only one constructor that takes the number of arguments + * specified in sec:args</dd> + * + * </p> + * + */ +public class SecurityEvaluatorAssembler extends AssemblerBase implements Assembler, AssemblerConstants { + // initialization and registration is performed by SecuredAssembler + + @Override + public SecurityEvaluator open(Assembler a, Resource root, Mode mode) { + + Literal className = getUniqueLiteral( root, EVALUATOR_CLASS ); + if (className == null) + { + throw new AssemblerException( root, String.format( NO_X_PROVIDED, EVALUATOR_CLASS, root )); + } + + Class<?> clazz; + try { + clazz = Class.forName(className.getString()); + } catch (ClassNotFoundException e1) { + throw new AssemblerException( root, String.format( "Can not locate class %s as specified by %s in %s", className, EVALUATOR_CLASS, root )); + } + if ( ! SecurityEvaluator.class.isAssignableFrom( clazz )) + { + throw new AssemblerException( root, String.format( "Class %s as specified by %s in %s does not implement SecurityEvaluator", className, EVALUATOR_CLASS, root )); + } + + // get the arguments as specified. + List<Object> args = new ArrayList<Object>(); + Resource argRes = getUniqueResource( root, ARGUMENT_LIST ); + if (argRes != null) + { + Seq seq = argRes.as( Seq.class ); + NodeIterator iter = seq.iterator(); + RDFNode n = null; + while (iter.hasNext()) + { + n = iter.next(); + if (n.isLiteral()) + { + args.add( n.asLiteral().getValue()); + } + else if (n.isResource()) + { + args.add( a.open( a, n.asResource(), mode ) ); + } + else + { + throw new AssemblerException( root, String.format( "%s must be a literal or a resource", n )); + } + } + } + + for (Constructor<?> c : clazz.getConstructors()) + { + if (c.getParameterTypes().length == args.size()) + { + try { + if (args.size() == 0) + { + return (SecurityEvaluator) c.newInstance(); + } + else + { + return (SecurityEvaluator) c.newInstance( args.toArray() ); + } + } catch (InstantiationException e) { + throw new AssemblerException( root, e.getMessage(), e ); + } catch (IllegalAccessException e) { + throw new AssemblerException( root, e.getMessage(), e ); + } catch (IllegalArgumentException e) { + throw new AssemblerException( root, e.getMessage(), e ); + } catch (InvocationTargetException e) { + throw new AssemblerException( root, e.getMessage(), e ); + } + } + + } + throw new AssemblerException( root, String.format( "Class %s does not have a %s argument constructor", className, args.size() )); + + } + +} http://git-wip-us.apache.org/repos/asf/jena/blob/c4b0113d/jena-permissions/src/main/java/org/apache/jena/permissions/graph/SecuredCapabilities.java ---------------------------------------------------------------------- diff --git a/jena-permissions/src/main/java/org/apache/jena/permissions/graph/SecuredCapabilities.java b/jena-permissions/src/main/java/org/apache/jena/permissions/graph/SecuredCapabilities.java new file mode 100644 index 0000000..1cb3890 --- /dev/null +++ b/jena-permissions/src/main/java/org/apache/jena/permissions/graph/SecuredCapabilities.java @@ -0,0 +1,151 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jena.permissions.graph; + +import org.apache.jena.graph.Capabilities ; +import org.apache.jena.permissions.SecurityEvaluator; +import org.apache.jena.permissions.SecurityEvaluator.Action; +import org.apache.jena.permissions.SecurityEvaluator.SecNode; +import org.apache.jena.permissions.SecurityEvaluator.SecTriple; +import org.apache.jena.permissions.SecurityEvaluator.SecNode.Type; + +/** + * The interface for secured Capabilities instances. + * + */ +public class SecuredCapabilities implements Capabilities +{ + // the security evaluator in use + private final SecurityEvaluator securityEvaluator; + // the graphIRI that the capabilities belong to. + private final SecNode graphIRI; + // the unsecured capabilities. + private final Capabilities capabilities; + + /** + * Constructor. + * + * @param securityEvaluator + * The security evaluator in use. + * @param graphURI + * The graphIRI that the capabilities describe. + * @param capabilities + * The unsecured capabilities. + */ + public SecuredCapabilities( final SecurityEvaluator securityEvaluator, + final String graphURI, final Capabilities capabilities ) + { + this.securityEvaluator = securityEvaluator; + this.graphIRI = new SecNode(Type.URI, graphURI); + this.capabilities = capabilities; + } + + /** + * @sec.graph Update + */ + @Override + public boolean addAllowed() + { + return securityEvaluator.evaluate(securityEvaluator.getPrincipal(), Action.Update, graphIRI) + && capabilities.addAllowed(); + } + + /** + * @sec.graph Update + * @sec.triple Create (if everyTriple is true) + */ + @Override + public boolean addAllowed( final boolean everyTriple ) + { + Object principal = securityEvaluator.getPrincipal(); + + boolean retval = securityEvaluator.evaluate(principal, Action.Update, graphIRI) + && capabilities.addAllowed(everyTriple); + if (retval && everyTriple) + { + // special security check + retval = securityEvaluator.evaluate(principal, Action.Create, graphIRI, + SecTriple.ANY); + } + return retval; + } + + @Override + public boolean canBeEmpty() + { + return capabilities.canBeEmpty(); + } + + /** + * @sec.graph Update + */ + @Override + public boolean deleteAllowed() + { + return securityEvaluator.evaluate(securityEvaluator.getPrincipal(), Action.Update, graphIRI) + && capabilities.deleteAllowed(); + } + + /** + * @sec.graph Update + * @sec.triple Delete (if everyTriple is true) + */ + @Override + public boolean deleteAllowed( final boolean everyTriple ) + { + Object principal = securityEvaluator.getPrincipal(); + + boolean retval = securityEvaluator.evaluate(principal, Action.Update, graphIRI) + && capabilities.addAllowed(everyTriple); + if (retval && everyTriple) + { + // special security check + retval = securityEvaluator.evaluate(principal, Action.Delete, graphIRI, + SecTriple.ANY); + } + return retval; + } + + @Override + public boolean findContractSafe() + { + return capabilities.findContractSafe(); + } + + @Override + public boolean handlesLiteralTyping() + { + return capabilities.handlesLiteralTyping(); + } + + /** + * @sec.graph Update + */ + @Override + public boolean iteratorRemoveAllowed() + { + return securityEvaluator.evaluate(securityEvaluator.getPrincipal(), Action.Update, graphIRI) + && capabilities.iteratorRemoveAllowed(); + } + + @Override + public boolean sizeAccurate() + { + return capabilities.sizeAccurate(); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/jena/blob/c4b0113d/jena-permissions/src/main/java/org/apache/jena/permissions/graph/SecuredGraph.java ---------------------------------------------------------------------- diff --git a/jena-permissions/src/main/java/org/apache/jena/permissions/graph/SecuredGraph.java b/jena-permissions/src/main/java/org/apache/jena/permissions/graph/SecuredGraph.java new file mode 100644 index 0000000..037c06c --- /dev/null +++ b/jena-permissions/src/main/java/org/apache/jena/permissions/graph/SecuredGraph.java @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jena.permissions.graph; + +import org.apache.jena.graph.Graph ; +import org.apache.jena.graph.GraphStatisticsHandler ; +import org.apache.jena.graph.Node ; +import org.apache.jena.graph.Triple ; +import org.apache.jena.permissions.AccessDeniedException; +import org.apache.jena.permissions.SecurityEvaluator; +import org.apache.jena.permissions.SecurityEvaluator.SecNode; +import org.apache.jena.shared.AddDeniedException ; +import org.apache.jena.shared.DeleteDeniedException ; +import org.apache.jena.util.iterator.ExtendedIterator ; + +/** + * The interface for secured Graph instances. + * + * Use the SecuredGraph.Factory to create instances + */ +public interface SecuredGraph extends Graph +{ + + /** + * @sec.graph Update + * @sec.triple Create + * @throws AccessDeniedException + * @throws AddDeniedException + */ + @Override + public void add( final Triple t ) throws AddDeniedException, + AccessDeniedException; + + /** + * @sec.graph Read + * @sec.triple Read + * @throws AccessDeniedException + */ + @Override + public boolean contains( final Node s, final Node p, final Node o ) + throws AccessDeniedException; + + /** + * @sec.graph Read + * @sec.triple Read + * @throws AccessDeniedException + */ + @Override + public boolean contains( final Triple t ) throws AccessDeniedException; + + /** + * @sec.graph Update + * @sec.triple Delete + * @throws AccessDeniedException + * @throws DeleteDeniedException + */ + @Override + public void delete( final Triple t ) throws DeleteDeniedException, + AccessDeniedException; + + /** + * @sec.graph Read + * @throws AccessDeniedException + */ + @Override + public boolean dependsOn( final Graph other ) throws AccessDeniedException; + + /** + * @sec.graph Read + * @sec.triple Read, otherwise filtered from iterator. + * @throws AccessDeniedException + */ + @Override + public ExtendedIterator<Triple> find( final Node s, final Node p, + final Node o ) throws AccessDeniedException; + + /** + * @sec.graph Read + * @sec.triple Read, otherwise filtered from iterator. + * @throws AccessDeniedException + */ + @Override + public ExtendedIterator<Triple> find( final Triple triple ) + throws AccessDeniedException; + + @Override + public SecuredCapabilities getCapabilities(); + + @Override + public SecuredGraphEventManager getEventManager(); + + public SecNode getModelNode(); + + @Override + public SecuredPrefixMapping getPrefixMapping(); + + public SecurityEvaluator getSecurityEvaluator(); + + /** + * @sec.graph Read + * @throws AccessDeniedException + */ + @Override + public GraphStatisticsHandler getStatisticsHandler() + throws AccessDeniedException; + + /** + * @sec.graph Read + * @throws AccessDeniedException + */ + @Override + public boolean isEmpty() throws AccessDeniedException; + + /** + * @sec.graph Read + * @sec.triple Read + * @throws AccessDeniedException + */ + @Override + public boolean isIsomorphicWith( final Graph g ) + throws AccessDeniedException; + + + /** + * @sec.graph Read + * @throws AccessDeniedException + */ + @Override + public int size() throws AccessDeniedException; + + /** + * @sec.graph Update + * @sec.triple Delete for every triple + * @throws AccessDeniedException + */ + @Override + public void clear(); + + /** + * @sec.graph Update + * @sec.triple Delete (s, p, o ) + * @throws AccessDeniedException + */ + @Override + public void remove( Node s, Node p, Node o ); + +} http://git-wip-us.apache.org/repos/asf/jena/blob/c4b0113d/jena-permissions/src/main/java/org/apache/jena/permissions/graph/SecuredGraphEventManager.java ---------------------------------------------------------------------- diff --git a/jena-permissions/src/main/java/org/apache/jena/permissions/graph/SecuredGraphEventManager.java b/jena-permissions/src/main/java/org/apache/jena/permissions/graph/SecuredGraphEventManager.java new file mode 100644 index 0000000..3b981e4 --- /dev/null +++ b/jena-permissions/src/main/java/org/apache/jena/permissions/graph/SecuredGraphEventManager.java @@ -0,0 +1,608 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jena.permissions.graph; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; + +import org.apache.jena.graph.Graph ; +import org.apache.jena.graph.GraphEventManager ; +import org.apache.jena.graph.GraphListener ; +import org.apache.jena.graph.Triple ; +import org.apache.jena.graph.impl.CollectionGraph ; +import org.apache.jena.permissions.SecurityEvaluator; +import org.apache.jena.permissions.SecurityEvaluator.Action; +import org.apache.jena.permissions.graph.impl.SecuredGraphImpl; +import org.apache.jena.permissions.impl.CachedSecurityEvaluator; +import org.apache.jena.permissions.impl.SecuredItemImpl; +import org.apache.jena.permissions.utils.PermTripleFilter; +import org.apache.jena.util.iterator.ExtendedIterator ; +import org.apache.jena.util.iterator.NiceIterator ; +import org.apache.jena.util.iterator.WrappedIterator ; + +/** + * Since we sit between the graph and other items we have to determine when the + * message is first seen and send it to the underlying graph if necessary. + */ +public class SecuredGraphEventManager implements GraphEventManager { + private class SecuredGraphListener implements GraphListener { + private final GraphListener wrapped; + private final Object runAs; + + SecuredGraphListener(final GraphListener wrapped) { + if (wrapped == null) { + throw new IllegalArgumentException( + "Wrapped listener may not be null"); + } + this.wrapped = wrapped; + this.runAs = securedGraph.getSecurityEvaluator().getPrincipal(); + } + + private Triple[] getArray(final Graph g, final Triple[] triples, + final Set<Action> perms) { + Triple[] retval = triples; + if (g instanceof SecuredGraphImpl) { + final SecuredGraphImpl sg = (SecuredGraphImpl) g; + final SecurityEvaluator evaluator = new CachedSecurityEvaluator(sg.getSecurityEvaluator(), runAs); + if (evaluator.evaluateAny(runAs, perms, sg.getModelNode())) { + if (!evaluator.evaluateAny(runAs, perms, sg.getModelNode(), + SecuredItemImpl.convert(Triple.ANY))) { + final List<Triple> list = wrapPermIterator(sg, + Arrays.asList(triples).iterator(), perms) + .toList(); + retval = list.toArray(new Triple[list.size()]); + } + else { + retval = triples; + } + } + else { + retval = new Triple[0]; + } + } + return retval; + } + + @Override + public void notifyAddArray(final Graph g, final Triple[] triples) { + final Triple[] added = getArray(g, triples, + SecuredGraphEventManager.ADD); + + if (added.length > 0) { + wrapped.notifyAddArray(g, added); + } + } + + @Override + public void notifyAddGraph(final Graph g, final Graph added) { + Graph addGraph = added; + if (g instanceof SecuredGraph) { + final SecuredGraph sg = (SecuredGraph) g; + final SecurityEvaluator evaluator = new CachedSecurityEvaluator(sg.getSecurityEvaluator(), runAs); + if (evaluator.evaluateAny(runAs, SecuredGraphEventManager.ADD, + sg.getModelNode())) { + if (!evaluator.evaluateAny(runAs, + SecuredGraphEventManager.ADD, sg.getModelNode(), + SecuredItemImpl.convert(Triple.ANY))) { + final List<Triple> lst = added.find(Triple.ANY) + .toList(); + addGraph = new CollectionGraph(Arrays.asList(getArray( + g, lst.toArray(new Triple[lst.size()]), + SecuredGraphEventManager.ADD))); + } + else { + addGraph = added; + } + } + else { + addGraph = new CollectionGraph( + Collections.<Triple> emptyList()); + } + } + if (addGraph.size() > 0) { + wrapped.notifyAddGraph(g, addGraph); + + } + } + + @Override + public void notifyAddIterator(final Graph g, final Iterator<Triple> it) { + + if (g instanceof SecuredGraphImpl) { + final SecuredGraphImpl sg = (SecuredGraphImpl) g; + final SecurityEvaluator evaluator = new CachedSecurityEvaluator(sg.getSecurityEvaluator(), runAs); + // only report if we can write to the graph + if (evaluator.evaluateAny(runAs, SecuredGraphEventManager.ADD, + sg.getModelNode())) { + final ExtendedIterator<Triple> iter = wrapPermIterator(sg, + it, SecuredGraphEventManager.ADD); + try { + wrapped.notifyAddIterator(g, iter); + } finally { + iter.close(); + } + } + } + else { + wrapped.notifyAddIterator(g, it); + } + + } + + @Override + public void notifyAddList(final Graph g, final List<Triple> triples) { + List<Triple> list = triples; + if (g instanceof SecuredGraphImpl) { + final SecuredGraphImpl sg = (SecuredGraphImpl) g; + final SecurityEvaluator evaluator = new CachedSecurityEvaluator(sg.getSecurityEvaluator(), runAs); + if (evaluator.evaluateAny(runAs, SecuredGraphEventManager.ADD, + sg.getModelNode())) { + if (!evaluator.evaluateAny(runAs, + SecuredGraphEventManager.ADD, sg.getModelNode(), + SecuredItemImpl.convert(Triple.ANY))) { + list = wrapPermIterator(sg, triples.iterator(), + SecuredGraphEventManager.ADD).toList(); + } + else { + list = triples; + } + } + else { + list = Collections.emptyList(); + } + } + + if (list.size() > 0) { + + wrapped.notifyAddList(g, list); + } + } + + @Override + public void notifyAddTriple(final Graph g, final Triple t) { + boolean notify = false; + if (g instanceof SecuredGraph) { + final SecuredGraph sg = (SecuredGraph) g; + final SecurityEvaluator evaluator = new CachedSecurityEvaluator(sg.getSecurityEvaluator(), runAs); + notify = evaluator.evaluateAny(runAs, + SecuredGraphEventManager.ADD, sg.getModelNode()); + if (notify) { + notify = evaluator.evaluateAny(runAs, + SecuredGraphEventManager.ADD, sg.getModelNode(), + SecuredItemImpl.convert(t)); + } + } + else { + notify = true; + } + if (notify) { + wrapped.notifyAddTriple(g, t); + } + } + + @Override + public void notifyDeleteArray(final Graph g, final Triple[] triples) { + Triple[] deleted = triples; + if (g instanceof SecuredGraphImpl) { + final SecuredGraphImpl sg = (SecuredGraphImpl) g; + final SecurityEvaluator evaluator = new CachedSecurityEvaluator(sg.getSecurityEvaluator(), runAs); + if (evaluator.evaluateAny(runAs, + SecuredGraphEventManager.DELETE, sg.getModelNode())) { + if (!evaluator.evaluateAny(runAs, + SecuredGraphEventManager.DELETE, sg.getModelNode(), + SecuredItemImpl.convert(Triple.ANY))) { + final List<Triple> list = wrapPermIterator(sg, + Arrays.asList(triples).iterator(), + SecuredGraphEventManager.DELETE).toList(); + deleted = list.toArray(new Triple[list.size()]); + } + else { + deleted = triples; + } + } + else { + deleted = new Triple[0]; + } + } + + if (deleted.length > 0) { + wrapped.notifyDeleteArray(g, deleted); + } + } + + @Override + public void notifyDeleteGraph(final Graph g, final Graph removed) { + if (g instanceof SecuredGraphImpl) { + final SecuredGraphImpl sg = (SecuredGraphImpl) g; + final SecurityEvaluator evaluator = new CachedSecurityEvaluator(sg.getSecurityEvaluator(), runAs); + if (evaluator.evaluateAny(runAs, + SecuredGraphEventManager.DELETE, sg.getModelNode())) { + Graph g2 = removed; + if (!evaluator.evaluateAny(runAs, + SecuredGraphEventManager.DELETE, sg.getModelNode(), + SecuredItemImpl.convert(Triple.ANY))) { + g2 = new CollectionGraph( + removed.find(Triple.ANY) + .filterKeep( + new PermTripleFilter( + SecuredGraphEventManager.DELETE, + sg, evaluator)) + .toList()); + + } + wrapped.notifyDeleteGraph(g, g2); + } + else { + // do nothing. + } + } + else { + wrapped.notifyDeleteGraph(g, removed); + } + } + + @Override + public void notifyDeleteIterator(final Graph g, + final Iterator<Triple> it) { + Iterator<Triple> iter = it; + if (g instanceof SecuredGraphImpl) { + final SecuredGraphImpl sg = (SecuredGraphImpl) g; + final SecurityEvaluator evaluator = new CachedSecurityEvaluator(sg.getSecurityEvaluator(), runAs); + if (evaluator.evaluateAny(runAs, + SecuredGraphEventManager.DELETE, sg.getModelNode())) { + + if (!evaluator.evaluateAny(runAs, + SecuredGraphEventManager.DELETE, sg.getModelNode(), + SecuredItemImpl.convert(Triple.ANY))) { + iter = WrappedIterator.create(it).filterKeep( + new PermTripleFilter( + SecuredGraphEventManager.DELETE, sg, + evaluator)); + } + // else use the default list as all can bee seen + wrapped.notifyDeleteIterator(g, iter); + } + else { + // do nothing. + } + } + else { + wrapped.notifyDeleteIterator(g, iter); + } + + } + + @Override + public void notifyDeleteList(final Graph g, final List<Triple> triples) { + List<Triple> list = triples; + if (g instanceof SecuredGraphImpl) { + final SecuredGraphImpl sg = (SecuredGraphImpl) g; + final SecurityEvaluator evaluator = new CachedSecurityEvaluator(sg.getSecurityEvaluator(), runAs); + if (evaluator.evaluateAny(runAs, + SecuredGraphEventManager.DELETE, sg.getModelNode())) { + if (!evaluator.evaluateAny(runAs, + SecuredGraphEventManager.DELETE, sg.getModelNode(), + SecuredItemImpl.convert(Triple.ANY))) { + list = WrappedIterator + .create(triples.iterator()) + .filterKeep( + new PermTripleFilter( + SecuredGraphEventManager.DELETE, + sg, evaluator)).toList(); + } + // else use the default list as all can bee seen + } + else { + list = Collections.emptyList(); + } + } + + if (list.size() > 0) { + wrapped.notifyDeleteList(g, list); + } + } + + @Override + public void notifyDeleteTriple(final Graph g, final Triple t) { + boolean notify = false; + if (g instanceof SecuredGraph) { + final SecuredGraph sg = (SecuredGraph) g; + final SecurityEvaluator evaluator = new CachedSecurityEvaluator(sg.getSecurityEvaluator(), runAs); + notify = evaluator.evaluateAny(runAs, + SecuredGraphEventManager.DELETE, sg.getModelNode()); + if (notify) { + notify = evaluator.evaluateAny(runAs, + SecuredGraphEventManager.DELETE, sg.getModelNode(), + SecuredItemImpl.convert(t)); + } + } + else { + notify = true; + } + if (notify) { + wrapped.notifyDeleteTriple(g, t); + } + } + + @Override + public void notifyEvent(final Graph source, final Object value) { + wrapped.notifyEvent(source, value); + } + + private ExtendedIterator<Triple> wrapPermIterator( + final SecuredGraphImpl sg, final Iterator<Triple> it, + final Set<Action> perms) { + final SecurityEvaluator evaluator = new CachedSecurityEvaluator(sg.getSecurityEvaluator(), runAs); + if (!evaluator.evaluateAny(runAs, perms, sg.getModelNode(), + SecuredItemImpl.convert(Triple.ANY))) { + // nope so wrap the iterator with security iterator + return WrappedIterator.create(it).filterKeep( + new PermTripleFilter(perms, sg, evaluator)); + } + return WrappedIterator.create(it); + } + + } + + // the security evaluator in use + private final SecuredGraph securedGraph; + private final Graph baseGraph; + private final Map<GraphListener, Stack<SecuredGraphListener>> listenerMap = new HashMap<GraphListener, Stack<SecuredGraphListener>>(); + private static Set<Action> DELETE; + + private static Set<Action> ADD; + + static { + SecuredGraphEventManager.ADD = new HashSet<Action>( + Arrays.asList(new Action[] { + Action.Create, Action.Read + })); + SecuredGraphEventManager.DELETE = new HashSet<Action>( + Arrays.asList(new Action[] { + Action.Delete, Action.Read + })); + } + + public SecuredGraphEventManager(final SecuredGraph securedGraph, + final Graph baseGraph, final GraphEventManager manager) { + this.securedGraph = securedGraph; + this.baseGraph = baseGraph; + manager.register(this); + } + + private synchronized Collection<SecuredGraphListener> getListenerCollection() { + ExtendedIterator<SecuredGraphListener> retval = NiceIterator + .emptyIterator(); + for (final Collection<SecuredGraphListener> coll : listenerMap.values()) { + retval = retval.andThen(coll.iterator()); + } + return retval.toList(); + } + + @Override + public boolean listening() { + return !listenerMap.isEmpty(); + } + + @Override + public void notifyAddArray(final Graph g, final Triple[] triples) { + final boolean wrap = baseGraph.equals(g); + + for (final SecuredGraphListener sgl : getListenerCollection()) { + if (wrap) { + sgl.notifyAddArray(securedGraph, triples); + } + else { + sgl.notifyAddArray(g, triples); + } + } + } + + @Override + public void notifyAddGraph(final Graph g, final Graph added) { + final boolean wrap = baseGraph.equals(g); + + for (final SecuredGraphListener sgl : getListenerCollection()) { + if (wrap) { + sgl.notifyAddGraph(securedGraph, added); + } + else { + sgl.notifyAddGraph(g, added); + } + } + } + + @Override + public void notifyAddIterator(final Graph g, final Iterator<Triple> it) { + notifyAddIterator(g, WrappedIterator.create(it).toList()); + baseGraph.equals(g); + } + + @Override + public void notifyAddIterator(final Graph g, final List<Triple> triples) { + final boolean wrap = baseGraph.equals(g); + + for (final SecuredGraphListener sgl : getListenerCollection()) { + if (wrap) { + sgl.notifyAddIterator(securedGraph, triples.iterator()); + } + else { + sgl.notifyAddIterator(g, triples.iterator()); + } + } + } + + @Override + public void notifyAddList(final Graph g, final List<Triple> triples) { + final boolean wrap = baseGraph.equals(g); + + for (final SecuredGraphListener sgl : getListenerCollection()) { + if (wrap) { + sgl.notifyAddList(securedGraph, triples); + } + else { + sgl.notifyAddList(g, triples); + } + } + } + + @Override + public void notifyAddTriple(final Graph g, final Triple t) { + final boolean wrap = baseGraph.equals(g); + + for (final SecuredGraphListener sgl : getListenerCollection()) { + if (wrap) { + sgl.notifyAddTriple(securedGraph, t); + } + else { + sgl.notifyAddTriple(g, t); + } + } + } + + @Override + public void notifyDeleteArray(final Graph g, final Triple[] triples) { + final boolean wrap = baseGraph.equals(g); + + for (final SecuredGraphListener sgl : getListenerCollection()) { + if (wrap) { + sgl.notifyDeleteArray(securedGraph, triples); + } + else { + sgl.notifyDeleteArray(g, triples); + } + } + } + + @Override + public void notifyDeleteGraph(final Graph g, final Graph removed) { + final boolean wrap = baseGraph.equals(g); + + for (final SecuredGraphListener sgl : getListenerCollection()) { + if (wrap) { + sgl.notifyDeleteGraph(securedGraph, removed); + } + else { + sgl.notifyDeleteGraph(g, removed); + } + } + } + + @Override + public void notifyDeleteIterator(final Graph g, final Iterator<Triple> it) { + notifyDeleteIterator(g, WrappedIterator.create(it).toList()); + } + + @Override + public void notifyDeleteIterator(final Graph g, final List<Triple> triples) { + final boolean wrap = baseGraph.equals(g); + + for (final SecuredGraphListener sgl : getListenerCollection()) { + if (wrap) { + sgl.notifyDeleteIterator(securedGraph, triples.iterator()); + } + else { + sgl.notifyDeleteIterator(g, triples.iterator()); + } + } + } + + @Override + public void notifyDeleteList(final Graph g, final List<Triple> L) { + final boolean wrap = baseGraph.equals(g); + + for (final SecuredGraphListener sgl : getListenerCollection()) { + if (wrap) { + sgl.notifyDeleteList(securedGraph, L); + } + else { + sgl.notifyDeleteList(g, L); + } + } + } + + @Override + public void notifyDeleteTriple(final Graph g, final Triple t) { + final boolean wrap = baseGraph.equals(g); + + for (final SecuredGraphListener sgl : getListenerCollection()) { + if (wrap) { + sgl.notifyDeleteTriple(securedGraph, t); + } + else { + sgl.notifyDeleteTriple(g, t); + } + } + } + + @Override + public void notifyEvent(final Graph source, final Object value) { + if ((source instanceof SecuredGraph) && securedGraph.equals(source)) { + baseGraph.getEventManager().notifyEvent(baseGraph, value); + } + else { + + final boolean wrap = baseGraph.equals(source); + + for (final SecuredGraphListener sgl : getListenerCollection()) { + if (wrap) { + sgl.notifyEvent(securedGraph, value); + } + else { + sgl.notifyEvent(source, value); + } + } + } + } + + @Override + public synchronized GraphEventManager register(final GraphListener listener) { + Stack<SecuredGraphListener> sgl = listenerMap.get(listener); + if (sgl == null) { + sgl = new Stack<SecuredGraphListener>(); + } + sgl.push(new SecuredGraphListener(listener)); + listenerMap.put(listener, sgl); + return this; + } + + @Override + public synchronized GraphEventManager unregister( + final GraphListener listener) { + final Stack<SecuredGraphListener> sgl = listenerMap.get(listener); + if (sgl != null) { + if (sgl.size() == 1) { + listenerMap.remove(listener); + } + else { + sgl.pop(); + listenerMap.put(listener, sgl); + } + } + return this; + } + +}
