Low level hooks in JDK for instrumentation of permission checks.

Peter Firmstone peter.firmstone at zeus.net.au
Wed Jun 9 01:35:25 UTC 2021


Apologies in advance if this seems like paranoid security.

As you are likely now aware, we have been using SecurityManager a little 
differently than recommended as we adapted it to our requirements.

Sometimes it's not always easy to explain or obvious why something is 
done in a certain way.

It's clear we can use StackWalker to implement AccessController 
functionality.  And it's also clear we can use ThreadLocal or Scope 
Local's to preserve the user Subject across threads.

Going forward we will need low level hooks in the JDK for our 
authentication layer, clearly this is an opportunity to further simplify 
and improve our authentication layer.

Because we use a remote service architecture, with proxy's, the proxy's 
are dynamically granted permission's after Service Authentication, these 
permissions also require the user principal to be logged in, we may have 
a number of services on the stack, for example to participate in a 
transaction.

We have a tool to generate least privilege policy files.

There are two reasons we do this:

 1. Simplicity of administration and auditing of policy files.
 2. Limit the permissions of code, and grant certain permissions to
    users to ensure users are authenticated before allowing data parsing.

An example of item two, is our services require users to be logged in to 
ensure that any data provided by the user is a trusted data source (we 
still check the data).   We re-implemented a subset of Java 
Serialization and have a DeSerializationPermission, which is granted to 
Principals of users.

If a user is not logged in, data cannot be de-serialized, because the 
code alone doesn't have permission to do so.

Hopefully modules and packages will have strong encapsulation in future 
so we don't need permission's like java.lang.RuntimePermission 
"accessClassInPackage.*"  No doubt we will need to create our own 
Permission's.

We would like to be able to limit data parsing, like XML or Java 
de-serialization, to logged in users only.

We don't break encapsulation, in future we will only use reflection to 
call public methods and constructors (we are currently in the process of 
doing so).   Our build systems use Maven, our build is modular.

I would also like to request that all JDK modules be given 
ProtectionDomain's following SecurityManager deprecation. Currently some 
modules have null ProtectionDomain's to show they have AllPermission.  
However we don't grant AllPermission to code in practise, we like to 
grant certain Permission's to Principal's, not code, where the Principal 
is the source of data, indicating the user has been authenticated and we 
only grant what's necessary and no more.

Examples of permission's granted to JDK modules in POLP policy files, 
taken from a test harness:

grant codebase "jrt:/jdk.security.jgss"
{
     permission java.lang.RuntimePermission 
"accessClassInPackage.sun.security.util";
     permission java.security.SecurityPermission 
"putProviderProperty.JdkSASL";
};

grant codebase "jrt:/jdk.crypto.mscapi"
{
     permission java.lang.RuntimePermission 
"accessClassInPackage.sun.security.util";
     permission java.lang.RuntimePermission "loadLibrary.sunmscapi";
     permission java.security.SecurityPermission 
"putProviderProperty.SunMSCAPI";
};

grant codebase "jrt:/jdk.localedata"
{
     permission java.lang.RuntimePermission 
"accessClassInPackage.sun.util.locale.provider";
     permission java.lang.RuntimePermission 
"accessClassInPackage.sun.util.resources";
};

grant codebase "jrt:/jdk.security.auth"
{
     permission java.io.FilePermission 
"C:\\Users\\peter\\Documents\\NetBeansProjects\\JGDMS\\qa\\lib\\jiniharness.jar", 
"read";
     permission javax.security.auth.AuthPermission "modifyPrincipals";
     permission javax.security.auth.AuthPermission 
"modifyPrivateCredentials";
     permission javax.security.auth.AuthPermission 
"modifyPublicCredentials";
     permission java.lang.RuntimePermission 
"accessClassInPackage.sun.security.krb5";
     permission java.lang.RuntimePermission 
"accessClassInPackage.sun.security.util";
     permission java.lang.RuntimePermission "getProtectionDomain";
};

Example of POLP grant to code with principal, code alone cannot access 
these, in case you are wondering, we use this to secure the RMI Registry 
using stateless TLSv1.3, it's used by our Service Watchdog, or Service 
Activation framework called Phoenix, it's the sole use we have of the 
Java RMI JRMP protocol, in cases where this isn't used we can disable 
Java Serialization completely:

grant codebase 
"file:/C:/Users/peter/Documents/NetBeansProjects/JGDMS/JGDMS/dist/target/JGDMS-3.1.1-SNAPSHOT/lib/jgdms-rmi-tls-3.1.1-SNAPSHOT.jar",
     principal javax.security.auth.x500.X500Principal "CN=Phoenix"
{
     permission java.util.PropertyPermission "javax.net.ssl.trustStore", 
"read";
     permission java.util.PropertyPermission 
"javax.net.ssl.trustStorePassword", "read";
     permission java.util.PropertyPermission 
"javax.net.ssl.trustStoreType", "read";
     permission java.util.PropertyPermission 
"org.apache.river.jeri.ssl.jceProvider", "read";
     permission java.util.PropertyPermission 
"org.apache.river.jeri.ssl.jsseProvider", "read";
     permission java.util.PropertyPermission 
"org.apache.river.jeri.ssl.secureRandomAlgorithm", "read";
     permission java.util.PropertyPermission 
"org.apache.river.jeri.ssl.sslProtocol", "read";
     permission java.util.PropertyPermission 
"org.apache.river.jeri.ssl.trustManagerFactoryAlgorithm", "read";
     permission java.io.FilePermission "harness\\trust\\truststore", "read";
     permission java.net.SocketPermission "localhost:1098", 
"listen,resolve";
};

