You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by bu...@apache.org on 2002/03/12 16:10:24 UTC

DO NOT REPLY [Bug 7052] New: - Security manager not initialised or accessed properly

DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://nagoya.apache.org/bugzilla/show_bug.cgi?id=7052>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://nagoya.apache.org/bugzilla/show_bug.cgi?id=7052

Security manager not initialised or accessed properly

           Summary: Security manager not initialised or accessed properly
           Product: Tomcat 4
           Version: 4.0.3 Final
          Platform: PC
        OS/Version: Windows NT/2K
            Status: NEW
          Severity: Blocker
          Priority: Other
         Component: Jasper
        AssignedTo: tomcat-dev@jakarta.apache.org
        ReportedBy: keithhb@rolemodellers.com


OS: Win2K

JDK: 1.3.1_02

Stack Trace:

java.lang.NullPointerException
at 
org.apache.jasper.servlet.JasperLoader.loadClass(JasperLoader.java:180)
at 
org.apache.jasper.servlet.JasperLoader.loadClass(JasperLoader.java:132)
at 
java.lang.ClassLoader.loadClassInternal(Unknown Source)
at 
org.apache.jsp.RMStartRim$jsp._jspService(RMStartRim$jsp.java:114)
at 
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:107)
at 
javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
at 
org.apache.jasper.servlet.JspServlet$JspServletWrapper.service(JspServlet.java:202)
at 
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:382)
at 
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:474)
at 
javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:247)
at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
at 
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:243)
at 
org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:566)
at 
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:472)
at 
org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:943)
at 
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:190)
at 
org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:566)
at 
org.apache.catalina.valves.CertificatesValve.invoke(CertificatesValve.java:246)
at 
org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:564)
at 
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:472)
at 
org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:943)
at 
org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2343)
at 
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:180)
at 
org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:566)
at 
org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherValve.java:170)
at 
org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:564)
at 
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:170)
at 
org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:564)
at 
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:472)
at 
org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:943)
at 
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:174)
at 
org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:566)
at 
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:472)
at 
org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:943)
at 
org.apache.catalina.connector.http.HttpProcessor.process(HttpProcessor.java:1012)
at 
org.apache.catalina.connector.http.HttpProcessor.run(HttpProcessor.java:1107)
at 
java.lang.Thread.run(Unknown Source)
--------------------------------------------------------------------------------

Investigation:

I have had a problem 
running JSPs under Tomcat 4.x embedded in JBoss 2.4.4, which I believe stems from the 
initialisation of the "java.security.manager" system property.

When running Tomcat 
inside JBoss, the security manager property does not seem to be automatically initialised, 
perhaps because JBoss uses a different security model.  If you try to initialise the system 
property value yourself by specifying a security manager class name in the JBoss startup file 
command line, you get a weird error, which I have not been able to debug since it crashes the JBoss 
VM entirely.

Anyway, this would perhaps not matter to some people, who can get away without 
specifying a security manager directly in their own code.  However, I need to set one for the RMI 
calls in Jini, since I persist data via a JavaSpace.  Hence a part of my application 
initialisation is to set the system security manager.

Now, the Tomcat class loader object 
(an instance of org.apache.jasper.servlet.JasperLoader) is created before any web apps are 
loaded, and there seems to be a bug in this class.  The class loader object sets its security 
manager as a private variable "securityManager" in the constructor from the System property.  
This is before I get a chance inside my app to set the property, so the securityManager variable is 
null in the Tomcat class loader object.

During a JSP, Tomcat then decides whether to do 
security checks by checking whether or not the system property is null.  If you have set it to a 
value, as I do, Tomcat will try and do security checks.  But it doesn't use the system property to 
actually do the security check - it uses the private variable, which is still null!  Hence, 
whenever I try to use Java code in a JSP, Tomcat crashes with a NullPointerException, which is not 
caught.  See attached stack trace.

To get my JSPs running, I have patched 
org.apache.jasper.servlet.JasperLoader to set the private variable "securityManager" if 
it is null when about to do a security check, using the system property value.  It was necessary to 
do this in 3 places inside the class (see listing below).  I put my version in a jar and placed it in 
the folder %CATALINA_HOME%\common\lib.  Since this is earlier on the classpath than the jar 
from which the class is normally loaded, my version is used instead of the normal one, and the JSPs 
now run OK.

If there is a better way to initialise the security manager in Tomcat4.x when 
embedded in JBoss I would be very interested to hear of it, since it is obviously not ideal to be 
patching Tomcat in order to get an app to run!

