tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject svn commit: r707757 - in /tomcat/tc6.0.x/trunk: ./ java/org/apache/catalina/realm/ java/org/apache/catalina/startup/ webapps/docs/ webapps/docs/config/
Date Fri, 24 Oct 2008 21:54:49 GMT
Author: markt
Date: Fri Oct 24 14:54:48 2008
New Revision: 707757

URL: http://svn.apache.org/viewvc?rev=707757&view=rev
Log:
Add LockOutRealm and CombinedRealm

Added:
    tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/CombinedRealm.java   (with props)
    tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LockOutRealm.java   (with props)
    tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/RealmRuleSet.java   (with props)
Modified:
    tomcat/tc6.0.x/trunk/STATUS.txt
    tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LocalStrings.properties
    tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/RealmBase.java
    tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/mbeans-descriptors.xml
    tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/ContextRuleSet.java
    tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/EngineRuleSet.java
    tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/HostRuleSet.java
    tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
    tomcat/tc6.0.x/trunk/webapps/docs/config/realm.xml
    tomcat/tc6.0.x/trunk/webapps/docs/realm-howto.xml

Modified: tomcat/tc6.0.x/trunk/STATUS.txt
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS.txt?rev=707757&r1=707756&r2=707757&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/STATUS.txt (original)
+++ tomcat/tc6.0.x/trunk/STATUS.txt Fri Oct 24 14:54:48 2008
@@ -126,11 +126,6 @@
   +1: rjung, mturk, markt, pero
    0: remm (also affects to the two other AJP connectors)
 
-* Add CombinedRealm and LockOutRealm with docs
-  http://people.apache.org/~markt/patches/2008-09-24-lockout-realm.patch
-  +1: markt, remm (but you should stop adding features at some point), fhanik
-  -1: 
-
 * Update tc-native to lastest version:
   http://people.apache.org/~jfclere/patches/patch.new-tcnative
   +1: jclere, markt, remm

