Return-Path: Delivered-To: apmail-avalon-cvs-archive@www.apache.org Received: (qmail 142 invoked from network); 19 Jan 2004 21:45:08 -0000 Received: from daedalus.apache.org (HELO mail.apache.org) (208.185.179.12) by minotaur-2.apache.org with SMTP; 19 Jan 2004 21:45:08 -0000 Received: (qmail 50501 invoked by uid 500); 19 Jan 2004 21:44:56 -0000 Delivered-To: apmail-avalon-cvs-archive@avalon.apache.org Received: (qmail 50455 invoked by uid 500); 19 Jan 2004 21:44:55 -0000 Mailing-List: contact cvs-help@avalon.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Avalon CVS List" Reply-To: "Avalon Developers List" Delivered-To: mailing list cvs@avalon.apache.org Received: (qmail 50442 invoked from network); 19 Jan 2004 21:44:55 -0000 Received: from unknown (HELO minotaur.apache.org) (209.237.227.194) by daedalus.apache.org with SMTP; 19 Jan 2004 21:44:55 -0000 Received: (qmail 99962 invoked by uid 1774); 19 Jan 2004 21:45:07 -0000 Date: 19 Jan 2004 21:45:07 -0000 Message-ID: <20040119214507.99961.qmail@minotaur.apache.org> From: niclas@apache.org To: avalon-cvs@apache.org Subject: cvs commit: avalon/merlin/activation/impl/src/java/org/apache/avalon/activation/appliance/impl AbstractBlock.java DefaultAppliance.java DefaultBlock.java Deployer.java X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: minotaur-2.apache.org 1.6.2 0/1000/N niclas 2004/01/19 13:45:07 Modified: merlin/activation/impl/src/java/org/apache/avalon/activation/appliance/impl AbstractBlock.java DefaultAppliance.java DefaultBlock.java Deployer.java Added: merlin/activation/impl project.properties Log: Code level security implemented in DefaultAppliance. Revision Changes Path 1.1 avalon/merlin/activation/impl/project.properties Index: project.properties =================================================================== maven.junit.fork=false maven.junit.sysproperties=java.security.policy java.security.policy=${basedir}/src/test/conf/security.policy 1.15 +56 -3 avalon/merlin/activation/impl/src/java/org/apache/avalon/activation/appliance/impl/AbstractBlock.java Index: AbstractBlock.java =================================================================== RCS file: /home/cvs/avalon/merlin/activation/impl/src/java/org/apache/avalon/activation/appliance/impl/AbstractBlock.java,v retrieving revision 1.14 retrieving revision 1.15 diff -u -r1.14 -r1.15 --- AbstractBlock.java 16 Jan 2004 16:39:02 -0000 1.14 +++ AbstractBlock.java 19 Jan 2004 21:45:06 -0000 1.15 @@ -51,6 +51,15 @@ package org.apache.avalon.activation.appliance.impl; import java.net.URL; +import java.net.URLClassLoader; + +import java.security.AccessControlContext; +import java.security.CodeSource; +import java.security.Permission; +import java.security.Permissions; +import java.security.ProtectionDomain; +import java.security.cert.Certificate; + import java.util.ArrayList; import java.util.Hashtable; @@ -70,6 +79,7 @@ import org.apache.avalon.composition.model.SystemContext; import org.apache.avalon.composition.model.ContainmentModel; +import org.apache.avalon.composition.model.ClassLoaderModel; import org.apache.avalon.composition.model.DependencyModel; import org.apache.avalon.composition.model.ComponentModel; import org.apache.avalon.composition.model.DeploymentModel; @@ -123,6 +133,7 @@ private final DefaultState m_self = new DefaultState(); private final Engine m_engine; + private final AccessControlContext m_accessControlContext; //------------------------------------------------------------------- // constructor @@ -137,7 +148,12 @@ AbstractBlock( ContainmentModel model, Engine engine ) { super( model ); - + ClassLoaderModel clmodel = model.getClassLoaderModel(); + if( model.isSecureExecutionEnabled() ) + m_accessControlContext = createAccessControlContext( clmodel ); + else + m_accessControlContext = null; + m_model = model; m_engine = engine; @@ -239,6 +255,42 @@ } } + protected AccessControlContext getAccessControlContext() + { + return m_accessControlContext; + } + + /** + * Creates the AccessControlContext based on the Permissons granted + * in the ContainmentModel and the ClassLoader used to load the class. + **/ + private AccessControlContext createAccessControlContext( ClassLoaderModel model ) + { + ClassLoader classloader = model.getClassLoader(); + if( classloader instanceof URLClassLoader ) + { + Permissions permissionGroup = new Permissions(); + Permission[] permissions = model.getSecurityPermissions(); + for( int i=0 ; i < permissions.length ; i++ ) + permissionGroup.add( permissions[i] ); + + Certificate[] certs = model.getCertificates(); + URL[] jars = ((URLClassLoader) classloader).getURLs(); + ProtectionDomain[] domains = new ProtectionDomain[ jars.length ]; + for( int i=0 ; i < jars.length ; i++ ) + { + CodeSource cs = new CodeSource( jars[i], certs ); + domains[i] = new ProtectionDomain( cs, permissionGroup ); + } + return new AccessControlContext( domains ); + } + else + { + // TODO: No other idea on how to handle this at the moment. + throw new SecurityException( "ClassLoader's must inherit from URLClassLoader." ); + } + } + //------------------------------------------------------------------- // Deployable //------------------------------------------------------------------- @@ -270,6 +322,7 @@ // ContainmentModel model = getContainmentModel(); + DeploymentModel[] startup = model.getStartupGraph(); long timeout = model.getDeploymentTimeout(); @@ -391,7 +444,7 @@ { getLogger().debug( "creating appliance: " + path ); ComponentModel component = (ComponentModel) model; - appliance = new DefaultAppliance( component, this ); + appliance = new DefaultAppliance( component, this, m_accessControlContext ); } else if( model instanceof ContainmentModel ) { 1.20 +242 -35 avalon/merlin/activation/impl/src/java/org/apache/avalon/activation/appliance/impl/DefaultAppliance.java Index: DefaultAppliance.java =================================================================== RCS file: /home/cvs/avalon/merlin/activation/impl/src/java/org/apache/avalon/activation/appliance/impl/DefaultAppliance.java,v retrieving revision 1.19 retrieving revision 1.20 diff -u -r1.19 -r1.20 --- DefaultAppliance.java 19 Jan 2004 01:27:01 -0000 1.19 +++ DefaultAppliance.java 19 Jan 2004 21:45:06 -0000 1.20 @@ -55,6 +55,10 @@ import java.lang.reflect.UndeclaredThrowableException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; import java.util.Hashtable; import java.util.ArrayList; import java.util.Map; @@ -151,6 +155,8 @@ private Object m_instance; + private AccessControlContext m_accessControlContext; + //------------------------------------------------------------------- // mutable state //------------------------------------------------------------------- @@ -182,11 +188,31 @@ // constructor //------------------------------------------------------------------- - public DefaultAppliance( ComponentModel model, Engine engine ) + public DefaultAppliance( ComponentModel model, + Engine engine, + AccessControlContext access ) { super( model ); m_model = (ComponentModel) model; m_engine = engine; + m_accessControlContext = access; + + // Enabled the SecurityManager is none already exists, and that + // the kernel setting for enabling the secure execution has been + // set. The parameter in the kernel is urn:composition:security.enabled + if( System.getSecurityManager() == null ) + { + System.setSecurityManager( new SecurityManager() ); + } + } + + public DefaultAppliance( ComponentModel model, + Engine engine ) + { + super( model ); + m_model = (ComponentModel) model; + m_engine = engine; + m_accessControlContext = null; } //------------------------------------------------------------------- @@ -431,8 +457,10 @@ */ private void release( Object instance, boolean finalized ) { - if( instance == null ) return; - if( !m_deployment.isEnabled() ) return; + if( instance == null ) + return; + if( !m_deployment.isEnabled() ) + return; releaseInstance( getProviderInstance( instance ) ); m_lifestyle.release( instance, finalized ); } @@ -515,7 +543,7 @@ } } - private void applyLogger( Object instance ) + private void applyLogger( final Object instance ) { if( instance instanceof LogEnabled ) { @@ -525,20 +553,34 @@ getLogger().debug( "applying logger to: " + id ); } final Logger logger = m_model.getLogger(); - ((LogEnabled)instance).enableLogging( logger ); + if( m_accessControlContext == null ) + { + ((LogEnabled)instance).enableLogging( logger ); + } + else + { + AccessController.doPrivileged( new PrivilegedAction() + { + public Object run() + { + ((LogEnabled)instance).enableLogging( logger ); + return null; + } + }, m_accessControlContext ); + } } } - private void applyContext( Object instance ) + private void applyContext( final Object instance ) throws Exception { - if( instance == null ) throw new NullPointerException( "context" ); - + if( instance == null ) + throw new NullPointerException( "context" ); final ContextModel model = m_model.getContextModel(); + if( model == null ) + return; - if( model == null ) return; - - Context context = model.getContext(); + final Context context = model.getContext(); if( m_contextualization != null ) { if( getLogger().isDebugEnabled() ) @@ -548,7 +590,21 @@ } try { - m_contextualization.contextualize( instance, context ); + if( m_accessControlContext == null ) + { + m_contextualization.contextualize( instance, context ); + } + else + { + AccessController.doPrivileged( new PrivilegedExceptionAction() + { + public Object run() throws Exception + { + m_contextualization.contextualize( instance, context ); + return null; + } + }, m_accessControlContext ); + } } catch( Throwable e ) { @@ -569,7 +625,21 @@ try { - ((Contextualizable)instance).contextualize( context ); + if( m_accessControlContext == null ) + { + ((Contextualizable)instance).contextualize( context ); + } + else + { + AccessController.doPrivileged( new PrivilegedExceptionAction() + { + public Object run() throws Exception + { + ((Contextualizable)instance).contextualize( context ); + return null; + } + }, m_accessControlContext ); + } } catch( Throwable e ) { @@ -582,7 +652,7 @@ } } - private void applyServices( Object instance ) + private void applyServices( final Object instance ) throws Exception { if( instance instanceof Serviceable ) @@ -594,12 +664,26 @@ } Map providers = getServiceProviders(); - ServiceManager manager = new DefaultServiceManager( getLogger(), providers ); - ((Serviceable)instance).service( manager ); + final ServiceManager manager = new DefaultServiceManager( getLogger(), providers ); + if( m_accessControlContext == null ) + { + ((Serviceable)instance).service( manager ); + } + else + { + AccessController.doPrivileged( new PrivilegedExceptionAction() + { + public Object run() throws Exception + { + ((Serviceable)instance).service( manager ); + return null; + } + }, m_accessControlContext ); + } } } - private void applyConfiguration( Object instance ) + private void applyConfiguration( final Object instance ) throws Exception { if( instance instanceof Configurable ) @@ -609,11 +693,25 @@ int id = System.identityHashCode( instance ); getLogger().debug( "applying configuration to: " + id ); } - ((Configurable)instance).configure( m_model.getConfiguration() ); + if( m_accessControlContext == null ) + { + ((Configurable)instance).configure( m_model.getConfiguration() ); + } + else + { + AccessController.doPrivileged( new PrivilegedExceptionAction() + { + public Object run() throws Exception + { + ((Configurable)instance).configure( m_model.getConfiguration() ); + return null; + } + }, m_accessControlContext ); + } } } - private void applyParameters( Object instance ) + private void applyParameters( final Object instance ) throws Exception { if( instance instanceof Parameterizable ) @@ -623,7 +721,21 @@ int id = System.identityHashCode( instance ); getLogger().debug( "applying parameters to: " + id ); } - ((Parameterizable)instance).parameterize( m_model.getParameters() ); + if( m_accessControlContext == null ) + { + ((Parameterizable)instance).parameterize( m_model.getParameters() ); + } + else + { + AccessController.doPrivileged( new PrivilegedExceptionAction() + { + public Object run() throws Exception + { + ((Parameterizable)instance).parameterize( m_model.getParameters() ); + return null; + } + }, m_accessControlContext ); + } } } @@ -807,7 +919,7 @@ return instance; } - private void applyInitialization( Object instance ) + private void applyInitialization( final Object instance ) throws LifecycleException { if( instance instanceof Initializable ) @@ -819,7 +931,21 @@ } try { - ((Initializable)instance).initialize(); + if( m_accessControlContext == null ) + { + ((Initializable)instance).initialize(); + } + else + { + AccessController.doPrivileged( new PrivilegedExceptionAction() + { + public Object run() throws Exception + { + ((Initializable)instance).initialize(); + return null; + } + }, m_accessControlContext ); + } } catch( Throwable e ) { @@ -830,7 +956,7 @@ } } - private void applyStart( Object instance ) + private void applyStart( final Object instance ) throws LifecycleException { if( instance instanceof Startable ) @@ -842,7 +968,21 @@ } try { - ((Startable)instance).start(); + if( m_accessControlContext == null ) + { + ((Startable)instance).start(); + } + else + { + AccessController.doPrivileged( new PrivilegedExceptionAction() + { + public Object run() throws Exception + { + ((Startable)instance).start(); + return null; + } + }, m_accessControlContext ); + } } catch( Throwable e ) { @@ -860,7 +1000,21 @@ } try { - ((Executable)instance).execute(); + if( m_accessControlContext == null ) + { + ((Executable)instance).execute(); + } + else + { + AccessController.doPrivileged( new PrivilegedExceptionAction() + { + public Object run() throws Exception + { + ((Executable)instance).execute(); + return null; + } + }, m_accessControlContext ); + } } catch( Throwable e ) { @@ -871,7 +1025,7 @@ } } - private void applyStop( Object instance ) + private void applyStop( final Object instance ) { if( instance instanceof Startable ) { @@ -882,7 +1036,21 @@ } try { - ((Startable)instance).stop(); + if( m_accessControlContext == null ) + { + ((Startable)instance).stop(); + } + else + { + AccessController.doPrivileged( new PrivilegedExceptionAction() + { + public Object run() throws Exception + { + ((Startable)instance).stop(); + return null; + } + }, m_accessControlContext ); + } } catch( Throwable e ) { @@ -893,7 +1061,7 @@ } } - private void applyDispose( Object instance ) + private void applyDispose( final Object instance ) { if( instance instanceof Disposable ) { @@ -904,7 +1072,21 @@ } try { - ((Disposable)instance).dispose(); + if( m_accessControlContext == null ) + { + ((Disposable)instance).dispose(); + } + else + { + AccessController.doPrivileged( new PrivilegedExceptionAction() + { + public Object run() throws Exception + { + ((Disposable)instance).dispose(); + return null; + } + }, m_accessControlContext ); + } } catch( Throwable e ) { @@ -1057,13 +1239,16 @@ final Object[] args ) throws Throwable { - if( proxy == null ) throw new NullPointerException( "proxy" ); - if( method == null ) throw new NullPointerException( "method" ); - if( m_destroyed ) throw new IllegalStateException( "destroyed" ); + if( proxy == null ) + throw new NullPointerException( "proxy" ); + if( method == null ) + throw new NullPointerException( "method" ); + if( m_destroyed ) + throw new IllegalStateException( "destroyed" ); try { - return method.invoke( m_instance, args ); + return secureInvocation( method, m_instance, args ); } catch( UndeclaredThrowableException e ) { @@ -1076,7 +1261,8 @@ catch( InvocationTargetException e ) { Throwable cause = e.getTargetException(); - if( cause != null ) throw cause; + if( cause != null ) + throw cause; final String error = "Delegation error raised by component: " + m_model.getQualifiedName(); throw new ApplianceException( error, e ); @@ -1117,6 +1303,27 @@ void notifyDestroyed() { m_destroyed = true; + } + + private Object secureInvocation( final Method method, final Object object, final Object[] args ) + throws Exception + { + if( m_accessControlContext == null ) + { + return method.invoke( object, args ); + } + else + { + Object result = AccessController.doPrivileged( + new PrivilegedExceptionAction() + { + public Object run() throws Exception + { + return method.invoke( object, args ); + } + }, m_accessControlContext ); + return result; + } } } 1.10 +5 -3 avalon/merlin/activation/impl/src/java/org/apache/avalon/activation/appliance/impl/DefaultBlock.java Index: DefaultBlock.java =================================================================== RCS file: /home/cvs/avalon/merlin/activation/impl/src/java/org/apache/avalon/activation/appliance/impl/DefaultBlock.java,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- DefaultBlock.java 13 Jan 2004 18:43:15 -0000 1.9 +++ DefaultBlock.java 19 Jan 2004 21:45:07 -0000 1.10 @@ -197,7 +197,8 @@ * @param block the underlying block implementation * @exception if an invocation handler establishment error occurs */ - protected BlockInvocationHandler( final Logger logger, final DefaultBlock block ) + protected BlockInvocationHandler( final Logger logger, + final DefaultBlock block ) throws Exception { if( block == null ) @@ -243,7 +244,8 @@ String path = service.getServiceDirective().getPath(); Appliance provider = (Appliance) m_block.locate( path ); - m_logger.debug( "delegating: " + method.getName() ); + if( m_logger.isDebugEnabled() ) + m_logger.debug( "delegating: " + method.getName() ); // // resolve the service object from the appliance 1.7 +2 -1 avalon/merlin/activation/impl/src/java/org/apache/avalon/activation/appliance/impl/Deployer.java Index: Deployer.java =================================================================== RCS file: /home/cvs/avalon/merlin/activation/impl/src/java/org/apache/avalon/activation/appliance/impl/Deployer.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- Deployer.java 16 Jan 2004 16:39:02 -0000 1.6 +++ Deployer.java 19 Jan 2004 21:45:07 -0000 1.7 @@ -97,6 +97,7 @@ Deployer( Logger logger ) { m_logger = logger; + m_deploymentThread = new Thread( this, "Deployer " + m_ThreadCounter++ ); m_deploymentThread.start(); --------------------------------------------------------------------- To unsubscribe, e-mail: cvs-unsubscribe@avalon.apache.org For additional commands, e-mail: cvs-help@avalon.apache.org