Best wishes
Keith Harrison-
Broninski
keithhb@rolemodellers.com

/*
 * 
====================================================================
 * 
 * The 
Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software 
Foundation.  All rights 
 * reserved.
 *
 * Redistribution and use in source and binary forms, 
with or without
 * modification, are permitted provided that the following conditions
 * are 
met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this 
list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must 
reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer 
in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. 
The end-user documentation included with the redistribution, if
 *    any, must include the 
following acknowlegement:  
 *       "This product includes software developed by the 
 *        Apache 
Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may 
appear in the software itself,
 *    if and wherever such third-party acknowlegements normally 
appear.
 *
 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
 *    
Foundation" must not be used to endorse or promote products derived
 *    from this software 
without prior written permission. For written 
 *    permission, please contact 
apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 
*    nor may "Apache" appear in their names without prior written
 *    permission of the Apache 
Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, 
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A 
PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * 
ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON 
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING 
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
THE POSSIBILITY OF
 * SUCH DAMAGE.
 * 
====================================================================
 *
 * This 
software consists of voluntary contributions made by many
 * individuals on behalf of the 
Apache Software Foundation.  For more
 * information on the Apache Software Foundation, 
please see
 * <http://www.apache.org/>.
 *
 */ 

package 
org.apache.jasper.servlet;

import java.io.ByteArrayOutputStream;
import 
java.io.InputStream;
import java.io.IOException;
import java.net.URL;
import 
java.net.URLClassLoader;
import java.security.AccessController;
import 
java.security.CodeSource;
import java.security.PermissionCollection;
import 
java.security.PrivilegedAction;
import java.security.ProtectionDomain;

import 
org.apache.jasper.JasperException;
import org.apache.jasper.Constants;
import 
org.apache.jasper.JspCompilationContext;
import 
org.apache.jasper.JspEngineContext;
import org.apache.jasper.Options;
import 
org.apache.jasper.compiler.Compiler;

import 
org.apache.jasper.logging.Logger;
import javax.servlet.http.*;
/**
 * This is a 
class loader that loads JSP files as though they were
 * Java classes. It calls the compiler to 
compile the JSP file into a
 * servlet and then loads the generated class. 
 *
 * @author Anil K. 
Vijendran
 * @author Harish Prabandham
 */
