KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > web > tomcat > tc5 > sso > ClusteredSingleSignOn


1 /*
2  * JBoss, the OpenSource WebOS
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7 package org.jboss.web.tomcat.tc5.sso;
8
9
10 import org.jboss.web.tomcat.tc5.Tomcat5;
11
12 import java.io.IOException JavaDoc;
13 import java.security.Principal JavaDoc;
14
15 import javax.servlet.ServletException JavaDoc;
16 import javax.servlet.http.Cookie JavaDoc;
17
18 import org.apache.catalina.LifecycleException;
19 import org.apache.catalina.Session;
20 import org.apache.catalina.Realm;
21 import org.apache.catalina.SessionEvent;
22 import org.apache.catalina.authenticator.Constants;
23 import org.apache.catalina.connector.Request;
24 import org.apache.catalina.connector.Response;
25
26
27 /**
28  * A <strong>Valve</strong> that supports a "single sign on" user experience,
29  * where the security identity of a user who successfully authenticates to one
30  * web application is propogated to other web applications in the same
31  * security domain. For successful use, the following requirements must
32  * be met:
33  * <ul>
34  * <li>This Valve must be configured on the Container that represents a
35  * virtual host (typically an implementation of <code>Host</code>).</li>
36  * <li>The <code>Realm</code> that contains the shared user and role
37  * information must be configured on the same Container (or a higher
38  * one), and not overridden at the web application level.</li>
39  * <li>The web applications themselves must use one of the standard
40  * Authenticators found in the
41  * <code>org.apache.catalina.authenticator</code> package.</li>
42  * </ul>
43  *
44  * @author Brian E. Stansberry based on the work of Craig R. McClanahan
45  * @version $Revision: 1.4.2.1 $ $Date: 2005/01/28 12:30:49 $
46  */

