alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

package org.apache.tomcat.j2ee;

import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.tomcat.core.*;
import com.sun.web.server.*;

import com.sun.enterprise.util.JarClassLoader;

import java.net.URL;
import java.net.InetAddress;
import java.io.File;
import java.io.IOException;
import java.security.Principal;
import java.util.*;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.net.ssl.*;
import javax.security.cert.X509Certificate;

import com.sun.enterprise.util.*;
import com.sun.enterprise.*;
import com.sun.enterprise.security.*;
import com.sun.enterprise.security.acl.*;
import com.sun.enterprise.log.*;
import com.sun.enterprise.deployment.WebBundleDescriptor;

import org.apache.tomcat.deployment.*;
import org.apache.tomcat.util.*;

// depends on servlet 2.2
import org.apache.tomcat.facade.*;
import org.apache.tomcat.helper.*;

/**
 * Adapter for j2ee.
 * 
 * @author Harish Prabandham
 * @author Costin Manolache
 */
public class J2EEInterceptor extends BaseInterceptor {
    InvocationManagerImpl invM;
    private static LocalStringManagerImpl localStrings;
    private static ServerConfiguration config;
    
    private Hashtable accessLogs = new Hashtable();
    private Hashtable errorLogs = new Hashtable();
    private static final String HTTP_ACCESS_LOG = "web.access.log";
    private static final String HTTP_ERROR_LOG = "web.error.log";
    private static final int BUFFER_SIZE = 1024;

    int userNote;
    int passwordNote;
    // auth
    private static int MAX_COUNT = 5;
    private static int SLEEP_TIME = 5000; // milliseconds....

    public J2EEInterceptor() {
	this.invM= (InvocationManagerImpl) Switch.getSwitch().
	    getInvocationManager();
	config= ServerConfiguration.getConfiguration();
	// minimize the changes in j2ee ( temp, until properties are moved)
	localStrings = new
	    LocalStringManagerImpl(com.sun.web.security.DataConstraint.class);
    }

    public void engineInit( ContextManager cm ) throws TomcatException {
	super.engineInit(cm);
	userNote=cm.getNoteId( ContextManager.REQUEST_NOTE,
			       "credentials.user");
	passwordNote=cm.getNoteId( ContextManager.REQUEST_NOTE,
				   "credentials.password");

	debug=10;
    }
    
    public void contextInit( Context ctx)
	throws TomcatException
    {
    }

    public int preService(Request request, Response response) {
	Context ctx = request.getContext();
	Handler sw=request.getHandler();
	if( ! (sw instanceof ServletHandler) )
	    return 0;
	try {
	    invM.preServletInvoke( (ServletContext)ctx.getFacade(),
				   ((ServletHandler)sw).getServlet(), 
				   (HttpServletRequest)request.getFacade(),
				   (HttpServletResponse)response.getFacade() );
	} catch(Exception ex ) {
	    return -1;
	}
	return 0;
    }
    public int postService(Request request, Response response) {
	Context ctx = request.getContext();
	Handler sw=request.getHandler();
	if( ! (sw instanceof ServletHandler) )
	    return 0;
	try {
	    invM.postServletInvoke( (ServletContext)ctx.getFacade(),
				    ((ServletHandler)sw).getServlet(), 
				    (HttpServletRequest)request.getFacade(),
				    (HttpServletResponse)response.getFacade());
	    intLogRequest( request.getContext().getPath(),
			   request.requestURI().toString(),
			   null);
	} catch(Exception ex ) {
	    return -1;
	}
	return 0;
    }
    
    /** Servlet Init  notification
     */
    public void preServletInit( Context ctx, Handler sw )
	throws TomcatException
    {
	if( ! (sw instanceof ServletHandler) )
	    return;
	try {
	    invM.preInitInvoke( (ServletContext)ctx.getFacade(),
				((ServletHandler)sw).getServlet());
	} catch(Exception ex ) {
	    log("XXX " + invM + " " + ctx + " " + sw );
	    throw new TomcatException( "Error in j2ee adapter " , ex );
	}
    }

    
    public void postServletInit( Context ctx, Handler sw )
	throws TomcatException
    {
	if( ! (sw instanceof ServletHandler) )
	    return;
	try {
	    invM.postInitInvoke( (ServletContext)ctx.getFacade(),
				 ((ServletHandler)sw).getServlet());
	} catch(Exception ex ) {
	    throw new TomcatException( "Error in j2ee adapter " , ex );
	}
    }

