"Craig R. McClanahan" <[EMAIL PROTECTED]> writes:

> On Wed, 21 Nov 2001, Daniel Rall wrote:
>
>> Using Tomcat 4.0.1, is there any way to emulate JServ's
>> session.topleveldomain context configuration?
>>
>> # Set the domain= header that gets sent with the cookie. This is
>> # entirely optional
>> # Default: null
>> # this is needed when we vhost to avoid multiple login
>> session.topleveldomain=.foo.com
>>
>> I would like all requests to the set of virtual hosts represented by
>> the glob *.foo.com to share the same session ID.
>
> Unfortunately, implementing this functionality would violate the Servlet
> spec's requirements about sessions being scoped to a single
> ServletContext.  Even if you were willing to do this, you're going to run
> into lots of technical problems due to the fact that each webapp is loaded
> by it's own classloader -- trying to access a session attribute loaded
> from a different webapp will throw ClassNotFoundException errors at you.

I wasn't clear enough in my original query -- I don't want to scope
one session to multiple contexts, but to a single context accessed by
multiple host names which correspond to the same physical host (the
default host in server.xml).

So, if the DNS for both baz.foo.com and bar.foo.com resolves to the
same IP, a request to /myapp for baz.foo.com will create a session
with a JSESSIONID cookie domain of .foo.com, allowing requests to
bar.foo.com (or any other DNS mappings) to /myapp servlet context to
share the same HttpSession.

I took a stab at implementing this as a <Valve>, with some success.
My original thought was to groom the JSESSIONID cookies in the request
and response -- however, they never seem to show up (i.e. I never have
any cookies available from HttpRequest::getCookies() or
HttpResponse::getCookies()).  Perhaps I just attached the Valve at the
wrong spot (in the config file)?  Because I haven't been able to
access the JSESSIONID cookies, I end up getting a two cookies written
on the original request, one for the first host requested
(baz.foo.com), and another from my Valve for .foo.com (also from the
first request).  I get the desired result from this (unfortunately
with an extra cookie set for baz.foo.com), but am curious why I those
JSESSIONID cookies haven't turned up.

Any comments would be appreciated.

Dan


/*
 * $Header: $
 * $Revision: $
 * $Date: $
 *
 * ====================================================================
 *
 * 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 [EMAIL PROTECTED]
 *
 * 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.catalina.valves;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.catalina.Context;
import org.apache.catalina.Globals;
import org.apache.catalina.HttpRequest;
import org.apache.catalina.HttpResponse;
import org.apache.catalina.Request;
import org.apache.catalina.Response;
import org.apache.catalina.ValveContext;

/**
 * <p>Provides control over the domain set for the cookie used to
 * store the session identifier.</p>
 *
 * <p>This <code>Valve</code> may be attached to any
 * <code>Container</code>, depending on the granularity of the logging
 * you wish to perform.</p>
 *
 * @author <a href="mailto:[EMAIL PROTECTED]";>Daniel Rall</a>
 * @version $Revision: $
 */

