KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > authenticator > AuthenticatorBase


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18
19 package org.apache.catalina.authenticator;
20
21
22 import java.io.IOException JavaDoc;
23 import java.security.MessageDigest JavaDoc;
24 import java.security.NoSuchAlgorithmException JavaDoc;
25 import java.security.Principal JavaDoc;
26 import java.text.SimpleDateFormat JavaDoc;
27 import java.util.Date JavaDoc;
28 import java.util.Locale JavaDoc;
29 import java.util.Random JavaDoc;
30
31 import javax.servlet.ServletException JavaDoc;
32 import javax.servlet.http.Cookie JavaDoc;
33
34 import org.apache.catalina.Authenticator;
35 import org.apache.catalina.Container;
36 import org.apache.catalina.Context;
37 import org.apache.catalina.Lifecycle;
38 import org.apache.catalina.LifecycleException;
39 import org.apache.catalina.LifecycleListener;
40 import org.apache.catalina.Pipeline;
41 import org.apache.catalina.Realm;
42 import org.apache.catalina.Session;
43 import org.apache.catalina.Valve;
44 import org.apache.catalina.connector.Request;
45 import org.apache.catalina.connector.Response;
46 import org.apache.catalina.deploy.LoginConfig;
47 import org.apache.catalina.deploy.SecurityConstraint;
48 import org.apache.catalina.util.DateTool;
49 import org.apache.catalina.util.LifecycleSupport;
50 import org.apache.catalina.util.StringManager;
51 import org.apache.catalina.valves.ValveBase;
52 import org.apache.commons.logging.Log;
53 import org.apache.commons.logging.LogFactory;
54
55
56 /**
57  * Basic implementation of the <b>Valve</b> interface that enforces the
58  * <code>&lt;security-constraint&gt;</code> elements in the web application
59  * deployment descriptor. This functionality is implemented as a Valve
60  * so that it can be ommitted in environments that do not require these
61  * features. Individual implementations of each supported authentication
62  * method can subclass this base class as required.
63  * <p>
64  * <b>USAGE CONSTRAINT</b>: When this class is utilized, the Context to
65  * which it is attached (or a parent Container in a hierarchy) must have an
66  * associated Realm that can be used for authenticating users and enumerating
67  * the roles to which they have been assigned.
68  * <p>
69  * <b>USAGE CONSTRAINT</b>: This Valve is only useful when processing HTTP
70  * requests. Requests of any other type will simply be passed through.
71  *
72  * @author Craig R. McClanahan
73  * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
74  */

