View | Details | Raw Unified | Return to bug 12428
Collapse All | Expand All

(-)AuthenticatorBase.java (-887 / +905 lines)
Lines 1-887 Link Here
1
/*
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
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
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
7
 * the License.  You may obtain a copy of the License at
8
 * 
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
15
 * limitations under the License.
16
 */
16
 */
17
17
18
18
19
package org.apache.catalina.authenticator;
19
package org.apache.catalina.authenticator;
20
20
21
21
22
import java.io.IOException;
22
import java.io.IOException;
23
import java.security.MessageDigest;
23
import java.security.MessageDigest;
24
import java.security.NoSuchAlgorithmException;
24
import java.security.NoSuchAlgorithmException;
25
import java.security.Principal;
25
import java.security.Principal;
26
import java.text.SimpleDateFormat;
26
import java.security.cert.X509Certificate;
27
import java.util.Date;
27
import java.text.SimpleDateFormat;
28
import java.util.Locale;
28
import java.util.Date;
29
import java.util.Random;
29
import java.util.Locale;
30
30
import java.util.Random;
31
import javax.servlet.ServletException;
31
32
import javax.servlet.http.Cookie;
32
import javax.servlet.ServletException;
33
33
import javax.servlet.http.Cookie;
34
import org.apache.catalina.Authenticator;
34
35
import org.apache.catalina.Container;
35
import org.apache.catalina.Authenticator;
36
import org.apache.catalina.Context;
36
import org.apache.catalina.Container;
37
import org.apache.catalina.Lifecycle;
37
import org.apache.catalina.Context;
38
import org.apache.catalina.LifecycleException;
38
import org.apache.catalina.Globals;
39
import org.apache.catalina.LifecycleListener;
39
import org.apache.catalina.Lifecycle;
40
import org.apache.catalina.Pipeline;
40
import org.apache.catalina.LifecycleException;
41
import org.apache.catalina.Realm;
41
import org.apache.catalina.LifecycleListener;
42
import org.apache.catalina.Session;
42
import org.apache.catalina.Pipeline;
43
import org.apache.catalina.Valve;
43
import org.apache.catalina.Realm;
44
import org.apache.catalina.connector.Request;
44
import org.apache.catalina.Session;
45
import org.apache.catalina.connector.Response;
45
import org.apache.catalina.Valve;
46
import org.apache.catalina.deploy.LoginConfig;
46
import org.apache.catalina.connector.Request;
47
import org.apache.catalina.deploy.SecurityConstraint;
47
import org.apache.catalina.connector.Response;
48
import org.apache.catalina.util.DateTool;
48
import org.apache.catalina.deploy.LoginConfig;
49
import org.apache.catalina.util.LifecycleSupport;
49
import org.apache.catalina.deploy.SecurityConstraint;
50
import org.apache.catalina.util.StringManager;
50
import org.apache.catalina.util.DateTool;
51
import org.apache.catalina.valves.ValveBase;
51
import org.apache.catalina.util.LifecycleSupport;
52
import org.apache.commons.logging.Log;
52
import org.apache.catalina.util.StringManager;
53
import org.apache.commons.logging.LogFactory;
53
import org.apache.catalina.valves.ValveBase;
54
54
import org.apache.commons.logging.Log;
55
55
import org.apache.commons.logging.LogFactory;
56
/**
56
57
 * Basic implementation of the <b>Valve</b> interface that enforces the
57
58
 * <code>&lt;security-constraint&gt;</code> elements in the web application
58
/**
59
 * deployment descriptor.  This functionality is implemented as a Valve
59
 * Basic implementation of the <b>Valve</b> interface that enforces the
60
 * so that it can be ommitted in environments that do not require these
60
 * <code>&lt;security-constraint&gt;</code> elements in the web application
61
 * features.  Individual implementations of each supported authentication
61
 * deployment descriptor.  This functionality is implemented as a Valve
62
 * method can subclass this base class as required.
62
 * so that it can be ommitted in environments that do not require these
63
 * <p>
63
 * features.  Individual implementations of each supported authentication
64
 * <b>USAGE CONSTRAINT</b>:  When this class is utilized, the Context to
64
 * method can subclass this base class as required.
65
 * which it is attached (or a parent Container in a hierarchy) must have an
65
 * <p>
66
 * associated Realm that can be used for authenticating users and enumerating
66
 * <b>USAGE CONSTRAINT</b>:  When this class is utilized, the Context to
67
 * the roles to which they have been assigned.
67
 * which it is attached (or a parent Container in a hierarchy) must have an
68
 * <p>
68
 * associated Realm that can be used for authenticating users and enumerating
69
 * <b>USAGE CONSTRAINT</b>:  This Valve is only useful when processing HTTP
69
 * the roles to which they have been assigned.
70
 * requests.  Requests of any other type will simply be passed through.
70
 * <p>
71
 *
71
 * <b>USAGE CONSTRAINT</b>:  This Valve is only useful when processing HTTP
72
 * @author Craig R. McClanahan
72
 * requests.  Requests of any other type will simply be passed through.
73
 * @version $Revision: 496025 $ $Date: 2007-01-13 20:18:06 -0700 (Sat, 13 Jan 2007) $
73
 *
74
 */
74
 * @author Craig R. McClanahan
75
75
 * @version $Revision: 496025 $ $Date: 2007-01-14 04:18:06 +0100 (Sun, 14 Jan 2007) $
76
76
 */
77
public abstract class AuthenticatorBase
77
78
    extends ValveBase
