How to check caller class origin in SecurityManager?
First, SecurityManager has a protected method getClassContext().
Your code would look like this:
System.setSecurityManager(new SecurityManager() {
public void checkPermission(Permission permission) {
Class<?> caller = getClassContext()[1];
ClassLoader ccl = caller.getClassLoader();
if (ccl != null || ccl != getClass().getClassLoader()) {
throw new SecurityException("You do not have permissions.");
}
}
});
Second, if you want to use a StackWalker
, it is recommended that you reuse the StackWalker
instance:
StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
System.setSecurityManager(new SecurityManager() {
public void checkPermission(Permission permission) {
Class<?> caller = walker.getCallerClass();
ClassLoader ccl = caller.getClassLoader();
if (ccl != null || ccl != getClass().getClassLoader()) {
throw new SecurityException("You do not have permissions.");
}
}
});
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 of java.security.Policy
.
Some hints for implementing a java.security.Policy
:
- Override
implies
and bothgetPermissions
methods. Seriously. - Catch your own
ProtectionDomain
of your Policy class. (private static final ProtectionDomain MY_PD = MyPolicy.class.getProtectionDomain()
) - Use a fast path if the check is for your own ProtectionDomain. Don't call other code in this case, otherwise you might end up with a StackOverflow.