Reputation: 10321
In a webapp deployed in tomcat with security manager, this works:
URL url = servletContext.getResource("/WEB-INF/internal/tika/tika-app-1.2.jar");
// test to see if the content can be read
String test = IOUtils.toString(url);
Tomcat uses jndi for internal URLs. According to tomcat documentation about security manager (link here), there is an implicit permission granted to resources inside the war file.
However, this doesn't work:
URL url = servletContext.getResource("/WEB-INF/internal/tika/tika-app-1.2.jar");
ClassLoader cl = new URLClassLoader(new URL[] { url }, this.getClass().getClassLoader());
// load a class from the jar
Class<TextExtractor> clz = (Class) cl.loadClass(" ... some class ...");
delegate = clz.newInstance();
The exception that I get is this:
Caused by: java.security.AccessControlException: access denied (org.apache.naming.JndiPermission jndi:/localhost/my_webapp/WEB-INF/internal/tika/tika-app-1.2.jar)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:374)
at java.security.AccessController.checkPermission(AccessController.java:546)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at java.net.URLClassLoader$4.run(URLClassLoader.java:515)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.getPermissions(URLClassLoader.java:513)
at java.security.SecureClassLoader.getProtectionDomain(SecureClassLoader.java:235)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at com.sample.myClass.afterPropertiesSet(TikaWrapper.java:38)
I guess my first question is: why?
If I add this to catalina.policy file then it works:
permission org.apache.naming.JndiPermission "jndi:/localhost/my_webapp/WEB-INF/internal/tika/tika-app-1.2.jar";
However, the client is not willing or can't change his policy file.
My second question is: any idea what to do? I can't put the jar under /WEB-INF/lib, otherwise I'd done it already. I can put it outside tomcat all together and load it with a file:// based URL, but I am trying to avoid it.
Upvotes: 2
Views: 576
Reputation: 804
As for your first question, there is a small note about class loading when running under a security manager in the documentation, citing it here for convenience:
When running under a security manager the locations from which classes are permitted to be loaded will also depend on the contents of your policy file.
So it appears that by default a webapp classloader is allowed to load classes from WEB-INF/lib and WEB-INF/classes directories only. In your case, it looks like you're assigning the webapp classloader as a parent to your custom classloader, and therefore the latter, same as its parent, is only able to load classes from WEB-INF/lib and WEB-INF/classes.
As for what to do, since client doesn't want or can't change the policy file, consider trying to change the policy programmatically. There is a good example here. However, it will only work if the current set of permissions allows to call java.security.Permission.setPolicy
() method, and I bet it doesn't because that would set a JVM-system wide policy.
Upvotes: 1