78
79
    implements Authenticator, Lifecycle {
79
public abstract class AuthenticatorBase
80
    private static Log log = LogFactory.getLog(AuthenticatorBase.class);
80
    extends ValveBase
81
81
    implements Authenticator, Lifecycle {
82
82
    private static Log log = LogFactory.getLog(AuthenticatorBase.class);
83
    // ----------------------------------------------------- Instance Variables
83
84
84
85
85
    // ----------------------------------------------------- Instance Variables
86
    /**
86
87
     * The default message digest algorithm to use if we cannot use
87
88
     * the requested one.
88
    /**
89
     */
89
     * The default message digest algorithm to use if we cannot use
90
    protected static final String DEFAULT_ALGORITHM = "MD5";
90
     * the requested one.
91
91
     */
92
92
    protected static final String DEFAULT_ALGORITHM = "MD5";
93
    /**
93
94
     * The number of random bytes to include when generating a
94
95
     * session identifier.
95
    /**
96
     */
96
     * The number of random bytes to include when generating a
97
    protected static final int SESSION_ID_BYTES = 16;
97
     * session identifier.
98
98
     */
99
99
    protected static final int SESSION_ID_BYTES = 16;
100
    /**
100
101
     * The message digest algorithm to be used when generating session
101
102
     * identifiers.  This must be an algorithm supported by the
102
    /**
103
     * <code>java.security.MessageDigest</code> class on your platform.
103
     * The message digest algorithm to be used when generating session
104
     */
104
     * identifiers.  This must be an algorithm supported by the
105
    protected String algorithm = DEFAULT_ALGORITHM;
105
     * <code>java.security.MessageDigest</code> class on your platform.
106
106
     */
107
107
    protected String algorithm = DEFAULT_ALGORITHM;
108
    /**
108
109
     * Should we cache authenticated Principals if the request is part of
109
110
     * an HTTP session?
110
    /**
111
     */
111
     * Should we cache authenticated Principals if the request is part of
112
    protected boolean cache = true;
112
     * an HTTP session?
113
113
     */
114
114
    protected boolean cache = true;
115
    /**
115
116
     * The Context to which this Valve is attached.
116
117
     */
117
    /**
118
    protected Context context = null;
118
     * The Context to which this Valve is attached.
119
119
     */
120
120
    protected Context context = null;
121
    /**
121
122
     * Return the MessageDigest implementation to be used when
122
123
     * creating session identifiers.
123
    /**
124
     */
124
     * Return the MessageDigest implementation to be used when
125
    protected MessageDigest digest = null;
125
     * creating session identifiers.
126
126
     */
127
127
    protected MessageDigest digest = null;
128
    /**
128
129
     * A String initialization parameter used to increase the entropy of
129
130
     * the initialization of our random number generator.
130
    /**
131
     */
131
     * A String initialization parameter used to increase the entropy of
132
    protected String entropy = null;
132
     * the initialization of our random number generator.
133
133
     */
134
134
    protected String entropy = null;
135
    /**
135
136
     * Descriptive information about this implementation.
136
137
     */
137
    /**
138
    protected static final String info =
138
     * Descriptive information about this implementation.
139
        "org.apache.catalina.authenticator.AuthenticatorBase/1.0";
139
     */
140
140
    protected static final String info =
141
    /**
141
        "org.apache.catalina.authenticator.AuthenticatorBase/1.0";
142
     * Flag to determine if we disable proxy caching, or leave the issue
142
143
     * up to the webapp developer.
143
    /**
144
     */
144
     * Flag to determine if we disable proxy caching, or leave the issue
145
    protected boolean disableProxyCaching = true;
145
     * up to the webapp developer.
146
146
     */
147
    /**
147
    protected boolean disableProxyCaching = true;
148
     * Flag to determine if we disable proxy caching with headers incompatible
148
149
     * with IE 
149
    /**
150
     */
150
     * Flag to determine if we disable proxy caching with headers incompatible
151
    protected boolean securePagesWithPragma = true;
151
     * with IE 
152
    
152
     */
153
    /**
153
    protected boolean securePagesWithPragma = true;
154
     * The lifecycle event support for this component.
154
    
155
     */
155
    /**
156
    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
156
     * The lifecycle event support for this component.
157
157
     */
158
158
    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
159
    /**
159
160
     * A random number generator to use when generating session identifiers.
160
161
     */
161
    /**
162
    protected Random random = null;
162
     * A random number generator to use when generating session identifiers.
163
163
     */
164
164
    protected Random random = null;
165
    /**
165
166
     * The Java class name of the random number generator class to be used
166
167
     * when generating session identifiers.
167
    /**
168
     */
168
     * The Java class name of the random number generator class to be used
169
    protected String randomClass = "java.security.SecureRandom";
169
     * when generating session identifiers.
170
170
     */
171
171
    protected String randomClass = "java.security.SecureRandom";
172
    /**
172
173
     * The string manager for this package.
173
174
     */
174
    /**
175
    protected static final StringManager sm =
175
     * The string manager for this package.
176
        StringManager.getManager(Constants.Package);
176
     */
177
177
    protected static final StringManager sm =
178
178
        StringManager.getManager(Constants.Package);
179
    /**
179
180
     * The SingleSignOn implementation in our request processing chain,
180
181
     * if there is one.
181
    /**
182
     */
182
     * The SingleSignOn implementation in our request processing chain,
183
    protected SingleSignOn sso = null;
183
     * if there is one.
184
184
     */
185
185
    protected SingleSignOn sso = null;
186
    /**
186
187
     * Has this component been started?
187
188
     */
188
    /**
189
    protected boolean started = false;
189
     * Has this component been started?
190
190
     */
191
191
    protected boolean started = false;
192
    /**
192
193
     * "Expires" header always set to Date(1), so generate once only
193
194
     */
194
    /**
195
    private static final String DATE_ONE =
195
     * "Expires" header always set to Date(1), so generate once only
196
        (new SimpleDateFormat(DateTool.HTTP_RESPONSE_DATE_HEADER,
196
     */
197
                              Locale.US)).format(new Date(1));
197
    private static final String DATE_ONE =
198
198
        (new SimpleDateFormat(DateTool.HTTP_RESPONSE_DATE_HEADER,
199
199
                              Locale.US)).format(new Date(1));
200
    // ------------------------------------------------------------- Properties
200
201
201
202
202
    // ------------------------------------------------------------- Properties
203
    /**
203
204
     * Return the message digest algorithm for this Manager.
204
205
     */
205
    /**
206
    public String getAlgorithm() {
206
     * Return the message digest algorithm for this Manager.
207
207
     */
208
        return (this.algorithm);
208
    public String getAlgorithm() {
209
209
210
    }
210
        return (this.algorithm);
211
211
212
212
    }
213
    /**
213
214
     * Set the message digest algorithm for this Manager.
214
215
     *
215
    /**
216
     * @param algorithm The new message digest algorithm
216
     * Set the message digest algorithm for this Manager.
217
     */
217
     *
218
    public void setAlgorithm(String algorithm) {
218
     * @param algorithm The new message digest algorithm
219
219
     */
220
        this.algorithm = algorithm;
220
    public void setAlgorithm(String algorithm) {
221
221
222
    }
222
        this.algorithm = algorithm;
223
223
224
224
    }
225
    /**
225
226
     * Return the cache authenticated Principals flag.
226
227
     */
227
    /**
228
    public boolean getCache() {
228
     * Return the cache authenticated Principals flag.
229
229
     */
230
        return (this.cache);
230
    public boolean getCache() {
231
231
232
    }
232
        return (this.cache);
233
233
234
234
    }
235
    /**
235
236
     * Set the cache authenticated Principals flag.
236
237
     *
237
    /**
238
     * @param cache The new cache flag
238
     * Set the cache authenticated Principals flag.
239
     */
239
     *
240
    public void setCache(boolean cache) {
240
     * @param cache The new cache flag
241
241
     */
242
        this.cache = cache;
242
    public void setCache(boolean cache) {
243
243
244
    }
244
        this.cache = cache;
245
245
246
246
    }
