Now, there is a continuation of my story. Here is what I want to achieve: 

I want to run a cluster (say, hostnames node1 and node2) with apache2 + mod_jk 
loadballancer (hostname apache) with failover and loadballancing capabilities 
and SSO across multiple applications. There are two aplications, of which one 
is used much more often than the other, here is the detailed description I 
submitted to tomcat-dev:

anonymous wrote : 
  | Let's assume there are two applications /app1 and /app2, and there is a SSO 
  | setup on them both. Now, user logs into the /app1 (which requires 
  | authentication) and /app2 (which uses SSO Cookie, no authentication then), 
  | and later on makes use of only one of them (say: /app1) for quite a long 
  | time, so that this period outlives the session expiry date of the unused 
  | application (/app2). Provided that both applications establish their own 
  | sessions the one created in the scope of constantly used application 
  | (/app1) wouldn't expire, while the second one definitely would. 
  | 
  | Now the question: As both sessions are gathered into a higher-level SSO 
  | session, would it be against the specification if *all* standard sessions 
  | were aged (eg. by calling session.access()) on each request containing 
  | valid SSO cookie? I suggest that there should be a flag on the SSO Valve, 
  | that is org.apache.catalina.authenticator.SingleSignOn allowing users to 
  | specify the behaviour.
  | 

You can find the original discussion here:
http://www.mail-archive.com/tomcat-dev@jakarta.apache.org/msg74023.html

