Using tapestry 4.0 with java 2 security enabled prevents the application from 
starting on several application servers (solution proposed)
-----------------------------------------------------------------------------------------------------------------------------------------

                 Key: HIVEMIND-192
                 URL: http://issues.apache.org/jira/browse/HIVEMIND-192
             Project: HiveMind
          Issue Type: Bug
    Affects Versions: 1.1
         Environment: java version 1.4.1_07 , apache tomcat server, 5.0  IBM 
Websphere server 5.0
            Reporter: lionel gomez


problem: Using tapestry 4.0 with java 2 security enabled on several application 
servers prevents the application from starting 

Cause: 
The SecurityManager do security checks for sensitive operation based on context 
of the current execution thread and its execution stack. The 
AccessControlContext obtains a stack of ProtectionDomains of all objects in the 
execution stack and checks if all these ProtectionDomain have all the permision 
required to perform the operation. 

Tapestry/Hivemind uses javassist library to create enhaced pages and components 
using bytecode manipulation and generates a ctClass object, then use 
HivemindPool wich ends up in a call to ClassPool.toClass(CtClass). 
Javassist uses reflection to make a call to ClassLoader.defineClass(String 
name, byte[] b, int off, int len) wich generates an object with a default 
ProtectionDomain. So pages and componentes will have the default 
ProtectionDomain. 

copied from java API: 
This method assigns a default ProtectionDomain to the newly defined class. The 
ProtectionDomain is effectively granted the same set of permissions returned 
when Policy.getPolicy().getPermissions(new CodeSource(null, null)) is invoked. 

When the AccessControlContext do the security checks on the ProtectionDomain of 
these enhaced classes it fails to find the required permisions, because they 
dont have any permision (or protectiondomain is null cant remember for sure any 
way fails to find required permisions). 

The solution is to instead use the method ClassLoader.defineClass(String name, 
byte[] b, int off, int len, ProtectionDomain protectionDomain) this way we can 
assign a ProtectionDomain that has the defined permisions in the policy. 

So this is really a javassist problem not a Tapestry/Hivemind problem. 

But fixing this in javassist is not easy. The ctClass class deal with bytecode 
manipulation only, and the ProtectionDomain is a responsability of the 
ClassLoader. Should javassist also take over the ClassLoader responsibility of 
assigning ProtectionDomains and get the assigned permisions from policy. What 
ProtectionDomain should a new set of bytecode have if made with makeClass() ? 

Until javassist solves this in another realease and this realease is included 
in another tapestry release, a solution is to modify the class HivemindPool. We 
have used this and work fine. it works without modifying javassist. 

Proposed Solution: 
1. Modifyng the HivemindClassPool class to assign the ProtectionDomain of the 
classloader or the HivemindClassPool to all the enhanced classes. 
2. Rebuild the hivemind.jar 
3. Modify the security policy file that grants the required permision for the 
application. (start by granting all permisions to test and then replace with 
the fine grained ones) 

This makes all enhaced class to have a ProtectionDomain with permisions granted 
on the policy file. Non enhaced classes will still have the fine grained 
permisions specified in the policy file, but enhaced class will have the same 
permision granted to the HivemindClassPool. 


In file org.apache.hivemind.service.impl.HiveMindClassPool replace the 
following : 

 public Class toClass(CtClass ctClass) throws CannotCompileException 
    { 
       return ctClass.toClass(_loader); 
    } 

with the following: 
It uses the other method of ClassLoader and pass the ProtectionDomain of the 
HivemindClassPool. 

 public Class toClass(CtClass ctClass) throws CannotCompileException 
    { 
return toClass(ctClass, _loader); 
    } 

     
    public Class toClass(CtClass ct, ClassLoader loader) 
    throws CannotCompileException 
{ 
    try { 
        byte[] b = ct.toBytecode(); 
        Class cl = Class.forName("java.lang.ClassLoader"); 
        java.lang.reflect.Method method = 
            cl.getDeclaredMethod("defineClass", 
                            new Class[] { String.class, byte[].class, 
                                          int.class, int.class, 
ProtectionDomain.class }); 
        method.setAccessible(true); 
        Object[] args = new Object[] { ct.getName(), b, new Integer(0), 
                                       new Integer(b.length), 
this.getClass().getProtectionDomain()}; 
        Class clazz = (Class)method.invoke(loader, args); 
        method.setAccessible(false); 
        return clazz; 
    } 
    catch (RuntimeException e) { 
        throw e; 
    } 
    catch (java.lang.reflect.InvocationTargetException e) { 
        throw new CannotCompileException(e.getTargetException()); 
    } 
    catch (Exception e) { 
        throw new CannotCompileException(e); 
    } 
}


-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: 
http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

Reply via email to