~ubuntu-branches/ubuntu/utopic/tomcat7/utopic-security

« back to all changes in this revision

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

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