Added: tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/CombinedRealm.java
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/CombinedRealm.java?rev=707757&view=auto
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/CombinedRealm.java (added)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/CombinedRealm.java Fri Oct 24 14:54:48 2008
@@ -0,0 +1,322 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.catalina.realm;
+
+import java.security.Principal;
+
+import java.security.cert.X509Certificate;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.management.ObjectName;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Realm;
+import org.apache.catalina.util.StringManager;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+/**
+ * Realm implementation that contains one or more realms. Authentication is
+ * attempted for each realm in the order they were configured. If any realm
+ * authenticates the user then the authentication succeeds. When combining
+ * realms usernames should be unique across all combined realms.
+ */
+public class CombinedRealm extends RealmBase {
+
+    private static Log log = LogFactory.getLog(CombinedRealm.class);
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+    
+    /**
+     * The list of Realms contained by this Realm.
+     */
+    protected List<Realm> realms = new LinkedList<Realm>();
+
+
+    /**
+     * Add a realm to the list of realms that will be used to authenticate
+     * users.
+     */
+    public void addRealm(Realm theRealm) {
+        realms.add(theRealm);
+        
+        if (log.isDebugEnabled()) {
+            sm.getString("combinedRealm.addRealm", theRealm.getInfo(), 
+                    Integer.toString(realms.size()));
+        }
+    }
+
+
+    /**
+     * Return the set of Realms that this Realm is wrapping
+     */
+    public ObjectName[] getRealms() {
+        ObjectName[] result = new ObjectName[realms.size()];
+        for (Realm realm : realms) {
+            if (realm instanceof RealmBase) {
+                result[realms.indexOf(realm)] =
+                    ((RealmBase) realm).getObjectName();
+            }
+        }
+        return result;
+    }
+
+
+    /**
+     * Return the Principal associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * @param username Username of the Principal to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    public Principal authenticate(String username, byte[] credentials) {
+        Principal authenticatedUser = null;
+        
+        for (Realm realm : realms) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("combinedRealm.authStart", username, realm.getInfo()));
+            }
+            
+            authenticatedUser = realm.authenticate(username, credentials);
+            
+            if (authenticatedUser == null) {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("combinedRealm.authFail", username, realm.getInfo()));
+                }
+            } else {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("combinedRealm.authSucess", username, realm.getInfo()));
+                }
+                break;
+            }
+        }
+        return authenticatedUser;
+    }
+
+
+    /**
+     * Return the Principal associated with the specified username, which
+     * matches the digest calculated using the given parameters using the
+     * method described in RFC 2069; otherwise return <code>null</code>.
+     *
+     * @param username Username of the Principal to look up
+     * @param clientDigest Digest which has been submitted by the client
+     * @param nOnce Unique (or supposedly unique) token which has been used
+     * for this request
+     * @param realm Realm name
+     * @param md5a2 Second MD5 digest used to calculate the digest :
+     * MD5(Method + ":" + uri)
+     */
+    public Principal authenticate(String username, String clientDigest,
+            String once, String nc, String cnonce, String qop,
+            String realmName, String md5a2) {
+        Principal authenticatedUser = null;
+        
+        for (Realm realm : realms) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("combinedRealm.authStart", username, realm.getInfo()));
+            }
+
+            authenticatedUser = realm.authenticate(username, clientDigest, once,
+                    nc, cnonce, qop, realmName, md5a2);
+
+            if (authenticatedUser == null) {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("combinedRealm.authFail", username, realm.getInfo()));
+                }
+            } else {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("combinedRealm.authSucess", username, realm.getInfo()));
+                }
+                break;
+            }
+        }
+        return authenticatedUser;
+    }
+
+
+    /**
+     * Return the Principal associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * @param username Username of the Principal to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    public Principal authenticate(String username, String credentials) {
+        Principal authenticatedUser = null;
+        
+        for (Realm realm : realms) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("combinedRealm.authStart", username, realm.getInfo()));
+            }
+
+            authenticatedUser = realm.authenticate(username, credentials);
+
+            if (authenticatedUser == null) {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("combinedRealm.authFail", username, realm.getInfo()));
+                }
+            } else {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("combinedRealm.authSucess", username, realm.getInfo()));
+                }
+                break;
+            }
+        }
+        return authenticatedUser;
+    }
+
+
+    /**
+     * Set the Container with which this Realm has been associated.
+     *
+     * @param container The associated Container
+     */
+    public void setContainer(Container container) {
+        for(Realm realm : realms) {
+            // Set the realmPath for JMX naming
+            if (realm instanceof RealmBase) {
+                ((RealmBase) realm).setRealmPath(
+                        getRealmPath() + "/realm" + realms.indexOf(realm));
+            }
+            
+            // Set the container for sub-realms. Mainly so logging works.
+            realm.setContainer(container);
+        }
+        super.setContainer(container);
+    }
+
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called before any of the public
+     * methods of this component are utilized.  It should also send a
+     * LifecycleEvent of type START_EVENT to any registered listeners.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+        // Start 'sub-realms' then this one
+        for (Realm realm : realms) {
+            if (realm instanceof Lifecycle) {
+                ((Lifecycle) realm).start();
+            }
+        }
+        super.start();
+    }
+
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.  It should also send a LifecycleEvent
+     * of type STOP_EVENT to any registered listeners.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+     public void stop() throws LifecycleException {
+        // Stop this realm, then the sub-realms (reverse order to start)
+        super.stop();
+        for (Realm realm : realms) {
+            if (realm instanceof Lifecycle) {
+                ((Lifecycle) realm).stop();
+            }
+        }        
+    }
+
+
+    /**
+     * Return the Principal associated with the specified chain of X509
+     * client certificates.  If there is none, return <code>null</code>.
+     *
+     * @param certs Array of client certificates, with the first one in
+     *  the array being the certificate of the client itself.
+     */
+    public Principal authenticate(X509Certificate[] certs) {
+        Principal authenticatedUser = null;
+        String username = null;
+        if (certs != null && certs.length >0) {
+            username = certs[0].getSubjectDN().getName();
+        }
+        
+        for (Realm realm : realms) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("combinedRealm.authStart", username, realm.getInfo()));
+            }
+
+            authenticatedUser = realm.authenticate(certs);
+
+            if (authenticatedUser == null) {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("combinedRealm.authFail", username, realm.getInfo()));
+                }
+            } else {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("combinedRealm.authSucess", username, realm.getInfo()));
+                }
+                break;
+            }
+        }
+        return authenticatedUser;
+    }
+
+    @Override
+    protected String getName() {
+        // This method should never be called
+        // Stack trace will show where this was called from
+        UnsupportedOperationException uoe =
+            new UnsupportedOperationException(
+                    sm.getString("combinedRealm.getName"));
+        log.error(sm.getString("combinedRealm.unexpectedMethod"), uoe);
+        throw uoe;
+    }
+
+    @Override
+    protected String getPassword(String username) {
+        // This method should never be called
+        // Stack trace will show where this was called from
+        UnsupportedOperationException uoe =
+            new UnsupportedOperationException(
+                    sm.getString("combinedRealm.getPassword"));
+        log.error(sm.getString("combinedRealm.unexpectedMethod"), uoe);
+        throw uoe;
+    }
+
+    @Override
+    protected Principal getPrincipal(String username) {
+        // This method should never be called
+        // Stack trace will show where this was called from
+        UnsupportedOperationException uoe =
+            new UnsupportedOperationException(
+                    sm.getString("combinedRealm.getPrincipal"));
+        log.error(sm.getString("combinedRealm.unexpectedMethod"), uoe);
+        throw uoe;
+    }
+
+}

Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/CombinedRealm.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/CombinedRealm.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LocalStrings.properties?rev=707757&r1=707756&r2=707757&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LocalStrings.properties (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LocalStrings.properties Fri Oct 24 14:54:48 2008
@@ -85,3 +85,13 @@
 dataSourceRealm.getPassword.exception=Exception retrieving password for "{0}"
 dataSourceRealm.getRoles.exception=Exception retrieving roles for "{0}"
 dataSourceRealm.open=Exception opening database connection
+combinedRealm.unexpectedMethod=An unexpected call was made to a method on the combined realm
+combinedRealm.getName=The getName() method should never be called
+combinedRealm.getPassword=The getPassword() method should never be called
+combinedRealm.getPrincipal=The getPrincipal() method should never be called
+combinedRealm.authStart=Attempting to authenticate user "{0}" with realm "{1}"
+combinedRealm.authFailed=Failed to authenticate user "{0}" with realm "{1}"
+combinedRealm.authSucess=Authenticated user "{0}" with realm "{1}"
+combinedRealm.addRealm=Add "{0}" realm, making a total of "{1}" realms
+lockOutRealm.authLockedUser=An attempt was made to authenticate the locked user "{0}"
+lockOutRealm.removeWarning=User "{0}" was removed from the failed users cache after {1} seconds to keep the cache size within the limit set
\ No newline at end of file

Added: tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LockOutRealm.java
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LockOutRealm.java?rev=707757&view=auto
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LockOutRealm.java (added)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LockOutRealm.java Fri Oct 24 14:54:48 2008
@@ -0,0 +1,415 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.catalina.realm;
+
+import java.security.Principal;
+import java.security.cert.X509Certificate;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.catalina.LifecycleException;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+/**
+ * This class extends the CombinedRealm (hence it can wrap other Realms) to
+ * provide a user lock out mechanism if there are too many failed
+ * authentication attempts in a given period of time. To ensure correct
+ * operation, there is a reasonable degree of synchronisation in this Realm.
+ * This Realm does not require modification to the underlying Realms or the
+ * associated user storage mecahisms. It achieves this by recording all failed
+ * logins, including those for users that do not exist. To prevent a DOS by
+ * deliberating making requests with invalid users (and hence causing this cache
+ * to grow) the size of the list of users that have failed authentication is
+ * limited.
+ */
+public class LockOutRealm extends CombinedRealm {
+
+    private static Log log = LogFactory.getLog(LockOutRealm.class);
+
+    /**
+     * The number of times in a row a user has to fail authentication to be
+     * locked out. Defaults to 5.
+     */
+    protected int failureCount = 5;
+    
+    /**
+     * The time (in seconds) a user is locked out for after too many
+     * authentication failures. Defaults to 300 (5 minutes). 
+     */
+    protected int lockOutTime = 300;
+
+    /**
+     * Number of users that have failed authentication to keep in cache. Over
+     * time the cache will grow to this size and may not shrink. Defaults to
+     * 1000.
+     */
+    protected int cacheSize = 1000;
+
+    /**
+     * If a failed user is removed from the cache because the cache is too big
+     * before it has been in the cache for at least this period of time (in
+     * seconds) a warning message will be logged. Defaults to 3600 (1 hour).
+     */
+    protected int cacheRemovalWarningTime = 3600;
+
+    /**
+     * Users whose last authentication attempt failed. Entries will be ordered
+     * in access order from least recent to most recent.
+     */
+    protected Map<String,LockRecord> failedUsers = null;
+
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called before any of the public
+     * methods of this component are utilized.  It should also send a
+     * LifecycleEvent of type START_EVENT to any registered listeners.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+        // Configure the list of failed users to delete the oldest entry once it
+        // exceeds the specified size
+        failedUsers = new LinkedHashMap<String, LockRecord>(cacheSize, 0.75f,
+                true) {
+            protected boolean removeEldestEntry(
+                    Map.Entry<String, LockRecord> eldest) {
+                if (size() > cacheSize) {
+                    // Check to see if this element has been removed too quickly
+                    long timeInCache = (System.currentTimeMillis() -
+                            eldest.getValue().getLastFailureTime())/1000;
+                    
+                    if (timeInCache < cacheRemovalWarningTime) {
+                        log.warn(sm.getString("lockOutRealm.removeWarning",
+                                eldest.getKey(), Long.valueOf(timeInCache)));
+                    }
+                    return true;
+                }
+                return false;
+            }
+        };
+
+        super.start();
+    }
+
+
+    /**
+     * Return the Principal associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * @param username Username of the Principal to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    public Principal authenticate(String username, byte[] credentials) {
+        if (isLocked(username)) {
+            // Trying to authenticate a locked user is an automatic failure
+            registerAuthFailure(username);
+            
+            log.warn(sm.getString("lockOutRealm.authLockedUser", username));
+            return null;
+        }
+
+        Principal authenticatedUser = super.authenticate(username, credentials);
+        
+        if (authenticatedUser == null) {
+            registerAuthFailure(username);
+        } else {
+            registerAuthSuccess(username);
+        }
+        return authenticatedUser;
+    }
+
+
+    /**
+     * Return the Principal associated with the specified username, which
+     * matches the digest calculated using the given parameters using the
+     * method described in RFC 2069; otherwise return <code>null</code>.
+     *
+     * @param username Username of the Principal to look up
+     * @param clientDigest Digest which has been submitted by the client
+     * @param nOnce Unique (or supposedly unique) token which has been used
+     * for this request
+     * @param realm Realm name
+     * @param md5a2 Second MD5 digest used to calculate the digest :
+     * MD5(Method + ":" + uri)
+     */
+    public Principal authenticate(String username, String clientDigest,
+            String once, String nc, String cnonce, String qop,
+            String realmName, String md5a2) {
+
+        if (isLocked(username)) {
+            // Trying to authenticate a locked user is an automatic failure
+            registerAuthFailure(username);
+            
+            log.warn(sm.getString("lockOutRealm.authLockedUser", username));
+            return null;
+        }
+
+        Principal authenticatedUser = super.authenticate(username, clientDigest,
+                once, nc, cnonce, qop, realmName, md5a2);
+        
+        if (authenticatedUser == null) {
+            registerAuthFailure(username);
+        } else {
+            registerAuthSuccess(username);
+        }
+        return authenticatedUser;
+    }
+
+
+    /**
+     * Return the Principal associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * @param username Username of the Principal to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    public Principal authenticate(String username, String credentials) {
+        if (isLocked(username)) {
+            // Trying to authenticate a locked user is an automatic failure
+            registerAuthFailure(username);
+            
+            log.warn(sm.getString("lockOutRealm.authLockedUser", username));
+            return null;
+        }
+
+        Principal authenticatedUser = super.authenticate(username, credentials);
+        
+        if (authenticatedUser == null) {
+            registerAuthFailure(username);
+        } else {
+            registerAuthSuccess(username);
+        }
+        return authenticatedUser;
+    }
+
+
+    /**
+     * Return the Principal associated with the specified chain of X509
+     * client certificates.  If there is none, return <code>null</code>.
+     *
+     * @param certs Array of client certificates, with the first one in
+     *  the array being the certificate of the client itself.
+     */
+    public Principal authenticate(X509Certificate[] certs) {
+        String username = null;
+        if (certs != null && certs.length >0) {
+            username = certs[0].getSubjectDN().getName();
+        }
+
+        if (isLocked(username)) {
+            // Trying to authenticate a locked user is an automatic failure
+            registerAuthFailure(username);
+            
+            log.warn(sm.getString("lockOutRealm.authLockedUser", username));
+            return null;
+        }
+
+        Principal authenticatedUser = super.authenticate(certs);
+        
+        if (authenticatedUser == null) {
+            registerAuthFailure(username);
+        } else {
+            registerAuthSuccess(username);
+        }
+        return authenticatedUser;
+    }
+
+
+    /**
+     * Unlock the specified username. This will remove all records of
+     * authentication failures for this user.
+     * 
+     * @param username The user to unlock
+     */
+    public void unlock(String username) {
+        // Auth success clears the lock record so... 
+        registerAuthSuccess(username);
+    }
+    
+    /*
+     * Checks to see if the current user is locked. If this is associated with
+     * a login attempt, then the last access time will be recorded and any
+     * attempt to authenticated a locked user will log a warning.
+     */
+    private boolean isLocked(String username) {
+        LockRecord lockRecord = null;
+        synchronized (this) {
+            lockRecord = failedUsers.get(username);
+        }
+        
+        // No lock record means user can't be locked
+        if (lockRecord == null) {
+            return false;
+        }
+        
+        // Check to see if user is locked
+        if (lockRecord.getFailures() >= failureCount &&
+                (System.currentTimeMillis() -
+                        lockRecord.getLastFailureTime())/1000 < lockOutTime) {
+            return true;
+        }
+        
+        // User has not, yet, exceeded lock thresholds
+        return false;
+    }
+
+
+    /*
+     * After successful authentication, any record of previous authentication
+     * failure is removed.
+     */
+    private synchronized void registerAuthSuccess(String username) {
+        // Successful authentication means removal from the list of failed users
+        failedUsers.remove(username);
+    }
+
+
+    /*
+     * After a failed authentication, add the record of the failed
+     * authentication. 
+     */
+    private void registerAuthFailure(String username) {
+        LockRecord lockRecord = null;
+        synchronized (this) {
+            if (!failedUsers.containsKey(username)) {
+                lockRecord = new LockRecord(); 
+                failedUsers.put(username, lockRecord);
+            } else {
+                lockRecord = failedUsers.get(username);
+                if (lockRecord.getFailures() >= failureCount &&
+                        ((System.currentTimeMillis() -
+                                lockRecord.getLastFailureTime())/1000)
+                                > lockOutTime) {
+                    // User was previously locked out but lockout has now
+                    // expired so reset failure count
+                    lockRecord.setFailures(0);
+                }
+            }
+        }
+        lockRecord.registerFailure();
+    }
+
+    
+    /**
+     * Get the number of failed authentication attempts required to lock the
+     * user account.
+     * @return the failureCount
+     */
+    public int getFailureCount() {
+        return failureCount;
+    }
+
+
+    /**
+     * Set the number of failed authentication attempts required to lock the
+     * user account.
+     * @param failureCount the failureCount to set
+     */
+    public void setFailureCount(int failureCount) {
+        this.failureCount = failureCount;
+    }
+
+
+    /**
+     * Get the period for which an account will be locked.
+     * @return the lockOutTime
+     */
+    public int getLockOutTime() {
+        return lockOutTime;
+    }
+
+
+    /**
+     * Set the period for which an account will be locked.
+     * @param lockOutTime the lockOutTime to set
+     */
+    public void setLockOutTime(int lockOutTime) {
+        this.lockOutTime = lockOutTime;
+    }
+
+
+    /**
+     * Get the maximum number of users for which authentication failure will be
+     * kept in the cache.
+     * @return the cacheSize
+     */
+    public int getCacheSize() {
+        return cacheSize;
+    }
+
+
+    /**
+     * Set the maximum number of users for which authentication failure will be
+     * kept in the cache.
+     * @param cacheSize the cacheSize to set
+     */
+    public void setCacheSize(int cacheSize) {
+        this.cacheSize = cacheSize;
+    }
+
+
+    /**
+     * Get the minimum period a failed authentication must remain in the cache
+     * to avoid generating a warning if it is removed from the cache to make
+     * space for a new entry.
+     * @return the cacheRemovalWarningTime
+     */
+    public int getCacheRemovalWarningTime() {
+        return cacheRemovalWarningTime;
+    }
+
+
+    /**
+     * Set the minimum period a failed authentication must remain in the cache
+     * to avoid generating a warning if it is removed from the cache to make
+     * space for a new entry.
+     * @param cacheRemovalWarningTime the cacheRemovalWarningTime to set
+     */
+    public void setCacheRemovalWarningTime(int cacheRemovalWarningTime) {
+        this.cacheRemovalWarningTime = cacheRemovalWarningTime;
+    }
+
+
+    protected class LockRecord {
+        private AtomicInteger failures = new AtomicInteger(0);
+        private long lastFailureTime = 0;
+        
+        public int getFailures() {
+            return failures.get();
+        }
+        
+        public void setFailures(int theFailures) {
+            failures.set(theFailures);
+        }
+
+        public long getLastFailureTime() {
+            return lastFailureTime;
+        }
+        
+        public void registerFailure() {
+            failures.incrementAndGet();
+            lastFailureTime = System.currentTimeMillis();
+        }
+    }
+}

Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LockOutRealm.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/LockOutRealm.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/RealmBase.java
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/RealmBase.java?rev=707757&r1=707756&r2=707757&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/RealmBase.java (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/RealmBase.java Fri Oct 24 14:54:48 2008
@@ -1285,6 +1285,7 @@
     protected String domain;
     protected String host;
     protected String path;
+    protected String realmPath = "/realm0";
     protected ObjectName oname;
     protected ObjectName controller;
     protected MBeanServer mserver;
@@ -1309,6 +1310,14 @@
         return type;
     }
 
