Version 9

    The JAAS layer is independent of the container context in which is performing the authentication. This means a JAAS login module has no information like the servlet context, session or request. If you need to pass information from the authentication layer to the web app, this can be done using a thread local to pass info from the login module to a servlet filter or tomcat valve. The following FormAuthValve associates the j_username from a FORM auth post with the session under the attribute name j_username for use by form login/error pages. A related BasicAuthValve exists for BASIC authentication. If the includePassword attribute is true, the j_password value is also included in the session under the attribute name j_password (4.0.3+). In addition, it maps any authentication exception found in the SecurityAssociation thread local to the session attribute name j_exception.

     

    Note: Access to the exception does not work correctly due to how the tomcat form authenticator forwards the error page request. See the jboss ExtendedFormAuthenticator for a proper replacement to the ExtendedFormAuthenticator.

     

    /*
     * JBoss, Home of Professional Open Source
     *
     * Distributable under LGPL license.
     * See terms of license at gnu.org.
     */
    package org.jboss.web.tomcat.security;
    
    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpSession;
    
    import org.apache.catalina.connector.Request;
    import org.apache.catalina.connector.Response;
    import org.apache.catalina.valves.ValveBase;
    import org.jboss.logging.Logger;
    
    /** A valve that associates the j_username with the session under the attribute
     * name j_username for use by form login/error pages. If the includePassword
     * attribute is true, the j_password value is also included in the session
     * under the attribute name j_password. In addition, it maps any
     * authentication exception found in the SecurityAssociation to the session
     * attribute name j_exception.
     *  
     * @author Scott.Stark@jboss.org
     * @version $Revision: 1.4 $
     */
    public class FormAuthValve
       extends ValveBase
    {
       private static Logger log = Logger.getLogger(FormAuthValve.class);
       private static boolean trace = log.isTraceEnabled();
       private boolean includePassword;
    
       public boolean isIncludePassword()
       {
          return includePassword;
       }
       public void setIncludePassword(boolean includePassword)
       {
          this.includePassword = includePassword;
       }
    
       public void invoke(Request request, Response response)
          throws IOException, ServletException
       {
          String username = request.getParameter("j_username");
          HttpSession session = request.getSession(false);
          if( trace )
             log.trace("Enter, j_username="+username);
          if( session != null )
          {
             if( username != null )
                session.setAttribute("j_username", username);
             if( includePassword )
             {
                Object pass = request.getParameter("j_password");
                if( pass != null )
                   session.setAttribute("j_password", pass);
             }
          }
    
          getNext().invoke(request, response);
    
          username = request.getParameter("j_username");
          session = request.getSession(false);
          if( session != null )
          {
             if( trace )
               log.trace("SessionID: "+session.getId());
             if( username != null )
                session.setAttribute("j_username", username);
             // Check the SecurityAssociation context exception
             Throwable t = (Throwable) SecurityAssociationActions.getAuthException();
             if( trace )
               log.trace("SecurityAssociation.exception: "+t);
             if( t != null )
                session.setAttribute("j_exception", t);
          }
          if( trace )
             log.trace("Exit, username: "+username);
       }
    }
    

     

    This valve can be added to a web app using a WEB-INF/context.xml like:

    <!-- Add the FormAuthValve to get access to the exception -->
    <Context cookies="true" crossContext="true">
       <Valve className="org.jboss.web.tomcat.security.FormAuthValve"
          includePassword="true" ></Valve>
    </Context>
    

     

    An example form-error-page jsp page which display the request and session attributes is:

     

    <%@ page import="java.util.Enumeration,
                     java.io.StringWriter,
                     java.io.PrintWriter"%>
    <%@ page isErrorPage="true" %>
    
    <html>
    <h1>Request Attributes</h1>
    <ul>
    <%
       Enumeration names = request.getAttributeNames();
       while( names.hasMoreElements() )
       {
          String name = (String) names.nextElement();
          Object value = request.getAttribute(name);
          out.println("<li>Name:<b>"+name+"</b> = "+value+"</li>");
       }
    %>
    </ul>
    <h1>Session Attributes</h1>
    <ul>
    <%
       names = session.getAttributeNames();
       while( names.hasMoreElements() )
       {
          String name = (String) names.nextElement();
          Object value = session.getAttribute(name);
          out.println("<li>Name:<b>"+name+"</b> = "+value+"</li>");
       }
    %>
    </ul>
    <h1>Caller Trace</h1>
    <pre>
    <%
       Throwable t = new Throwable();
       PrintWriter pw = new PrintWriter(out);
       t.printStackTrace(pw);
       pw.flush();
    %>
    </pre>
    </html>
    

     

    Valves vs Filters

    A tomcat valve is a relatively deep integration with the web container. Is similar in concept to a standard servlet filter, but it has access to more internal tomcat information. The drawback to using valves is that they are specific to the tomcat web container. The benefit to using valves is that you have a great deal of ability to customize the tomcat web containers behavior. Valves can also influence security decisions before the declartive security checks have been performed.

     

    Servlet filters are called after any declarative security checks required by the web.xml settings. This means that a servlet filter cannot participate in FORM based authentication requests. The typical use of a filter in the context of security decisions is to either augment or replace the servlet declarative security model.