47 public class ClusteredSingleSignOn
48    extends org.apache.catalina.authenticator.SingleSignOn
49 {
50
51    // Override the superclass value
52
static
53    {
54       info = ClusteredSingleSignOn.class.getName();
55    }
56     
57    // ----------------------------------------------------- Instance Variables
58

59  
60    /**
61     * Fully qualified name of a class implementing
62     * {@link SSOClusterManager SSOClusterManager} that will be used
63     * to manage SSOs across a cluster.
64     */

65    private String JavaDoc clusterManagerClass =
66       TreeCacheSSOClusterManager.class.getName();
67
68    /**
69     * Object used to provide cross-cluster support for single sign on.
70     */

71    private SSOClusterManager ssoClusterManager = null;
72
73    /**
74     * Object name of the tree cache used by SSOClusterManager.
75     * Only relevant if the SSOClusterManager implementation is
76     * TreeCacheSSOClusterManager.
77     */

78    private String JavaDoc treeCacheName = Tomcat5.DEFAULT_CACHE_NAME;
79
80    // ------------------------------------------------------------- Properties
81

82    /**
83     * Gets the object that provides SSO support across a cluster.
84     *
85     * @return the object provided cluster support, or <code>null</code> if
86     * no such object has been configured.
87     */

88    public SSOClusterManager getClusterManager()
89    {
90       return this.ssoClusterManager;
91    }
92
93
94    /**
95     * Sets the object that provides SSO support across a cluster.
96     *
97     * @param clusterManager the object that provides SSO support.
98     * @throws IllegalStateException if this method is invoked after this valve
99     * has been started.
100     */

101    public void setClusterManager(SSOClusterManager clusterManager)
102    {
103       if (started && (clusterManager != ssoClusterManager))
104       {
105          throw new IllegalStateException JavaDoc("already started -- cannot set a " +
106             "new SSOClusterManager");
107       }
108
109       this.ssoClusterManager = clusterManager;
110
111       if (clusterManager != null)
112       {
113          clusterManagerClass = clusterManager.getClass().getName();
114       }
115    }
116
117
118    /**
119     * Gets the name of the class that will be used to provide SSO support
120     * across a cluster.
121     *
122     * @return Fully qualified name of a class implementing
123     * {@link SSOClusterManager SSOClusterManager}
124     * that is being used to manage SSOs across a cluster.
125     * May return <code>null</code> (the default) if clustered
126     * SSO support is not configured.
127     */

128    public String JavaDoc getClusterManagerClass()
129    {
130       return clusterManagerClass;
131    }
132
133
134    /**
135     * Sets the name of the class that will be used to provide SSO support
136     * across a cluster.
137     * <p><b>NOTE: </b>
138     * If this Valve has already started, and no SSOClusterManager has been
139     * configured for it, calling this method will
140     *
141     * @param managerClass Fully qualified name of a class implementing
142     * {@link SSOClusterManager SSOClusterManager}
143     * that will be used to manage SSOs across a cluster.
144     * Class must declare a public no-arguments
145     * constructor. <code>null</code> is allowed.
146     */

147    public void setClusterManagerClass(String JavaDoc managerClass)
148    {
149       if (!started)
150       {
151          clusterManagerClass = managerClass;
152       }
153       else if (ssoClusterManager == null)
154       {
155          try
156          {
157             createClusterManager(managerClass);
158          }
159          catch (LifecycleException e)
160          {
161             getContainer().getLogger().error("Exception creating SSOClusterManager " +
162                managerClass, e);
163          }
164       }
165       else
166       {
167           getContainer().getLogger().error("Cannot set clusterManagerClass to " + managerClass +
168             "; already started using " + clusterManagerClass);
169       }
170    }
171
172    /**
173     * Object name of the tree cache used by SSOClusterManager.
174     * Only relevant if the SSOClusterManager implementation is
175     * TreeCacheSSOClusterManager.
176     */

177    public String JavaDoc getTreeCacheName()
178    {
179       return treeCacheName;
180    }
181
182    /**
183     * Sets the object name of the tree cache used by SSOClusterManager.
184     * Only relevant if the SSOClusterManager implementation is
185     * TreeCacheSSOClusterManager.
186     */

187    public void setTreeCacheName(String JavaDoc cacheName)
188       throws Exception JavaDoc
189    {
190       this.treeCacheName = cacheName;
191       if (ssoClusterManager != null
192          && ssoClusterManager instanceof TreeCacheSSOClusterManager)
193       {
194          ((TreeCacheSSOClusterManager) ssoClusterManager).setCacheName(cacheName);
195       }
196    }
197
198
199    // ------------------------------------------------------ Lifecycle Methods
200

201
202    /**
203     * Prepare for the beginning of active use of the public methods of this
204     * component. This method should be called after <code>configure()</code>,
205     * and before any of the public methods of the component are utilized.
206     *
207     * @throws LifecycleException if this component detects a fatal error
208     * that prevents this component from being used
209     */

210    public void start() throws LifecycleException
211    {
212       // Validate and update our current component state
213
if (started)
214       {
215          throw new LifecycleException
216             (sm.getString("authenticator.alreadyStarted"));
217       }
218
219       // Attempt to create an SSOClusterManager
220
createClusterManager(getClusterManagerClass());
221
222       lifecycle.fireLifecycleEvent(START_EVENT, null);
223       started = true;
224
225       if (ssoClusterManager != null)
226       {
227          ssoClusterManager.start();
228       }
229
230    }
231
232
233    /**
234     * Gracefully terminate the active use of the public methods of this
235     * component. This method should be the last one called on a given
236     * instance of this component.
237     *
238     * @throws LifecycleException if this component detects a fatal error
239     * that needs to be reported
240     */

241    public void stop() throws LifecycleException
242    {
243       // Validate and update our current component state
244
if (!started)
245       {
246          throw new LifecycleException
247             (sm.getString("authenticator.notStarted"));
248       }
249
250       if (ssoClusterManager != null)
251       {
252          ssoClusterManager.stop();
253       }
254
255       lifecycle.fireLifecycleEvent(STOP_EVENT, null);
256       started = false;
257
258    }
259
260
261    // ------------------------------------------------ SessionListener Methods
262

263
264    /**
265     * Updates the state of a single sign on session to reflect the destruction
266     * of a standard HTTP session.
267     * <p/>
268     * If the given event is a {@link Session#SESSION_DESTROYED_EVENT
269     * Session destroyed event}, checks whether the session was destroyed due
270     * to timeout or user action (i.e. logout). If due to timeout, disassociates
271     * the Session from the single sign on session. If due to logout, invokes
272     * the {@link #logout} method.
273     *
274     * @param event SessionEvent that has occurred
275     */

276    public void sessionEvent(SessionEvent event)
277    {
278       // We only care about session destroyed events
279
if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType()))
280          return;
281
282       // Look up the single session id associated with this session (if any)
283
Session session = event.getSession();
284       if (getContainer().getLogger().isDebugEnabled())
285           getContainer().getLogger().debug("Process session destroyed on " + session);
286
287       String JavaDoc ssoId = null;
288       synchronized (reverse)
289       {
290          ssoId = (String JavaDoc) reverse.get(session);
291       }
292       if (ssoId == null)
293          return;
294
295       // Was the session destroyed as the result of a timeout?
296
// If so, we'll just remove the expired session from the
297
// SSO. If the session was logged out, we'll log out
298
// of all sessions associated with the SSO.
299
if ((session.getMaxInactiveInterval() > 0)
300          && (System.currentTimeMillis() - session.getLastAccessedTime() >=
301          session.getMaxInactiveInterval() * 1000))
302       {
303          removeSession(ssoId, session);
304       }
305       else
306       {
307          // The session was logged out.
308
logout(ssoId);
309       }
310
311    }
312
313
314    // ---------------------------------------------------------- Valve Methods
315

