/* * 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)); } }