To achieve this I added a simple aging logic to the ClusteredSingleSignOn. The 
logic behind this is to age (call session.access()) all of the sessions that 
are federated under the incoming SSO, provided that the requested session ID is 
among them.  Here is how my invoke() method looks like now (I have stripped 
comments for brevity):


  | public void invoke(Request request, Response response, ValveContext context)
  |             throws IOException, ServletException {
  |     if (!(request instanceof HttpRequest)
  |                     || !(response instanceof HttpResponse)) {
  |             context.invokeNext(request, response);
  |             return;
  |     }
  |     HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
  |     HttpServletResponse hres = (HttpServletResponse) response.getResponse();
  |     request.removeNote(Constants.REQ_SSOID_NOTE);
  | 
  |     if (debug >= 1)
  |             log("Process request for '" + hreq.getRequestURI() + "'");
  |     if (hreq.getUserPrincipal() != null) {
  |             if (debug >= 1)
  |                     log(" Principal '" + hreq.getUserPrincipal().getName()
  |                                     + "' has already been authenticated");
  |             context.invokeNext(request, response);
  |             return;
  |     }
  | 
  |     if (debug >= 1)
  |             log(" Checking for SSO cookie");
  |     Cookie cookie = null;
  |     Cookie cookies[] = hreq.getCookies();
  |     if (cookies == null)
  |             cookies = new Cookie[0];
  |     for (int i = 0; i < cookies.length; i++) {
  |             if (Constants.SINGLE_SIGN_ON_COOKIE.equals(cookies.getName())) {
  |                     cookie = cookies;
  |                     break;
  |             }
  |     }
  |     if (cookie == null) {
  |             if (debug >= 1)
  |                     log(" SSO cookie is not present");
  |             context.invokeNext(request, response);
  |             return;
  |     }
  | 
  |     if (debug >= 1)
  |             log(" Checking for cached principal for " + cookie.getValue());
  |     SingleSignOnEntry entry = getSingleSignOnEntry(cookie.getValue());
  |     if (entry != null) {
  |             Principal ssoPrinc = entry.getPrincipal();
  |             if (debug >= 1) {
  |                     log(" Found cached principal '"
  |                             + (ssoPrinc == null ? "NULL" : 
ssoPrinc.getName())
  |                             + "' with auth type '" + entry.getAuthType() + 
"'");
  |             }
  |             request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue());
  |             if (!getRequireReauthentication() && ssoPrinc != null) {
  |                     ((HttpRequest) 
request).setAuthType(entry.getAuthType());
  |                     ((HttpRequest) request).setUserPrincipal(ssoPrinc);
  |             }
  | 
  |             if (keepaliveSessions) {
  | 
  |                     Session[] sessions = entry.findSessions();
  |                     String reqSessId = hreq.getRequestedSessionId();
  |                     if (debug >= 90) {
  |                             log("requested session id " + reqSessId);
  |                     }
  | 
  |                     boolean amongFlag = false;
  |                     if (reqSessId != null) {
  |                             for (int i = 0; i < sessions.length; i++) {
  |                                     Session session = sessions;
  |                                     if (session.getId().equals(reqSessId)) {
  |                                             amongFlag = true;
  |                                             if (debug >= 90) {
  |                                                     log("SSO contains 
requested sessid");
  |                                             }
  |                                             break;
  |                                     }
  |                             }
  |                     }
  | 
  |                     if (amongFlag) {
  | 
  |                             if (debug >= 1) {
  |                                     log("Keepalive " + sessions.length + " 
sessions");
  |                             }
  |                             for (int i = 0; i < sessions.length; i++) {
  |                                     Session session = sessions;
  |                                     session.access();
  |                                     if (debug >= 90) {
  |                                             log("Aged " + session.getId());
  |                                     }
  |                             }
  |                     }
  |             }
  | 
  |     } else {
  |             if (debug >= 1)
  |                     log(" No cached principal found, erasing SSO cookie");
  |             cookie.setMaxAge(0);
  |             hres.addCookie(cookie);
  |     }
  | 
  |     // Invoke the next Valve in our pipeline
  |     context.invokeNext(request, response);
  | }
  | 

Now what my setup looks like: there are two jbosses (config as described in 
earlier posts), each bound to one ip, and apache 2.0.54 + latest mod_jk with 
the following workers.properties - nuthin' unusual I suppose. LB works like a 
charm, but there are issues with replication


  | 
  | worker.node1.port=8009
  | worker.node1.host=node1
  | worker.node1.type=ajp13
  | worker.node1.socket_timeout=3
  | worker.node1.retries=3
  | worker.node1.socket_keepalive=120
  | worker.node1.recycle_timeout=240
  | worker.node1.lbfactor=1 
  | worker.node1.cachesize=1
  | worker.node1.cache_timeout=240
  | 
  | worker.node2.port=8009
  | worker.node2.host=node2
  | worker.node2.type=ajp13
  | worker.node2.socket_timeout=3
  | worker.node2.retries=3
  | worker.node2.socket_keepalive=120
  | worker.node2.recycle_timeout=240
  | worker.node2.lbfactor=1 
  | worker.node2.cachesize=1
  | worker.node2.cache_timeout=240
  | 
  | worker.loadbalancer.type=lb
  | worker.loadbalancer.balance_workers=node1,node2
  | worker.loadbalancer.sticky_session=true
  | worker.loadbalancer.sticky_session_force=false
  | 
  | worker.status.type=status
  | worker.list=loadbalancer,status
  | 

There are two applications /c1 and /c2. Here are the steps performed with the 
description of what happens:
1. /c1 is accessed for the first time, request is directed to node2
2. HTTP 401 is returned, user authenticates herself, another request is sent, 
new session is created, two Set-Cooke headers are sent in the response 
containing SSO session id an standard session id
3. So far, so good, using jmx-console I observe the appearance od SSO and 
JSESSIONID in the node2 TreeCache, the same applies to node1 cache, so the 
sessions (both standard and SSO) seem to replicate


  | /JSESSION
  | 
  | /c1
  | 
  | /rPa-0to9ouutQSCVeosCQA**
  | VERSION: 1
  | rPa-0to9ouutQSCVeosCQA**: [EMAIL PROTECTED]
  | 
  | /SSO
  | 
  | /87FFE0E5ACABC19049C5075B90364F2E
  | 
  | /credentials
  | key: [EMAIL PROTECTED]
  | 
  | /sessions
  | key: [rPa-0to9ouutQSCVeosCQA**.node2]
  | 

4. /c1 is accessed for the second time, request is paseed to node2 (as 
expected, we have a sticky session after all), my added logic kicks off and 
ages all the sessions under passed SSO, namely the one and only session there 
is, that is the session that was passed in along the second request. So far, 
everything is fine.
5. /c2 is accessed for the first. SSO cookie gets sent, but no session has been 
started yet. request gets passed to the node1 (we have a loadballancer after 
all). No Authentication required, as the appropriate SSO session is in place 
(in the replicated TreeCache on node1, that is)


  | /JSESSION
  | 
  | /c2
  | 
  | /XAcHQMEFfm8cb1mFUWF9Aw**
  | VERSION: 1
  | XAcHQMEFfm8cb1mFUWF9Aw**: [EMAIL PROTECTED]
  | 
  | /KNRsop2ihZVcuouXQ46IGw**
  | VERSION: 1
  | KNRsop2ihZVcuouXQ46IGw**: [EMAIL PROTECTED]
  | 
  | /c1
  | 
  | /rPa-0to9ouutQSCVeosCQA**
  | VERSION: 1
  | rPa-0to9ouutQSCVeosCQA**: [EMAIL PROTECTED]
  | 
  | /SSO
  | 
  | /87FFE0E5ACABC19049C5075B90364F2E
  | 
  | /credentials
  | key: [EMAIL PROTECTED]
  | 
  | /sessions
  | key: [rPa-0to9ouutQSCVeosCQA**.node2, KNRsop2ihZVcuouXQ46IGw**.node1, 
XAcHQMEFfm8cb1mFUWF9Aw**.node1]
  | 

6. another peek at the jmx-console on both nodes reveals that everything works 
as expected: the most recently created session gets replicated from node1 to 
node2, and SSO now is comprised of both sessions. Both nodes contain identical 
entries in the TreeCache.
7. another request to /c2 or /c2 reveals something strange - my aging logic 
should age all sessions in the particular SSO entry, but there seem to be only 
one session inserted in the SSO session (which is not consistent with what the 
jmx-console shows). when accessing /c1 only session originaly created on the 
first access to /c1 is aged. The same applies to /c2.

This behaviour doesn't seem to have much in common with my change, it must have 
already worked like that. My change just helped me reveal this.

Now, when one node goes down (I killed the proccess on node2) and I access the 
app wchich was originally served by node2, that is /c1, SSO automagically 
starts seeing all federated sessions and my aging algorithm starts working as 
expected, that is it has access to all sessions under the same SSO Session. 

Is it designed this way to reduce the replication overhead?
Is it possible to achieve aging this way?
What do you thing about my proposal of aging federated sessions (for the sake 
of the consistency, as operations on one session, namely invalidate(), *do* 
affect the rest of the sessions in the scope of the same SSO session)?

cheers,
/dd

View the original post : 
http://www.jboss.org/index.html?module=bb&op=viewtopic&p=3888625#3888625

Reply to the post : 
http://www.jboss.org/index.html?module=bb&op=posting&mode=reply&p=3888625


-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
JBoss-user mailing list
JBoss-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jboss-user

Reply via email to