I want to allow scripts in a sandbox to access system properties but I get AccessControlException
s. Here is the 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<String> action = new PrivilegedAction<String>() {
@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 )" );
}
}
}
When debugging this, I see this output:
...
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 <no signer certificates>)
null
<no principals>
java.security.Permissions@78ce5b1c (
(java.util.PropertyPermission foo read)
)
access: domain 1 ProtectionDomain (file:/.../project/target-eclipse/test-classes/ <no signer certificates>)
sun.misc.Launcher$AppClassLoader@5d0385c1
<no principals>
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)
(invoke the code with -Djava.security.debug=all
to get the same output)
The first block comes from the global java.policy
file that comes with the JRE.
Next block is when the code tried to check the access to java.version
.
The last block shows that this fails.
This surprised me because access to the propery is allowed in the policy file.
To help, I enabled the commented out line which adds PropertyPermission
for java.version
. Now the first System.getProperty( "java.version" )
passes.
But the second one still fails:
access: domain that failed ProtectionDomain (file:/.../project/target-eclipse/test-classes/ <no signer certificates>)
sun.misc.Launcher$AppClassLoader@5d0385c1
<no principals>
java.security.Permissions@6ddf073d (
(java.io.FilePermission /.../project/target-eclipse/test-classes/- read)
(java.lang.RuntimePermission exitVM)
)
I'm really stumped by this. From the code, it seems that Java always checks all ProtectionDomain
s in order (I have four). If any of them doesn't like your access, it will be denied.
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.
What am I missing?