316
317    /**
318     * Perform single-sign-on support processing for this request.
319     * <p/>
320     * Overrides the superclass version by handling the fact that a
321     * single sign on may have been originated on another cluster node and
322     * thus may not have a <code>Principal</code> object associated with it
323     * on this node.
324     *
325     * @param request The servlet request we are processing
326     * @param response The servlet response we are creating
327     * @param context The valve context used to invoke the next valve
328     * in the current processing pipeline
329     * @throws IOException if an input/output error occurs
330     * @throws ServletException if a servlet error occurs
331     */

332    public void invoke(Request request, Response response)
333       throws IOException JavaDoc, ServletException JavaDoc
334    {
335       request.removeNote(Constants.REQ_SSOID_NOTE);
336
337       // Has a valid user already been authenticated?
338
if (getContainer().getLogger().isDebugEnabled())
339          getContainer().getLogger().debug("Process request for '" + request.getRequestURI() + "'");
340       if (request.getUserPrincipal() != null)
341       {
342          if (getContainer().getLogger().isDebugEnabled())
343             getContainer().getLogger().debug(" Principal '" + request.getUserPrincipal().getName() +
344                "' has already been authenticated");
345          getNext().invoke(request, response);
346          return;
347       }
348
349       // Check for the single sign on cookie
350
Cookie JavaDoc cookie = null;
351       Cookie JavaDoc cookies[] = request.getCookies();
352       if (cookies == null)
353          cookies = new Cookie JavaDoc[0];
354       for (int i = 0; i < cookies.length; i++)
355       {
356          if (Constants.SINGLE_SIGN_ON_COOKIE.equals(cookies[i].getName()))
357          {
358             cookie = cookies[i];
359             break;
360          }
361       }
362       if (cookie == null)
363       {
364          if (getContainer().getLogger().isDebugEnabled())
365             getContainer().getLogger().debug(" SSO cookie is not present");
366          getNext().invoke(request, response);
367          return;
368       }
369
370       // Look up the cached Principal associated with this cookie value
371
if (getContainer().getLogger().isDebugEnabled())
372           getContainer().getLogger().debug(" Checking for cached principal for " + cookie.getValue());
373       SingleSignOnEntry entry = getSingleSignOnEntry(cookie.getValue());
374       if (entry != null)
375       {
376          Principal JavaDoc ssoPrinc = entry.getPrincipal();
377          // have to deal with the fact that the entry may not have an
378
// associated Principal. SSO entries retrieved via a lookup from a
379
// cluster will not have a Principal, as Principal is not Serializable
380
if (getContainer().getLogger().isDebugEnabled())
381          {
382              getContainer().getLogger().debug(" Found cached principal '" +
383                (ssoPrinc == null ? "NULL" : ssoPrinc.getName()) +
384                "' with auth type '" + entry.getAuthType() + "'");
385          }
386          request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue());
387          // Only set security elements if per-request reauthentication is
388
// not required AND the SSO entry had a Principal.
389
if (!getRequireReauthentication() && ssoPrinc != null)
390          {
391             request.setAuthType(entry.getAuthType());
392             request.setUserPrincipal(ssoPrinc);
393          }
394       }
395       else
396       {
397          if (getContainer().getLogger().isDebugEnabled())
398             getContainer().getLogger().debug(" No cached principal found, erasing SSO cookie");
399          cookie.setMaxAge(0);
400          response.addCookie(cookie);
401       }
402
403       // Invoke the next Valve in our pipeline
404
getNext().invoke(request, response);
405    }
406
407
408    // ------------------------------------------------------ Protected Methods
409