public class JasperLoader extends 
URLClassLoader {

    protected class PrivilegedLoadClass
        implements PrivilegedAction 
{

        PrivilegedLoadClass() {
        }
         
        public Object run() {
            return 
Thread.currentThread().getContextClassLoader();
        }

    }

    private 
PermissionCollection permissionCollection = null;
    private CodeSource codeSource = 
null;
    private String className = null;
    private ClassLoader parent = null;
    private 
SecurityManager securityManager = null;
    private PrivilegedLoadClass privLoadClass = 
null;

    JasperLoader(URL [] urls, String className, ClassLoader parent,
		 
PermissionCollection permissionCollection,
		 CodeSource codeSource) 
{
	super(urls,parent);
	this.permissionCollection = 
permissionCollection;
	this.codeSource = codeSource;
	this.className = 
className;
	this.parent = parent;
        this.privLoadClass = new 
PrivilegedLoadClass();
	this.securityManager = System.getSecurityManager();
    }

    
/**
     * Load the class with the specified name.  This method searches for
     * classes in the same 
manner as <code>loadClass(String, boolean)</code>
     * with <code>false</code> as the 
second argument.
     *
     * @param name Name of the class to be loaded
     *
     * @exception 
ClassNotFoundException if the class was not found
     */
    public Class loadClass(String name) 
throws ClassNotFoundException {

        return (loadClass(name, false));

    }


    /**
     * 
Load the class with the specified name, searching using the following
     * algorithm until it 
finds and returns the class.  If the class cannot
     * be found, returns 
<code>ClassNotFoundException</code>.
     * <ul>
     * <li>Call 
<code>findLoadedClass(String)</code> to check if the
     *     class has already been loaded.  If it 
has, the same
     *     <code>Class</code> object is returned.</li>
     * <li>If the 
<code>delegate</code> property is set to <code>true</code>,
     *     call the 
<code>loadClass()</code> method of the parent class
     *     loader, if any.</li>            
     * <li>Call 
<code>findClass()</code> to find this class in our locally
     *     defined repositories.</li>      
     
* <li>Call the <code>loadClass()</code> method of our parent
     *     class loader, if any.</li>      
     
* </ul>
     * If the class was found using the above steps, and the
     * <code>resolve</code> flag is 
<code>true</code>, this method will then
     * call <code>resolveClass(Class)</code> on the 
resulting Class object.
     *                                     
     * @param name Name of the class to be loaded
     * @param resolve If 
<code>true</code> then resolve the class
     *                                     
     * @exception ClassNotFoundException if the 
class was not found
     */                                    
    public Class loadClass(String name, boolean resolve)
        throws 
ClassNotFoundException {

        Class clazz = null;                
                                           
        // (0) Check our previously loaded class 
cache
        clazz = findLoadedClass(name);     
        if (clazz != null) {               
            if (resolve)                   
                
resolveClass(clazz);       
            return (clazz);        
        }                          
                          
        // (.5) Permission to access this class when 
using a SecurityManager
	int dot = name.lastIndexOf('.');
        if 
(System.getSecurityManager() != null) {

			// Start of patch 1/3 by Keith Harrison-
Broninski
   		    if( securityManager == null ) {
				securityManager = 
System.getSecurityManager();
            }
			// End of patch 1/3 by Keith Harrison-Broninski

            if 
(dot >= 0) {
                try {                    
                    securityManager.checkPackageAccess(name.substring(0,dot));
                } 
catch (SecurityException se) {
                    String error = "Security Violation, attempt to use " +
                        
"Restricted Class: " + name;
                    System.out.println(error);
                    throw new 
ClassNotFoundException(error);
                }                          
            }                              
        }

	// Class is in a package, delegate to thread 
context class loader
	if( !name.startsWith(Constants.JSP_PACKAGE_NAME) ) 
{
		ClassLoader classLoader = null;
	    if (System.getSecurityManager() != null) 
{

			// Start of patch 2/3 by Keith Harrison-Broninski
   		    if( securityManager == null ) 
{
				securityManager = System.getSecurityManager();
            }
			// End of patch 2/3 by Keith 
Harrison-Broninski

		   	classLoader = (ClassLoader) 
AccessController.doPrivileged(privLoadClass);
        } else {
	        classLoader = 
Thread.currentThread().getContextClassLoader();
        }
        clazz = 
classLoader.loadClass(name);
	    if( resolve )
			resolveClass(clazz);
	    return 
clazz;
	}

	// Only load classes for this JSP page
	if( 
name.startsWith(Constants.JSP_PACKAGE_NAME + "." + className) ) {
	    String classFile = 
name.substring(Constants.JSP_PACKAGE_NAME.length()+1) +
		".class";
	    byte [] cdata 
= loadClassDataFromFile(classFile);
	    if( cdata == null )
		throw new 
ClassNotFoundException(name);
	    if( System.getSecurityManager() != null ) {
		
			// 
Start of patch 3/3 by Keith Harrison-Broninski
		    if( securityManager == null ) 
{
				securityManager = System.getSecurityManager();
            }
			// End of patch 3/3 by Keith 
Harrison-Broninski

			ProtectionDomain pd = new 
ProtectionDomain(
				codeSource,
                permissionCollection);
			clazz = 
defineClass(name,cdata,0,cdata.length,pd);
	    } else {
			clazz = 
defineClass(name,cdata,0,cdata.length);
	    }
	    if( clazz != null ) {
		if( resolve )                
		    
resolveClass(clazz);
		return clazz;
	    }
	}

	throw new 
ClassNotFoundException(name);
    }

    /**
     * Get the Permissions for a CodeSource.
     *
     * 
Since this ClassLoader is only used for a JSP page in
     * a web application context, we just return 
our preset
     * PermissionCollection for the web app context.
     *
     * @param CodeSource where 
the code was loaded from
     * @return PermissionCollection for CodeSource
     */
    protected 
final PermissionCollection getPermissions(CodeSource codeSource) {
        return 
permissionCollection;
    }


    /**
     * Load JSP class data from file.
     */
    protected 
byte[] loadClassDataFromFile(String fileName) {
        byte[] classBytes = null;
        try {
            
InputStream in = getResourceAsStream(fileName);
            if (in == null) {
		return null;
	    }
            
ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte buf[] = new byte[1024];
            
for(int i = 0; (i = in.read(buf)) != -1; )
                baos.write(buf, 0, i);
            in.close();     
            
baos.close();    
            classBytes = baos.toByteArray();
        } catch(Exception ex) {
	    
ex.printStackTrace();
            return null;     
        }                    
        return classBytes;
    }

}

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>