public class SessionIdValve
    extends ValveBase {

    /**
     * Descriptive information about this <code>Valve</code>
     * implementation.
     */
    protected static String info =
        "org.apache.catalina.valves.SessionIdValve/1.0a";


    // ----------------------------------------------------- Instance Variables


    /**
     * The value to use for the <code>;Domain=</code> portion of the
     * cookie used to store the session identifier.
     */
    private String cookieDomain;


    // ------------------------------------------------------------- Properties


    /**
     * Gets the domain of the cookie used to store the session identifier.
     *
     * @return The cookie domain to use.
     */
    public String getCookieDomain() {

        return cookieDomain;

    }


    /**
     * Sets the domain of the cookie used to store the session identifier.
     *
     * @param cookieDomain The cookie domain to use.  If a value of
     * <code>null</code> is used, no domain is set for the cookie;
     * this causes the HTTP client to associate the cookie with the
     * domain the request was made of on its own.  Client behavior
     * differs -- Mozilla, for instance, sets the domain to the host
     * portion of the HTTP Host header.
     */
    public void setCookieDomain(String cookieDomain) {

        System.out.println("SessionIdValve: Setting cookieDomain to " +
                           cookieDomain);
        this.cookieDomain = cookieDomain;

    }


    /**
     * Return descriptive information about this Valve implementation.
     */
    public String getInfo() {

        return info;

    }


    // --------------------------------------------------------- Public Methods


    /**
     * Sets the domain for the cookie which is used to store the
     * session identifier.
     *
     * @see org.apache.catalina.Valve#invoke(Request, Response, ValveContext)
     */
    public void invoke(Request req, Response res, ValveContext context)
        throws IOException, ServletException {

        // Possibilities:

        // o request has no session id, response has session id (new
        // session)

        // o request has session id, response has session id
        // (established session)

        // o request has no session id, response has no session id (no
        // session yet established)

        // Only HTTP communications will have associated cookies.
        boolean isHttpRequest =
            (req instanceof HttpRequest && res instanceof HttpResponse);
        System.out.println("SessionIdValve: isHttpRequest=" + isHttpRequest);

        // HELP: Is the check of request session cookies necessary,
        // since we groom the response session cookies?
        Context resContext = res.getContext();
        if (resContext != null && resContext.getCookies() && isHttpRequest) {
            System.out.println("SessionIdValve: Checking request cookies");
            HttpServletRequest hreq = (HttpServletRequest) req.getRequest();
            modifyCookieDomain("request", hreq.getCookies());
        }

        context.invokeNext(req, res);

        resContext = res.getContext();
        if (resContext != null && resContext.getCookies() && isHttpRequest) {
            System.out.println("SessionIdValve: Checking response cookies");
            HttpServletRequest hreq = (HttpServletRequest) req.getRequest();
            HttpServletResponse hres = (HttpServletResponse) res.getResponse();

            // Add the session identifier cookie if a session exists
            // for the provided request.
            HttpSession session = hreq.getSession(false);

            if (session != null) {
                System.out.println("SessionIdValve: Session exists");
                if (session.isNew()) {
                    System.out.println("SessionIdValve: Session is new");
                    Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,
                                               session.getId());
                    cookie.setMaxAge(-1);
                    String contextPath = resContext.getPath();
                    if (contextPath == null || contextPath.length() == 0)
                        contextPath = "/";
                    cookie.setPath(contextPath);
                    if (hreq.isSecure())
                        cookie.setSecure(true);
                    cookie.setDomain(getCookieDomain());
                    System.out.println("SessionIdValve: Adding cookie " +
                                       cookie);
                    hres.addCookie(cookie);
                } else {
                    System.out.println("SessionIdValve: Session not new");
                    modifyCookieDomain("response",
                                       ((HttpResponse) res).getCookies());
                }
            }
        }

    }


    /**
     * Return a text representation of this object.
     */
    public String toString() {

        return ("SessionIdValve[container=" + container.getName() +
                "; domain=" + getCookieDomain() + ']');

    }


    /**
     * Modifies the domain for the provided cookies to the value of
     * {@link #getCookieDomain()}.
     *
     * @param commPhase The phase of communication whose data
     * structure is being modified (either <code>request</code> or
     * <code>response</code>.
     * @param cookies The <code>Cookie</code> objects to modify.
     */
    private void modifyCookieDomain(String commPhase, Cookie[] cookies) {

        System.out.println("SessionIdValve: Grooming " +
                           (cookies != null ? cookies.length : 0) +
                           " cookies");
        if (cookies != null && cookies.length > 0) {
            Cookie cookie;
            for (int i = 0; i < cookies.length; i++) {
                cookie = (Cookie) cookies[i];
                System.out.println("SessionIdValve: Cookie name is " +
                                   cookie.getName());
                if (Globals.SESSION_COOKIE_NAME.equals(cookie.getName())) {
                    /* HELP: How do I get access to debug and log()?
                    if (debug >= 1) {
                        log("Changing domain for " + commPhase + ' ' +
                            Globals.SESSION_COOKIE_NAME + " cookie from " +
                            cookie.getDomain() + " to " + cookieDomain);
                    }
                    */
                    System.out.println("SessionIdValve: Changing domain for " +
                                       commPhase + ' ' +
                                       Globals.SESSION_COOKIE_NAME +
                                       " cookie from " + cookie.getDomain() +
                                       " to " + cookieDomain);
                    cookie.setDomain(getCookieDomain());
                }
            }
        }

    }


}

--
To unsubscribe:   <mailto:[EMAIL PROTECTED]>
For additional commands: <mailto:[EMAIL PROTECTED]>
Troubles with the list: <mailto:[EMAIL PROTECTED]>

Reply via email to