410
411    /**
412     * Associate the specified single sign on identifier with the
413     * specified Session.
414     * <p/>
415     * Differs from the superclass version in that it notifies the cluster
416     * of any new association of SSO and Session.
417     *
418     * @param ssoId Single sign on identifier
419     * @param session Session to be associated
420     */

421    protected void associate(String JavaDoc ssoId, Session session)
422    {
423       if (getContainer().getLogger().isDebugEnabled())
424           getContainer().getLogger().debug("Associate sso id " + ssoId + " with session " + session);
425
426       SingleSignOnEntry sso = getSingleSignOnEntry(ssoId);
427       boolean added = false;
428       if (sso != null)
429          added = sso.addSession(this, session);
430
431       synchronized (reverse)
432       {
433          reverse.put(session, ssoId);
434       }
435
436       // If we made a change, notify any cluster
437
if (added && ssoClusterManager != null)
438          ssoClusterManager.addSession(ssoId, session);
439    }
440
441
442    /**
443     * Deregister the specified session. If it is the last session,
444     * then also get rid of the single sign on identifier.
445     * <p/>
446     * Differs from the superclass version in that it notifies the cluster
447     * of any disassociation of SSO and Session.
448     *
449     * @param ssoId Single sign on identifier
450     * @param session Session to be deregistered
451     */

452    protected void deregister(String JavaDoc ssoId, Session session)
453    {
454       synchronized (reverse)
455       {
456          reverse.remove(session);
457       }
458
459       SingleSignOnEntry sso = getSingleSignOnEntry(ssoId);
460       if (sso == null)
461          return;
462
463       boolean removed = sso.removeSession(session);
464       // If we changed anything, notify any cluster
465
if (removed && ssoClusterManager != null)
466       {
467          ssoClusterManager.removeSession(ssoId, session);
468       }
469
470       // see if this was the last session on this node,
471
// if remove sso entry from our local cache
472
if (sso.getSessionCount() == 0)
473       {
474          synchronized (cache)
475          {
476             sso = (SingleSignOnEntry) cache.remove(ssoId);
477          }
478       }
479    }
480
481
482    /**
483     * Deregister the specified single sign on identifier, and invalidate
484     * any associated sessions.
485     *
486     * @param ssoId Single sign on identifier to deregister
487     */

488    protected void deregister(String JavaDoc ssoId)
489    {
490       if (getContainer().getLogger().isDebugEnabled())
491           getContainer().getLogger().debug("Deregistering sso id '" + ssoId + "'");
492
493       // Look up and remove the corresponding SingleSignOnEntry
494
SingleSignOnEntry sso = null;
495       synchronized (cache)
496       {
497          sso = (SingleSignOnEntry) cache.remove(ssoId);
498       }
499
500       if (sso == null)
501          return;
502
503       // Expire any associated sessions
504
Session sessions[] = sso.findSessions();
505       for (int i = 0; i < sessions.length; i++)
506       {
507          if (getContainer().getLogger().isTraceEnabled())
508              getContainer().getLogger().trace(" Invalidating session " + sessions[i]);
509          // Remove from reverse cache first to avoid recursion
510
synchronized (reverse)
511          {
512             reverse.remove(sessions[i]);
513          }
514          // Invalidate this session
515
sessions[i].expire();
516       }
517
518       // NOTE: Clients may still possess the old single sign on cookie,
519
// but it will be removed on the next request since it is no longer
520
// in the cache
521
}
522
523
524    /**
525     * Deregister the given SSO, invalidating any associated sessions, then
526     * notify any cluster of the logout.
527     *
528     * @param ssoId the id of the SSO session
529     */