+    public String getRealmPath() {
+        return realmPath;
+    }
+    
+    public void setRealmPath(String theRealmPath) {
+        realmPath = theRealmPath;
+    }
+
     public ObjectName preRegister(MBeanServer server,
                                   ObjectName name) throws Exception {
         oname=name;
@@ -1370,7 +1379,8 @@
             // register
             try {
                 ContainerBase cb=(ContainerBase)container;
-                oname=new ObjectName(cb.getDomain()+":type=Realm" + cb.getContainerSuffix());
+                oname=new ObjectName(cb.getDomain()+":type=Realm" +
+                        getRealmSuffix() + cb.getContainerSuffix());
                 Registry.getRegistry(null, null).registerComponent(this, oname, null );
                 if(log.isDebugEnabled())
                     log.debug("Register Realm "+oname);
@@ -1382,6 +1392,11 @@
     }
 
 
+    protected String getRealmSuffix() {
+        return ",realmPath=" + getRealmPath();
+    }
+
+
     protected static class AllRolesMode {
         
         private String name;

Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/mbeans-descriptors.xml
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/mbeans-descriptors.xml?rev=707757&r1=707756&r2=707757&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/mbeans-descriptors.xml (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/mbeans-descriptors.xml Fri Oct 24 14:54:48 2008
@@ -34,8 +34,7 @@
                  type="java.lang.String"/>
 
     <attribute   name="digest"
-          description="Digest algorithm used in storing passwords in a
-                        non-plaintext format"
+          description="Digest algorithm used in storing passwords in a non-plaintext format"
                  type="java.lang.String"/>
 
     <attribute   name="localDataSource"
@@ -47,18 +46,15 @@
                  type="java.lang.String"/>
 
     <attribute   name="userCredCol"
-          description="The column in the user table that holds the user's
-                        credentials"
+          description="The column in the user table that holds the user's credentials"
                  type="java.lang.String"/>
 
     <attribute   name="userNameCol"
-          description="The column in the user table that holds the user's
-                        username"
+          description="The column in the user table that holds the user's username"
                  type="java.lang.String"/>
 
     <attribute   name="userRoleTable"
-          description="The table that holds the relation between user's and
-                        roles"
+          description="The table that holds the relation between user's and roles"
                  type="java.lang.String"/>
 
     <attribute   name="userTable"
@@ -74,16 +70,13 @@
   </mbean>
 
   <mbean         name="JAASRealm"
-          description="Implmentation of Realm that authenticates users via the
-                       Java Authentication and Authorization Service (JAAS)"
+          description="Implmentation of Realm that authenticates users via the Java Authentication and Authorization Service (JAAS)"
                domain="Catalina"
                 group="Realm"
                  type="org.apache.catalina.realm.JAASRealm">
 
     <attribute   name="appName"
-          description="The application name passed to the JAAS LoginContext,
-                       which uses it to select the set of relevant
-                       LoginModules"
+          description="The application name passed to the JAAS LoginContext, which uses it to select the set of relevant LoginModules"
                  type="java.lang.String"/>
 
     <attribute   name="className"
@@ -92,23 +85,19 @@
             writeable="false"/>
 
     <attribute   name="digest"
-          description="Digest algorithm used in storing passwords in a
-                       non-plaintext format"
+          description="Digest algorithm used in storing passwords in a non-plaintext format"
                  type="java.lang.String"/>
 
     <attribute   name="roleClassNames"
-          description="Comma-delimited list of javax.security.Principal classes
-                       that represent security roles"
+          description="Comma-delimited list of javax.security.Principal classes that represent security roles"
                  type="java.lang.String"/>
 
     <attribute   name="userClassNames"
-          description="Comma-delimited list of javax.security.Principal classes
-                       that represent individual users"
+          description="Comma-delimited list of javax.security.Principal classes that represent individual users"
                  type="java.lang.String"/>
 
     <attribute   name="validate"
-          description="Should we validate client certificate chains when they
-                       are presented?"
+          description="Should we validate client certificate chains when they are presented?"
                  type="java.lang.String"/>
 
 
@@ -120,8 +109,7 @@
 
 
   <mbean         name="JDBCRealm"
-          description="Implementation of Realm that works with any JDBC
-                       supported database"
+          description="Implementation of Realm that works with any JDBC supported database"
                domain="Catalina"
                 group="Realm"
                  type="org.apache.catalina.realm.JDBCRealm">
@@ -132,23 +120,19 @@
             writeable="false"/>
 
     <attribute   name="connectionName"
-          description="The connection username to use when trying to connect to
-                       the database"
+          description="The connection username to use when trying to connect to the database"
                  type="java.lang.String"/>
 
     <attribute   name="connectionPassword"
-          description="The connection URL to use when trying to connect to the
-                       database"
+          description="The connection URL to use when trying to connect to the database"
                  type="java.lang.String"/>
 
     <attribute   name="connectionURL"
-          description="The connection URL to use when trying to connect to the
-                       database"
+          description="The connection URL to use when trying to connect to the database"
                  type="java.lang.String"/>
 
     <attribute   name="digest"
-          description="Digest algorithm used in storing passwords in a
-                       non-plaintext format"
+          description="Digest algorithm used in storing passwords in a non-plaintext format"
                  type="java.lang.String"/>
 
     <attribute   name="driverName"
@@ -160,18 +144,15 @@
                  type="java.lang.String"/>
 
     <attribute   name="userCredCol"
-          description="The column in the user table that holds the user's
-                       credentials"
+          description="The column in the user table that holds the user's credentials"
                  type="java.lang.String"/>
 
     <attribute   name="userNameCol"
-          description="The column in the user table that holds the user's
-                       username"
+          description="The column in the user table that holds the user's username"
                  type="java.lang.String"/>
 
     <attribute   name="userRoleTable"
-          description="The table that holds the relation between user's and
-                       roles"
+          description="The table that holds the relation between user's and roles"
                  type="java.lang.String"/>
 
     <attribute   name="userTable"
@@ -186,9 +167,7 @@
   </mbean>
 
   <mbean         name="JNDIRealm"
-          description="Implementation of Realm that works with a directory
-                       server accessed via the Java Naming and Directory
-                       Interface (JNDI) APIs"
+          description="Implementation of Realm that works with a directory server accessed via the Java Naming and Directory Interface (JNDI) APIs"
                domain="Catalina"
                 group="Realm"
                  type="org.apache.catalina.realm.JNDIRealm">
@@ -215,8 +194,7 @@
                  type="java.lang.String"/>
 
     <attribute   name="digest"
-          description="Digest algorithm used in storing passwords in a
-                       non-plaintext format"
+          description="Digest algorithm used in storing passwords in a non-plaintext format"
                  type="java.lang.String"/>
 
     <attribute   name="roleBase"
@@ -232,8 +210,7 @@
                  type="java.lang.String"/>
 
     <attribute   name="roleSubtree"
-          description="Should we search the entire subtree for matching
-                       memberships?"
+          description="Should we search the entire subtree for matching memberships?"
                  type="boolean"/>
 
     <attribute   name="userBase"
@@ -249,8 +226,7 @@
                  type="java.lang.String"/>
 
      <attribute   name="userRoleName"
-          description="The name of the attribute in the user's entry containing
-                       roles for that user"
+          description="The name of the attribute in the user's entry containing roles for that user"
                  type="java.lang.String"/>
 
    <attribute   name="userSearch"
@@ -258,8 +234,7 @@
                 type="java.lang.String"/>
 
     <attribute   name="userSubtree"
-          description="Should we search the entire subtree for matching
-                       users?"
+          description="Should we search the entire subtree for matching users?"
                  type="boolean"/>
 
 
@@ -270,8 +245,7 @@
   </mbean>
 
   <mbean         name="MemoryRealm"
-          description="Simple implementation of Realm that reads an XML file to
-                       configure the valid users, passwords, and roles"
+          description="Simple implementation of Realm that reads an XML file to configure the valid users, passwords, and roles"
                domain="Catalina"
                 group="Realm"
                  type="org.apache.catalina.realm.MemoryRealm">
@@ -282,8 +256,7 @@
             writeable="false"/>
 
     <attribute   name="pathname"
-          description="The pathname of the XML file containing our database
-                       information"
+          description="The pathname of the XML file containing our database information"
                  type="java.lang.String"/>
 
     <operation name="start" description="Start" impact="ACTION" returnType="void" />
@@ -294,8 +267,7 @@
   </mbean>
 
   <mbean         name="UserDatabaseRealm"
-          description="Realm connected to a UserDatabase as a global JNDI
-                       resource"
+          description="Realm connected to a UserDatabase as a global JNDI resource"
                domain="Catalina"
                 group="Realm"
                  type="org.apache.catalina.realm.UserDatabaseRealm">
@@ -311,4 +283,103 @@
 
   </mbean>
 
+  <mbean         name="CombinedRealm"
+          description="Realm implementation that can be used to chain multiple realms"
+               domain="Catalina"
+                group="Realm"
+                 type="org.apache.catalina.realm.CombinedRealm">
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="realms"
+          description="The set of realms that the combined realm is wrapping"
+                 type="[Ljavax.management.ObjectName;"
+            writeable="false"/>
+
+    <operation   name="addRealm"
+          description="Add a new Realm to the set of Realms wrapped by this realm"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="theRealm"
+                 description="New Realm to add"
+                 type="org.apache.catalina.Realm"/>
+    </operation>
+
+    <operation   name="start"
+          description="Start"
+               impact="ACTION"
+           returnType="void" />
+
+    <operation   name="stop"
+          description="Stop"
+               impact="ACTION"
+           returnType="void" />
+
+  </mbean>
+
+  <mbean         name="LockOutRealm"
+          description="Realm implementation that can be used to wrap existing realms to provide a user lock-out capability"
+               domain="Catalina"
+                group="Realm"
+                 type="org.apache.catalina.realm.LockOutRealm">
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="realms"
+          description="The set of realms that the lockout realm is wrapping"
+                 type="[Ljavax.management.ObjectName;"
+            writeable="false"/>
+
+    <attribute   name="cacheRemovalWarningTime"
+          description="If a failed user is removed from the cache because the cache is too big before it has been in the cache for at least this period of time (in seconds) a warning message will be logged. Defaults to 3600 (1 hour)."
+                 type="int" />
+
+    <attribute   name="cacheSize"
+          description="Number of users that have failed authentication to keep in cache. Over time the cache will grow to this size and may not shrink. Defaults to 1000."
+                 type="int" />
+
+    <attribute   name="failureCount"
+          description="The number of times in a row a user has to fail authentication to be locked out. Defaults to 5."
+                 type="int" />
+
+    <attribute   name="lockOutTime"
+          description="The time (in seconds) a user is locked out for after too many authentication failures. Defaults to 300 (5 minutes)."
+                 type="int" />
+
+    <operation   name="addRealm"
+          description="Add a new Realm to the set of Realms wrapped by this realm"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="theRealm"
+                 description="New Realm to add"
+                 type="org.apache.catalina.Realm"/>
+    </operation>
+
+    <operation   name="unlock"
+          description="Unlock the specified user"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="username"
+                 description="User to unlock"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="start"
+          description="Start"
+               impact="ACTION"
+           returnType="void" />
+
+    <operation   name="stop"
+          description="Stop"
+               impact="ACTION"
+           returnType="void" />
+
+  </mbean>
+
 </mbeans-descriptors>

Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/ContextRuleSet.java
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/ContextRuleSet.java?rev=707757&r1=707756&r2=707757&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/ContextRuleSet.java (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/ContextRuleSet.java Fri Oct 24 14:54:48 2008
@@ -170,13 +170,7 @@
                             "addApplicationParameter",
                             "org.apache.catalina.deploy.ApplicationParameter");
 
-        digester.addObjectCreate(prefix + "Context/Realm",
-                                 null, // MUST be specified in the element
-                                 "className");
-        digester.addSetProperties(prefix + "Context/Realm");
-        digester.addSetNext(prefix + "Context/Realm",
-                            "setRealm",
-                            "org.apache.catalina.Realm");
+        digester.addRuleSet(new RealmRuleSet(prefix + "Context/"));
 
         digester.addObjectCreate(prefix + "Context/Resources",
                                  "org.apache.naming.resources.FileDirContext",

Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/EngineRuleSet.java
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/EngineRuleSet.java?rev=707757&r1=707756&r2=707757&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/EngineRuleSet.java (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/EngineRuleSet.java Fri Oct 24 14:54:48 2008
@@ -121,13 +121,7 @@
                             "org.apache.catalina.LifecycleListener");
 
 
-        digester.addObjectCreate(prefix + "Engine/Realm",
-                                 null, // MUST be specified in the element
-                                 "className");
-        digester.addSetProperties(prefix + "Engine/Realm");
-        digester.addSetNext(prefix + "Engine/Realm",
-                            "setRealm",
-                            "org.apache.catalina.Realm");
+        digester.addRuleSet(new RealmRuleSet(prefix + "Engine/"));
 
         digester.addObjectCreate(prefix + "Engine/Valve",
                                  null, // MUST be specified in the element

Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/HostRuleSet.java
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/HostRuleSet.java?rev=707757&r1=707756&r2=707757&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/HostRuleSet.java (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/HostRuleSet.java Fri Oct 24 14:54:48 2008
@@ -124,13 +124,7 @@
                             "addLifecycleListener",
                             "org.apache.catalina.LifecycleListener");
 
-        digester.addObjectCreate(prefix + "Host/Realm",
-                                 null, // MUST be specified in the element
-                                 "className");
-        digester.addSetProperties(prefix + "Host/Realm");
-        digester.addSetNext(prefix + "Host/Realm",
-                            "setRealm",
-                            "org.apache.catalina.Realm");
+        digester.addRuleSet(new RealmRuleSet(prefix + "Host/"));
 
         digester.addObjectCreate(prefix + "Host/Valve",
                                  null, // MUST be specified in the element

Added: tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/RealmRuleSet.java
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/RealmRuleSet.java?rev=707757&view=auto
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/RealmRuleSet.java (added)
+++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/RealmRuleSet.java Fri Oct 24 14:54:48 2008
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.catalina.startup;
+
+
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.RuleSetBase;
+
+
+/**
+ * <p><strong>RuleSet</strong> for processing the contents of a Realm definition
+ * element.  This <code>RuleSet</code> supports Realms such as the
+ * <code>CombinedRealm</code> that used nested Realms.</p>
+ *
+ * @version $Revision$ $Date$
+ */
+
+public class RealmRuleSet extends RuleSetBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The matching pattern prefix to use for recognizing our elements.
+     */
+    protected String prefix = null;
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the default
+     * matching pattern prefix.
+     */
+    public RealmRuleSet() {
+
+        this("");
+
+    }
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the specified
+     * matching pattern prefix.
+     *
+     * @param prefix Prefix for matching pattern rules (including the
+     *  trailing slash character)
+     */
+    public RealmRuleSet(String prefix) {
+
+        super();
+        this.namespaceURI = null;
+        this.prefix = prefix;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Add the set of Rule instances defined in this RuleSet to the
+     * specified <code>Digester</code> instance, associating them with
+     * our namespace URI (if any).  This method should only be called
+     * by a Digester instance.</p>
+     *
+     * @param digester Digester instance to which the new Rule instances
+     *  should be added.
+     */
+    public void addRuleInstances(Digester digester) {
+
+        digester.addObjectCreate(prefix + "Realm",
+                                 null, // MUST be specified in the element,
+                                 "className");
+        digester.addSetProperties(prefix + "Realm");
+        digester.addSetNext(prefix + "Realm",
+                            "setRealm",
+                            "org.apache.catalina.Realm");
+
+        digester.addObjectCreate(prefix + "Realm/Realm",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Realm/Realm");
+        digester.addSetNext(prefix + "Realm/Realm",
+                            "addRealm",
+                            "org.apache.catalina.Realm");
+
+    }
+
+
+}

Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/RealmRuleSet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/RealmRuleSet.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=707757&r1=707756&r2=707757&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Fri Oct 24 14:54:48 2008
@@ -93,6 +93,15 @@
         <bug>45823</bug>: Log missing request headers as '-' not 'null'. Based
         on a patch by Per Landberg. (markt)
       </fix>
+      <add>
+        Add the CombinedRealm that enables authentication to be attempted
+        against multiple realms. (markt) 
+      </add>
+      <add>
+        Add the LockOutRealm that enables a standard Realm to be wrapped with
+        the functionality to lock out a user after too many failed logins.
+        (markt)
+      </add>
     </changelog>
   </subsection>
   <subsection name="Coyote">

Modified: tomcat/tc6.0.x/trunk/webapps/docs/config/realm.xml
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/config/realm.xml?rev=707757&r1=707756&r2=707757&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/webapps/docs/config/realm.xml (original)
+++ tomcat/tc6.0.x/trunk/webapps/docs/config/realm.xml Fri Oct 24 14:54:48 2008
@@ -565,6 +565,86 @@
     Guide</a> for more information on setting up container managed security
     using the JAAS Realm component.</p>
 
+    <h3>Combined Realm (org.apache.catalina.realm.CombinedRealm)</h3>
+
+    <p><strong>CombinedRealm</strong> is an implementation of the Tomcat 6
+    <code>Realm</code> interface that authenticates users through one or more
+    sub-Realms.</p>
+
+    <p>Using CombinedRealm gives the developer the ability to combine multiple
+    Realms of the same or different types. This can be used to authenticate
+    against different sources, provide fall back in case one Realm fails or for
+    any other purpose that requires multiple Realms.</p>
+
+    <p>Sub-realms are defined by nesting <code>Realm</code> elements inside the
+    <code>Realm</code> element that defines the CombinedRealm. Authentication
+    will be attempted against each <code>Realm</code> in the order they are
+    listed. Authentication against any Realm will be sufficient to authenticate
+    the user.</p>
+
+    <p>The CombinedRealm implementation does not support any additional
+    attributes.</p>
+
+    <p>See the <a href="../realm-howto.html">Container-Managed Security
+    Guide</a> for more information on setting up container managed security
+    using the CombinedRealm component.</p>
+
+    <h3>LockOut Realm (org.apache.catalina.realm.LockOutRealm)</h3>
+
+    <p><strong>LockOutRealm</strong> is an implementation of the Tomcat 6
+    <code>Realm</code> interface that extends the CombinedRealm to provide lock
+    out functionality to provide a user lock out mechanism if there are too many
+    failed authentication attempts in a given period of time.</p>
+    
+    <p>To ensure correct operation, there is a reasonable degree of
+    synchronisation in this Realm.</p>
+    
+    <p>This Realm does not require modification to the underlying Realms or the
+    associated user storage mecahisms. It achieves this by recording all failed
+    logins, including those for users that do not exist. To prevent a DOS by
+    deliberating making requests with invalid users (and hence causing this
+    cache to grow) the size of the list of users that have failed authentication
+    is limited.</p>
+
+    <p>Sub-realms are defined by nesting <code>Realm</code> elements inside the
+    <code>Realm</code> element that defines the LockOutRealm. Authentication
+    will be attempted against each <code>Realm</code> in the order they are
+    listed. Authentication against any Realm will be sufficient to authenticate
+    the user.</p>
+
+    <p>The LockOutRealm implementation supports the following additional
+    attributes.</p>
+
+    <attributes>
+
+      <attribute name="cacheRemovalWarningTime" required="false">
+       <p>If a failed user is removed from the cache because the cache is too
+       big before it has been in the cache for at least this period of time (in
+       seconds) a warning message will be logged. Defaults to 3600 (1 hour).</p>
+      </attribute>
+
+      <attribute name="cacheSize" required="false">
+       <p>Number of users that have failed authentication to keep in cache. Over
+       time the cache will grow to this size and may not shrink. Defaults to
+       1000.</p>
+      </attribute>
+
+      <attribute name="failureCount" required="false">
+       <p>The number of times in a row a user has to fail authentication to be
+       locked out. Defaults to 5.</p>
+      </attribute>
+
+      <attribute name="lockOutTime" required="false">
+       <p>The time (in seconds) a user is locked out for after too many
+       authentication failures. Defaults to 300 (5 minutes).</p>
+      </attribute>
+
+    </attributes>
+
+    <p>See the <a href="../realm-howto.html">Container-Managed Security
+    Guide</a> for more information on setting up container managed security
+    using the LockOutRealm component.</p>
+
   </subsection>
 
 
@@ -573,7 +653,15 @@
 
 <section name="Nested Components">
 
-  <p>No components may be nested inside a <strong>Realm</strong> element.</p>
+  <h3>CombinedRealm Implementation</h3>
+
+  <p>If you are using the <em>CombinedRealm Implementation</em> or a Realm
+  that extends the CombinedRealm, e.g. the LockOutRealm,
+  <strong>&lt;Realm&gt;</strong> elements may be nested inside it.</p>
+
+  <h3>Other Realm Implementations</h3>
+  
+  <p>No other Realm implementation supports nested components.</p>
 
 </section>
 

Modified: tomcat/tc6.0.x/trunk/webapps/docs/realm-howto.xml
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/realm-howto.xml?rev=707757&r1=707756&r2=707757&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/webapps/docs/realm-howto.xml (original)
+++ tomcat/tc6.0.x/trunk/webapps/docs/realm-howto.xml Fri Oct 24 14:54:48 2008
@@ -55,6 +55,8 @@
 <a href="#JNDIRealm">JNDIRealm</a><br />
 <a href="#MemoryRealm">MemoryRealm</a><br />
 <a href="#JAASRealm">JAASRealm</a><br />
+<a href="#CombinedRealm">CombinedRealm</a><br />
+<a href="#LockOutRealm">LockOutRealm</a><br />
 </blockquote>
 </p>
 
@@ -1440,6 +1442,140 @@
 </subsection>
 
 
+<subsection name="CombinedRealm">
+
+    <h3>Introduction</h3>
+
+    <p><strong>CombinedRealm</strong> is an implementation of the Tomcat 6
+    <code>Realm</code> interface that authenticates users through one or more
+    sub-Realms.</p>
+
+    <p>Using CombinedRealm gives the developer the ability to combine multiple
+    Realms of the same or different types. This can be used to authenticate
+    against different sources, provide fall back in case one Realm fails or for
+    any other purpose that requires multiple Realms.</p>
+
+    <p>Sub-realms are defined by nesting <code>Realm</code> elements inside the
+    <code>Realm</code> element that defines the CombinedRealm. Authentication
+    will be attempted against each <code>Realm</code> in the order they are
+    listed. Authentication against any Realm will be sufficient to authenticate
+    the user.</p>
+
+    <h3>Realm Element Attributes</h3>
+    <p>To configure a CombinedRealm, you create a <code>&lt;Realm&gt;</code>
+    element and nest it in your <code>$CATALINA_BASE/conf/server.xml</code>
+    file within your <code>&lt;Engine&gt;</code> or <code>&lt;Host&gt;</code>.
+    You can also nest inside a <code>&lt;Context&gt;</code> node in a
+    <code>context.xml</code> file. The following attributes are supported by
+    this implementation:</p>
+
+<attributes>
+
+  <attribute name="className" required="true">
+    <p>The fully qualified Java class name of this Realm implementation.
+    You <strong>MUST</strong> specify the value
+    "<code>org.apache.catalina.realm.CombinedRealm</code>" here.</p>
+  </attribute>
+
+</attributes>
+
+<h3>Example</h3>
+
+<p>Here is an example of how your server.xml snippet should look to use a
+UserDatabase Realm and a DataSource Realm.</p>
+
+<source>
+&lt;Realm className="org.apache.catalina.realm.CombinedRealm" &gt;
+   &lt;Realm className="org.apache.catalina.realm.UserDatabaseRealm"
+             resourceName="UserDatabase"/&gt;
+   &lt;Realm className="org.apache.catalina.realm.DataSourceRealm" debug="99"
+             dataSourceName="jdbc/authority"
+             userTable="users" userNameCol="user_name" userCredCol="user_pass"
+             userRoleTable="user_roles" roleNameCol="role_name"/&gt;
+&lt;Realm/&gt;
+</source>
+
+</subsection>
+
+<subsection name="LockOutRealm">
+
+    <h3>Introduction</h3>
+
+    <p><strong>LockOutRealm</strong> is an implementation of the Tomcat 6
+    <code>Realm</code> interface that extends the CombinedRealm to provide lock
+    out functionality to provide a user lock out mechanism if there are too many
+    failed authentication attempts in a given period of time.</p>
+    
+    <p>To ensure correct operation, there is a reasonable degree of
+    synchronisation in this Realm.</p>
+    
+    <p>This Realm does not require modification to the underlying Realms or the
+    associated user storage mecahisms. It achieves this by recording all failed
+    logins, including those for users that do not exist. To prevent a DOS by
+    deliberating making requests with invalid users (and hence causing this
+    cache to grow) the size of the list of users that have failed authentication
+    is limited.</p>
+
+    <p>Sub-realms are defined by nesting <code>Realm</code> elements inside the
+    <code>Realm</code> element that defines the LockOutRealm. Authentication
+    will be attempted against each <code>Realm</code> in the order they are
+    listed. Authentication against any Realm will be sufficient to authenticate
+    the user.</p>
+
+    <h3>Realm Element Attributes</h3>
+    <p>To configure a LockOutRealm, you create a <code>&lt;Realm&gt;</code>
+    element and nest it in your <code>$CATALINA_BASE/conf/server.xml</code>
+    file within your <code>&lt;Engine&gt;</code> or <code>&lt;Host&gt;</code>.
+    You can also nest inside a <code>&lt;Context&gt;</code> node in a
+    <code>context.xml</code> file. The following attributes are supported by
+    this implementation:</p>
+
+<attributes>
+
+  <attribute name="className" required="true">
+    <p>The fully qualified Java class name of this Realm implementation.
+    You <strong>MUST</strong> specify the value
+    "<code>org.apache.catalina.realm.LockOutRealm</code>" here.</p>
+  </attribute>
+
+  <attribute name="cacheRemovalWarningTime" required="false">
+    <p>If a failed user is removed from the cache because the cache is too
+    big before it has been in the cache for at least this period of time (in
+    seconds) a warning message will be logged. Defaults to 3600 (1 hour).</p>
+  </attribute>
+
+  <attribute name="cacheSize" required="false">
+    <p>Number of users that have failed authentication to keep in cache. Over
+    time the cache will grow to this size and may not shrink. Defaults to
+    1000.</p>
+  </attribute>
+
+  <attribute name="failureCount" required="false">
+    <p>The number of times in a row a user has to fail authentication to be
+    locked out. Defaults to 5.</p>
+  </attribute>
+
+  <attribute name="lockOutTime" required="false">
+    <p>The time (in seconds) a user is locked out for after too many
+    authentication failures. Defaults to 300 (5 minutes).</p>
+  </attribute>
+
+</attributes>
+
+<h3>Example</h3>
+
+<p>Here is an example of how your server.xml snippet should look to add lock out
+functionality to a UserDatabase Realm.</p>
+
+<source>
+&lt;Realm className="org.apache.catalina.realm.LockOutRealm" &gt;
+   &lt;Realm className="org.apache.catalina.realm.UserDatabaseRealm"
+             resourceName="UserDatabase"/&gt;
+&lt;Realm/&gt;
+</source>
+
+</subsection>
+
 </section>
 
 </body>



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Mime
View raw message