~ubuntu-branches/ubuntu/vivid/tomcat6/vivid

« back to all changes in this revision

Viewing changes to .pc/0016-CVE-2012-3546.patch/java/org/apache/catalina/realm/RealmBase.java

  • Committer: Package Import Robot
  • Author(s): tony mancill
  • Date: 2012-12-06 21:10:11 UTC
  • Revision ID: package-import@ubuntu.com-20121206211011-zuimndvjmjiwul9z
Tags: 6.0.35-6
* Acknowledge NMU: 6.0.35-5+nmu1 (Closes: #692440)
  - Thank you to Michael Gilbert.
* Add patches for the following security issues: (Closes: #695250)
  - CVE-2012-4534, CVE-2012-4431, CVE-2012-3546

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.realm;
 
20
 
 
21
 
 
22
import java.beans.PropertyChangeListener;
 
23
import java.beans.PropertyChangeSupport;
 
24
import java.io.IOException;
 
25
import java.io.UnsupportedEncodingException;
 
26
import java.security.MessageDigest;
 
27
import java.security.NoSuchAlgorithmException;
 
28
import java.security.Principal;
 
29
import java.security.cert.X509Certificate;
 
30
import java.util.ArrayList;
 
31
 
 
32
import javax.management.Attribute;
 
33
import javax.management.MBeanRegistration;
 
34
import javax.management.MBeanServer;
 
35
import javax.management.ObjectName;
 
36
import javax.servlet.http.HttpServletResponse;
 
37
 
 
38
import org.apache.catalina.Container;
 
39
import org.apache.catalina.Context;
 
40
import org.apache.catalina.Globals;
 
41
import org.apache.catalina.Lifecycle;
 
42
import org.apache.catalina.LifecycleException;
 
43
import org.apache.catalina.LifecycleListener;
 
44
import org.apache.catalina.Realm;
 
45
import org.apache.catalina.connector.Request;
 
46
import org.apache.catalina.connector.Response;
 
47
import org.apache.catalina.core.ContainerBase;
 
48
import org.apache.catalina.deploy.LoginConfig;
 
49
import org.apache.catalina.deploy.SecurityConstraint;
 
50
import org.apache.catalina.deploy.SecurityCollection;
 
51
import org.apache.catalina.util.HexUtils;
 
52
import org.apache.catalina.util.LifecycleSupport;
 
53
import org.apache.catalina.util.MD5Encoder;
 
54
import org.apache.catalina.util.StringManager;
 
55
import org.apache.juli.logging.Log;
 
56
import org.apache.juli.logging.LogFactory;
 
57
import org.apache.tomcat.util.modeler.Registry;
 
58
 
 
59
/**
 
60
 * Simple implementation of <b>Realm</b> that reads an XML file to configure
 
61
 * the valid users, passwords, and roles.  The file format (and default file
 
62
 * location) are identical to those currently supported by Tomcat 3.X.
 
63
 *
 
64
 * @author Craig R. McClanahan
 
65
 * @version $Id: RealmBase.java 1158180 2011-08-16 10:11:43Z markt $
 
66
 */
 
67
 
 
68
public abstract class RealmBase
 
69
    implements Lifecycle, Realm, MBeanRegistration {
 
70
 
 
71
    private static Log log = LogFactory.getLog(RealmBase.class);
 
72
 
 
73
    // ----------------------------------------------------- Instance Variables
 
74
 
 
75
 
 
76
    /**
 
77
     * The Container with which this Realm is associated.
 
78
     */
 
79
    protected Container container = null;
 
80
 
 
81
 
 
82
    /**
 
83
     * Container log
 
84
     */
 
85
    protected Log containerLog = null;
 
86
 
 
87
 
 
88
    /**
 
89
     * Digest algorithm used in storing passwords in a non-plaintext format.
 
90
     * Valid values are those accepted for the algorithm name by the
 
91
     * MessageDigest class, or <code>null</code> if no digesting should
 
92
     * be performed.
 
93
     */
 
94
    protected String digest = null;
 
95
 
 
96
    /**
 
97
     * The encoding charset for the digest.
 
98
     */
 
99
    protected String digestEncoding = null;
 
100
 
 
101
 
 
102
    /**
 
103
     * Descriptive information about this Realm implementation.
 
104
     */
 
105
    protected static final String info =
 
106
        "org.apache.catalina.realm.RealmBase/1.0";
 
107
 
 
108
 
 
109
    /**
 
110
     * The lifecycle event support for this component.
 
111
     */
 
112
    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
 
113
 
 
114
 
 
115
    /**
 
116
     * The MessageDigest object for digesting user credentials (passwords).
 
117
     */
 
118
    protected MessageDigest md = null;
 
119
 
 
120
 
 
121
    /**
 
122
     * The MD5 helper object for this class.
 
123
     */
 
124
    protected static final MD5Encoder md5Encoder = new MD5Encoder();
 
125
 
 
126
 
 
127
    /**
 
128
     * MD5 message digest provider.
 
129
     */
 
130
    protected static MessageDigest md5Helper;
 
131
 
 
132
 
 
133
    /**
 
134
     * The string manager for this package.
 
135
     */
 
136
    protected static StringManager sm =
 
137
        StringManager.getManager(Constants.Package);
 
138
 
 
139
 
 
140
    /**
 
141
     * Has this component been started?
 
142
     */
 
143
    protected boolean started = false;
 
144
 
 
145
 
 
146
    /**
 
147
     * The property change support for this component.
 
148
     */
 
149
    protected PropertyChangeSupport support = new PropertyChangeSupport(this);
 
150
 
 
151
 
 
152
    /**
 
153
     * Should we validate client certificate chains when they are presented?
 
154
     */
 
155
    protected boolean validate = true;
 
156
 
 
157
    
 
158
    /**
 
159
     * The all role mode.
 
160
     */
 
161
    protected AllRolesMode allRolesMode = AllRolesMode.STRICT_MODE;
 
162
    
 
163
 
 
164
    // ------------------------------------------------------------- Properties
 
165
 
 
166
 
 
167
    /**
 
168
     * Return the Container with which this Realm has been associated.
 
169
     */
 
170
    public Container getContainer() {
 
171
 
 
172
        return (container);
 
173
 
 
174
    }
 
175
 
 
176
 
 
177
    /**
 
178
     * Set the Container with which this Realm has been associated.
 
179
     *
 
180
     * @param container The associated Container
 
181
     */
 
182
    public void setContainer(Container container) {
 
183
 
 
184
        Container oldContainer = this.container;
 
185
        this.container = container;
 
186
        support.firePropertyChange("container", oldContainer, this.container);
 
187
 
 
188
    }
 
189
 
 
190
    /**
 
191
     * Return the all roles mode.
 
192
     */
 
193
    public String getAllRolesMode() {
 
194
 
 
195
        return allRolesMode.toString();
 
196
 
 
197
    }
 
198
 
 
199
 
 
200
    /**
 
201
     * Set the all roles mode.
 
202
     */
 
203
    public void setAllRolesMode(String allRolesMode) {
 
204
 
 
205
        this.allRolesMode = AllRolesMode.toMode(allRolesMode);
 
206
 
 
207
    }
 
208
 
 
209
    /**
 
210
     * Return the digest algorithm  used for storing credentials.
 
211
     */
 
212
    public String getDigest() {
 
213
 
 
214
        return digest;
 
215
 
 
216
    }
 
217
 
 
218
 
 
219
    /**
 
220
     * Set the digest algorithm used for storing credentials.
 
221
     *
 
222
     * @param digest The new digest algorithm
 
223
     */
 
224
    public void setDigest(String digest) {
 
225
 
 
226
        this.digest = digest;
 
227
 
 
228
    }
 
229
 
 
230
    /**
 
231
     * Returns the digest encoding charset.
 
232
     *
 
233
     * @return The charset (may be null) for platform default
 
234
     */
 
235
    public String getDigestEncoding() {
 
236
        return digestEncoding;
 
237
    }
 
238
 
 
239
    /**
 
240
     * Sets the digest encoding charset.
 
241
     *
 
242
     * @param charset The charset (null for platform default)
 
243
     */
 
244
    public void setDigestEncoding(String charset) {
 
245
        digestEncoding = charset;
 
246
    }
 
247
 
 
248
    /**
 
249
     * Return descriptive information about this Realm implementation and
 
250
     * the corresponding version number, in the format
 
251
     * <code>&lt;description&gt;/&lt;version&gt;</code>.
 
252
     */
 
253
    public String getInfo() {
 
254
 
 
255
        return info;
 
256
 
 
257
    }
 
258
 
 
259
 
 
260
    /**
 
261
     * Return the "validate certificate chains" flag.
 
262
     */
 
263
    public boolean getValidate() {
 
264
 
 
265
        return (this.validate);
 
266
 
 
267
    }
 
268
 
 
269
 
 
270
    /**
 
271
     * Set the "validate certificate chains" flag.
 
272
     *
 
273
     * @param validate The new validate certificate chains flag
 
274
     */
 
275
    public void setValidate(boolean validate) {
 
276
 
 
277
        this.validate = validate;
 
278
 
 
279
    }
 
280
 
 
281
 
 
282
    // --------------------------------------------------------- Public Methods
 
283
 
 
284
 
 
285
    
 
286
    /**
 
287
     * Add a property change listener to this component.
 
288
     *
 
289
     * @param listener The listener to add
 
290
     */
 
291
    public void addPropertyChangeListener(PropertyChangeListener listener) {
 
292
 
 
293
        support.addPropertyChangeListener(listener);
 
294
 
 
295
    }
 
296
 
 
297
 
 
298
    /**
 
299
     * Return the Principal associated with the specified username and
 
300
     * credentials, if there is one; otherwise return <code>null</code>.
 
301
     *
 
302
     * @param username Username of the Principal to look up
 
303
     * @param credentials Password or other credentials to use in
 
304
     *  authenticating this username
 
305
     */
 
306
    public Principal authenticate(String username, String credentials) {
 
307
 
 
308
        String serverCredentials = getPassword(username);
 
309
 
 
310
        boolean validated ;
 
311
        if ( serverCredentials == null ) {
 
312
            validated = false;
 
313
        } else if(hasMessageDigest()) {
 
314
            validated = serverCredentials.equalsIgnoreCase(digest(credentials));
 
315
        } else {
 
316
            validated = serverCredentials.equals(credentials);
 
317
        }
 
318
        if(! validated ) {
 
319
            if (containerLog.isTraceEnabled()) {
 
320
                containerLog.trace(sm.getString("realmBase.authenticateFailure",
 
321
                                                username));
 
322
            }
 
323
            return null;
 
324
        }
 
325
        if (containerLog.isTraceEnabled()) {
 
326
            containerLog.trace(sm.getString("realmBase.authenticateSuccess",
 
327
                                            username));
 
328
        }
 
329
 
 
330
        return getPrincipal(username);
 
331
    }
 
332
 
 
333
 
 
334
    /**
 
335
     * Return the Principal associated with the specified username and
 
336
     * credentials, if there is one; otherwise return <code>null</code>.
 
337
     *
 
338
     * @param username Username of the Principal to look up
 
339
     * @param credentials Password or other credentials to use in
 
340
     *  authenticating this username
 
341
     */
 
342
    public Principal authenticate(String username, byte[] credentials) {
 
343
 
 
344
        return (authenticate(username, credentials.toString()));
 
345
 
 
346
    }
 
347
 
 
348
 
 
349
    /**
 
350
     * Return the Principal associated with the specified username, which
 
351
     * matches the digest calculated using the given parameters using the
 
352
     * method described in RFC 2069; otherwise return <code>null</code>.
 
353
     *
 
354
     * @param username Username of the Principal to look up
 
355
     * @param clientDigest Digest which has been submitted by the client
 
356
     * @param nonce Unique (or supposedly unique) token which has been used
 
357
     * for this request
 
358
     * @param realm Realm name
 
359
     * @param md5a2 Second MD5 digest used to calculate the digest :
 
360
     * MD5(Method + ":" + uri)
 
361
     */
 
362
    public Principal authenticate(String username, String clientDigest,
 
363
                                  String nonce, String nc, String cnonce,
 
364
                                  String qop, String realm,
 
365
                                  String md5a2) {
 
366
 
 
367
        String md5a1 = getDigest(username, realm);
 
368
        if (md5a1 == null)
 
369
            return null;
 
370
        String serverDigestValue;
 
371
        if (qop == null) {
 
372
            serverDigestValue = md5a1 + ":" + nonce + ":" + md5a2;
 
373
        } else {
 
374
            serverDigestValue = md5a1 + ":" + nonce + ":" + nc + ":" +
 
375
                    cnonce + ":" + qop + ":" + md5a2;
 
376
        }
 
377
 
 
378
        byte[] valueBytes = null;
 
379
        if(getDigestEncoding() == null) {
 
380
            valueBytes = serverDigestValue.getBytes();
 
381
        } else {
 
382
            try {
 
383
                valueBytes = serverDigestValue.getBytes(getDigestEncoding());
 
384
            } catch (UnsupportedEncodingException uee) {
 
385
                log.error("Illegal digestEncoding: " + getDigestEncoding(), uee);
 
386
                throw new IllegalArgumentException(uee.getMessage());
 
387
            }
 
388
        }
 
389
 
 
390
        String serverDigest = null;
 
391
        // Bugzilla 32137
 
392
        synchronized(md5Helper) {
 
393
            serverDigest = md5Encoder.encode(md5Helper.digest(valueBytes));
 
394
        }
 
395
 
 
396
        if (log.isDebugEnabled()) {
 
397
            log.debug("Digest : " + clientDigest + " Username:" + username 
 
398
                    + " ClientSigest:" + clientDigest + " nonce:" + nonce 
 
399
                    + " nc:" + nc + " cnonce:" + cnonce + " qop:" + qop 
 
400
                    + " realm:" + realm + "md5a2:" + md5a2 
 
401
                    + " Server digest:" + serverDigest);
 
402
        }
 
403
        
 
404
        if (serverDigest.equals(clientDigest))
 
405
            return getPrincipal(username);
 
406
        else
 
407
            return null;
 
408
    }
 
409
 
 
410
 
 
411
 
 
412
    /**
 
413
     * Return the Principal associated with the specified chain of X509
 
414
     * client certificates.  If there is none, return <code>null</code>.
 
415
     *
 
416
     * @param certs Array of client certificates, with the first one in
 
417
     *  the array being the certificate of the client itself.
 
418
     */
 
419
    public Principal authenticate(X509Certificate certs[]) {
 
420
 
 
421
        if ((certs == null) || (certs.length < 1))
 
422
            return (null);
 
423
 
 
424
        // Check the validity of each certificate in the chain
 
425
        if (log.isDebugEnabled())
 
426
            log.debug("Authenticating client certificate chain");
 
427
        if (validate) {
 
428
            for (int i = 0; i < certs.length; i++) {
 
429
                if (log.isDebugEnabled())
 
430
                    log.debug(" Checking validity for '" +
 
431
                        certs[i].getSubjectDN().getName() + "'");
 
432
                try {
 
433
                    certs[i].checkValidity();
 
434
                } catch (Exception e) {
 
435
                    if (log.isDebugEnabled())
 
436
                        log.debug("  Validity exception", e);
 
437
                    return (null);
 
438
                }
 
439
            }
 
440
        }
 
441
 
 
442
        // Check the existence of the client Principal in our database
 
443
        return (getPrincipal(certs[0]));
 
444
 
 
445
    }
 
446
 
 
447
    
 
448
    /**
 
449
     * Execute a periodic task, such as reloading, etc. This method will be
 
450
     * invoked inside the classloading context of this container. Unexpected
 
451
     * throwables will be caught and logged.
 
452
     */
 
453
    public void backgroundProcess() {
 
454
    }
 
455
 
 
456
 
 
457
    /**
 
458
     * Return the SecurityConstraints configured to guard the request URI for
 
459
     * this request, or <code>null</code> if there is no such constraint.
 
460
     *
 
461
     * @param request Request we are processing
 
462
     * @param context Context the Request is mapped to
 
463
     */
 
464
    public SecurityConstraint [] findSecurityConstraints(Request request,
 
465
                                                         Context context) {
 
466
 
 
467
        ArrayList<SecurityConstraint> results = null;
 
468
        // Are there any defined security constraints?
 
469
        SecurityConstraint constraints[] = context.findConstraints();
 
470
        if ((constraints == null) || (constraints.length == 0)) {
 
471
            if (log.isDebugEnabled())
 
472
                log.debug("  No applicable constraints defined");
 
473
            return (null);
 
474
        }
 
475
 
 
476
        // Check each defined security constraint
 
477
        String uri = request.getRequestPathMB().toString();
 
478
        // Bug47080 - in rare cases this may be null
 
479
        // Mapper treats as '/' do the same to prevent NPE
 
480
        if (uri == null) {
 
481
            uri = "/";
 
482
        }
 
483
        
 
484
        String method = request.getMethod();
 
485
        int i;
 
486
        boolean found = false;
 
487
        for (i = 0; i < constraints.length; i++) {
 
488
            SecurityCollection [] collection = constraints[i].findCollections();
 
489
                     
 
490
            // If collection is null, continue to avoid an NPE
 
491
            // See Bugzilla 30624
 
492
            if ( collection == null) {
 
493
                continue;
 
494
            }
 
495
 
 
496
            if (log.isDebugEnabled()) {
 
497
                log.debug("  Checking constraint '" + constraints[i] +
 
498
                    "' against " + method + " " + uri + " --> " +
 
499
                    constraints[i].included(uri, method));
 
500
            }
 
501
 
 
502
            for(int j=0; j < collection.length; j++){
 
503
                String [] patterns = collection[j].findPatterns();
 
504
 
 
505
                // If patterns is null, continue to avoid an NPE
 
506
                // See Bugzilla 30624
 
507
                if ( patterns == null) {
 
508
                    continue;
 
509
                }
 
510
 
 
511
                for(int k=0; k < patterns.length; k++) {
 
512
                    if(uri.equals(patterns[k])) {
 
513
                        found = true;
 
514
                        if(collection[j].findMethod(method)) {
 
515
                            if(results == null) {
 
516
                                results = new ArrayList<SecurityConstraint>();
 
517
                            }
 
518
                            results.add(constraints[i]);
 
519
                        }
 
520
                    }
 
521
                }
 
522
            }
 
523
        }
 
524
 
 
525
        if(found) {
 
526
            return resultsToArray(results);
 
527
        }
 
528
 
 
529
        int longest = -1;
 
530
 
 
531
        for (i = 0; i < constraints.length; i++) {
 
532
            SecurityCollection [] collection = constraints[i].findCollections();
 
533
            
 
534
            // If collection is null, continue to avoid an NPE
 
535
            // See Bugzilla 30624
 
536
            if ( collection == null) {
 
537
                continue;
 
538
            }
 
539
 
 
540
            if (log.isDebugEnabled()) {
 
541
                log.debug("  Checking constraint '" + constraints[i] +
 
542
                    "' against " + method + " " + uri + " --> " +
 
543
                    constraints[i].included(uri, method));
 
544
            }
 
545
 
 
546
            for(int j=0; j < collection.length; j++){
 
547
                String [] patterns = collection[j].findPatterns();
 
548
 
 
549
                // If patterns is null, continue to avoid an NPE
 
550
                // See Bugzilla 30624
 
551
                if ( patterns == null) {
 
552
                    continue;
 
553
                }
 
554
 
 
555
                boolean matched = false;
 
556
                int length = -1;
 
557
                for(int k=0; k < patterns.length; k++) {
 
558
                    String pattern = patterns[k];
 
559
                    if(pattern.startsWith("/") && pattern.endsWith("/*") && 
 
560
                       pattern.length() >= longest) {
 
561
                            
 
562
                        if(pattern.length() == 2) {
 
563
                            matched = true;
 
564
                            length = pattern.length();
 
565
                        } else if(pattern.regionMatches(0,uri,0,
 
566
                                                        pattern.length()-1) ||
 
567
                                  (pattern.length()-2 == uri.length() &&
 
568
                                   pattern.regionMatches(0,uri,0,
 
569
                                                        pattern.length()-2))) {
 
570
                            matched = true;
 
571
                            length = pattern.length();
 
572
                        }
 
573
                    }
 
574
                }
 
575
                if(matched) {
 
576
                    found = true;
 
577
                    if(length > longest) {
 
578
                        if(results != null) {
 
579
                            results.clear();
 
580
                        }
 
581
                        longest = length;
 
582
                    }
 
583
                    if(collection[j].findMethod(method)) {
 
584
                        if(results == null) {
 
585
                            results = new ArrayList<SecurityConstraint>();
 
586
                        }
 
587
                        results.add(constraints[i]);
 
588
                    }
 
589
                }
 
590
            }
 
591
        }
 
592
 
 
593
        if(found) {
 
594
            return  resultsToArray(results);
 
595
        }
 
596
 
 
597
        for (i = 0; i < constraints.length; i++) {
 
598
            SecurityCollection [] collection = constraints[i].findCollections();
 
599
 
 
600
            // If collection is null, continue to avoid an NPE
 
601
            // See Bugzilla 30624
 
602
            if ( collection == null) {
 
603
                continue;
 
604
            }
 
605
            
 
606
            if (log.isDebugEnabled()) {
 
607
                log.debug("  Checking constraint '" + constraints[i] +
 
608
                    "' against " + method + " " + uri + " --> " +
 
609
                    constraints[i].included(uri, method));
 
610
            }
 
611
 
 
612
            boolean matched = false;
 
613
            int pos = -1;
 
614
            for(int j=0; j < collection.length; j++){
 
615
                String [] patterns = collection[j].findPatterns();
 
616
 
 
617
                // If patterns is null, continue to avoid an NPE
 
618
                // See Bugzilla 30624
 
619
                if ( patterns == null) {
 
620
                    continue;
 
621
                }
 
622
 
 
623
                for(int k=0; k < patterns.length && !matched; k++) {
 
624
                    String pattern = patterns[k];
 
625
                    if(pattern.startsWith("*.")){
 
626
                        int slash = uri.lastIndexOf("/");
 
627
                        int dot = uri.lastIndexOf(".");
 
628
                        if(slash >= 0 && dot > slash &&
 
629
                           dot != uri.length()-1 &&
 
630
                           uri.length()-dot == pattern.length()-1) {
 
631
                            if(pattern.regionMatches(1,uri,dot,uri.length()-dot)) {
 
632
                                matched = true;
 
633
                                pos = j;
 
634
                            }
 
635
                        }
 
636
                    }
 
637
                }
 
638
            }
 
639
            if(matched) {
 
640
                found = true;
 
641
                if(collection[pos].findMethod(method)) {
 
642
                    if(results == null) {
 
643
                        results = new ArrayList<SecurityConstraint>();
 
644
                    }
 
645
                    results.add(constraints[i]);
 
646
                }
 
647
            }
 
648
        }
 
649
 
 
650
        if(found) {
 
651
            return resultsToArray(results);
 
652
        }
 
653
 
 
654
        for (i = 0; i < constraints.length; i++) {
 
655
            SecurityCollection [] collection = constraints[i].findCollections();
 
656
            
 
657
            // If collection is null, continue to avoid an NPE
 
658
            // See Bugzilla 30624
 
659
            if ( collection == null) {
 
660
                continue;
 
661
            }
 
662
 
 
663
            if (log.isDebugEnabled()) {
 
664
                log.debug("  Checking constraint '" + constraints[i] +
 
665
                    "' against " + method + " " + uri + " --> " +
 
666
                    constraints[i].included(uri, method));
 
667
            }
 
668
 
 
669
            for(int j=0; j < collection.length; j++){
 
670
                String [] patterns = collection[j].findPatterns();
 
671
 
 
672
                // If patterns is null, continue to avoid an NPE
 
673
                // See Bugzilla 30624
 
674
                if ( patterns == null) {
 
675
                    continue;
 
676
                }
 
677
 
 
678
                boolean matched = false;
 
679
                for(int k=0; k < patterns.length && !matched; k++) {
 
680
                    String pattern = patterns[k];
 
681
                    if(pattern.equals("/")){
 
682
                        matched = true;
 
683
                    }
 
684
                }
 
685
                if(matched) {
 
686
                    if(results == null) {
 
687
                        results = new ArrayList<SecurityConstraint>();
 
688
                    }                    
 
689
                    results.add(constraints[i]);
 
690
                }
 
691
            }
 
692
        }
 
693
 
 
694
        if(results == null) {
 
695
            // No applicable security constraint was found
 
696
            if (log.isDebugEnabled())
 
697
                log.debug("  No applicable constraint located");
 
698
        }
 
699
        return resultsToArray(results);
 
700
    }
 
701
 
 
702
    /**
 
703
     * Convert an ArrayList to a SecurityContraint [].
 
704
     */
 
705
    private SecurityConstraint [] resultsToArray(
 
706
            ArrayList<SecurityConstraint> results) {
 
707
        if(results == null) {
 
708
            return null;
 
709
        }
 
710
        SecurityConstraint [] array = new SecurityConstraint[results.size()];
 
711
        results.toArray(array);
 
712
        return array;
 
713
    }
 
714
 
 
715
    
 
716
    /**
 
717
     * Perform access control based on the specified authorization constraint.
 
718
     * Return <code>true</code> if this constraint is satisfied and processing
 
719
     * should continue, or <code>false</code> otherwise.
 
720
     *
 
721
     * @param request Request we are processing
 
722
     * @param response Response we are creating
 
723
     * @param constraints Security constraint we are enforcing
 
724
     * @param context The Context to which client of this class is attached.
 
725
     *
 
726
     * @exception IOException if an input/output error occurs
 
727
     */
 
728
    public boolean hasResourcePermission(Request request,
 
729
                                         Response response,
 
730
                                         SecurityConstraint []constraints,
 
731
                                         Context context)
 
732
        throws IOException {
 
733
 
 
734
        if (constraints == null || constraints.length == 0)
 
735
            return (true);
 
736
 
 
737
        // Specifically allow access to the form login and form error pages
 
738
        // and the "j_security_check" action
 
739
        LoginConfig config = context.getLoginConfig();
 
740
        if ((config != null) &&
 
741
            (Constants.FORM_METHOD.equals(config.getAuthMethod()))) {
 
742
            String requestURI = request.getRequestPathMB().toString();
 
743
            String loginPage = config.getLoginPage();
 
744
            if (loginPage.equals(requestURI)) {
 
745
                if (log.isDebugEnabled())
 
746
                    log.debug(" Allow access to login page " + loginPage);
 
747
                return (true);
 
748
            }
 
749
            String errorPage = config.getErrorPage();
 
750
            if (errorPage.equals(requestURI)) {
 
751
                if (log.isDebugEnabled())
 
752
                    log.debug(" Allow access to error page " + errorPage);
 
753
                return (true);
 
754
            }
 
755
            if (requestURI.endsWith(Constants.FORM_ACTION)) {
 
756
                if (log.isDebugEnabled())
 
757
                    log.debug(" Allow access to username/password submission");
 
758
                return (true);
 
759
            }
 
760
        }
 
761
 
 
762
        // Which user principal have we already authenticated?
 
763
        Principal principal = request.getPrincipal();
 
764
        boolean status = false;
 
765
        boolean denyfromall = false;
 
766
        for(int i=0; i < constraints.length; i++) {
 
767
            SecurityConstraint constraint = constraints[i];
 
768
 
 
769
            String roles[];
 
770
            if (constraint.getAllRoles()) {
 
771
                // * means all roles defined in web.xml
 
772
                roles = request.getContext().findSecurityRoles();
 
773
            } else {
 
774
                roles = constraint.findAuthRoles();
 
775
            }
 
776
 
 
777
            if (roles == null)
 
778
                roles = new String[0];
 
779
 
 
780
            if (log.isDebugEnabled())
 
781
                log.debug("  Checking roles " + principal);
 
782
 
 
783
            if (roles.length == 0 && !constraint.getAllRoles()) {
 
784
                if(constraint.getAuthConstraint()) {
 
785
                    if( log.isDebugEnabled() )
 
786
                        log.debug("No roles ");
 
787
                    status = false; // No listed roles means no access at all
 
788
                    denyfromall = true;
 
789
                    break;
 
790
                } else {
 
791
                    if(log.isDebugEnabled())
 
792
                        log.debug("Passing all access");
 
793
                    status = true;
 
794
                }
 
795
            } else if (principal == null) {
 
796
                if (log.isDebugEnabled())
 
797
                    log.debug("  No user authenticated, cannot grant access");
 
798
            } else {
 
799
                for (int j = 0; j < roles.length; j++) {
 
800
                    if (hasRole(principal, roles[j])) {
 
801
                        status = true;
 
802
                        if( log.isDebugEnabled() )
 
803
                            log.debug( "Role found:  " + roles[j]);
 
804
                    }
 
805
                    else if( log.isDebugEnabled() )
 
806
                        log.debug( "No role found:  " + roles[j]);
 
807
                }
 
808
            }
 
809
        }
 
810
 
 
811
        if (!denyfromall && allRolesMode != AllRolesMode.STRICT_MODE &&
 
812
                !status && principal != null) {
 
813
            if (log.isDebugEnabled()) {
 
814
                log.debug("Checking for all roles mode: " + allRolesMode);
 
815
            }
 
816
            // Check for an all roles(role-name="*")
 
817
            for (int i = 0; i < constraints.length; i++) {
 
818
                SecurityConstraint constraint = constraints[i];
 
819
                String roles[];
 
820
                // If the all roles mode exists, sets
 
821
                if (constraint.getAllRoles()) {
 
822
                    if (allRolesMode == AllRolesMode.AUTH_ONLY_MODE) {
 
823
                        if (log.isDebugEnabled()) {
 
824
                            log.debug("Granting access for role-name=*, auth-only");
 
825
                        }
 
826
                        status = true;
 
827
                        break;
 
828
                    }
 
829
                    
 
830
                    // For AllRolesMode.STRICT_AUTH_ONLY_MODE there must be zero roles
 
831
                    roles = request.getContext().findSecurityRoles();
 
832
                    if (roles.length == 0 && allRolesMode == AllRolesMode.STRICT_AUTH_ONLY_MODE) {
 
833
                        if (log.isDebugEnabled()) {
 
834
                            log.debug("Granting access for role-name=*, strict auth-only");
 
835
                        }
 
836
                        status = true;
 
837
                        break;
 
838
                    }
 
839
                }
 
840
            }
 
841
        }
 
842
        
 
843
        // Return a "Forbidden" message denying access to this resource
 
844
        if(!status) {
 
845
            response.sendError
 
846
                (HttpServletResponse.SC_FORBIDDEN,
 
847
                 sm.getString("realmBase.forbidden"));
 
848
        }
 
849
        return status;
 
850
 
 
851
    }
 
852
    
 
853
    
 
854
    /**
 
855
     * Return <code>true</code> if the specified Principal has the specified
 
856
     * security role, within the context of this Realm; otherwise return
 
857
     * <code>false</code>.  This method can be overridden by Realm
 
858
     * implementations, but the default is adequate when an instance of
 
859
     * <code>GenericPrincipal</code> is used to represent authenticated
 
860
     * Principals from this Realm.
 
861
     *
 
862
     * @param principal Principal for whom the role is to be checked
 
863
     * @param role Security role to be checked
 
864
     */
 
865
    public boolean hasRole(Principal principal, String role) {
 
866
 
 
867
        // Should be overriten in JAASRealm - to avoid pretty inefficient conversions
 
868
        if ((principal == null) || (role == null) ||
 
869
            !(principal instanceof GenericPrincipal))
 
870
            return (false);
 
871
 
 
872
        GenericPrincipal gp = (GenericPrincipal) principal;
 
873
        if (!(gp.getRealm() == this)) {
 
874
            if(log.isDebugEnabled())
 
875
                log.debug("Different realm " + this + " " + gp.getRealm());//    return (false);
 
876
        }
 
877
        boolean result = gp.hasRole(role);
 
878
        if (log.isDebugEnabled()) {
 
879
            String name = principal.getName();
 
880
            if (result)
 
881
                log.debug(sm.getString("realmBase.hasRoleSuccess", name, role));
 
882
            else
 
883
                log.debug(sm.getString("realmBase.hasRoleFailure", name, role));
 
884
        }
 
885
        return (result);
 
886
 
 
887
    }
 
888
 
 
889
    
 
890
    /**
 
891
     * Enforce any user data constraint required by the security constraint
 
892
     * guarding this request URI.  Return <code>true</code> if this constraint
 
893
     * was not violated and processing should continue, or <code>false</code>
 
894
     * if we have created a response already.
 
895
     *
 
896
     * @param request Request we are processing
 
897
     * @param response Response we are creating
 
898
     * @param constraints Security constraint being checked
 
899
     *
 
900
     * @exception IOException if an input/output error occurs
 
901
     */
 
902
    public boolean hasUserDataPermission(Request request,
 
903
                                         Response response,
 
904
                                         SecurityConstraint []constraints)
 
905
        throws IOException {
 
906
 
 
907
        // Is there a relevant user data constraint?
 
908
        if (constraints == null || constraints.length == 0) {
 
909
            if (log.isDebugEnabled())
 
910
                log.debug("  No applicable security constraint defined");
 
911
            return (true);
 
912
        }
 
913
        for(int i=0; i < constraints.length; i++) {
 
914
            SecurityConstraint constraint = constraints[i];
 
915
            String userConstraint = constraint.getUserConstraint();
 
916
            if (userConstraint == null) {
 
917
                if (log.isDebugEnabled())
 
918
                    log.debug("  No applicable user data constraint defined");
 
919
                return (true);
 
920
            }
 
921
            if (userConstraint.equals(Constants.NONE_TRANSPORT)) {
 
922
                if (log.isDebugEnabled())
 
923
                    log.debug("  User data constraint has no restrictions");
 
924
                return (true);
 
925
            }
 
926
 
 
927
        }
 
928
        // Validate the request against the user data constraint
 
929
        if (request.getRequest().isSecure()) {
 
930
            if (log.isDebugEnabled())
 
931
                log.debug("  User data constraint already satisfied");
 
932
            return (true);
 
933
        }
 
934
        // Initialize variables we need to determine the appropriate action
 
935
        int redirectPort = request.getConnector().getRedirectPort();
 
936
 
 
937
        // Is redirecting disabled?
 
938
        if (redirectPort <= 0) {
 
939
            if (log.isDebugEnabled())
 
940
                log.debug("  SSL redirect is disabled");
 
941
            response.sendError
 
942
                (HttpServletResponse.SC_FORBIDDEN,
 
943
                 request.getRequestURI());
 
944
            return (false);
 
945
        }
 
946
 
 
947
        // Redirect to the corresponding SSL port
 
948
        StringBuffer file = new StringBuffer();
 
949
        String protocol = "https";
 
950
        String host = request.getServerName();
 
951
        // Protocol
 
952
        file.append(protocol).append("://").append(host);
 
953
        // Host with port
 
954
        if(redirectPort != 443) {
 
955
            file.append(":").append(redirectPort);
 
956
        }
 
957
        // URI
 
958
        file.append(request.getRequestURI());
 
959
        String requestedSessionId = request.getRequestedSessionId();
 
960
        if ((requestedSessionId != null) &&
 
961
            request.isRequestedSessionIdFromURL()) {
 
962
            file.append(";");
 
963
            file.append(Globals.SESSION_PARAMETER_NAME);
 
964
            file.append("=");
 
965
            file.append(requestedSessionId);
 
966
        }
 
967
        String queryString = request.getQueryString();
 
968
        if (queryString != null) {
 
969
            file.append('?');
 
970
            file.append(queryString);
 
971
        }
 
972
        if (log.isDebugEnabled())
 
973
            log.debug("  Redirecting to " + file.toString());
 
974
        response.sendRedirect(file.toString());
 
975
        return (false);
 
976
 
 
977
    }
 
978
    
 
979
    
 
980
    /**
 
981
     * Remove a property change listener from this component.
 
982
     *
 
983
     * @param listener The listener to remove
 
984
     */
 
985
    public void removePropertyChangeListener(PropertyChangeListener listener) {
 
986
 
 
987
        support.removePropertyChangeListener(listener);
 
988
 
 
989
    }
 
990
 
 
991
 
 
992
    // ------------------------------------------------------ Lifecycle Methods
 
993
 
 
994
 
 
995
    /**
 
996
     * Add a lifecycle event listener to this component.
 
997
     *
 
998
     * @param listener The listener to add
 
999
     */
 
1000
    public void addLifecycleListener(LifecycleListener listener) {
 
1001
 
 
1002
        lifecycle.addLifecycleListener(listener);
 
1003
 
 
1004
    }
 
1005
 
 
1006
 
 
1007
    /**
 
1008
     * Get the lifecycle listeners associated with this lifecycle. If this 
 
1009
     * Lifecycle has no listeners registered, a zero-length array is returned.
 
1010
     */
 
1011
    public LifecycleListener[] findLifecycleListeners() {
 
1012
 
 
1013
        return lifecycle.findLifecycleListeners();
 
1014
 
 
1015
    }
 
1016
 
 
1017
 
 
1018
    /**
 
1019
     * Remove a lifecycle event listener from this component.
 
1020
     *
 
1021
     * @param listener The listener to remove
 
1022
     */
 
1023
    public void removeLifecycleListener(LifecycleListener listener) {
 
1024
 
 
1025
        lifecycle.removeLifecycleListener(listener);
 
1026
 
 
1027
    }
 
1028
 
 
1029
    /**
 
1030
     * Prepare for the beginning of active use of the public methods of this
 
1031
     * component.  This method should be called before any of the public
 
1032
     * methods of this component are utilized.  It should also send a
 
1033
     * LifecycleEvent of type START_EVENT to any registered listeners.
 
1034
     *
 
1035
     * @exception LifecycleException if this component detects a fatal error
 
1036
     *  that prevents this component from being used
 
1037
     */
 
1038
    public void start() throws LifecycleException {
 
1039
 
 
1040
        // Validate and update our current component state
 
1041
        if (started) {
 
1042
            if(log.isInfoEnabled())
 
1043
                log.info(sm.getString("realmBase.alreadyStarted"));
 
1044
            return;
 
1045
        }
 
1046
        if( !initialized ) {
 
1047
            init();
 
1048
        }
 
1049
        lifecycle.fireLifecycleEvent(START_EVENT, null);
 
1050
        started = true;
 
1051
 
 
1052
        // Create a MessageDigest instance for credentials, if desired
 
1053
        if (digest != null) {
 
1054
            try {
 
1055
                md = MessageDigest.getInstance(digest);
 
1056
            } catch (NoSuchAlgorithmException e) {
 
1057
                throw new LifecycleException
 
1058
                    (sm.getString("realmBase.algorithm", digest), e);
 
1059
            }
 
1060
        }
 
1061
 
 
1062
    }
 
1063
 
 
1064
 
 
1065
    /**
 
1066
     * Gracefully terminate the active use of the public methods of this
 
1067
     * component.  This method should be the last one called on a given
 
1068
     * instance of this component.  It should also send a LifecycleEvent
 
1069
     * of type STOP_EVENT to any registered listeners.
 
1070
     *
 
1071
     * @exception LifecycleException if this component detects a fatal error
 
1072
     *  that needs to be reported
 
1073
     */
 
1074
    public void stop()
 
1075
        throws LifecycleException {
 
1076
 
 
1077
        // Validate and update our current component state
 
1078
        if (!started) {
 
1079
            if(log.isInfoEnabled())
 
1080
                log.info(sm.getString("realmBase.notStarted"));
 
1081
            return;
 
1082
        }
 
1083
        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
 
1084
        started = false;
 
1085
 
 
1086
        // Clean up allocated resources
 
1087
        md = null;
 
1088
        
 
1089
        destroy();
 
1090
    
 
1091
    }
 
1092
    
 
1093
    public void destroy() {
 
1094
    
 
1095
        // unregister this realm
 
1096
        if ( oname!=null ) {   
 
1097
            try {   
 
1098
                Registry.getRegistry(null, null).unregisterComponent(oname); 
 
1099
                if(log.isDebugEnabled())
 
1100
                    log.debug( "unregistering realm " + oname );   
 
1101
            } catch( Exception ex ) {   
 
1102
                log.error( "Can't unregister realm " + oname, ex);   
 
1103
            }      
 
1104
        }
 
1105
          
 
1106
    }
 
1107
 
 
1108
    // ------------------------------------------------------ Protected Methods
 
1109
 
 
1110
 
 
1111
    /**
 
1112
     * Digest the password using the specified algorithm and
 
1113
     * convert the result to a corresponding hexadecimal string.
 
1114
     * If exception, the plain credentials string is returned.
 
1115
     *
 
1116
     * @param credentials Password or other credentials to use in
 
1117
     *  authenticating this username
 
1118
     */
 
1119
    protected String digest(String credentials)  {
 
1120
 
 
1121
        // If no MessageDigest instance is specified, return unchanged
 
1122
        if (hasMessageDigest() == false)
 
1123
            return (credentials);
 
1124
 
 
1125
        // Digest the user credentials and return as hexadecimal
 
1126
        synchronized (this) {
 
1127
            try {
 
1128
                md.reset();
 
1129
    
 
1130
                byte[] bytes = null;
 
1131
                if(getDigestEncoding() == null) {
 
1132
                    bytes = credentials.getBytes();
 
1133
                } else {
 
1134
                    try {
 
1135
                        bytes = credentials.getBytes(getDigestEncoding());
 
1136
                    } catch (UnsupportedEncodingException uee) {
 
1137
                        log.error("Illegal digestEncoding: " + getDigestEncoding(), uee);
 
1138
                        throw new IllegalArgumentException(uee.getMessage());
 
1139
                    }
 
1140
                }
 
1141
                md.update(bytes);
 
1142
 
 
1143
                return (HexUtils.convert(md.digest()));
 
1144
            } catch (Exception e) {
 
1145
                log.error(sm.getString("realmBase.digest"), e);
 
1146
                return (credentials);
 
1147
            }
 
1148
        }
 
1149
 
 
1150
    }
 
1151
 
 
1152
    protected boolean hasMessageDigest() {
 
1153
        return !(md == null);
 
1154
    }
 
1155
 
 
1156
    /**
 
1157
     * Return the digest associated with given principal's user name.
 
1158
     */
 
1159
    protected String getDigest(String username, String realmName) {
 
1160
        if (md5Helper == null) {
 
1161
            try {
 
1162
                md5Helper = MessageDigest.getInstance("MD5");
 
1163
            } catch (NoSuchAlgorithmException e) {
 
1164
                log.error("Couldn't get MD5 digest: ", e);
 
1165
                throw new IllegalStateException(e.getMessage());
 
1166
            }
 
1167
        }
 
1168
 
 
1169
        if (hasMessageDigest()) {
 
1170
                // Use pre-generated digest
 
1171
                return getPassword(username);
 
1172
        }
 
1173
        
 
1174
        String digestValue = username + ":" + realmName + ":"
 
1175
            + getPassword(username);
 
1176
 
 
1177
        byte[] valueBytes = null;
 
1178
        if(getDigestEncoding() == null) {
 
1179
            valueBytes = digestValue.getBytes();
 
1180
        } else {
 
1181
            try {
 
1182
                valueBytes = digestValue.getBytes(getDigestEncoding());
 
1183
            } catch (UnsupportedEncodingException uee) {
 
1184
                log.error("Illegal digestEncoding: " + getDigestEncoding(), uee);
 
1185
                throw new IllegalArgumentException(uee.getMessage());
 
1186
            }
 
1187
        }
 
1188
 
 
1189
        byte[] digest = null;
 
1190
        // Bugzilla 32137
 
1191
        synchronized(md5Helper) {
 
1192
            digest = md5Helper.digest(valueBytes);
 
1193
        }
 
1194
 
 
1195
        return md5Encoder.encode(digest);
 
1196
    }
 
1197
 
 
1198
 
 
1199
    /**
 
1200
     * Return a short name for this Realm implementation, for use in
 
1201
     * log messages.
 
1202
     */
 
1203
    protected abstract String getName();
 
1204
 
 
1205
 
 
1206
    /**
 
1207
     * Return the password associated with the given principal's user name.
 
1208
     */
 
1209
    protected abstract String getPassword(String username);
 
1210
 
 
1211
 
 
1212
    /**
 
1213
     * Return the Principal associated with the given certificate.
 
1214
     */
 
1215
    protected Principal getPrincipal(X509Certificate usercert) {
 
1216
        return(getPrincipal(usercert.getSubjectDN().getName()));
 
1217
    }
 
1218
    
 
1219
 
 
1220
    /**
 
1221
     * Return the Principal associated with the given user name.
 
1222
     */
 
1223
    protected abstract Principal getPrincipal(String username);
 
1224
 
 
1225
 
 
1226
    // --------------------------------------------------------- Static Methods
 
1227
 
 
1228
 
 
1229
    /**
 
1230
     * Digest password using the algorithm specified and
 
1231
     * convert the result to a corresponding hex string.
 
1232
     * If exception, the plain credentials string is returned
 
1233
     *
 
1234
     * @param credentials Password or other credentials to use in
 
1235
     *  authenticating this username
 
1236
     * @param algorithm Algorithm used to do the digest
 
1237
     * @param encoding Character encoding of the string to digest
 
1238
     */
 
1239
    public final static String Digest(String credentials, String algorithm,
 
1240
                                      String encoding) {
 
1241
 
 
1242
        try {
 
1243
            // Obtain a new message digest with "digest" encryption
 
1244
            MessageDigest md =
 
1245
                (MessageDigest) MessageDigest.getInstance(algorithm).clone();
 
1246
 
 
1247
            // encode the credentials
 
1248
            // Should use the digestEncoding, but that's not a static field
 
1249
            if (encoding == null) {
 
1250
                md.update(credentials.getBytes());
 
1251
            } else {
 
1252
                md.update(credentials.getBytes(encoding));                
 
1253
            }
 
1254
 
 
1255
            // Digest the credentials and return as hexadecimal
 
1256
            return (HexUtils.convert(md.digest()));
 
1257
        } catch(Exception ex) {
 
1258
            log.error(ex);
 
1259
            return credentials;
 
1260
        }
 
1261
 
 
1262
    }
 
1263
 
 
1264
 
 
1265
    /**
 
1266
     * Digest password using the algorithm specified and
 
1267
     * convert the result to a corresponding hex string.
 
1268
     * If exception, the plain credentials string is returned
 
1269
     */
 
1270
    public static void main(String args[]) {
 
1271
 
 
1272
        String encoding = null;
 
1273
        int firstCredentialArg = 2;
 
1274
        
 
1275
        if (args.length > 4 && args[2].equalsIgnoreCase("-e")) {
 
1276
            encoding = args[3];
 
1277
            firstCredentialArg = 4;
 
1278
        }
 
1279
        
 
1280
        if(args.length > firstCredentialArg && args[0].equalsIgnoreCase("-a")) {
 
1281
            for(int i=firstCredentialArg; i < args.length ; i++){
 
1282
                System.out.print(args[i]+":");
 
1283
                System.out.println(Digest(args[i], args[1], encoding));
 
1284
            }
 
1285
        } else {
 
1286
            System.out.println
 
1287
                ("Usage: RealmBase -a <algorithm> [-e <encoding>] <credentials>");
 
1288
        }
 
1289
 
 
1290
    }
 
1291
 
 
1292
 
 
1293
    // -------------------- JMX and Registration  --------------------
 
1294
    protected String type;
 
1295
    protected String domain;
 
1296
    protected String host;
 
1297
    protected String path;
 
1298
    protected String realmPath = "/realm0";
 
1299
    protected ObjectName oname;
 
1300
    protected ObjectName controller;
 
1301
    protected MBeanServer mserver;
 
1302
 
 
1303
    public ObjectName getController() {
 
1304
        return controller;
 
1305
    }
 
1306
 
 
1307
    public void setController(ObjectName controller) {
 
1308
        this.controller = controller;
 
1309
    }
 
1310
 
 
1311
    public ObjectName getObjectName() {
 
1312
        return oname;
 
1313
    }
 
1314
 
 
1315
    public String getDomain() {
 
1316
        return domain;
 
1317
    }
 
1318
 
 
1319
    public String getType() {
 
1320
        return type;
 
1321
    }
 
1322
 
 
1323
    public String getRealmPath() {
 
1324
        return realmPath;
 
1325
    }
 
1326
    
 
1327
    public void setRealmPath(String theRealmPath) {
 
1328
        realmPath = theRealmPath;
 
1329
    }
 
1330
 
 
1331
    public ObjectName preRegister(MBeanServer server,
 
1332
                                  ObjectName name) throws Exception {
 
1333
        oname=name;
 
1334
        mserver=server;
 
1335
        domain=name.getDomain();
 
1336
 
 
1337
        type=name.getKeyProperty("type");
 
1338
        host=name.getKeyProperty("host");
 
1339
        path=name.getKeyProperty("path");
 
1340
 
 
1341
        return name;
 
1342
    }
 
1343
 
 
1344
    public void postRegister(Boolean registrationDone) {
 
1345
    }
 
1346
 
 
1347
    public void preDeregister() throws Exception {
 
1348
    }
 
1349
 
 
1350
    public void postDeregister() {
 
1351
    }
 
1352
 
 
1353
    protected boolean initialized=false;
 
1354
    
 
1355
    public void init() {
 
1356
        if( initialized && container != null ) return;
 
1357
 
 
1358
        // We want logger as soon as possible
 
1359
        if (container != null) {
 
1360
            this.containerLog = container.getLogger();
 
1361
        }
 
1362
        
 
1363
        initialized=true;
 
1364
        if( container== null ) {
 
1365
            ObjectName parent=null;
 
1366
            // Register with the parent
 
1367
            try {
 
1368
                if( host == null ) {
 
1369
                    // global
 
1370
                    parent=new ObjectName(domain +":type=Engine");
 
1371
                } else if( path==null ) {
 
1372
                    parent=new ObjectName(domain +
 
1373
                            ":type=Host,host=" + host);
 
1374
                } else {
 
1375
                    parent=new ObjectName(domain +":j2eeType=WebModule,name=//" +
 
1376
                            host + path);
 
1377
                }
 
1378
                if( mserver.isRegistered(parent ))  {
 
1379
                    if(log.isDebugEnabled())
 
1380
                        log.debug("Register with " + parent);
 
1381
                    mserver.setAttribute(parent, new Attribute("realm", this));
 
1382
                }
 
1383
            } catch (Exception e) {
 
1384
                log.error("Parent not available yet: " + parent);  
 
1385
            }
 
1386
        }
 
1387
        
 
1388
        if( oname==null ) {
 
1389
            // register
 
1390
            try {
 
1391
                ContainerBase cb=(ContainerBase)container;
 
1392
                oname=new ObjectName(cb.getDomain()+":type=Realm" +
 
1393
                        getRealmSuffix() + cb.getContainerSuffix());
 
1394
                Registry.getRegistry(null, null).registerComponent(this, oname, null );
 
1395
                if(log.isDebugEnabled())
 
1396
                    log.debug("Register Realm "+oname);
 
1397
            } catch (Throwable e) {
 
1398
                log.error( "Can't register " + oname, e);
 
1399
            }
 
1400
        }
 
1401
 
 
1402
    }
 
1403
 
 
1404
 
 
1405
    protected String getRealmSuffix() {
 
1406
        return ",realmPath=" + getRealmPath();
 
1407
    }
 
1408
 
 
1409
 
 
1410
    protected static class AllRolesMode {
 
1411
        
 
1412
        private String name;
 
1413
        /** Use the strict servlet spec interpretation which requires that the user
 
1414
         * have one of the web-app/security-role/role-name 
 
1415
         */
 
1416
        public static final AllRolesMode STRICT_MODE = new AllRolesMode("strict");
 
1417
        /** Allow any authenticated user
 
1418
         */
 
1419
        public static final AllRolesMode AUTH_ONLY_MODE = new AllRolesMode("authOnly");
 
1420
        /** Allow any authenticated user only if there are no web-app/security-roles
 
1421
         */
 
1422
        public static final AllRolesMode STRICT_AUTH_ONLY_MODE = new AllRolesMode("strictAuthOnly");
 
1423
        
 
1424
        static AllRolesMode toMode(String name)
 
1425
        {
 
1426
            AllRolesMode mode;
 
1427
            if( name.equalsIgnoreCase(STRICT_MODE.name) )
 
1428
                mode = STRICT_MODE;
 
1429
            else if( name.equalsIgnoreCase(AUTH_ONLY_MODE.name) )
 
1430
                mode = AUTH_ONLY_MODE;
 
1431
            else if( name.equalsIgnoreCase(STRICT_AUTH_ONLY_MODE.name) )
 
1432
                mode = STRICT_AUTH_ONLY_MODE;
 
1433
            else
 
1434
                throw new IllegalStateException("Unknown mode, must be one of: strict, authOnly, strictAuthOnly");
 
1435
            return mode;
 
1436
        }
 
1437
        
 
1438
        private AllRolesMode(String name)
 
1439
        {
 
1440
            this.name = name;
 
1441
        }
 
1442
        
 
1443
        public boolean equals(Object o)
 
1444
        {
 
1445
            boolean equals = false;
 
1446
            if( o instanceof AllRolesMode )
 
1447
            {
 
1448
                AllRolesMode mode = (AllRolesMode) o;
 
1449
                equals = name.equals(mode.name);
 
1450
            }
 
1451
            return equals;
 
1452
        }
 
1453
        public int hashCode()
 
1454
        {
 
1455
            return name.hashCode();
 
1456
        }
 
1457
        public String toString()
 
1458
        {
 
1459
            return name;
 
1460
        }
 
1461
    }
 
1462
 
 
1463
}