247
    /**
247
248
     * Return the Container to which this Valve is attached.
248
249
     */
249
    /**
250
    public Container getContainer() {
250
     * Return the Container to which this Valve is attached.
251
251
     */
252
        return (this.context);
252
    public Container getContainer() {
253
253
254
    }
254
        return (this.context);
255
255
256
256
    }
257
    /**
257
258
     * Set the Container to which this Valve is attached.
258
259
     *
259
    /**
260
     * @param container The container to which we are attached
260
     * Set the Container to which this Valve is attached.
261
     */
261
     *
262
    public void setContainer(Container container) {
262
     * @param container The container to which we are attached
263
263
     */
264
        if (!(container instanceof Context))
264
    public void setContainer(Container container) {
265
            throw new IllegalArgumentException
265
266
                (sm.getString("authenticator.notContext"));
266
        if (!(container instanceof Context))
267
267
            throw new IllegalArgumentException
268
        super.setContainer(container);
268
                (sm.getString("authenticator.notContext"));
269
        this.context = (Context) container;
269
270
270
        super.setContainer(container);
271
    }
271
        this.context = (Context) container;
272
272
273
273
    }
274
    /**
274
275
     * Return the entropy increaser value, or compute a semi-useful value
275
276
     * if this String has not yet been set.
276
    /**
277
     */
277
     * Return the entropy increaser value, or compute a semi-useful value
278
    public String getEntropy() {
278
     * if this String has not yet been set.
279
279
     */
280
        // Calculate a semi-useful value if this has not been set
280
    public String getEntropy() {
281
        if (this.entropy == null)
281
282
            setEntropy(this.toString());
282
        // Calculate a semi-useful value if this has not been set
283
283
        if (this.entropy == null)
284
        return (this.entropy);
284
            setEntropy(this.toString());
285
285
286
    }
286
        return (this.entropy);
287
287
288
288
    }
289
    /**
289
290
     * Set the entropy increaser value.
290
291
     *
291
    /**
292
     * @param entropy The new entropy increaser value
292
     * Set the entropy increaser value.
293
     */
293
     *
294
    public void setEntropy(String entropy) {
294
     * @param entropy The new entropy increaser value
295
295
     */
296
        this.entropy = entropy;
296
    public void setEntropy(String entropy) {
297
297
298
    }
298
        this.entropy = entropy;
299
299
300
300
    }
301
    /**
301
302
     * Return descriptive information about this Valve implementation.
302
303
     */
303
    /**
304
    public String getInfo() {
304
     * Return descriptive information about this Valve implementation.
305
305
     */
306
        return (info);
306
    public String getInfo() {
307
307
308
    }
308
        return (info);
309
309
310
310
    }
311
    /**
311
312
     * Return the random number generator class name.
312
313
     */
313
    /**
314
    public String getRandomClass() {
314
     * Return the random number generator class name.
315
315
     */
316
        return (this.randomClass);
316
    public String getRandomClass() {
317
317
318
    }
318
        return (this.randomClass);
319
319
320
320
    }
321
    /**
321
322
     * Set the random number generator class name.
322
323
     *
323
    /**
324
     * @param randomClass The new random number generator class name
324
     * Set the random number generator class name.
325
     */
325
     *