    /** Servlet Destroy  notification
     */
    public void preServletDestroy( Context ctx, Handler sw )
	throws TomcatException
    {
	if( ! (sw instanceof ServletHandler) )
	    return;
	try {
	    if( sw != null && ctx != null )
		invM.preDestroyInvoke( (ServletContext)ctx.getFacade(),
				       ((ServletHandler)sw).getServlet());
	    else
		log("XXX J2EEInterceptor: sw, ctx=" +
				   sw + " " +ctx);
	} catch(Exception ex ) {
	    ex.printStackTrace();
	    throw new TomcatException( "Error in j2ee adapter " , ex );
	}
    }

    
    public void postServletDestroy( Context ctx, Handler sw )
	throws TomcatException
    {
	if( ! (sw instanceof ServletHandler) )
	    return;
	try {
	    if( sw != null && ctx != null )
		invM.postDestroyInvoke( (ServletContext)ctx.getFacade(),
					((ServletHandler)sw).getServlet());
	    else
		log("XXX J2EEInterceptor: sw, ctx=" +
				   sw + " " +ctx);
	} catch(Exception ex ) {
	    throw new TomcatException( "Error in j2ee adapter " , ex );
	}
    }

    // -------------------- Authentication hooks --------------------
    
    public int authenticate( Request req, Response res ) {
	Context ctx=req.getContext();
	
	// This realm will use only username and password callbacks
	String user=(String)req.getNote( userNote );
	String password=(String)req.getNote( passwordNote );;
	if( debug>0 ) log( "Try to auth " + user + " " + password);

	if( user==null || password == null ) {
	    // Need auth, but have no user/pass
	    return DECLINED;
	}
	byte authData[]=password.getBytes();
	
	String realm="default";  //ctx.getRealmName();
	String authM=null;// ctx.getAuthMethod();

	LoginContext lc = initLoginContext(realm);
	if( lc==null ) {
	    log("Authenticate - Can't get LoginContext....");
	    return DECLINED;
	}
	
	if(authM != null) 
	    lc.setAuthenticationMethod(authM);
	
	SecurityContext.setCurrent(null);

	try {
	    lc.login(user,authData);
	} catch (LoginException le) {
	    // Log the information here
	    // le.printStackTrace();
	    Log.err.println(le);
	    //le.printStackTrace();
	    log("Login failed for..: " + user);
	    return DECLINED; // or 401 ?
 	}

	if(debug>0) {
	    log("Login succeeded for..: " + user);
	}

	req.setRemoteUser( user );
	req.setUserPrincipal( getUserPrincipal() );

	return OK;
    }

    public int authorize( Request req, Response response, String roles[] )
    {
	if( roles==null || roles.length==0 ) {
	    return OK;
	}
	
	Context ctx=req.getContext();
	WebBundleDescriptor wbd = (WebBundleDescriptor) 
	    Switch.getSwitch().getDescriptorFor(ctx.getFacade());

	String appName="default";
	if(wbd != null)
	    appName=wbd.getApplication().getName();
	if( debug>0) log("appname=" + appName);

	// call back the authenticate hooks
	String user=req.getRemoteUser();
	if( user==null ) {
	    // Need auth, but have no user/pass
	    if( debug>0) log("no username");
	    return DECLINED;
	}
	String userRoles[]=null;

	String realm="default";  //ctx.getRealmName();

	Handler h=req.getHandler();
	ServletHandler sw=(ServletHandler)h;
	String mappedRole=null;
	String role=null;
	for( int i=0; i< roles.length ; i++ ) {
	    role=roles[i];
	    mappedRole=sw.getServletInfo().getSecurityRole( role );
	    if( mappedRole==null) mappedRole=role;
	    
	    if(isUserInRole(appName, mappedRole) ) {
		if( debug>0 ) log("Role match " +
				  roles[i] + " " +  mappedRole);
		return OK;
	    }
	    if( debug>0 ) log("Role match failed " +
			      roles[i] + " " + mappedRole);
	}
	
	if( debug>0  ) log("UnAuthorized " +
					role + " " + mappedRole);
 	return DECLINED;
	// XXX check transport
    }

    
    // -------------------- Security --------------------