530    protected void logout(String JavaDoc ssoId)
531    {
532       deregister(ssoId);
533       // broadcast logout to any cluster
534
if (ssoClusterManager != null)
535          ssoClusterManager.logout(ssoId);
536    }
537
538
539    /**
540     * Look up and return the cached SingleSignOn entry associated with this
541     * sso id value, if there is one; otherwise return <code>null</code>.
542     *
543     * @param ssoId Single sign on identifier to look up
544     */

545    protected SingleSignOnEntry getSingleSignOnEntry(String JavaDoc ssoId)
546    {
547       SingleSignOnEntry sso = localLookup(ssoId);
548       // If we don't have one locally and there is a cluster,
549
// query the cluster for the SSO
550
if (sso == null && ssoClusterManager != null)
551       {
552          sso = ssoClusterManager.lookup(ssoId);
553          if (sso != null)
554          {
555             // Store it locally
556
synchronized (cache)
557             {
558                cache.put(ssoId, sso);
559             }
560          }
561       }
562
563       return sso;
564    }
565
566
567    /**
568     * Attempts reauthentication to the given <code>Realm</code> using
569     * the credentials associated with the single sign-on session
570     * identified by argument <code>ssoId</code>.
571     * <p/>
572     * If reauthentication is successful, the <code>Principal</code> and
573     * authorization type associated with the SSO session will be bound
574     * to the given <code>HttpRequest</code> object via calls to
575     * {@link HttpRequest#setAuthType HttpRequest.setAuthType()} and
576     * {@link HttpRequest#setUserPrincipal HttpRequest.setUserPrincipal()}
577     * </p>
578     *
579     * @param ssoId identifier of SingleSignOn session with which the
580     * caller is associated
581     * @param realm Realm implementation against which the caller is to
582     * be authenticated
583     * @param request the request that needs to be authenticated
584     * @return <code>true</code> if reauthentication was successful,
585     * <code>false</code> otherwise.
586     */

587    protected boolean reauthenticate(String JavaDoc ssoId, Realm realm,
588       Request request)
589    {
590       if (ssoId == null || realm == null)
591          return false;
592
593       boolean reauthenticated = false;
594
595       SingleSignOnEntry entry = getSingleSignOnEntry(ssoId);
596       if (entry != null && entry.getCanReauthenticate())
597       {
598
599          String JavaDoc username = entry.getUsername();
600          if (username != null)
601          {
602             Principal JavaDoc reauthPrincipal =
603                realm.authenticate(username, entry.getPassword());
604             if (reauthPrincipal != null)
605             {
606                reauthenticated = true;
607                // Bind the authorization credentials to the request
608
request.setAuthType(entry.getAuthType());
609                request.setUserPrincipal(reauthPrincipal);
610             }
611          }
612       }
613
614       return reauthenticated;
615    }
616
617
618    /**
619     * Register the specified Principal as being associated with the specified
620     * value for the single sign on identifier.
621     * <p/>
622     * Differs from the superclass version in that it notifies the cluster
623     * of the registration.
624     *
625     * @param ssoId Single sign on identifier to register
626     * @param principal Associated user principal that is identified
627     * @param authType Authentication type used to authenticate this
628     * user principal
629     * @param username Username used to authenticate this user
630     * @param password Password used to authenticate this user
631     */

632    protected void register(String JavaDoc ssoId, Principal JavaDoc principal, String JavaDoc authType,
633       String JavaDoc username, String JavaDoc password)
634    {
635       registerLocal(ssoId, principal, authType, username, password);
636
637       // broadcast change to any cluster
638
if (ssoClusterManager != null)
639          ssoClusterManager.register(ssoId, authType, username, password);
640    }
641
642
643    /**
644     * Remove a single Session from a SingleSignOn. Called when
645     * a session is timed out and no longer active.
646     * <p/>
647     * Differs from the superclass version in that it notifies the cluster
648     * of any disassociation of SSO and Session.
649     *
650     * @param ssoId Single sign on identifier from which to remove the session.
651     * @param session the session to be removed.
652     */

