I've got one ClassLoader for trusted application code and a seperate ClassLoader for user-submitted (untrusted) code.
I want the user-submitted code to be restricted by the Security Manager. How do I check the caller origin from within the SecurityManager? See the psuedocode:
System.setSecurityManager(new SecurityManager() {
public void checkPermission(Permission permission) {
if (/*caller class is not loaded by the trusted classloader*/) {
throw new SecurityException("You do not have permissions.");
}
}
});
What I've tried already:
StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass().getClassLoader()
checks for permissions first so it gives a stack overflow exception.Thread.currentThread().getStackTrace()[2].getClassLoaderName()
is insecure because it only gives the classloader name and not class object, if the untrusted loader's canonical name is the same as the trusted loader then that's a security issue.
First, SecurityManager has a protected method getClassContext().
Your code would look like this:
Second, if you want to use a
StackWalker
, it is recommended that you reuse theStackWalker
instance:Third, this will most likely not do what you want. Security checks are done all over the JDK, so the caller might be any amount of stack levels away, requiring you to check the entire stack (Hint: break at the second time you visit your SecurityManager in the stack).
Instead, define a policy (create a java policy file) where you grant your code all permissions and use the java.lang.SecurityManager.
If it is not possible to write your own policy file, you can also use
Policy.setPolicy()
to install your own implementation ofjava.security.Policy
.Some hints for implementing a
java.security.Policy
:implies
and bothgetPermissions
methods. Seriously.ProtectionDomain
of your Policy class. (private static final ProtectionDomain MY_PD = MyPolicy.class.getProtectionDomain()
)