    /*
      J2EE stores the security information in per/thread data
      ( SecurityContext). The web server will respect web.xml -
      including constraints, roles, auth methods.

      In order to access the J2EE realm it will use those methods.
      
      XXX This is based on how the current code works. It may be a
      good idea to make authenticate return the Principal or null,
      drop getUserPrincipal, and pass the Principal to isUserInRole.
      ( this avoids per/thread data - and it's more generic )
     */
      
    private LoginContext initLoginContext(String realm) {
	for(int i=0; i < MAX_COUNT; ++i) {
	    try {
		if (debug>0) log("Getting auth for:" + i);
		LoginContext lc= new LoginContext();
		lc.setRealmName(realm);
		return lc;
	    } catch(Exception e) {
		e.printStackTrace(Log.err);
		try { 
		    Thread.sleep(SLEEP_TIME); 
		}catch(InterruptedException ie) {
		}
	    }
	}
	return null;
    }

    /** Return the current user, as set by authenticate()
     */
    public Principal getUserPrincipal() {
	SecurityContext sc=SecurityContext.getCurrent();
	if( sc==null ) return null;
	return sc.getCallerPrincipal();
    }
    
    /** Check if the current user has the specified role.
     *  The user is set in the thread data.
     *
     *  It will be called with the role specified in web.xml/role-ref
     */
    public boolean isUserInRole(String appName, String rname) {
	RoleMapper rmap = RoleMapper.getRoleMapper( appName );

	if(debug>0) log("Mapping role " + rname + " " + rmap);
	if(rmap != null) {
	    for(Enumeration e =
		    rmap.getCurrentRoles(); e.hasMoreElements();) {
		Role r = (Role) e.nextElement();
		if( debug>0) log("Try " + r.getName());
		if(r.getName().equals(rname))
		    return true;
	    }
	}
	return false;
    }

    
    // -------------------- Logging implementation --------------------

    /* Very inefficient - we do a hashtable lookup per context.
       We could use context notes to speed up if needed.
    */
    
    private synchronized void intLogRequest(String ctxPath, String uri,
					    String respString ) {   
	Log accessLog = getAccessLog(ctxPath);
	accessLog.println(localStrings.
			  getLocalString( "web.security.request.on.at", 
					  "Request for  {0} on {1} at {2} ", 
					  new Object[] {uri,
							ctxPath,
							new Date() +
							"." + respString }));
	accessLog.flush();
    }


    private synchronized void intLogError(String ctxPath, String uri,
					  String respString)
    {
	Log errorLog = getErrorLog(ctxPath);
	errorLog.println("Error serving Request " + uri +
			 " on " + ctxPath + " at " +
			 new Date() + ". " + respString);
	errorLog.flush();
    }


    private synchronized Log getLog(String contextName, String propName,
				    String defaultValue) {
	try {
	    File dir = LogUtil.getLogDirectory(contextName, LogUtil.WEB_LOG);
	    String fname = config.getProperty(propName, defaultValue);
	    File logFile =  new File(dir, fname);
	    
	    if(!logFile.exists()) {
		logFile.createNewFile();
	    }

	    FileLogWriter fwriter = new FileLogWriter(logFile, BUFFER_SIZE);
	    return Log.getLog(fwriter);
	} catch(Exception e) {
	    e.printStackTrace();
	    Log.err.println(e);
	    return Log.err;
	}
    }

    private Log getAccessLog(String contextName) {
	Log aLog = (Log) accessLogs.get(contextName);
	if(aLog == null) {
	    aLog = getLog(contextName, HTTP_ACCESS_LOG, "access.log");
	    accessLogs.put(contextName, aLog);
	}
	
	return aLog;
    }

    private Log getErrorLog(String contextName) {
	Log aLog = (Log) errorLogs.get(contextName);
	if(aLog == null) {
	    aLog = getLog(contextName, HTTP_ERROR_LOG, "error.log");
	    errorLogs.put(contextName, aLog);
	}
	
	return aLog;
    }
}

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.