SecurityManager issue using logback

Hello Ceki said my “bug” report isn’t actually a bug, but didn’t have the tell to tell me what’s wrong: http://jira.qos.ch/browse/LBCLASSIC-304 Can anyone here help? In short: package be.removed.fun.removed; import java.rmi.RMISecurityManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TestMain { private static final Logger logger = LoggerFactory.getLogger(TestMain.class); public static void main(String[] args) throws Exception { System.setProperty("java.security.policy", "./src/main/config/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/main/config/java.policy"); } } ...runs fine using log4j: <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> ...and gives an exception when switching to logback: <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</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> The exception is thrown at the last line of the main: 01:05:37.702 [main] DEBUG be.removed.fun.removed.TestMain - Policy location: ./src/main/config/java.policy Exception in thread "main" java.security.AccessControlException: access denied (java.util.PropertyPermission java.security.policy write) 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.System.setProperty(System.java:725) at be.removed.fun.removed.TestMain.main(TestMain.java:18) The policy file is: grant { permission java.security.AllPermission; }; The problem gets fixed if I put this file into: $JAVA_HOME/jre/lib/security Thank you for your time! Best regards Andrew Bourgeois

The sample throws an exception when no logging library is present. So the issue is unrelated to logback, log4j, slf4j or any other logging library. If the code works with log4j, I am inclined to think that there other change you are not taking into account. Again, the sample code throws an exception when no logging library is present. You should look into that first. HTH, -- Ceki http://twitter.com/#!/ceki On 05/11/2011 12:00 PM, Andrew Bourgeois wrote:
Hello Ceki said my “bug” report isn’t actually a bug, but didn’t have the tell to tell me what’s wrong: http://jira.qos.ch/browse/LBCLASSIC-304 Can anyone here help?**In short: package be.removed.fun.removed;

Hello Ceki the example you gave me yesterday without logging DIDN'T throw an exception. This is what I replied yesterday (maybe the sentence is wrong?): "I wanted to say 'This code runs FINE indeed', so yes, without exceptions." So to reformulate: The exception IS thrown when we have SLF4J code The exception ISN'T thrown when we remove the SLF4J. Thank you for your time! Best regards Andrew Bourgeois -----Original Message----- From: ceki Sent: Saturday, November 05, 2011 12:09 AM To: logback users list Subject: Re: [logback-user] SecurityManager issue using logback The sample throws an exception when no logging library is present. So the issue is unrelated to logback, log4j, slf4j or any other logging library. If the code works with log4j, I am inclined to think that there other change you are not taking into account. Again, the sample code throws an exception when no logging library is present. You should look into that first. HTH, -- Ceki http://twitter.com/#!/ceki On 05/11/2011 12:00 PM, Andrew Bourgeois wrote:
Hello Ceki said my “bug” report isn’t actually a bug, but didn’t have the tell to tell me what’s wrong: http://jira.qos.ch/browse/LBCLASSIC-304 Can anyone here help?**In short: package be.removed.fun.removed;
_______________________________________________ Logback-user mailing list Logback-user@qos.ch http://mailman.qos.ch/mailman/listinfo/logback-user

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

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

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, you're right, I do get the exception when executing that block of code. I have 2 workarounds for my problem: 1) Put the java.policy file into $JAVA_HOME/jre/lib/security: That's too dirty, I'll skip this one. 2) Initialize the security manager before initializing logback: @Test public void loggingAfterSecurityManager() { System.setProperty("java.security.policy", "./src/test/resources/java.policy"); if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } Logger logger = LoggerFactory.getLogger(SecurityManagerTest.class); logger.debug("Policy location: {}", System.getProperty("java.security.policy")); System.setProperty("java.security.policy", "./src/test/resources/java.policy"); } The test passes because I did what I had to do before loading the logback classes. The following doesn't pass: @Test public void loggingBeforeSecurityManager() { Logger logger = LoggerFactory.getLogger(SecurityManagerTest.class); logger.debug("Policy location: {}", System.getProperty("java.security.policy")); System.setProperty("java.security.policy", "./src/test/resources/java.policy"); if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } logger.debug("Policy location: {}", System.getProperty("java.security.policy")); } If I dare to initialize logback before initializing a security manager, once I do it, it all goes wrong with code that uses the SecurityManager (so the last logger.debug(...) fails!). I'm not an expert so I can't say it's bad, but it's annoying. Thank you for your help! Best regards Andrew Bourgeois -----Original Message----- From: ceki Sent: Saturday, November 05, 2011 4:25 PM To: logback users list Subject: Re: [logback-user] SecurityManager issue using logback 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.
_______________________________________________ Logback-user mailing list Logback-user@qos.ch http://mailman.qos.ch/mailman/listinfo/logback-user

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/AccessControl... 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.
_______________________________________________ Logback-user mailing list Logback-user@qos.ch http://mailman.qos.ch/mailman/listinfo/logback-user

