开发者

Tomcat - SSO Without Realm?

I'm trying to enable SSO under Tomcat such that users who go to http://mydomain.com and http://www.mydomain.com will have their session cookie available for requests made to http://subdomain.mydomain.com. All three of these domains go to the same 开发者_开发技巧webapp, so ideally I'd like to not mess with SSO at all and just set the domain on the standard JSESSIONID cookie.

However, that doesn't seem possible, so I'm trying to enable Tomcat's SSO Valve. The problem is that the Valve requires a definition of a Realm, and a Realm is supposed to specify a database of users and roles. However, I am not using container-based authentication nor role-based authorization, so I do not need or want to configure a Realm. All I want is for the session cookie(s) to be able to be shared across each of these different subdomains.

Is there any straightforward way to do this?

Edit

My current workaround for this is to have the server redirect every incoming request to the "canonical" server name. This works well enough, but obviously it is not actually solving the problem.


We were having the same problem and created a Tomcat Valve that would overwrite or set the Domain part of the session Cookie. Quite a simple thing and it already works for many years. The code goes like this:

public class CrossSubdomainSessionValve extends ValveBase {
  public CrossSubdomainSessionValve() {
    super();
    info = "common-tomcat-CrossSubdomainSessionValve";
  }

  @Override
  public void invoke(Request request, Response response) throws IOException, ServletException {
    // cookie will only need to be changed, if this session is created by this request.
    if (request.getSession(true).isNew()) {
      Cookie sessionCookie = findSessionCookie(response.getCookies());
      if (sessionCookie != null) {
        String cookieDomainToSet = getCookieDomainToSet(request.getServerName());
        if (cookieDomainToSet != null) {
          // changing the cookie only does not help, because tomcat immediately sets
          // a string representation of this cookie as MimeHeader, thus we also
          // have to change this representation
          replaceCookie(response.getCoyoteResponse().getMimeHeaders(), sessionCookie, cookieDomainToSet);
        }
      }
    }

    // process the next valve
    getNext().invoke(request, response);
  }

  protected Cookie findSessionCookie(Cookie[] cookies) {
    if (cookies != null)
      for (Cookie cookie : cookies)
        if (Globals.SESSION_COOKIE_NAME.equals(cookie.getName())) {
          return cookie;
    return null;
  }

  protected void replaceCookie(MimeHeaders headers, Cookie originalCookie, String domainToSet) {
    // if the response has already been committed, our replacementstrategy will have no effect

    // find the Set-Cookie header for the existing cookie and replace its value with new cookie
    for (int i = 0, size = headers.size(); i < size; i++) {
      if (headers.getName(i).equals("Set-Cookie")) {
        MessageBytes value = headers.getValue(i);
        if (value.indexOf(originalCookie.getName()) >= 0) {
          if (originalCookie.getDomain() == null) {
            StringBuilder builder = new StringBuilder(value.getString()).append("; Domain=").append(domainToSet);
            value.setString(builder.toString());
          } else {
            String newDomain = value.getString().replaceAll("Domain=[A-Za-z0-9.-]*", "Domain=" + domainToSet);
            value.setString(newDomain);
          }
        }
      }
    }
  }

  protected String getCookieDomainToSet(String cookieDomain) {
    String[] parts = cookieDomain.split("\\.");
    if (parts.length >= 3) {
      return "." + parts[parts.length - 2] + "." + parts[parts.length - 1];
    }
    return null;
  }

  public String toString() {
    return ("CrossSubdomainSessionValve[container=" + container.getName() + ']');
  }
}

The algorithm works like this: - Only if the session is new - find the session cookie - Get the requested host name - Split the host name with '.' - If it has at least 3 parts (like www.google.de), remove first part (to .google.de) - Reset the cookie

In your Context configuration you can apply the valve like this

<Valve className="my.package.CrossSubdomainSessionValve" httpOnlyEnabled="true" />

Caveat: In the code the Valve creates a session if no session was created before and does not care if you need a session at all...

Hope that helps... Good luck!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