653    protected void removeSession(String JavaDoc ssoId, Session session)
654    {
655       if (getContainer().getLogger().isDebugEnabled())
656           getContainer().getLogger().debug("Removing session " + session.toString() +
657             " from sso id " + ssoId);
658
659       // Get a reference to the SingleSignOn
660
SingleSignOnEntry entry = getSingleSignOnEntry(ssoId);
661       if (entry == null)
662          return;
663
664       // Remove the inactive session from SingleSignOnEntry
665
boolean removed = entry.removeSession(session);
666       // If we changed anything, notify any cluster
667
if (removed && ssoClusterManager != null)
668       {
669          ssoClusterManager.removeSession(ssoId, session);
670       }
671
672       // Remove the inactive session from the 'reverse' Map.
673
synchronized (reverse)
674       {
675          reverse.remove(session);
676       }
677
678       // If there are no sessions left in the SingleSignOnEntry,
679
// deregister the entry.
680
if (entry.getSessionCount() == 0)
681       {
682          deregister(ssoId);
683       }
684    }
685
686
687    /**
688     * Updates any <code>SingleSignOnEntry</code> found under key
689     * <code>ssoId</code> with the given authentication data.
690     * <p/>
691     * The purpose of this method is to allow an SSO entry that was
692     * established without a username/password combination (i.e. established
693     * following DIGEST or CLIENT-CERT authentication) to be updated with
694     * a username and password if one becomes available through a subsequent
695     * BASIC or FORM authentication. The SSO entry will then be usable for
696     * reauthentication.
697     * <p/>
698     * <b>NOTE:</b> Only updates the SSO entry if a call to
699     * <code>SingleSignOnEntry.getCanReauthenticate()</code> returns
700     * <code>false</code>; otherwise, it is assumed that the SSO entry already
701     * has sufficient information to allow reauthentication and that no update
702     * is needed.
703     * <p/>
704     * Differs from the superclass version in that it notifies the cluster
705     * of any update.
706     *
707     * @param ssoId identifier of Single sign to be updated
708     * @param principal the <code>Principal</code> returned by the latest
709     * call to <code>Realm.authenticate</code>.
710     * @param authType the type of authenticator used (BASIC, CLIENT-CERT,
711     * DIGEST or FORM)
712     * @param username the username (if any) used for the authentication
713     * @param password the password (if any) used for the authentication
714     */

715    protected void update(String JavaDoc ssoId, Principal JavaDoc principal, String JavaDoc authType,
716       String JavaDoc username, String JavaDoc password)
717    {
718       boolean needToBroadcast = updateLocal(ssoId, principal, authType,
719          username, password);
720                                     
721       // if there was a change, broadcast it to any cluster
722
if (needToBroadcast && ssoClusterManager != null)
723       {
724          ssoClusterManager.updateCredentials(ssoId, authType,
725             username, password);
726       }
727    }
728
729    //---------------------------------------------- Package-Protected Methods
730

731    /**
732     * Search in our local cache for an SSO entry.
733     *
734     * @param ssoId the id of the SSO session
735     * @return any SingleSignOnEntry associated with the given id, or
736     * <code>null</code> if there is none.
737     */

738    SingleSignOnEntry localLookup(String JavaDoc ssoId)
739    {
740       synchronized (cache)
741       {
742          return ((SingleSignOnEntry) cache.get(ssoId));
743       }
744
745    }
746
747    /**
748     * Create a SingleSignOnEntry using the passed configuration parameters and
749     * register it in the local cache, bound to the given id.
750     *
751     * @param ssoId the id of the SSO session
752     * @param principal the <code>Principal</code> returned by the latest
753     * call to <code>Realm.authenticate</code>.
754     * @param authType the type of authenticator used (BASIC, CLIENT-CERT,
755     * DIGEST or FORM)
756     * @param username the username (if any) used for the authentication
757     * @param password the password (if any) used for the authentication
758     */

759    void registerLocal(String JavaDoc ssoId, Principal JavaDoc principal, String JavaDoc authType,
760       String JavaDoc username, String JavaDoc password)
761    {
762       if (getContainer().getLogger().isDebugEnabled())
763       {
764           getContainer().getLogger().debug("Registering sso id '" + ssoId + "' for user '" +
765             principal.getName() + "' with auth type '" + authType + "'");
766       }
767
768       synchronized (cache)
769       {
770          cache.put(ssoId, new SingleSignOnEntry(principal, authType,
771             username, password));
772       }
773    }
774
775    /**
776     * Updates any <code>SingleSignOnEntry</code> found under key
777     * <code>ssoId</code> with the given authentication data.
778     *
779     * @param ssoId identifier of Single sign to be updated
780     * @param principal the <code>Principal</code> returned by the latest
781     * call to <code>Realm.authenticate</code>.
782     * @param authType the type of authenticator used (BASIC, CLIENT-CERT,
783     * DIGEST or FORM)
784     * @param username the username (if any) used for the authentication
785     * @param password the password (if any) used for the authentication
786     * @return <code>true</code> if the update resulted in an actual change
787     * to the entry's authType, username or principal properties
788     */