75
76
77 public abstract class AuthenticatorBase
78     extends ValveBase
79     implements Authenticator, Lifecycle {
80     private static Log log = LogFactory.getLog(AuthenticatorBase.class);
81
82
83     // ----------------------------------------------------- Instance Variables
84

85
86     /**
87      * The default message digest algorithm to use if we cannot use
88      * the requested one.
89      */

90     protected static final String JavaDoc DEFAULT_ALGORITHM = "MD5";
91
92
93     /**
94      * The number of random bytes to include when generating a
95      * session identifier.
96      */

97     protected static final int SESSION_ID_BYTES = 16;
98
99
100     /**
101      * The message digest algorithm to be used when generating session
102      * identifiers. This must be an algorithm supported by the
103      * <code>java.security.MessageDigest</code> class on your platform.
104      */

105     protected String JavaDoc algorithm = DEFAULT_ALGORITHM;
106
107
108     /**
109      * Should we cache authenticated Principals if the request is part of
110      * an HTTP session?
111      */

112     protected boolean cache = true;
113
114
115     /**
116      * The Context to which this Valve is attached.
117      */

118     protected Context context = null;
119
120
121     /**
122      * Return the MessageDigest implementation to be used when
123      * creating session identifiers.
124      */

125     protected MessageDigest JavaDoc digest = null;
126
127
128     /**
129      * A String initialization parameter used to increase the entropy of
130      * the initialization of our random number generator.
131      */

132     protected String JavaDoc entropy = null;
133
134
135     /**
136      * Descriptive information about this implementation.
137      */

138     protected static final String JavaDoc info =
139         "org.apache.catalina.authenticator.AuthenticatorBase/1.0";
140
141     /**
142      * Flag to determine if we disable proxy caching, or leave the issue
143      * up to the webapp developer.
144      */

145     protected boolean disableProxyCaching = true;
146
147     /**
148      * Flag to determine if we disable proxy caching with headers incompatible
149      * with IE
150      */

151     protected boolean securePagesWithPragma = true;
152     
153     /**
154      * The lifecycle event support for this component.
155      */

156     protected LifecycleSupport lifecycle = new LifecycleSupport(this);
157
158
159     /**
160      * A random number generator to use when generating session identifiers.
161      */

162     protected Random JavaDoc random = null;
163
164
165     /**
166      * The Java class name of the random number generator class to be used
167      * when generating session identifiers.
168      */

169     protected String JavaDoc randomClass = "java.security.SecureRandom";
170
171
172     /**
173      * The string manager for this package.
174      */

175     protected static final StringManager sm =
176         StringManager.getManager(Constants.Package);
177
178
179     /**
180      * The SingleSignOn implementation in our request processing chain,
181      * if there is one.
182      */

183     protected SingleSignOn sso = null;
184
185
186     /**
187      * Has this component been started?
188      */

189     protected boolean started = false;
190
191
192     /**
193      * "Expires" header always set to Date(1), so generate once only
194      */

195     private static final String JavaDoc DATE_ONE =
196         (new SimpleDateFormat JavaDoc(DateTool.HTTP_RESPONSE_DATE_HEADER,
197                               Locale.US)).format(new Date JavaDoc(1));
198
199
200     // ------------------------------------------------------------- Properties
201

202
203     /**
204      * Return the message digest algorithm for this Manager.
205      */

206     public String JavaDoc getAlgorithm() {
207
208         return (this.algorithm);
209
210     }
211
212
213     /**
214      * Set the message digest algorithm for this Manager.
215      *
216      * @param algorithm The new message digest algorithm
217      */

218     public void setAlgorithm(String JavaDoc algorithm) {
219
220         this.algorithm = algorithm;
221
222     }
223
224
225     /**
226      * Return the cache authenticated Principals flag.
227      */

228     public boolean getCache() {
229
230         return (this.cache);
231
232     }
233
234
235     /**
236      * Set the cache authenticated Principals flag.
237      *
238      * @param cache The new cache flag
239      */

240     public void setCache(boolean cache) {
241
242         this.cache = cache;
243
244     }
245
246
247     /**
248      * Return the Container to which this Valve is attached.
249      */

250     public Container getContainer() {
251
252         return (this.context);
253
254     }
255
256
257     /**
258      * Set the Container to which this Valve is attached.
259      *
260      * @param container The container to which we are attached
261      */

262     public void setContainer(Container container) {
263
264         if (!(container instanceof Context))
265             throw new IllegalArgumentException JavaDoc
266                 (sm.getString("authenticator.notContext"));
267
268         super.setContainer(container);
269         this.context = (Context) container;
270
271     }
272
273
274     /**
275      * Return the entropy increaser value, or compute a semi-useful value
276      * if this String has not yet been set.
277      */

278     public String JavaDoc getEntropy() {
279
280         // Calculate a semi-useful value if this has not been set
281
if (this.entropy == null)
282             setEntropy(this.toString());
283
284         return (this.entropy);
285
286     }
287
288
289     /**
290      * Set the entropy increaser value.
291      *
292      * @param entropy The new entropy increaser value
293      */

294     public void setEntropy(String JavaDoc entropy) {
295
296         this.entropy = entropy;
297
298     }
299
300
301     /**
302      * Return descriptive information about this Valve implementation.
303      */

304     public String JavaDoc getInfo() {
305
306         return (info);
307
308     }
309
310
311     /**
312      * Return the random number generator class name.
313      */

314     public String JavaDoc getRandomClass() {
315
316         return (this.randomClass);
317
318     }
319
320
321     /**
322      * Set the random number generator class name.
323      *
324      * @param randomClass The new random number generator class name
325      */

326     public void setRandomClass(String JavaDoc randomClass) {
327
328         this.randomClass = randomClass;
329
330     }
331
332     /**
333      * Return the flag that states if we add headers to disable caching by
334      * proxies.
335      */

336     public boolean getDisableProxyCaching() {
337         return disableProxyCaching;
338     }
339
340     /**
341      * Set the value of the flag that states if we add headers to disable
342      * caching by proxies.
343      * @param nocache <code>true</code> if we add headers to disable proxy
344      * caching, <code>false</code> if we leave the headers alone.
345      */

346     public void setDisableProxyCaching(boolean nocache) {
347         disableProxyCaching = nocache;
348     }
349     
350     /**
351      * Return the flag that states, if proxy caching is disabled, what headers
352      * we add to disable the caching.
353      */

354     public boolean getSecurePagesWithPragma() {
355         return securePagesWithPragma;
356     }
357
358     /**
359      * Set the value of the flag that states what headers we add to disable
360      * proxy caching.
361      * @param securePagesWithPragma <code>true</code> if we add headers which
362      * are incompatible with downloading office documents in IE under SSL but
363      * which fix a caching problem in Mozilla.
364      */

365     public void setSecurePagesWithPragma(boolean securePagesWithPragma) {
366         this.securePagesWithPragma = securePagesWithPragma;
367     }
368
369     // --------------------------------------------------------- Public Methods
370

371
372     /**
373      * Enforce the security restrictions in the web application deployment
374      * descriptor of our associated Context.
375      *
376      * @param request Request to be processed
377      * @param response Response to be processed
378      *
379      * @exception IOException if an input/output error occurs
380      * @exception ServletException if thrown by a processing element
381      */

382     public void invoke(Request request, Response response)
383         throws IOException JavaDoc, ServletException JavaDoc {
384
385         if (log.isDebugEnabled())
386             log.debug("Security checking request " +
387                 request.getMethod() + " " + request.getRequestURI());
388         LoginConfig config = this.context.getLoginConfig();
389
390         // Have we got a cached authenticated Principal to record?
391
if (cache) {
392             Principal JavaDoc principal = request.getUserPrincipal();
393             if (principal == null) {
394                 Session session = request.getSessionInternal(false);
395                 if (session != null) {
396                     principal = session.getPrincipal();
397                     if (principal != null) {
398                         if (log.isDebugEnabled())
399                             log.debug("We have cached auth type " +
400                                 session.getAuthType() +
401                                 " for principal " +
402                                 session.getPrincipal());
403                         request.setAuthType(session.getAuthType());
404                         request.setUserPrincipal(principal);
405                     }
406                 }
407             }
408         }
409
410         // Special handling for form-based logins to deal with the case
411
// where the login form (and therefore the "j_security_check" URI
412
// to which it submits) might be outside the secured area
413
String JavaDoc contextPath = this.context.getPath();
414         String JavaDoc requestURI = request.getDecodedRequestURI();
415         if (requestURI.startsWith(contextPath) &&
416             requestURI.endsWith(Constants.FORM_ACTION)) {
417             if (!authenticate(request, response, config)) {
418                 if (log.isDebugEnabled())
419                     log.debug(" Failed authenticate() test ??" + requestURI );
420                 return;
421             }
422         }
423
424         Realm realm = this.context.getRealm();
425         // Is this request URI subject to a security constraint?
426
SecurityConstraint [] constraints
427             = realm.findSecurityConstraints(request, this.context);
428        
429         if ((constraints == null) /* &&
430             (!Constants.FORM_METHOD.equals(config.getAuthMethod())) */
) {
431             if (log.isDebugEnabled())
432                 log.debug(" Not subject to any constraint");
433             getNext().invoke(request, response);
434             return;
435         }
436
437         // Make sure that constrained resources are not cached by web proxies
438
// or browsers as caching can provide a security hole
439
if (disableProxyCaching &&
440             // FIXME: Disabled for Mozilla FORM support over SSL
441
// (improper caching issue)
442
//!request.isSecure() &&
443
!"POST".equalsIgnoreCase(request.getMethod())) {
444             if (securePagesWithPragma) {
445                 // FIXME: These cause problems with downloading office docs
446
// from IE under SSL and may not be needed for newer Mozilla
447
// clients.
448
response.setHeader("Pragma", "No-cache");
449                 response.setHeader("Cache-Control", "no-cache");
450             } else {
451                 response.setHeader("Cache-Control", "private");
452             }
453             response.setHeader("Expires", DATE_ONE);
454         }
455
456         int i;
457         // Enforce any user data constraint for this security constraint
458
if (log.isDebugEnabled()) {
459             log.debug(" Calling hasUserDataPermission()");
460         }
461         if (!realm.hasUserDataPermission(request, response,
462                                          constraints)) {
463             if (log.isDebugEnabled()) {
464                 log.debug(" Failed hasUserDataPermission() test");
465             }
466             /*
467              * ASSERT: Authenticator already set the appropriate
468              * HTTP status code, so we do not have to do anything special
469              */

470             return;
471         }
472
473         // Since authenticate modifies the response on failure,
474
// we have to check for allow-from-all first.
475
boolean authRequired = true;
476         for(i=0; i < constraints.length && authRequired; i++) {
477             if(!constraints[i].getAuthConstraint()) {
478                 authRequired = false;
479             } else if(!constraints[i].getAllRoles()) {
480                 String JavaDoc [] roles = constraints[i].findAuthRoles();
481                 if(roles == null || roles.length == 0) {
482                     authRequired = false;
483                 }
484             }
485         }
486              
487         if(authRequired) {
488             if (log.isDebugEnabled()) {
489                 log.debug(" Calling authenticate()");
490             }
491             if (!authenticate(request, response, config)) {
492                 if (log.isDebugEnabled()) {
493                     log.debug(" Failed authenticate() test");
494                 }
495                 /*
496                  * ASSERT: Authenticator already set the appropriate
497                  * HTTP status code, so we do not have to do anything
498                  * special
499                  */

500                 return;
501             }
502         }
503     
504         if (log.isDebugEnabled()) {
505             log.debug(" Calling accessControl()");
506         }
507         if (!realm.hasResourcePermission(request, response,
508                                          constraints,
509                                          this.context)) {
510             if (log.isDebugEnabled()) {
511                 log.debug(" Failed accessControl() test");
512             }
513             /*
514              * ASSERT: AccessControl method has already set the
515              * appropriate HTTP status code, so we do not have to do
516              * anything special
517              */

518             return;
519         }
520     
521         // Any and all specified constraints have been satisfied
522
if (log.isDebugEnabled()) {
523             log.debug(" Successfully passed all security constraints");
524         }
525         getNext().invoke(request, response);
526
527     }
528
529
530     // ------------------------------------------------------ Protected Methods
531

532
533
534
535     /**
536      * Associate the specified single sign on identifier with the
537      * specified Session.
538      *
539      * @param ssoId Single sign on identifier
540      * @param session Session to be associated
541      */

542     protected void associate(String JavaDoc ssoId, Session session) {
543
544         if (sso == null)
545             return;
546         sso.associate(ssoId, session);
547
548     }
549
550
551     /**
552      * Authenticate the user making this request, based on the specified
553      * login configuration. Return <code>true</code> if any specified
554      * constraint has been satisfied, or <code>false</code> if we have
555      * created a response challenge already.
556      *
557      * @param request Request we are processing
558      * @param response Response we are creating
559      * @param config Login configuration describing how authentication
560      * should be performed
561      *
562      * @exception IOException if an input/output error occurs
563      */

564     protected abstract boolean authenticate(Request request,
565                                             Response response,
566                                             LoginConfig config)
567         throws IOException JavaDoc;
568
569
570     /**
571      * Generate and return a new session identifier for the cookie that
572      * identifies an SSO principal.
573      */

574     protected synchronized String JavaDoc generateSessionId() {
575
576         // Generate a byte array containing a session identifier
577
byte bytes[] = new byte[SESSION_ID_BYTES];
578         getRandom().nextBytes(bytes);
579         bytes = getDigest().digest(bytes);
580
581         // Render the result as a String of hexadecimal digits
582
StringBuffer JavaDoc result = new StringBuffer JavaDoc();
583         for (int i = 0; i < bytes.length; i++) {
584             byte b1 = (byte) ((bytes[i] & 0xf0) >> 4);
585             byte b2 = (byte) (bytes[i] & 0x0f);
586             if (b1 < 10)
587                 result.append((char) ('0' + b1));
588             else
589                 result.append((char) ('A' + (b1 - 10)));
590             if (b2 < 10)
591                 result.append((char) ('0' + b2));
592             else
593                 result.append((char) ('A' + (b2 - 10)));
594         }
595         return (result.toString());
596
597     }
598
599
600     /**
601      * Return the MessageDigest object to be used for calculating
602      * session identifiers. If none has been created yet, initialize
603      * one the first time this method is called.
604      */

605     protected synchronized MessageDigest JavaDoc getDigest() {
606
607         if (this.digest == null) {
608             try {
609                 this.digest = MessageDigest.getInstance(algorithm);
610             } catch (NoSuchAlgorithmException JavaDoc e) {
611                 try {
612                     this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
613                 } catch (NoSuchAlgorithmException JavaDoc f) {
614                     this.digest = null;
615                 }
616             }
617         }
618
619         return (this.digest);
620
621     }
622
623
624     /**
625      * Return the random number generator instance we should use for
626      * generating session identifiers. If there is no such generator
627      * currently defined, construct and seed a new one.
628      */

629     protected synchronized Random JavaDoc getRandom() {
630
631         if (this.random == null) {
632             try {
633                 Class JavaDoc clazz = Class.forName(randomClass);
634                 this.random = (Random JavaDoc) clazz.newInstance();
635                 long seed = System.currentTimeMillis();
636                 char entropy[] = getEntropy().toCharArray();
637                 for (int i = 0; i < entropy.length; i++) {
638                     long update = ((byte) entropy[i]) << ((i % 8) * 8);
639                     seed ^= update;
640                 }
641                 this.random.setSeed(seed);
642             } catch (Exception JavaDoc e) {
643                 this.random = new java.util.Random JavaDoc();
644             }
645         }
646
647         return (this.random);
648
649     }
650
651
652     /**
653      * Attempts reauthentication to the <code>Realm</code> using
654      * the credentials included in argument <code>entry</code>.
655      *
656      * @param ssoId identifier of SingleSignOn session with which the
657      * caller is associated
658      * @param request the request that needs to be authenticated
659      */

660     protected boolean reauthenticateFromSSO(String JavaDoc ssoId, Request request) {
661
662         if (sso == null || ssoId == null)
663             return false;
664
665         boolean reauthenticated = false;
666
667         Container parent = getContainer();
668         if (parent != null) {
669             Realm realm = parent.getRealm();
670             if (realm != null) {
671                 reauthenticated = sso.reauthenticate(ssoId, realm, request);
672             }
673         }
674
675         if (reauthenticated) {
676             associate(ssoId, request.getSessionInternal(true));
677
678             if (log.isDebugEnabled()) {
679                 log.debug(" Reauthenticated cached principal '" +
680                           request.getUserPrincipal().getName() +
681                           "' with auth type '" + request.getAuthType() + "'");
682             }
683         }
684
685         return reauthenticated;
686     }
687
688
689     /**
690      * Register an authenticated Principal and authentication type in our
691      * request, in the current session (if there is one), and with our
692      * SingleSignOn valve, if there is one. Set the appropriate cookie
693      * to be returned.
694      *
695      * @param request The servlet request we are processing
696      * @param response The servlet response we are generating
697      * @param principal The authenticated Principal to be registered
698      * @param authType The authentication type to be registered
699      * @param username Username used to authenticate (if any)
700      * @param password Password used to authenticate (if any)
701      */

702     protected void register(Request request, Response response,
703                             Principal JavaDoc principal, String JavaDoc authType,
704                             String JavaDoc username, String JavaDoc password) {
705
706         if (log.isDebugEnabled())
707             log.debug("Authenticated '" + principal.getName() + "' with type '"
708                 + authType + "'");
709
710         // Cache the authentication information in our request
711
request.setAuthType(authType);
712         request.setUserPrincipal(principal);
713
714         Session session = request.getSessionInternal(false);
715         // Cache the authentication information in our session, if any
716
if (cache) {
717             if (session != null) {
718                 session.setAuthType(authType);
719                 session.setPrincipal(principal);
720                 if (username != null)
721                     session.setNote(Constants.SESS_USERNAME_NOTE, username);
722                 else
723                     session.removeNote(Constants.SESS_USERNAME_NOTE);
724                 if (password != null)
725                     session.setNote(Constants.SESS_PASSWORD_NOTE, password);
726                 else
727                     session.removeNote(Constants.SESS_PASSWORD_NOTE);
728             }
729         }
730
731         // Construct a cookie to be returned to the client
732
if (sso == null)
733             return;
734
735         // Only create a new SSO entry if the SSO did not already set a note
736
// for an existing entry (as it would do with subsequent requests
737
// for DIGEST and SSL authenticated contexts)
738
String JavaDoc ssoId = (String JavaDoc) request.getNote(Constants.REQ_SSOID_NOTE);
739         if (ssoId == null) {
740             // Construct a cookie to be returned to the client
741
ssoId = generateSessionId();
742             Cookie JavaDoc cookie = new Cookie JavaDoc(Constants.SINGLE_SIGN_ON_COOKIE, ssoId);
743             cookie.setMaxAge(-1);
744             cookie.setPath("/");
745             
746             // Bugzilla 34724
747
String JavaDoc ssoDomain = sso.getCookieDomain();
748             if(ssoDomain != null) {
749                 cookie.setDomain(ssoDomain);
750             }
751
752             response.addCookie(cookie);
753
754             // Register this principal with our SSO valve
755
sso.register(ssoId, principal, authType, username, password);
756             request.setNote(Constants.REQ_SSOID_NOTE, ssoId);
757
758         } else {
759             // Update the SSO session with the latest authentication data
760
sso.update(ssoId, principal, authType, username, password);
761         }
762
763         // Fix for Bug 10040
764
// Always associate a session with a new SSO reqistration.
765
// SSO entries are only removed from the SSO registry map when
766
// associated sessions are destroyed; if a new SSO entry is created
767
// above for this request and the user never revisits the context, the
768
// SSO entry will never be cleared if we don't associate the session
769
if (session == null)
770             session = request.getSessionInternal(true);
771         sso.associate(ssoId, session);
772
773     }
774
775
776     // ------------------------------------------------------ Lifecycle Methods
777

778
779     /**
780      * Add a lifecycle event listener to this component.
781      *
782      * @param listener The listener to add
783      */

784     public void addLifecycleListener(LifecycleListener listener) {
785
786         lifecycle.addLifecycleListener(listener);
787
788     }
789
790
791     /**
792      * Get the lifecycle listeners associated with this lifecycle. If this
793      * Lifecycle has no listeners registered, a zero-length array is returned.
794      */

795     public LifecycleListener[] findLifecycleListeners() {
796
797         return lifecycle.findLifecycleListeners();
798
799     }
800
801
802     /**
803      * Remove a lifecycle event listener from this component.
804      *
805      * @param listener The listener to remove
806      */

807     public void removeLifecycleListener(LifecycleListener listener) {
808
809         lifecycle.removeLifecycleListener(listener);
810
811     }
812
813
814     /**
815      * Prepare for the beginning of active use of the public methods of this
816      * component. This method should be called after <code>configure()</code>,
817      * and before any of the public methods of the component are utilized.
818      *
819      * @exception LifecycleException if this component detects a fatal error
820      * that prevents this component from being used
821      */

822     public void start() throws LifecycleException {
823
824         // Validate and update our current component state
825
if (started)
826             throw new LifecycleException
827                 (sm.getString("authenticator.alreadyStarted"));
828         lifecycle.fireLifecycleEvent(START_EVENT, null);
829         started = true;
830
831         // Look up the SingleSignOn implementation in our request processing
832
// path, if there is one
833
Container parent = context.getParent();
834         while ((sso == null) && (parent != null)) {
835             if (!(parent instanceof Pipeline)) {
836                 parent = parent.getParent();
837                 continue;
838             }
839             Valve valves[] = ((Pipeline) parent).getValves();
840             for (int i = 0; i < valves.length; i++) {
841                 if (valves[i] instanceof SingleSignOn) {
842                     sso = (SingleSignOn) valves[i];
843                     break;
844                 }
845             }
846             if (sso == null)
847                 parent = parent.getParent();
848         }
849         if (log.isDebugEnabled()) {
850             if (sso != null)
851                 log.debug("Found SingleSignOn Valve at " + sso);
852             else
853                 log.debug("No SingleSignOn Valve is present");
854         }
855
856     }
857
858
859     /**
860      * Gracefully terminate the active use of the public methods of this
861      * component. This method should be the last one called on a given
862      * instance of this component.
863      *
864      * @exception LifecycleException if this component detects a fatal error
865      * that needs to be reported
866      */

867     public void stop() throws LifecycleException {
868
869         // Validate and update our current component state
870
if (!started)
871             throw new LifecycleException
872                 (sm.getString("authenticator.notStarted"));
873         lifecycle.fireLifecycleEvent(STOP_EVENT, null);
874         started = false;
875
876         sso = null;
877
878     }
879
880
881 }
882
Popular Tags