Bug 37882

Summary: ClassCircularityError when principal included in security policy
Product: Tomcat 5 Reporter: James Woods <james.woods>
Component: CatalinaAssignee: Tomcat Developers Mailing List <dev>
Status: RESOLVED WORKSFORME    
Severity: blocker Keywords: ErrorMessage
Priority: P1    
Version: 5.5.14   
Target Milestone: ---   
Hardware: All   
OS: All   

Description James Woods 2005-12-13 02:06:54 UTC
Symptoms:

If catalina.policy is changed to include grants that have any principals
specified (including wildcard principals "* *") then any web application that is
protected with a security constraint will cause a
java.lang.ClassCircularityError to be thrown when an attempt is made to log into it.

How to reproduce:

1. In the jsp-examples web application edit web.xml and comment out or delete
the following lines:

<servlet>
  <servlet-name>org.apache.jsp.security.protected_.index_jsp</servlet-name>
  <servlet-class>org.apache.jsp.security.protected_.index_jsp</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>org.apache.jsp.security.protected_.index_jsp</servlet-name>
  <url-pattern>/security/protected/index.jsp</url-pattern>
</servlet-mapping>

2. Add the following grant to catalina.policy:
  grant principal * * {
      permission java.util.PropertyPermission "*", "read";
  };

3. Start tomcat with the security manager enabled (-security).

4. Attempt to log into the jsp-examples protected application with the following
URL (modified to suit of course)
  http://<ip address>:<port>/jsp-examples/security/protected/index.jsp

You should then see the following exception:

java.lang.ClassCircularityError: WILDCARD_PRINCIPAL_CLASS
	java.lang.Class.forName0(Native Method)
	java.lang.Class.forName(Class.java:242)
	sun.security.provider.PolicyFile.addPermissions(PolicyFile.java:1403)
	sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1307)
	sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1270)
	sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1211)
	sun.security.provider.PolicyFile.implies(PolicyFile.java:1166)
	java.security.ProtectionDomain.implies(ProtectionDomain.java:195)
	java.security.AccessControlContext.checkPermission(AccessControlContext.java:249)
	java.security.AccessController.checkPermission(AccessController.java:427)
	java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
	java.lang.SecurityManager.checkRead(SecurityManager.java:871)
	java.io.File.exists(File.java:700)
	org.apache.naming.resources.FileDirContext.file(FileDirContext.java:826)
	org.apache.naming.resources.FileDirContext.lookup(FileDirContext.java:210)
	org.apache.naming.resources.ProxyDirContext.lookup(ProxyDirContext.java:293)
	org.apache.catalina.loader.WebappClassLoader.findResourceInternal(WebappClassLoader.java:1851)
	org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:1716)
	org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:866)
	org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1319)
	org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1198)
	java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
	java.lang.Class.forName0(Native Method)
	java.lang.Class.forName(Class.java:242)
	sun.security.provider.PolicyFile.addPermissions(PolicyFile.java:1403)
	sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1307)
	sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1270)
	sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1211)
	sun.security.provider.PolicyFile.implies(PolicyFile.java:1166)
	java.security.ProtectionDomain.implies(ProtectionDomain.java:195)
	java.security.AccessControlContext.checkPermission(AccessControlContext.java:249)
	java.security.AccessController.checkPermission(AccessController.java:427)
	java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
	java.lang.SecurityManager.checkPackageAccess(SecurityManager.java:1512)
	sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:265)
	java.lang.ClassLoader.loadClass(ClassLoader.java:299)
	java.lang.ClassLoader.loadClass(ClassLoader.java:251)
	java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
	org.apache.jasper.servlet.JspServletWrapper.<init>(JspServletWrapper.java:101)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:307)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:264)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
	sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	java.lang.reflect.Method.invoke(Method.java:585)
	org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:243)
	java.security.AccessController.doPrivileged(Native Method)
	javax.security.auth.Subject.doAsPrivileged(Subject.java:517)
	org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:275)
	org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:161)

Notes:

The same error will occur no matter what principal class you try. It looks like
the code is trying to load the principal class when refreshing the policy but
then checks its permission to load the class and trys to refresh the policy to
do that and then gets the ClassCircularityError.

Note that the error will not occur if you leave web.xml as it is. This is
obviously a point of some importance but the error was originally seen with our
web application that has all of its JSP's mapped to servlets in web.xml using
similar declarations created by JSPC so it doesn't appear that modifying web.xml
is going to help us in this regard.

This problem has been seen by other people. One of them proposed moving all
classes to the shared directory but this had no effect in our case. Here are
some references:

http://marc.theaimsgroup.com/?l=tomcat-user&m=108497966630946&w=2
http://mail-archives.apache.org/mod_mbox/jakarta-tomcat-user/200408.mbox/%3CBC6E0186-E532-11D8-B5E8-000A95B26EEC@suranyami.com%3E

Finally, as noted in the second reference, the problem doesn't seem to happen in
tomcat 5.0.19 (but then we have other problems, as well as having to go
backwards in tomcat revisions)
Comment 1 James Woods 2005-12-13 05:31:42 UTC
After comparing SecurityUtil.java in 5.0.19 to 5.0.28 it can be seen that in
5.0.19 the principal was not being associated with the subject. It seems likely
then that the reason that the ClassCircularityError did not appear under 5.0.19
was simply because the security check failed because the subject had no
principals and it was looking at a grant that had principals specified. In turn
this avoided the security code needing to load the principal class and hence no
ClassCircularityError.
Comment 2 James Woods 2005-12-13 22:33:53 UTC
In further investigation we built the 5.5.14 source and ran that instead. We
found that in this case that all secured applications (including the management
application) were affected by this error.
Comment 3 Yoav Shapira 2006-04-13 18:28:56 UTC
Suggested patch?
Comment 4 James Woods 2006-04-17 23:36:53 UTC
(In reply to comment #3)
> Suggested patch?

We've since written our own policy implementation that bypasses the Sun
implementation (we were going to do this anyway as we wanted to use a database
as our policy repository). Our hack to get around the ClassCircularityError is
to always grant java.io.FilePermission, java.lang.RuntimePermission
"accessClassInPackage", and java.lang.RuntimePermission "defineClassInPackage"
when the file or class in question relates to our Principal class. Not very
elegant I know but it works for us.

If we could get access to the Sun policy implementation source code we might be
able to work out why the error occurred in the first place.
Comment 5 maris 2006-09-14 08:38:23 UTC
any updates on this bug ... any patch rleased
Comment 6 Yoav Shapira 2006-12-24 19:41:49 UTC
maris, I would use James' workaround for now.  As he said, it might not be the
prettiest, but it works.  Since the bug appears to be in Sun's policy
implementation, you might want to check out their BugParade.