title: Granting script under a SecurityManager to access system properties
body: <p>I want to allow scripts in a sandbox to access system properties but I get <code>AccessControlException</code>s. Here is the code:</p>
  
  <pre><code>import static org.junit.Assert.*;
  import java.security.AccessControlContext;
  import java.security.AccessController;
  import java.security.CodeSource;
  import java.security.Permission;
  import java.security.Permissions;
  import java.security.PrivilegedAction;
  import java.security.ProtectionDomain;
  import java.security.cert.Certificate;
  import java.util.PropertyPermission;
  import org.junit.Test;
  
  public class AccessControlTest {
  
      @Test
      public void testAccessControl() throws Exception {
  
          PrivilegedAction&lt;String&gt; action = new PrivilegedAction&lt;String&gt;() {
  
              @Override
              public String run() {
                  System.getProperty( "java.version" ); // doesn't work
                  return System.getProperty( "foo" ); // doesn't work
              }
          };
  
  
          SecurityManager sm = new SecurityManager() {
              @Override
              public void checkPermission( Permission perm ) {
  
                  if( "setSecurityManager".equals( perm.getName() ) ) {
                      return;
                  }
  
                  System.out.println( perm );
                  super.checkPermission( perm );
              }
          };
  
          Permissions perms = new Permissions();
          perms.add( new PropertyPermission( "foo", "read" ) );
  //        perms.add( new PropertyPermission( "java.version", "read" ) );
  
          ProtectionDomain domain = new ProtectionDomain( new CodeSource( null, (Certificate[]) null ), perms );
          AccessControlContext context = new AccessControlContext( new ProtectionDomain[] { domain } );
  
          try {
              System.setSecurityManager( sm );
  
              Object result = AccessController.doPrivileged( action, context );
              assertEquals( Boolean.TRUE, result );
          } finally {
              System.setSecurityManager( null );
              System.out.println( "setSecurityManager( null )" );
          }
  
  
      }
  
  }
  </code></pre>
  
  <p>When debugging this, I see this output:</p>
  
  <pre><code>...
  policy:   granting (java.lang.RuntimePermission stopThread)
  policy:   granting (java.net.SocketPermission localhost:1024- listen,resolve)
  policy:   granting (java.util.PropertyPermission java.version read)
  ...
  (java.util.PropertyPermission java.version read)
  java.lang.Exception: Stack trace
      at java.lang.Thread.dumpStack(Thread.java:1249)
      at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)
      at java.security.AccessController.checkPermission(AccessController.java:549)
      at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
      at com.avanon.script.AccessControlTest$2.checkPermission(AccessControlTest.java:39)
      at java.lang.SecurityManager.checkPropertyAccess(SecurityManager.java:1285)
      at java.lang.System.getProperty(System.java:650)
  ...
  access: domain 0 ProtectionDomain  (null &lt;no signer certificates&gt;)
   null
   &lt;no principals&gt;
   java.security.Permissions@78ce5b1c (
   (java.util.PropertyPermission foo read)
  )
  
  
  access: domain 1 ProtectionDomain  (file:/.../project/target-eclipse/test-classes/ &lt;no signer certificates&gt;)
   sun.misc.Launcher$AppClassLoader@5d0385c1
   &lt;no principals&gt;
   java.security.Permissions@6ddf073d (
   (java.io.FilePermission /.../project/target-eclipse/test-classes/- read)
   (java.lang.RuntimePermission exitVM)
  )
  
  
  access: access denied (java.util.PropertyPermission java.version read)
  </code></pre>
  
  <p>(invoke the code with <code>-Djava.security.debug=all</code> to get the same output)</p>
  
  <p>The first block comes from the global <code>java.policy</code> file that comes with the JRE.</p>
  
  <p>Next block is when the code tried to check the access to <code>java.version</code>.</p>
  
  <p>The last block shows that this fails.</p>
  
  <p>This surprised me because access to the propery is allowed in the policy file.</p>
  
  <p>To help, I enabled the commented out line which adds <code>PropertyPermission</code> for <code>java.version</code>. Now the first <code>System.getProperty( "java.version" )</code> passes.</p>
  
  <p>But the second one still fails:</p>
  
  <pre><code>access: domain that failed ProtectionDomain  (file:/.../project/target-eclipse/test-classes/ &lt;no signer certificates&gt;)
   sun.misc.Launcher$AppClassLoader@5d0385c1
   &lt;no principals&gt;
   java.security.Permissions@6ddf073d (
   (java.io.FilePermission /.../project/target-eclipse/test-classes/- read)
   (java.lang.RuntimePermission exitVM)
  )
  </code></pre>
  
  <p>I'm really stumped by this. From the code, it seems that Java always checks all <code>ProtectionDomain</code>s in order (I have four). If any of them doesn't like your access, it will be denied.</p>
  
  <p>But I don't see how the second domain allows access to any properties, so I was expecting either both to fail or both to succeed.</p>
  
  <p>What am I missing?</p>