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><Realm></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><Realm></code> + <p>To configure a CombinedRealm, you create a <code><Realm></code> element and nest it in your <code>$CATALINA_BASE/conf/server.xml</code> file within your <code><Engine></code> or <code><Host></code>. You can also nest inside a <code><Context></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><Realm></code> + element and nest it in your <code>$CATALINA_BASE/conf/server.xml</code> + file within your <code><Engine></code> or <code><Host></code>. + You can also nest inside a <code><Context></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> +<Realm className="org.apache.catalina.realm.LockOutRealm" > + <Realm className="org.apache.catalina.realm.UserDatabaseRealm" + resourceName="UserDatabase"/> +<Realm/> +</source> + +</subsection> + </section> </body> --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]