I think this is how it should be done: https://github.com/ceki/logback/tree/LBCLASSIC-304 The behavior is mostly unchanged if no SecurityManager is installed since System.getSecurityManager() is cheap. Additional checks are only performed if that call returns a non-null result.
The fact that Permission can only be checked by catching an AccessControlException is giving me the creeps, though. Must be rather old code... Joern On 06.11.2011, at 07:42, ceki wrote: > Keep in mind that the SecurityManager is usually installed by the > container very early in the container life cycle and one usually does > not change security managers on the fly, but your point is a good one > nonetheless. > > On 11/6/2011 1:32 AM, Joern Huxhorn wrote: >> There is one issue with the code in http://goo.gl/zASBm, though: >> It checks for getClassLoader permission in a static code block only, i.e. >> when the class is initially loaded by the classloader, and saves that >> information for later reference. >> >> I don't think that this is a valid optimization for precisely the reason >> that this permission can change during runtime (according to >> http://download.oracle.com/javase/1.4.2/docs/api/java/security/AccessController.html >> even per thread), for example if a different SecurityManager is installed. >> >> The method using the statically initialized boolean should probably look >> like this instead: >> >> public static ClassLoader getClassLoaderAsPrivileged(final Class clazz) { >> try { >> AccessController.checkPermission(new >> RuntimePermission("getClassLoader")); >> return AccessController.doPrivileged( >> new PrivilegedAction<ClassLoader>() { >> public ClassLoader run() { >> return clazz.getClassLoader(); >> } >> }); >> } catch (AccessControlException e) { >> return null; >> } >> } >> >> Not sure if this would solve the problem at hand... >> >> Joern. >> >> On 05.11.2011, at 16:25, ceki wrote: >> >>> >>> Thanks for the sample project. I can confirm that I observe a >>> AccessControlException when logback is present. The >>> AccessControlException is not thrown if slf4j-nop, slf4j-simple or >>> slf4j-log4j are used as the slf4j binding. >>> >>> Although logback does not install its own SecurityManager or modify >>> the security configuration, it does attempt to determine whether it >>> has "getClassLoader" permission. See http://goo.gl/zASBm >>> >>> Here is the code in question: >>> >>> AccessController.doPrivileged(new PrivilegedAction<Boolean>() { >>> public Boolean run() { >>> try { >>> AccessController.checkPermission( >>> new RuntimePermission("getClassLoader")); >>> return true; >>> } catch (AccessControlException e) { >>> return false; >>> } >>> } >>> }); >>> >>> >>> If the privileged block above code is removed, then the >>> AccessControlException goes away. The privileged block looks quite >>> legitimate to me so I don't think it's a bug in logback. >>> >>> To convince yourself the the privileged block is key, you can remove >>> all logging related calls and all logging related dependencies, add >>> the privileged block at the beginning of the test. You should observe >>> an AccessControlException being thrown. >>> >>> -- >>> Ceki >>> http://twitter.com/#!/ceki >>> >>> >>> >>> On 11/5/2011 1:42 PM, Andrew Bourgeois wrote: >>>> Ceki, >>>> >>>> I redid the test in a clean Maven project. I don't know if attachments >>>> will pass through, so: >>>> >>>> 1) pom.xml: >>>> >>>> <project xmlns="http://maven.apache.org/POM/4.0.0" >>>> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >>>> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 >>>> http://maven.apache.org/maven-v4_0_0.xsd"> >>>> <modelVersion>4.0.0</modelVersion> >>>> <name>test</name> >>>> <groupId>be.test.fun</groupId> >>>> <artifactId>test</artifactId> >>>> <version>0.1.0-RC1</version> >>>> <dependencies> >>>> <dependency> >>>> <groupId>org.slf4j</groupId> >>>> <artifactId>slf4j-api</artifactId> >>>> <version>1.6.0</version> >>>> </dependency> >>>> >>>> <dependency> >>>> <groupId>log4j</groupId> >>>> <artifactId>log4j</artifactId> >>>> <version>1.2.16</version> >>>> </dependency> >>>> <dependency> >>>> <groupId>org.slf4j</groupId> >>>> <artifactId>slf4j-log4j12</artifactId> >>>> <version>1.6.0</version> >>>> </dependency> >>>> >>>> <!--dependency> >>>> <groupId>ch.qos.logback</groupId> >>>> <artifactId>logback-core</artifactId> >>>> <version>1.0.0</version> >>>> </dependency> >>>> <dependency> >>>> <groupId>ch.qos.logback</groupId> >>>> <artifactId>logback-classic</artifactId> >>>> <version>1.0.0</version> >>>> </dependency--> >>>> >>>> <dependency> >>>> <groupId>junit</groupId> >>>> <artifactId>junit</artifactId> >>>> <version>4.4</version> >>>> <scope>test</scope> >>>> </dependency> >>>> </dependencies> >>>> <build> >>>> <resources> >>>> </resources> >>>> <plugins> >>>> <plugin> >>>> <artifactId>maven-compiler-plugin</artifactId> >>>> <configuration> >>>> <source>1.6</source> >>>> <target>1.6</target> >>>> <verbose>true</verbose> >>>> </configuration> >>>> </plugin> >>>> </plugins> >>>> </build> >>>> </project> >>>> >>>> 2) The JUnit test: >>>> >>>> package be.test.fun; >>>> >>>> import org.junit.Test; >>>> import java.rmi.RMISecurityManager; >>>> import org.slf4j.Logger; >>>> import org.slf4j.LoggerFactory; >>>> >>>> public class SecurityManagerTest { >>>> >>>> @Test >>>> public void securityManagerWithLogs() { >>>> Logger logger = LoggerFactory.getLogger(SecurityManagerTest.class); >>>> >>>> System.setProperty("java.security.policy", >>>> "./src/test/resources/java.policy"); >>>> logger.debug("Policy location: {}", >>>> System.getProperty("java.security.policy")); >>>> if (System.getSecurityManager() == null) { >>>> System.setSecurityManager(new RMISecurityManager()); >>>> } >>>> System.setProperty("java.security.policy", >>>> "./src/test/resources/java.policy"); >>>> } >>>> >>>> // @Test >>>> // public void securityManagerWithoutLogs() { >>>> // System.setProperty("java.security.policy", >>>> "./src/test/resources/java.policy"); >>>> // if (System.getSecurityManager() == null) { >>>> // System.setSecurityManager(new RMISecurityManager()); >>>> // } >>>> // System.setProperty("java.security.policy", >>>> "./src/test/resources/java.policy"); >>>> // } >>>> } >>>> >>>> 3) java.policy that you put into src/test.resources: >>>> >>>> grant { >>>> permission java.security.AllPermission; >>>> }; >>>> >>>> So.... if you run this: >>>> ------------------------------------------------------- >>>> T E S T S >>>> ------------------------------------------------------- >>>> Running be.test.fun.SecurityManagerTest >>>> 2011-11-05 13:36:33,828 [main] DEBUG - (be.test.fun.SecurityManagerTest) >>>> - Policy location: ./src/test/resources/java.policy >>>> Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.201 sec >>>> >>>> Results : >>>> >>>> Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 >>>> >>>> Now, comment the 2 LOG4J-related dependencies inside the POM, and >>>> uncomment the logback ones: >>>> ------------------------------------------------------- >>>> T E S T S >>>> ------------------------------------------------------- >>>> Running be.test.fun.SecurityManagerTest >>>> 13:38:04.222 [main] DEBUG be.test.fun.SecurityManagerTest - Policy >>>> location: ./src/test/resources/java.policy >>>> java.security.AccessControlException: access denied >>>> (java.lang.RuntimePermission setContextClassLoader) >>>> at >>>> java.security.AccessControlContext.checkPermission(AccessControlContext.java:323) >>>> >>>> at >>>> java.security.AccessController.checkPermission(AccessController.java:546) >>>> at java.lang.SecurityManager.checkPermission(SecurityManager.java:532) >>>> at java.lang.Thread.setContextClassLoader(Thread.java:1394) >>>> at >>>> org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:366) >>>> >>>> at >>>> org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1021) >>>> >>>> [INFO] >>>> ------------------------------------------------------------------------ >>>> [INFO] BUILD FAILURE >>>> [INFO] >>>> ------------------------------------------------------------------------ >>>> [INFO] Total time: 2.202s >>>> >>>> And now comment the "securityManagerWithLogs" test method, and uncomment >>>> the "securityManagerWithoutLogs" one: >>>> ------------------------------------------------------- >>>> T E S T S >>>> ------------------------------------------------------- >>>> Running be.test.fun.SecurityManagerTest >>>> Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.105 sec >>>> >>>> Results : >>>> >>>> Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 >>>> >>>> Do you have the same output? >>>> >>>> FYI: >>>> >>>> [xvepak@localhost test]$ mvn -version >>>> Apache Maven 3.0.1 (r1038046; 2010-11-23 11:58:32+0100) >>>> Java version: 1.6.0_23 >>>> Java home: /home/xvepak/software/jdk1.6.0_23/jre >>>> Default locale: en_US, platform encoding: UTF-8 >>>> OS name: "linux" version: "2.6.18-238.12.1.el5" arch: "i386" Family: "unix" >>>> >>>> Thank you for trying to help out!! >>>> >>>> Best regards >>>> >>>> Andrew Bourgeois >>>> >>>> -----Original Message----- From: ceki >>>> Sent: Saturday, November 05, 2011 1:03 AM >>>> To: logback users list >>>> Subject: Re: [logback-user] SecurityManager issue using logback >>>> >>>> On 05/11/2011 12:47 PM, Andrew Bourgeois wrote: >>>> >>>>> So to reformulate: >>>>> The exception IS thrown when we have SLF4J code >>>>> The exception ISN'T thrown when we remove the SLF4J. >>>> >>>> That's not what I observe. An exception is thrown in both cases. >> > > > -- > Ceki > http://twitter.com/#!/ceki > _______________________________________________ > Logback-user mailing list > Logback-user@qos.ch > http://mailman.qos.ch/mailman/listinfo/logback-user _______________________________________________ Logback-user mailing list Logback-user@qos.ch http://mailman.qos.ch/mailman/listinfo/logback-user