If we really want to get into detail, instances of GrantPermission shows 
the permissions that are granted dynamically, in this case you can see 
that provided the Mahalo Service is run with it's principal CN=Mahalo, 
it has permission to de-serialize a MarshalledObject (it doesn't 
actually unmarshall it though, it uses it for equals comparison), the 
GrantPermission shows that it grants permission to de-serialize (ATOMIC, 
which means atomic input validation, prior to object creation), after 
authenticating the proxy's service.

grant codebase 
"file:/C:/Users/peter/Documents/NetBeansProjects/JGDMS/JGDMS/dist/target/JGDMS-3.1.1-SNAPSHOT/lib/mahalo-service-3.1.1-SNAPSHOT.jar",
     principal javax.security.auth.x500.X500Principal "CN=Mahalo"
{
     permission org.apache.river.api.io.DeSerializationPermission 
"MARSHALL";
     permission java.util.PropertyPermission "org.apache.river.qa.home", 
"read";
     permission org.apache.river.phoenix.dl.MonitorPermission 
"net.jini.activation.arg.ActivationMonitor.inactiveObject";
     permission net.jini.security.AuthenticationPermission 
"javax.security.auth.x500.X500Principal \"CN=Mahalo\"", "connect";
     permission net.jini.security.AuthenticationPermission 
"javax.security.auth.x500.X500Principal \"CN=Mahalo\"", "listen";
     permission net.jini.security.AuthenticationPermission 
"javax.security.auth.x500.X500Principal \"CN=Mahalo\" peer 
javax.security.auth.x500.X500Principal \"CN=Tester\"", "accept";
     permission java.net.SocketPermission "DESKTOP-R0ORPA2", "resolve";
     permission java.net.SocketPermission "DESKTOP-R0ORPA2.lan", "resolve";
     permission java.net.SocketPermission "DESKTOP-R0ORPA2:9082", 
"connect,resolve";
     permission java.net.SocketPermission 
"[fe80:0:0:0:9ca0:dfeb:b9a7:96fd%16]:1024-", "connect,resolve";
     permission java.net.SocketPermission 
"[fe80:0:0:0:9ca0:dfeb:b9a7:96fd%16]:1024-", "accept,resolve";
     permission java.net.SocketPermission "localhost:0", "listen,resolve";
     permission net.jini.security.GrantPermission 
"net.jini.security.AuthenticationPermission 
\"javax.security.auth.x500.X500Principal \\\"CN=Mahalo\\\" peer 
javax.security.auth.x500.X500Principal \\\"CN=Phoenix\\\"\", \"connect\";";
     permission net.jini.security.GrantPermission 
"net.jini.security.AuthenticationPermission 
\"javax.security.auth.x500.X500Principal \\\"CN=Mahalo\\\" peer 
javax.security.auth.x500.X500Principal \\\"CN=Tester\\\"\", \"connect\"; 
net.jini.security.AuthenticationPermission 
\"javax.security.auth.x500.X500Principal \\\"CN=Mahalo\\\" peer 
javax.security.auth.x500.X500Principal \\\"CN=Outrigger\\\"\", 
\"connect\";";
     permission net.jini.security.GrantPermission 
"org.apache.river.api.io.DeSerializationPermission \"ATOMIC\"; 
org.apache.river.api.io.DeSerializationPermission \"MARSHALL\"; 
org.apache.river.api.io.DeSerializationPermission \"ATOMIC\"; 
java.lang.RuntimePermission \"accessClassInPackage.com.sun.proxy\", \"\";";
     permission javax.security.auth.AuthPermission "getSubject";
     permission java.io.FilePermission 
"C:\\Users\\peter\\AppData\\Local\\Temp\\-", "delete";
     permission java.io.FilePermission 
"C:\\Users\\peter\\AppData\\Local\\Temp\\-", "read";
     permission java.io.FilePermission 
"C:\\Users\\peter\\AppData\\Local\\Temp\\-", "write";
     permission java.io.FilePermission 
"C:\\Users\\peter\\Documents\\NetBeansProjects\\JGDMS\\JGDMS\\dist\\target\\JGDMS-3.1.1-SNAPSHOT\\lib-dl\\mahalo-dl-3.1.1-SNAPSHOT.jar", 
"read";
     permission java.io.FilePermission 
"C:\\Users\\peter\\Documents\\NetBeansProjects\\JGDMS\\JGDMS\\dist\\target\\JGDMS-3.1.1-SNAPSHOT\\lib\\mahalo-service-3.1.1-SNAPSHOT.jar", 
"read";
     permission java.io.FilePermission 
"C:\\Users\\peter\\Documents\\NetBeansProjects\\JGDMS\\qa\\harness\\trust\\mahalo.keystore", 
"read";
     permission java.io.FilePermission 
"C:\\Users\\peter\\Documents\\NetBeansProjects\\JGDMS\\qa\\harness\\trust\\outrigger.keystore", 
"read";
     permission java.io.FilePermission 
"C:\\Users\\peter\\Documents\\NetBeansProjects\\JGDMS\\qa\\harness\\trust\\phoenix.keystore", 
"read";
     permission java.io.FilePermission 
"C:\\Users\\peter\\Documents\\NetBeansProjects\\JGDMS\\qa\\harness\\trust\\reggie.keystore", 
"read";
     permission java.io.FilePermission 
"C:\\Users\\peter\\Documents\\NetBeansProjects\\JGDMS\\qa\\harness\\trust\\tester.keystore", 
"read";
     permission java.lang.RuntimePermission "getClassLoader";
     permission java.lang.RuntimePermission "modifyThread";
     permission net.jini.discovery.DiscoveryPermission 
"QATestDefaultGroup_DESKTOP-R0ORPA2_1623111918992";
};

-- 
Regards,
  
Peter Firmstone
Zeus Project Services Pty Ltd.



More information about the jdk-dev mailing list