You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2008/09/23 18:49:25 UTC

svn commit: r698236 - in /tomcat/trunk: java/org/apache/catalina/realm/ webapps/docs/ webapps/docs/config/

Author: markt
Date: Tue Sep 23 09:49:25 2008
New Revision: 698236

URL: http://svn.apache.org/viewvc?rev=698236&view=rev
Log:
Add new LockOut Realm plus docs

Added:
    tomcat/trunk/java/org/apache/catalina/realm/LockOutRealm.java   (with props)
Modified:
    tomcat/trunk/java/org/apache/catalina/realm/LocalStrings.properties
    tomcat/trunk/java/org/apache/catalina/realm/mbeans-descriptors.xml
    tomcat/trunk/webapps/docs/config/realm.xml
    tomcat/trunk/webapps/docs/realm-howto.xml

Modified: tomcat/trunk/java/org/apache/catalina/realm/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/realm/LocalStrings.properties?rev=698236&r1=698235&r2=698236&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/realm/LocalStrings.properties (original)
+++ tomcat/trunk/java/org/apache/catalina/realm/LocalStrings.properties Tue Sep 23 09:49:25 2008
@@ -92,4 +92,6 @@
 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
\ No newline at end of file
+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/trunk/java/org/apache/catalina/realm/LockOutRealm.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/realm/LockOutRealm.java?rev=698236&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/realm/LockOutRealm.java (added)
+++ tomcat/trunk/java/org/apache/catalina/realm/LockOutRealm.java Tue Sep 23 09:49:25 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/trunk/java/org/apache/catalina/realm/LockOutRealm.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/java/org/apache/catalina/realm/mbeans-descriptors.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/realm/mbeans-descriptors.xml?rev=698236&r1=698235&r2=698236&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/realm/mbeans-descriptors.xml (original)
+++ tomcat/trunk/java/org/apache/catalina/realm/mbeans-descriptors.xml Tue Sep 23 09:49:25 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/trunk/webapps/docs/config/realm.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/realm.xml?rev=698236&r1=698235&r2=698236&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/realm.xml (original)
+++ tomcat/trunk/webapps/docs/config/realm.xml Tue Sep 23 09:49:25 2008
@@ -608,12 +608,68 @@
     listed. Authentication against any Realm will be sufficient to authenticate
     the user.</p>
 
-    <p>The Combined Realm implementation does not support any additional
+    <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 Combined Realm component.</p>
+    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>
 
@@ -623,9 +679,10 @@
 
 <section name="Nested Components">
 
-  <h3>Combined Realm Implementation</h3>
+  <h3>CombinedRealm Implementation</h3>
 
-  <p>If you are using the <em>Combined Realm Implementation</em>
+  <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>

Modified: tomcat/trunk/webapps/docs/realm-howto.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/realm-howto.xml?rev=698236&r1=698235&r2=698236&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/realm-howto.xml (original)
+++ tomcat/trunk/webapps/docs/realm-howto.xml Tue Sep 23 09:49:25 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>
 
@@ -1485,7 +1487,7 @@
     the user.</p>
 
     <h3>Realm Element Attributes</h3>
-    <p>To configure CombinedRealm, you create a <code>&lt;Realm&gt;</code>
+    <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
@@ -1520,6 +1522,85 @@
 
 </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