326
    public void setRandomClass(String randomClass) {
326
     * @param randomClass The new random number generator class name
327
327
     */
328
        this.randomClass = randomClass;
328
    public void setRandomClass(String randomClass) {
329
329
330
    }
330
        this.randomClass = randomClass;
331
331
332
    /**
332
    }
333
     * Return the flag that states if we add headers to disable caching by
333
334
     * proxies.
334
    /**
335
     */
335
     * Return the flag that states if we add headers to disable caching by
336
    public boolean getDisableProxyCaching() {
336
     * proxies.
337
        return disableProxyCaching;
337
     */
338
    }
338
    public boolean getDisableProxyCaching() {
339
339
        return disableProxyCaching;
340
    /**
340
    }
341
     * Set the value of the flag that states if we add headers to disable
341
342
     * caching by proxies.
342
    /**
343
     * @param nocache <code>true</code> if we add headers to disable proxy 
343
     * Set the value of the flag that states if we add headers to disable
344
     *              caching, <code>false</code> if we leave the headers alone.
344
     * caching by proxies.
345
     */
345
     * @param nocache <code>true</code> if we add headers to disable proxy 
346
    public void setDisableProxyCaching(boolean nocache) {
346
     *              caching, <code>false</code> if we leave the headers alone.
347
        disableProxyCaching = nocache;
347
     */
348
    }
348
    public void setDisableProxyCaching(boolean nocache) {
349
    
349
        disableProxyCaching = nocache;
350
    /**
350
    }
351
     * Return the flag that states, if proxy caching is disabled, what headers
351
    
352
     * we add to disable the caching.
352
    /**
353
     */
353
     * Return the flag that states, if proxy caching is disabled, what headers
354
    public boolean getSecurePagesWithPragma() {
354
     * we add to disable the caching.
355
        return securePagesWithPragma;
355
     */
356
    }
356
    public boolean getSecurePagesWithPragma() {
357
357
        return securePagesWithPragma;
358
    /**
358
    }
359
     * Set the value of the flag that states what headers we add to disable
359
360
     * proxy caching.
360
    /**
361
     * @param securePagesWithPragma <code>true</code> if we add headers which 
361
     * Set the value of the flag that states what headers we add to disable
362
     * are incompatible with downloading office documents in IE under SSL but
362
     * proxy caching.
363
     * which fix a caching problem in Mozilla.
363
     * @param securePagesWithPragma <code>true</code> if we add headers which 
364
     */
364
     * are incompatible with downloading office documents in IE under SSL but
365
    public void setSecurePagesWithPragma(boolean securePagesWithPragma) {
365
     * which fix a caching problem in Mozilla.
366
        this.securePagesWithPragma = securePagesWithPragma;
366
     */
367
    }    
367
    public void setSecurePagesWithPragma(boolean securePagesWithPragma) {
368
368
        this.securePagesWithPragma = securePagesWithPragma;
369
    // --------------------------------------------------------- Public Methods
369
    }    
370
370
371
371
    // --------------------------------------------------------- Public Methods
372
    /**
372
373
     * Enforce the security restrictions in the web application deployment
373
374
     * descriptor of our associated Context.
374
    /**
375
     *
375
     * Enforce the security restrictions in the web application deployment
376
     * @param request Request to be processed
376
     * descriptor of our associated Context.
377
     * @param response Response to be processed
377
     *
378
     *
378
     * @param request Request to be processed
379
     * @exception IOException if an input/output error occurs
379
     * @param response Response to be processed
380
     * @exception ServletException if thrown by a processing element
380
     *
381
     */
381
     * @exception IOException if an input/output error occurs
382
    public void invoke(Request request, Response response)
382
     * @exception ServletException if thrown by a processing element
383
        throws IOException, ServletException {
383
     */
384
384
    public void invoke(Request request, Response response)
385
        if (log.isDebugEnabled())
385
        throws IOException, ServletException {
386
            log.debug("Security checking request " +
386
387
                request.getMethod() + " " + request.getRequestURI());
387
        if (log.isDebugEnabled())
388
        LoginConfig config = this.context.getLoginConfig();
388
            log.debug("Security checking request " +
389
389
                request.getMethod() + " " + request.getRequestURI());
390
        // Have we got a cached authenticated Principal to record?
390
        LoginConfig config = this.context.getLoginConfig();
391
        if (cache) {
391
392
            Principal principal = request.getUserPrincipal();
392
        // Have we got a cached authenticated Principal to record?
393
            if (principal == null) {
393
        if (cache) {
394
                Session session = request.getSessionInternal(false);
394
            Principal principal = request.getUserPrincipal();
395
                if (session != null) {
395
            if (principal == null) {
396
                    principal = session.getPrincipal();
396
                Session session = request.getSessionInternal(false);
397
                    if (principal != null) {
397
                if (session != null) {
398
                        if (log.isDebugEnabled())
398
                    principal = session.getPrincipal();
399
                            log.debug("We have cached auth type " +
399
                    if (principal != null) {
400
                                session.getAuthType() +
400
                        if (log.isDebugEnabled())
401
                                " for principal " +
401
                            log.debug("We have cached auth type " +
402
                                session.getPrincipal());
402
                                session.getAuthType() +
403
                        request.setAuthType(session.getAuthType());
403
                                " for principal " +
404
                        request.setUserPrincipal(principal);
404
                                session.getPrincipal());
405
                    }
405
                        request.setAuthType(session.getAuthType());
406
                }
406
                        request.setUserPrincipal(principal);
407
            }
407
                    }
408
        }
408
                }
409
409
            }
410
        // Special handling for form-based logins to deal with the case
410
        }
411
        // where the login form (and therefore the "j_security_check" URI
411
412
        // to which it submits) might be outside the secured area
412
        // Special handling for form-based logins to deal with the case
413
        String contextPath = this.context.getPath();
413
        // where the login form (and therefore the "j_security_check" URI
414
        String requestURI = request.getDecodedRequestURI();
414
        // to which it submits) might be outside the secured area
415
        if (requestURI.startsWith(contextPath) &&
415
        String contextPath = this.context.getPath();
416
            requestURI.endsWith(Constants.FORM_ACTION)) {
416
        String requestURI = request.getDecodedRequestURI();
417
            if (!authenticate(request, response, config)) {
417
        if (requestURI.startsWith(contextPath) &&
418
                if (log.isDebugEnabled())
418
            requestURI.endsWith(Constants.FORM_ACTION)) {
419
                    log.debug(" Failed authenticate() test ??" + requestURI );
419
            if (!authenticate(request, response, config)) {
420
                return;
420
                if (log.isDebugEnabled())
421
            }
421
                    log.debug(" Failed authenticate() test ??" + requestURI );
422
        }
422
                return;
423
423
            }
424
        Realm realm = this.context.getRealm();
424
        }
425
        // Is this request URI subject to a security constraint?
425
426
        SecurityConstraint [] constraints
426
        Realm realm = this.context.getRealm();
427
            = realm.findSecurityConstraints(request, this.context);
427
        // Is this request URI subject to a security constraint?
428
       
428
        SecurityConstraint [] constraints
429
        if ((constraints == null) /* &&
429
            = realm.findSecurityConstraints(request, this.context);
430
            (!Constants.FORM_METHOD.equals(config.getAuthMethod())) */ ) {
430
       
431
            if (log.isDebugEnabled())
431
        // Make sure that constrained resources are not cached by web proxies
432
                log.debug(" Not subject to any constraint");
432
        // or browsers as caching can provide a security hole
433
            getNext().invoke(request, response);
433
        if (disableProxyCaching && 
434
            return;
434
            // FIXME: Disabled for Mozilla FORM support over SSL 
435
        }
435
            // (improper caching issue)
436
436
            //!request.isSecure() &&
437
        // Make sure that constrained resources are not cached by web proxies
437
            !"POST".equalsIgnoreCase(request.getMethod())) {
438
        // or browsers as caching can provide a security hole
438
            if (securePagesWithPragma) {
439
        if (disableProxyCaching && 
439
                // FIXME: These cause problems with downloading office docs
440
            // FIXME: Disabled for Mozilla FORM support over SSL 
440
                // from IE under SSL and may not be needed for newer Mozilla
441
            // (improper caching issue)
441
                // clients.
442
            //!request.isSecure() &&
442
                response.setHeader("Pragma", "No-cache");
443
            !"POST".equalsIgnoreCase(request.getMethod())) {
443
                response.setHeader("Cache-Control", "no-cache");
444
            if (securePagesWithPragma) {
444
            } else {
445
                // FIXME: These cause problems with downloading office docs
445
                response.setHeader("Cache-Control", "private");
446
                // from IE under SSL and may not be needed for newer Mozilla
446
            }
447
                // clients.
447
            response.setHeader("Expires", DATE_ONE);
448
                response.setHeader("Pragma", "No-cache");
448
        }
449
                response.setHeader("Cache-Control", "no-cache");
449
450
            } else {
450
        int i;
451
                response.setHeader("Cache-Control", "private");
451
        if (constraints != null) {
452
            }
452
          // Enforce any user data constraint for this security constraint
453
            response.setHeader("Expires", DATE_ONE);
453
          if (log.isDebugEnabled()) {
454
        }
454
              log.debug(" Calling hasUserDataPermission()");
455
455
          }
456
        int i;
456
          if (!realm.hasUserDataPermission(request, response,
457
        // Enforce any user data constraint for this security constraint
457
                                           constraints)) {
458
        if (log.isDebugEnabled()) {
458
              if (log.isDebugEnabled()) {
459
            log.debug(" Calling hasUserDataPermission()");
459
                  log.debug(" Failed hasUserDataPermission() test");
460
        }
460
              }
461
        if (!realm.hasUserDataPermission(request, response,
461
              /*
462
                                         constraints)) {
462
               * ASSERT: Authenticator already set the appropriate
463
            if (log.isDebugEnabled()) {
463
               * HTTP status code, so we do not have to do anything special
464
                log.debug(" Failed hasUserDataPermission() test");
464
               */
465
            }
465
              return;
466
            /*
466
          }
467
             * ASSERT: Authenticator already set the appropriate
467
        }
468
             * HTTP status code, so we do not have to do anything special
468
469
             */
469
        // Since authenticate modifies the response on failure,
470
            return;
470
        // we have to check for allow-from-all first.
471
        }
471
        boolean authRequired;
472
472
        if (constraints == null) {
473
        // Since authenticate modifies the response on failure,
473
          authRequired = false;
474
        // we have to check for allow-from-all first.
474
        } else {
475
        boolean authRequired = true;
475
          authRequired = true;
476
        for(i=0; i < constraints.length && authRequired; i++) {
476
          for(i=0; i < constraints.length && authRequired; i++) {
477
            if(!constraints[i].getAuthConstraint()) {
477
              if(!constraints[i].getAuthConstraint()) {
478
                authRequired = false;
478
                  authRequired = false;
479
            } else if(!constraints[i].getAllRoles()) {
479
              } else if(!constraints[i].getAllRoles()) {
480
                String [] roles = constraints[i].findAuthRoles();
480
                  String [] roles = constraints[i].findAuthRoles();
481
                if(roles == null || roles.length == 0) {
481
                  if(roles == null || roles.length == 0) {
482
                    authRequired = false;
482
                      authRequired = false;
483
                }
483
                  }
484
            }
484
              }
485
        }
485
          }
486
             
486
        }
487
        if(authRequired) {  
487
             
488
            if (log.isDebugEnabled()) {
488
        if (!authRequired)
489
                log.debug(" Calling authenticate()");
489
        {
490
            }
490
          authRequired =
491
            if (!authenticate(request, response, config)) {
491
            request.getCoyoteRequest().getMimeHeaders().
492
                if (log.isDebugEnabled()) {
492
              getValue("authorization") != null;
493
                    log.debug(" Failed authenticate() test");
493
        }
494
                }
494
495
                /*
495
        if (!authRequired)
496
                 * ASSERT: Authenticator already set the appropriate
496
        {
497
                 * HTTP status code, so we do not have to do anything
497
          X509Certificate[] certs =
498
                 * special
498
            (X509Certificate[]) request.getAttribute(Globals.CERTIFICATES_ATTR);
499
                 */
499
500
                return;
500
          authRequired = certs != null && certs.length > 0;
501
            } 
501
        }
502
        }
502
503
    
503
        if(authRequired) {  
504
        if (log.isDebugEnabled()) {
504
            if (log.isDebugEnabled()) {
505
            log.debug(" Calling accessControl()");
505
                log.debug(" Calling authenticate()");
506
        }
506
            }
507
        if (!realm.hasResourcePermission(request, response,
507
            if (!authenticate(request, response, config)) {
508
                                         constraints,
508
                if (log.isDebugEnabled()) {
509
                                         this.context)) {
509
                    log.debug(" Failed authenticate() test");
510
            if (log.isDebugEnabled()) {
510
                }
511
                log.debug(" Failed accessControl() test");
511
                /*
512
            }
512
                 * ASSERT: Authenticator already set the appropriate
513
            /*
513
                 * HTTP status code, so we do not have to do anything
514
             * ASSERT: AccessControl method has already set the
514
                 * special
515
             * appropriate HTTP status code, so we do not have to do
515
                 */
516
             * anything special
516
                return;
517
             */
517
            } 
518
            return;
518
        }
519
        }
519
    
520
    
520
        if (constraints != null) {
521
        // Any and all specified constraints have been satisfied
521
          if (log.isDebugEnabled()) {
522
        if (log.isDebugEnabled()) {
522
              log.debug(" Calling accessControl()");
523
            log.debug(" Successfully passed all security constraints");
523
          }
524
        }
524
          if (!realm.hasResourcePermission(request, response,
525
        getNext().invoke(request, response);
525
                                           constraints,
526
526
                                           this.context)) {
527
    }
527
              if (log.isDebugEnabled()) {
528
528
                  log.debug(" Failed accessControl() test");
529
529
              }
530
    // ------------------------------------------------------ Protected Methods
530
              /*
531
531
               * ASSERT: AccessControl method has already set the
532
532
               * appropriate HTTP status code, so we do not have to do
533
533
               * anything special
534
534
               */
535
    /**
535
              return;
536
     * Associate the specified single sign on identifier with the
536
          }
537
     * specified Session.
537
        }
538
     *
538
    
539
     * @param ssoId Single sign on identifier
539
        // Any and all specified constraints have been satisfied
540
     * @param session Session to be associated
540
        if (log.isDebugEnabled()) {
541
     */
541
            log.debug(" Successfully passed all security constraints");
542
    protected void associate(String ssoId, Session session) {
542
        }
543
543
        getNext().invoke(request, response);
544
        if (sso == null)
544
545
            return;
545
    }
546
        sso.associate(ssoId, session);
546
547
547
548
    }
548
    // ------------------------------------------------------ Protected Methods
549
549
550
550
551
    /**
551
552
     * Authenticate the user making this request, based on the specified
552
553
     * login configuration.  Return <code>true</code> if any specified
553
    /**
554
     * constraint has been satisfied, or <code>false</code> if we have
554
     * Associate the specified single sign on identifier with the
555
     * created a response challenge already.
555
     * specified Session.
556
     *
556
     *
557
     * @param request Request we are processing
557
     * @param ssoId Single sign on identifier
558
     * @param response Response we are creating
558
     * @param session Session to be associated
559
     * @param config    Login configuration describing how authentication
559
     */
560
     *              should be performed
560
    protected void associate(String ssoId, Session session) {
561
     *
561
562
     * @exception IOException if an input/output error occurs
562
        if (sso == null)
563
     */
563
            return;
564
    protected abstract boolean authenticate(Request request,
564
        sso.associate(ssoId, session);
565
                                            Response response,
565
566
                                            LoginConfig config)
566
    }
567
        throws IOException;
567
568
568
569
569
    /**
570
    /**
570
     * Authenticate the user making this request, based on the specified
571
     * Generate and return a new session identifier for the cookie that
571
     * login configuration.  Return <code>true</code> if any specified
572
     * identifies an SSO principal.
572
     * constraint has been satisfied, or <code>false</code> if we have
573
     */
573
     * created a response challenge already.
574
    protected synchronized String generateSessionId() {
574
     *
575
575
     * @param request Request we are processing
576
        // Generate a byte array containing a session identifier
576
     * @param response Response we are creating
577
        byte bytes[] = new byte[SESSION_ID_BYTES];
577
     * @param config    Login configuration describing how authentication
578
        getRandom().nextBytes(bytes);
578
     *              should be performed
579
        bytes = getDigest().digest(bytes);
579
     *
580
580
     * @exception IOException if an input/output error occurs
581
        // Render the result as a String of hexadecimal digits
581
     */
582
        StringBuffer result = new StringBuffer();
582
    protected abstract boolean authenticate(Request request,
583
        for (int i = 0; i < bytes.length; i++) {
583
                                            Response response,
584
            byte b1 = (byte) ((bytes[i] & 0xf0) >> 4);
584
                                            LoginConfig config)
585
            byte b2 = (byte) (bytes[i] & 0x0f);
585
        throws IOException;
586
            if (b1 < 10)
586
587
                result.append((char) ('0' + b1));
587
588
            else
588
    /**
589
                result.append((char) ('A' + (b1 - 10)));
589
     * Generate and return a new session identifier for the cookie that
590
            if (b2 < 10)
590
     * identifies an SSO principal.
591
                result.append((char) ('0' + b2));
591
     */
592
            else
592
    protected synchronized String generateSessionId() {
593
                result.append((char) ('A' + (b2 - 10)));
593
594
        }
594
        // Generate a byte array containing a session identifier
595
        return (result.toString());
595
        byte bytes[] = new byte[SESSION_ID_BYTES];
596
596
        getRandom().nextBytes(bytes);
597
    }
597
        bytes = getDigest().digest(bytes);
598
598
599
599
        // Render the result as a String of hexadecimal digits
600
    /**
600
        StringBuffer result = new StringBuffer();
601
     * Return the MessageDigest object to be used for calculating
601
        for (int i = 0; i < bytes.length; i++) {
602
     * session identifiers.  If none has been created yet, initialize
602
            byte b1 = (byte) ((bytes[i] & 0xf0) >> 4);
603
     * one the first time this method is called.
603
            byte b2 = (byte) (bytes[i] & 0x0f);
604
     */
604
            if (b1 < 10)
605
    protected synchronized MessageDigest getDigest() {
605
                result.append((char) ('0' + b1));
606
606
            else
607
        if (this.digest == null) {
607
                result.append((char) ('A' + (b1 - 10)));
608
            try {
608
            if (b2 < 10)
609
                this.digest = MessageDigest.getInstance(algorithm);
609
                result.append((char) ('0' + b2));
610
            } catch (NoSuchAlgorithmException e) {
610
            else
611
                try {
611
                result.append((char) ('A' + (b2 - 10)));
612
                    this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
612
        }
613
                } catch (NoSuchAlgorithmException f) {
613
        return (result.toString());
614
                    this.digest = null;
614
615
                }
615
    }
616
            }
616
617
        }
617
618
618
    /**
619
        return (this.digest);
619
     * Return the MessageDigest object to be used for calculating
620
620
     * session identifiers.  If none has been created yet, initialize
621
    }
621
     * one the first time this method is called.
622
622
     */
623
623
    protected synchronized MessageDigest getDigest() {
624
    /**
624
625
     * Return the random number generator instance we should use for
625
        if (this.digest == null) {
626
     * generating session identifiers.  If there is no such generator
626
            try {
627
     * currently defined, construct and seed a new one.
627
                this.digest = MessageDigest.getInstance(algorithm);
628
     */
628
            } catch (NoSuchAlgorithmException e) {
629
    protected synchronized Random getRandom() {
629
                try {
630
630
                    this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
631
        if (this.random == null) {
631
                } catch (NoSuchAlgorithmException f) {
632
            try {
632
                    this.digest = null;
633
                Class clazz = Class.forName(randomClass);
633
                }
634
                this.random = (Random) clazz.newInstance();
634
            }
635
                long seed = System.currentTimeMillis();
635
        }
636
                char entropy[] = getEntropy().toCharArray();
636
637
                for (int i = 0; i < entropy.length; i++) {
637
        return (this.digest);
638
                    long update = ((byte) entropy[i]) << ((i % 8) * 8);
638
639
                    seed ^= update;
639
    }
640
                }
640
641
                this.random.setSeed(seed);
641
642
            } catch (Exception e) {
642
    /**
643
                this.random = new java.util.Random();
643
     * Return the random number generator instance we should use for
644
            }
644
     * generating session identifiers.  If there is no such generator
645
        }
645
     * currently defined, construct and seed a new one.
646
646
     */
647
        return (this.random);
647
    protected synchronized Random getRandom() {
648
648
649
    }
649
        if (this.random == null) {
650
650
            try {
651
651
                Class clazz = Class.forName(randomClass);
652
    /**
652
                this.random = (Random) clazz.newInstance();
653
     * Attempts reauthentication to the <code>Realm</code> using
653
                long seed = System.currentTimeMillis();
654
     * the credentials included in argument <code>entry</code>.
654
                char entropy[] = getEntropy().toCharArray();
655
     *
655
                for (int i = 0; i < entropy.length; i++) {
656
     * @param ssoId identifier of SingleSignOn session with which the
656
                    long update = ((byte) entropy[i]) << ((i % 8) * 8);
657
     *              caller is associated
657
                    seed ^= update;
658
     * @param request   the request that needs to be authenticated
658
                }
659
     */
659
                this.random.setSeed(seed);
660
    protected boolean reauthenticateFromSSO(String ssoId, Request request) {
660
            } catch (Exception e) {
661
661
                this.random = new java.util.Random();
662
        if (sso == null || ssoId == null)
662
            }
663
            return false;
663
        }
664
664
665
        boolean reauthenticated = false;
665
        return (this.random);
666
666
667
        Container parent = getContainer();
667
    }
668
        if (parent != null) {
668
669
            Realm realm = parent.getRealm();
669
670
            if (realm != null) {
670
    /**
671
                reauthenticated = sso.reauthenticate(ssoId, realm, request);
671
     * Attempts reauthentication to the <code>Realm</code> using
672
            }
672
     * the credentials included in argument <code>entry</code>.
673
        }
673
     *
674
674
     * @param ssoId identifier of SingleSignOn session with which the
675
        if (reauthenticated) {
675
     *              caller is associated
676
            associate(ssoId, request.getSessionInternal(true));
676
     * @param request   the request that needs to be authenticated
677
677
     */
678
            if (log.isDebugEnabled()) {
678
    protected boolean reauthenticateFromSSO(String ssoId, Request request) {
679
                log.debug(" Reauthenticated cached principal '" +
679
680
                          request.getUserPrincipal().getName() +
680
        if (sso == null || ssoId == null)
681
                          "' with auth type '" +  request.getAuthType() + "'");
681
            return false;
682
            }
682
683
        }
683
        boolean reauthenticated = false;
684
684
685
        return reauthenticated;
685
        Container parent = getContainer();
686
    }
686
        if (parent != null) {
687
687
            Realm realm = parent.getRealm();
688
688
            if (realm != null) {
689
    /**
689
                reauthenticated = sso.reauthenticate(ssoId, realm, request);
690
     * Register an authenticated Principal and authentication type in our
690
            }
691
     * request, in the current session (if there is one), and with our
691
        }
692
     * SingleSignOn valve, if there is one.  Set the appropriate cookie
692
693
     * to be returned.
693
        if (reauthenticated) {
694
     *
694
            associate(ssoId, request.getSessionInternal(true));
695
     * @param request The servlet request we are processing
695
696
     * @param response The servlet response we are generating
696
            if (log.isDebugEnabled()) {
697
     * @param principal The authenticated Principal to be registered
697
                log.debug(" Reauthenticated cached principal '" +
698
     * @param authType The authentication type to be registered
698
                          request.getUserPrincipal().getName() +
699
     * @param username Username used to authenticate (if any)
699
                          "' with auth type '" +  request.getAuthType() + "'");
700
     * @param password Password used to authenticate (if any)
700
            }
701
     */
701
        }
702
    protected void register(Request request, Response response,
702
703
                            Principal principal, String authType,
703
        return reauthenticated;
704
                            String username, String password) {
704
    }
705
705
706
        if (log.isDebugEnabled()) {
706
707
            // Bugzilla 39255: http://issues.apache.org/bugzilla/show_bug.cgi?id=39255
707
    /**
708
            String name = (principal == null) ? "none" : principal.getName();
708
     * Register an authenticated Principal and authentication type in our
709
            log.debug("Authenticated '" + name + "' with type '"
709
     * request, in the current session (if there is one), and with our
710
                + authType + "'");
710
     * SingleSignOn valve, if there is one.  Set the appropriate cookie
711
        }
711
     * to be returned.
712
712
     *
713
        // Cache the authentication information in our request
713
     * @param request The servlet request we are processing
714
        request.setAuthType(authType);
714
     * @param response The servlet response we are generating
715
        request.setUserPrincipal(principal);
715
     * @param principal The authenticated Principal to be registered
716
716
     * @param authType The authentication type to be registered
717
        Session session = request.getSessionInternal(false);
717
     * @param username Username used to authenticate (if any)
718
        // Cache the authentication information in our session, if any
718
     * @param password Password used to authenticate (if any)
719
        if (cache) {
719
     */
720
            if (session != null) {
720
    protected void register(Request request, Response response,
721
                session.setAuthType(authType);
721
                            Principal principal, String authType,
722
                session.setPrincipal(principal);
722
                            String username, String password) {
723
                if (username != null)
723
724
                    session.setNote(Constants.SESS_USERNAME_NOTE, username);
724
        if (log.isDebugEnabled()) {
725
                else
725
            // Bugzilla 39255: http://issues.apache.org/bugzilla/show_bug.cgi?id=39255
726
                    session.removeNote(Constants.SESS_USERNAME_NOTE);
726
            String name = (principal == null) ? "none" : principal.getName();
727
                if (password != null)
727
            log.debug("Authenticated '" + name + "' with type '"
728
                    session.setNote(Constants.SESS_PASSWORD_NOTE, password);
728
                + authType + "'");
729
                else
729
        }
730
                    session.removeNote(Constants.SESS_PASSWORD_NOTE);
730
731
            }
731
        // Cache the authentication information in our request
732
        }
732
        request.setAuthType(authType);
733
733
        request.setUserPrincipal(principal);
734
        // Construct a cookie to be returned to the client
734
735
        if (sso == null)
735
        Session session = request.getSessionInternal(false);
736
            return;
736
        // Cache the authentication information in our session, if any
737
737
        if (cache) {
738
        // Only create a new SSO entry if the SSO did not already set a note
738
            if (session != null) {
739
        // for an existing entry (as it would do with subsequent requests
739
                session.setAuthType(authType);
740
        // for DIGEST and SSL authenticated contexts)
740
                session.setPrincipal(principal);
741
        String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
741
                if (username != null)
742
        if (ssoId == null) {
742
                    session.setNote(Constants.SESS_USERNAME_NOTE, username);
743
            // Construct a cookie to be returned to the client
743
                else
744
            ssoId = generateSessionId();
744
                    session.removeNote(Constants.SESS_USERNAME_NOTE);
745
            Cookie cookie = new Cookie(Constants.SINGLE_SIGN_ON_COOKIE, ssoId);
745
                if (password != null)
746
            cookie.setMaxAge(-1);
746
                    session.setNote(Constants.SESS_PASSWORD_NOTE, password);
747
            cookie.setPath("/");
747
                else
748
            
748
                    session.removeNote(Constants.SESS_PASSWORD_NOTE);
749
            // Bugzilla 41217
749
            }
750
            cookie.setSecure(request.isSecure());
750
        }
751
            
751
752
            // Bugzilla 34724
752
        // Construct a cookie to be returned to the client
753
            String ssoDomain = sso.getCookieDomain();
753
        if (sso == null)
754
            if(ssoDomain != null) {
754
            return;
755
                cookie.setDomain(ssoDomain);
755
756
            }
756
        // Only create a new SSO entry if the SSO did not already set a note
757
757
        // for an existing entry (as it would do with subsequent requests
758
            response.addCookie(cookie);
758
        // for DIGEST and SSL authenticated contexts)
759
759
        String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
760
            // Register this principal with our SSO valve
760
        if (ssoId == null) {
761
            sso.register(ssoId, principal, authType, username, password);
761
            // Construct a cookie to be returned to the client
762
            request.setNote(Constants.REQ_SSOID_NOTE, ssoId);
762
            ssoId = generateSessionId();
763
763
            Cookie cookie = new Cookie(Constants.SINGLE_SIGN_ON_COOKIE, ssoId);
764
        } else {
764
            cookie.setMaxAge(-1);
765
            // Update the SSO session with the latest authentication data
765
            cookie.setPath("/");
766
            sso.update(ssoId, principal, authType, username, password);
766
            
767
        }
767
            // Bugzilla 41217
768
768
            cookie.setSecure(request.isSecure());
769
        // Fix for Bug 10040
769
            
770
        // Always associate a session with a new SSO reqistration.
770
            // Bugzilla 34724
771
        // SSO entries are only removed from the SSO registry map when
771
            String ssoDomain = sso.getCookieDomain();
772
        // associated sessions are destroyed; if a new SSO entry is created
772
            if(ssoDomain != null) {
773
        // above for this request and the user never revisits the context, the
773
                cookie.setDomain(ssoDomain);
774
        // SSO entry will never be cleared if we don't associate the session
774
            }
775
        if (session == null)
775
776
            session = request.getSessionInternal(true);
776
            response.addCookie(cookie);
777
        sso.associate(ssoId, session);
777
778
778
            // Register this principal with our SSO valve
779
    }
779
            sso.register(ssoId, principal, authType, username, password);
780
780
            request.setNote(Constants.REQ_SSOID_NOTE, ssoId);
781
781
782
    // ------------------------------------------------------ Lifecycle Methods
782
        } else {
783
783
            // Update the SSO session with the latest authentication data
784
784
            sso.update(ssoId, principal, authType, username, password);
785
    /**
785
        }
786
     * Add a lifecycle event listener to this component.
786
787
     *
787
        // Fix for Bug 10040
788
     * @param listener The listener to add
788
        // Always associate a session with a new SSO reqistration.
789
     */
789
        // SSO entries are only removed from the SSO registry map when
790
    public void addLifecycleListener(LifecycleListener listener) {
790
        // associated sessions are destroyed; if a new SSO entry is created
791
791
        // above for this request and the user never revisits the context, the
792
        lifecycle.addLifecycleListener(listener);
792
        // SSO entry will never be cleared if we don't associate the session
793
793
        if (session == null)
794
    }
794
            session = request.getSessionInternal(true);
795
795
        sso.associate(ssoId, session);
796
796
797
    /**
797
    }
798
     * Get the lifecycle listeners associated with this lifecycle. If this 
798
799
     * Lifecycle has no listeners registered, a zero-length array is returned.
799
800
     */
800
    // ------------------------------------------------------ Lifecycle Methods
801
    public LifecycleListener[] findLifecycleListeners() {
801
802
802
803
        return lifecycle.findLifecycleListeners();
803
    /**
804
804
     * Add a lifecycle event listener to this component.
805
    }
805
     *
806
806
     * @param listener The listener to add
807
807
     */
808
    /**
808
    public void addLifecycleListener(LifecycleListener listener) {
809
     * Remove a lifecycle event listener from this component.
809
810
     *
810
        lifecycle.addLifecycleListener(listener);
811
     * @param listener The listener to remove
811
812
     */
812
    }
813
    public void removeLifecycleListener(LifecycleListener listener) {
813
814
814
815
        lifecycle.removeLifecycleListener(listener);
815
    /**
816
816
     * Get the lifecycle listeners associated with this lifecycle. If this 
817
    }
817
     * Lifecycle has no listeners registered, a zero-length array is returned.
818
818
     */
819
819
    public LifecycleListener[] findLifecycleListeners() {
820
    /**
820
821
     * Prepare for the beginning of active use of the public methods of this
821
        return lifecycle.findLifecycleListeners();
822
     * component.  This method should be called after <code>configure()</code>,
822
823
     * and before any of the public methods of the component are utilized.
823
    }
824
     *
824
825
     * @exception LifecycleException if this component detects a fatal error
825
826
     *  that prevents this component from being used
826
    /**
827
     */
827
     * Remove a lifecycle event listener from this component.
828
    public void start() throws LifecycleException {
828
     *
829
829
     * @param listener The listener to remove
830
        // Validate and update our current component state
830
     */
831
        if (started)
831
    public void removeLifecycleListener(LifecycleListener listener) {
832
            throw new LifecycleException
832
833
                (sm.getString("authenticator.alreadyStarted"));
833
        lifecycle.removeLifecycleListener(listener);
834
        lifecycle.fireLifecycleEvent(START_EVENT, null);
834
835
        started = true;
835
    }
836
836
837
        // Look up the SingleSignOn implementation in our request processing
837
838
        // path, if there is one
838
    /**
839
        Container parent = context.getParent();
839
     * Prepare for the beginning of active use of the public methods of this
840
        while ((sso == null) && (parent != null)) {
840
     * component.  This method should be called after <code>configure()</code>,
841
            if (!(parent instanceof Pipeline)) {
841
     * and before any of the public methods of the component are utilized.
842
                parent = parent.getParent();
842
     *
843
                continue;
843
     * @exception LifecycleException if this component detects a fatal error
844
            }
844
     *  that prevents this component from being used
845
            Valve valves[] = ((Pipeline) parent).getValves();
845
     */
846
            for (int i = 0; i < valves.length; i++) {
846
    public void start() throws LifecycleException {
847
                if (valves[i] instanceof SingleSignOn) {
847
848
                    sso = (SingleSignOn) valves[i];
848
        // Validate and update our current component state
849
                    break;
849
        if (started)
850
                }
850
            throw new LifecycleException
851
            }
851
                (sm.getString("authenticator.alreadyStarted"));
852
            if (sso == null)
852
        lifecycle.fireLifecycleEvent(START_EVENT, null);
853
                parent = parent.getParent();
853
        started = true;
854
        }
854
855
        if (log.isDebugEnabled()) {
855
        // Look up the SingleSignOn implementation in our request processing
856
            if (sso != null)
856
        // path, if there is one
857
                log.debug("Found SingleSignOn Valve at " + sso);
857
        Container parent = context.getParent();
858
            else
858
        while ((sso == null) && (parent != null)) {
859
                log.debug("No SingleSignOn Valve is present");
859
            if (!(parent instanceof Pipeline)) {
860
        }
860
                parent = parent.getParent();
861
861
                continue;
862
    }
862
            }
863
863
            Valve valves[] = ((Pipeline) parent).getValves();
864
864
            for (int i = 0; i < valves.length; i++) {
865
    /**
865
                if (valves[i] instanceof SingleSignOn) {
866
     * Gracefully terminate the active use of the public methods of this
866
                    sso = (SingleSignOn) valves[i];
867
     * component.  This method should be the last one called on a given
867
                    break;
868
     * instance of this component.
868
                }
869
     *
869
            }
870
     * @exception LifecycleException if this component detects a fatal error
870
            if (sso == null)
871
     *  that needs to be reported
871
                parent = parent.getParent();
872
     */
872
        }
873
    public void stop() throws LifecycleException {
873
        if (log.isDebugEnabled()) {
874
874
            if (sso != null)
875
        // Validate and update our current component state
875
                log.debug("Found SingleSignOn Valve at " + sso);
876
        if (!started)
876
            else
877
            throw new LifecycleException
877
                log.debug("No SingleSignOn Valve is present");
878
                (sm.getString("authenticator.notStarted"));
878
        }
879
        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
879
880
        started = false;
880
    }
881
881
882
        sso = null;
882
883
883
    /**
884
    }
884
     * Gracefully terminate the active use of the public methods of this
885
885
     * component.  This method should be the last one called on a given
886
886
     * instance of this component.
887
}
887
     *
888
     * @exception LifecycleException if this component detects a fatal error
889
     *  that needs to be reported
890
     */
891
    public void stop() throws LifecycleException {
892
893
        // Validate and update our current component state
894
        if (!started)
895
            throw new LifecycleException
896
                (sm.getString("authenticator.notStarted"));
897
        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
898
        started = false;
899
900
        sso = null;
901
902
    }
903
904
905
}

Return to bug 12428