789    boolean updateLocal(String JavaDoc ssoId, Principal JavaDoc principal, String JavaDoc authType,
790       String JavaDoc username, String JavaDoc password)
791    {
792       boolean shouldBroadcast = false;
793
794       SingleSignOnEntry sso = getSingleSignOnEntry(ssoId);
795       // Only update if the entry is missing information
796
if (sso != null)
797       {
798          if (sso.getCanReauthenticate() == false)
799          {
800             if (getContainer().getLogger().isDebugEnabled())
801                 getContainer().getLogger().debug("Update sso id " + ssoId + " to auth type " + authType);
802
803             synchronized (sso)
804             {
805                shouldBroadcast = sso.updateCredentials(principal, authType,
806                   username, password);
807             }
808          }
809          else if (sso.getPrincipal() == null && principal != null)
810          {
811             if (getContainer().getLogger().isDebugEnabled())
812                 getContainer().getLogger().debug("Update sso id " + ssoId + " with principal " +
813                   principal.getName());
814
815             synchronized (sso)
816             {
817                sso.setPrincipal(principal);
818                // No need to notify cluster; Principals don't replicate
819
}
820          }
821
822       }
823
824       return shouldBroadcast;
825
826    }
827
828    void remoteUpdate(String JavaDoc ssoId, String JavaDoc authType,
829       String JavaDoc username, String JavaDoc password)
830    {
831       SingleSignOnEntry sso = getSingleSignOnEntry(ssoId);
832       // Only update if the entry is missing information
833
if (sso != null && sso.getCanReauthenticate() == false)
834       {
835          if (getContainer().getLogger().isDebugEnabled())
836              getContainer().getLogger().debug("Update sso id " + ssoId + " to auth type " + authType);
837
838          synchronized (sso)
839          {
840             // Use the existing principal
841
Principal JavaDoc p = sso.getPrincipal();
842             sso.updateCredentials(p, authType, username, password);
843          }
844       }
845
846    }
847
848    
849    // ------------------------------------------------------- Private Methods
850

851    
852    /**
853     * Instantiates an instance of the given class, making it this valve's
854     * SSOClusterManager.
855     * <p/>
856     * If this valve has been started and the given class implements
857     * <code>Lifecycle</code>, starts the new SSOClusterManager.
858     *
859     * @param className fully qualified class name of an implementation
860     * of {@link SSOClusterManager SSOClusterManager}.
861     * @throws LifecycleException if there is any problem instantiating or
862     * starting the object, or if the created
863     * object does not implement
864     * <code>SSOClusterManger</code>
865     */

866    private void createClusterManager(String JavaDoc className)
867       throws LifecycleException
868    {
869       if (ssoClusterManager != null)
870          return;
871
872       if (className != null)
873       {
874          SSOClusterManager mgr = null;
875          try
876          {
877             ClassLoader JavaDoc tcl =
878                Thread.currentThread().getContextClassLoader();
879             Class JavaDoc clazz = tcl.loadClass(className);
880             mgr = (SSOClusterManager) clazz.newInstance();
881             mgr.setSingleSignOnValve(this);
882             if (mgr instanceof TreeCacheSSOClusterManager)
883             {
884                ((TreeCacheSSOClusterManager) mgr).setCacheName(getTreeCacheName());
885             }
886             ssoClusterManager = mgr;
887             clusterManagerClass = className;
888          }
889          catch (Throwable JavaDoc t)
890          {
891             throw new LifecycleException("Cannot create " +
892                "SSOClusterManager using " +
893                className, t);
894          }
895
896          if (started)
897          {
898             ssoClusterManager.start();
899          }
900       }
901    }
902
903 }
Popular Tags