I'm using Tomcat 6.0.24, as packaged for Ubuntu Karmic. The default security policy of Ubuntu's Tomcat package is pretty stringent, but appears straightforward. In /var/lib/tomcat6/conf/policy.d
, there are a variety of files that establish default policy.
Worth noting at the start:
- I've not changed the stock tomcat install at all -- no new jars into its common lib directory(ies), no
server.xml
changes, etc. Putting the .war file in thewebapps
directory is the only deployment action. - the web application I'm deploying fails with thousands of access denials under this default policy (as reported to the log thanks to the
-Djava.security.debug="access,stack,failure"
system property). - turning off the security manager entirely results in no errors whatsoever, and proper app functionality
What I'd like to do is add an application-specific security policy file to the policy.d
directory, which seems to be the recommended practice. I added this to policy.d/100myapp.policy
(as a starting point -- I would like to eventually trim back the granted permissions to only what the app actually needs):
grant codeBase "file:${catalina.base}/webapps/ROOT.war" {
permission java.security.AllPermission;
};
grant codeBase "file:${catalina.base}/webapps/ROOT/-" {
permission java.security.AllPermission;
};
grant codeBase "file:${catalina.base}/webapps/ROOT/WEB-INF/-" {
permission java.security.AllPermission;
};
grant codeBase "file:${catalina.base}/webapps/ROOT/WEB-INF/lib/-" {
permission java.security.AllPermission;
};
grant codeBase "file:${catalina.base}/webapps/ROOT/WEB-INF/classes/-" {
permission java.security.AllPermission;
};
Note the thrashing around attempting to find the right codeBase
declaration. I think that's likely my fundamental problem.
Anyway, the above (really only the first two grants appear to have any effect) almost works: the thousands of access denials are gone, and I'm left with just one. Relevant stack trace:
java.security.AccessControlException: access denied (java.io.FilePermission /var/lib/tomcat6/webapps/ROOT/WEB-INF/classes/com/foo/some-file-here.txt read)
java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)
java.security.AccessController.checkPermission(AccessController.java:546)
java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
java.lang.SecurityManager.checkRead(SecurityManager.java:871)
java.io.File.exists(File.java:731)
org.apache.naming.resources.FileDirContext.file(FileDirContext.java:785)
org.apache.naming.resources.FileDirContext.lookup(FileDirContext.java:206)
org.apache.naming.resources.ProxyDirContext.lookup(ProxyDirContext.java:299)
org.apache.catalina.loader.WebappClassLoader.findResourceInternal(WebappClassLoader.java:1937)
org.apache.catalina.loader.WebappClassLoader.findResource(WebappClassLoader.java:973)
org.apache.catalina.loader.WebappClassLoader.getResource(WebappClassLoader.java:1108)
java.lang.ClassLoader.getResource(ClassLoader.java:973)
I'm pretty convinced that the actual file that's triggering the denial is irrelevant -- it's just some properties file that we check for optional configuration parameters. What's interesting is that:
- it doesn't exist in this context
- the fact that the file doesn't exist ends up throwing a security exception, rather than
java.io.File.exists()
simply returning false (although I suppose that's just a matter of the semantics of the read permission).
Another workaround (besides just disabling the security manager in tomcat) is to add an open-ended permission to my policy file:
grant {
permission java.security.AllPermission;
};
I presume this is functionally equivalent to turning off the security manager.
I suppose I must be getting the codeBase
declaration in my grants subtly wrong, but I'm not seeing it at the moment.