What I find interesting is that IntelliJ says getClassLoaderAsPrivileged isn't even used by anything in Logback. Ralph On Nov 5, 2011, at 5:32 PM, 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/AccessControl... 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.
_______________________________________________ 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

Correct. getClassLoaderAsPrivileged is not even used anywhere. That's the result of a compromise: http://jira.qos.ch/browse/LBCLASSIC-263 On 11/6/2011 2:47 AM, Ralph Goers wrote:
What I find interesting is that IntelliJ says getClassLoaderAsPrivileged isn't even used by anything in Logback.
Ralph
On Nov 5, 2011, at 5:32 PM, 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/AccessControl... 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

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/AccessControl... 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

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/AccessControl... 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

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.
The reference is never used anywhere getClassLoaderAsPrivileged method is never invoked by logback. The privileged block is result of a compromise: http://jira.qos.ch/browse/LBCLASSIC-263
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/AccessControl...
even per thread), for example if a different SecurityManager is installed.
One rarely installs a different SecurityManager but in general you are right.
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...
It'll probably make the SecurityException in LBCLASSIC-303 go away by virtue of call reordering. However, it does not explain why invoking AccessController.doPrivileged changes the behavior of RMISecurityManger.
Joern.
-- Ceki http://twitter.com/#!/ceki

On 06.11.2011, at 19:07, ceki wrote:
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.
The reference is never used anywhere getClassLoaderAsPrivileged method is never invoked by logback. The privileged block is result of a compromise: http://jira.qos.ch/browse/LBCLASSIC-263
Yes, I checked out that issue.
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/AccessControl... even per thread), for example if a different SecurityManager is installed.
One rarely installs a different SecurityManager but in general you are right.
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...
It'll probably make the SecurityException in LBCLASSIC-303 go away by virtue of call reordering. However, it does not explain why invoking AccessController.doPrivileged changes the behavior of RMISecurityManger.
I don't get it, either. I just think that the current code in Logback is wrong anyway and should therefore be fixed. First of all, it doesn't make sense to execute AccessController.checkPermission(new RuntimePermission("getClassLoader")) wrapped into a PrivilegedAction since it is always allowed to check for permission. Wouldn't make sense otherwise, too. Secondly, the current implementation does not take into account that different threads may have different permissions. This could by a real problem in certain environments where, e.g., a worker-thread does not have the required permissions while the main app has it. My code in https://github.com/ceki/logback/tree/LBCLASSIC-304 should handle those scenarios gracefully while not degrading performance if no SecurityManager is in place. If this makes the problem go away I'm 90% fine with it. The remaining 10% of me would really like to understand the reason for all of this. :p One thing that could be somehow responsible for the test failure is the rather complex way "java.security.policy" is evaluated. See http://download.oracle.com/javase/1.4.2/docs/guide/security/PolicyFiles.html and search for it. It assumes an URL and not a file. Further, it has to be specified with and additional = to replace existing rules instead of merging them. So the line in the test should probably (!!) look like this instead: System.setProperty("java.security.policy","=./src/test/resources/java.policy"); or, even more likely, URL policyUrl = SecurityManagerTest.class.getResource("/java.policy"); String policyUrlString = policyUrl.toString(); System.setProperty("java.security.policy","="+policyUrlString); Joern.
participants (4)
-
Andrew Bourgeois
-
ceki
-
Joern Huxhorn
-
Ralph Goers