Repository: jena Updated Branches: refs/heads/master 7e256560e -> d1b5e21df
Changes to implement JENA-847 Added SecurityEvaluatorAssembler. Extracted AssemblerConstants from SecuredAssembler Added SecurityEvaluatorAssembler testing to SecuredAssemblerTest Project: http://git-wip-us.apache.org/repos/asf/jena/repo Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/d1b5e21d Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/d1b5e21d Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/d1b5e21d Branch: refs/heads/master Commit: d1b5e21dfdb3f83ee6855df9c92b9db54690b3c5 Parents: 7e25656 Author: claude <[email protected]> Authored: Tue Jan 13 19:56:10 2015 +0000 Committer: claude <[email protected]> Committed: Tue Jan 13 19:56:10 2015 +0000 ---------------------------------------------------------------------- .../jena/security/AssemblerConstants.java | 44 +++++ .../apache/jena/security/SecuredAssembler.java | 157 +++++++++++----- .../security/SecurityEvaluatorAssembler.java | 186 +++++++++++++++++++ .../jena/security/SecuredAssemblerTest.java | 17 ++ .../jena/security/SecuredAssemblerTest.ttl | 20 ++ 5 files changed, 382 insertions(+), 42 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jena/blob/d1b5e21d/jena-security/src/main/java/org/apache/jena/security/AssemblerConstants.java ---------------------------------------------------------------------- diff --git a/jena-security/src/main/java/org/apache/jena/security/AssemblerConstants.java b/jena-security/src/main/java/org/apache/jena/security/AssemblerConstants.java new file mode 100644 index 0000000..43c2034 --- /dev/null +++ b/jena-security/src/main/java/org/apache/jena/security/AssemblerConstants.java @@ -0,0 +1,44 @@ +package org.apache.jena.security; + +import com.hp.hpl.jena.rdf.model.Property; +import com.hp.hpl.jena.rdf.model.ResourceFactory; + +public interface AssemblerConstants { + public static final String URI = "http://apache.org/jena/security/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/d1b5e21d/jena-security/src/main/java/org/apache/jena/security/SecuredAssembler.java ---------------------------------------------------------------------- diff --git a/jena-security/src/main/java/org/apache/jena/security/SecuredAssembler.java b/jena-security/src/main/java/org/apache/jena/security/SecuredAssembler.java index 04964dc..f3a9716 100644 --- a/jena-security/src/main/java/org/apache/jena/security/SecuredAssembler.java +++ b/jena-security/src/main/java/org/apache/jena/security/SecuredAssembler.java @@ -25,10 +25,9 @@ import com.hp.hpl.jena.assembler.assemblers.ModelAssembler; import com.hp.hpl.jena.assembler.exceptions.AssemblerException; import com.hp.hpl.jena.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.Model; -import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.Resource; -import com.hp.hpl.jena.rdf.model.ResourceFactory; import com.hp.hpl.jena.sparql.util.MappingRegistry; + import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -42,52 +41,97 @@ import java.lang.reflect.Modifier; * <>; ja:loadClass "org.apache.jena.security.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> - * [] a ja:Model ; - * sec:baseModel jena_model ; - * ja:modelName "modelName"; - * sec:evaluatorFactory "javaclass"; + * my:secModel a sec:Model ; + * sec:baseModel my:baseModel ; + * ja:modelName "http://example.com/securedModel" ; + * sec:evaluatorFactory "org.apache.jena.security.MockSecurityEvaluator" ; * . * </pre></code> * * Terms used in above example: + * * <dl> - * <dt> - * jena_model</dt><dd>Another model defined in the assembler file. - * </dd><dt> - * "modelName"</dt><dd>The name of the model as identified in the security manager - * </dd><dt> - * "javaclass"</dt><dd>The name of a java class that implements a Evaluator Factory. The Factory must have - * static method <code>getInstance()</code> that returns a SecurityEvaluator. + * <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 security 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 security environment + * (see ja:NamedModel examples from Jena)</dd> + * + * <dt>sec:evaluatorFactory</dt> + * <dd>Identifies "org.apache.jena.security.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 security 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 security 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 { +public class SecuredAssembler extends ModelAssembler implements AssemblerConstants { private static boolean initialized; - public static final String URI = "http://apache.org/jena/security/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" ); - // message formats - private static final String NO_X_PROVIDED = "No %s provided for %s"; private static final String ERROR_FINDING_FACTORY = "Error finding factory class %s: %s"; static { init() ; } @@ -115,6 +159,7 @@ public class SecuredAssembler extends ModelAssembler { if ( group == null ) group = Assembler.general ; group.implementWith( SECURED_MODEL, new SecuredAssembler()) ; + group.implementWith( EVALUATOR_ASSEMBLER, new SecurityEvaluatorAssembler()); } @Override @@ -125,7 +170,7 @@ public class SecuredAssembler extends ModelAssembler { { throw new AssemblerException( root, String.format( NO_X_PROVIDED, BASE_MODEL, root )); } - Model baseModel = a.openModel(rootModel, mode); + Model baseModel = a.openModel(rootModel, Mode.ANY); Literal modelName = getUniqueLiteral( root, JA.modelName ); if (modelName == null) @@ -134,11 +179,38 @@ public class SecuredAssembler extends ModelAssembler { } Literal factoryName = getUniqueLiteral( root, EVALUATOR_FACTORY ); - if (factoryName == null) + 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( NO_X_PROVIDED, EVALUATOR_FACTORY, root )); + 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() ); @@ -151,7 +223,7 @@ public class SecuredAssembler extends ModelAssembler { { throw new AssemblerException( root, String.format( "%s (found at %s for %s) getInstance() must be a static method", factoryName, EVALUATOR_FACTORY, root )); } - securityEvaluator = (SecurityEvaluator) method.invoke( null ); + return (SecurityEvaluator) method.invoke( null ); } catch (SecurityException e) { @@ -177,15 +249,16 @@ public class SecuredAssembler extends ModelAssembler { { throw new AssemblerException( root, String.format( ERROR_FINDING_FACTORY, factoryName, e.getMessage() ), e); } - - 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 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/d1b5e21d/jena-security/src/main/java/org/apache/jena/security/SecurityEvaluatorAssembler.java ---------------------------------------------------------------------- diff --git a/jena-security/src/main/java/org/apache/jena/security/SecurityEvaluatorAssembler.java b/jena-security/src/main/java/org/apache/jena/security/SecurityEvaluatorAssembler.java new file mode 100644 index 0000000..0669c5d --- /dev/null +++ b/jena-security/src/main/java/org/apache/jena/security/SecurityEvaluatorAssembler.java @@ -0,0 +1,186 @@ +/* + * 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.security; + +import com.hp.hpl.jena.assembler.Assembler; +import com.hp.hpl.jena.assembler.Mode; +import com.hp.hpl.jena.assembler.assemblers.AssemblerBase; +import com.hp.hpl.jena.assembler.exceptions.AssemblerException; +import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.NodeIterator; +import com.hp.hpl.jena.rdf.model.RDFNode; +import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.rdf.model.Seq; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +/** + * 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()) + { + 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/d1b5e21d/jena-security/src/test/java/org/apache/jena/security/SecuredAssemblerTest.java ---------------------------------------------------------------------- diff --git a/jena-security/src/test/java/org/apache/jena/security/SecuredAssemblerTest.java b/jena-security/src/test/java/org/apache/jena/security/SecuredAssemblerTest.java index c53ac78..ed5a265 100644 --- a/jena-security/src/test/java/org/apache/jena/security/SecuredAssemblerTest.java +++ b/jena-security/src/test/java/org/apache/jena/security/SecuredAssemblerTest.java @@ -57,4 +57,21 @@ public class SecuredAssemblerTest Assert.assertTrue( o instanceof SecuredModel ); } + @Test + public void testCreationWithArgs() throws Exception { + + Resource r = model.createResource( "http://apache.org/jena/security/test#secModel2"); + Object o = assembler.open( r ); + Assert.assertTrue( o instanceof Model); + Assert.assertTrue( o instanceof SecuredModel ); + } + + @Test + public void testSecurityEvaluatorWithArgs() throws Exception { + + Resource r = model.createResource( "http://apache.org/jena/security/test#secEvaluator"); + Object o = assembler.open( r ); + Assert.assertTrue( o instanceof SecurityEvaluator ); + Assert.assertTrue( o instanceof MockSecurityEvaluator ); + } } http://git-wip-us.apache.org/repos/asf/jena/blob/d1b5e21d/jena-security/src/test/resources/org/apache/jena/security/SecuredAssemblerTest.ttl ---------------------------------------------------------------------- diff --git a/jena-security/src/test/resources/org/apache/jena/security/SecuredAssemblerTest.ttl b/jena-security/src/test/resources/org/apache/jena/security/SecuredAssemblerTest.ttl index 711cfec..60ac5bb 100644 --- a/jena-security/src/test/resources/org/apache/jena/security/SecuredAssemblerTest.ttl +++ b/jena-security/src/test/resources/org/apache/jena/security/SecuredAssemblerTest.ttl @@ -5,6 +5,7 @@ @prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> . @prefix sec: <http://apache.org/jena/security/Assembler#> . @prefix my: <http://apache.org/jena/security/test#> . +@prefix xsd: <http://www.w3.org/2001/XMLSchema#> <> ja:loadClass "org.apache.jena.security.SecuredAssembler" . @@ -23,3 +24,22 @@ my:secModel sec:evaluatorFactory "org.apache.jena.security.MockSecurityEvaluator" ; . +my:secModel2 + a sec:Model; + sec:baseModel my:baseModel ; + ja:modelName "http://example.com/securedModel2" ; + sec:evaluatorImpl my:secEvaluator ; + . + +my:secEvaluator + a sec:Evaluator ; + sec:args [ rdf:_1 "true"^^xsd:boolean ; + rdf:_2 "false"^^xsd:boolean ; + rdf:_3 "true"^^xsd:boolean ; + rdf:_4 "true"^^xsd:boolean ; + rdf:_5 "true"^^xsd:boolean ; + rdf:_6 "false"^^xsd:boolean ; + ] ; + sec:evaluatorClass "org.apache.jena.security.MockSecurityEvaluator" ; + . + \ No newline at end of file
