/* * 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;
/** * 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 mechanisms. 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.
*/ publicclass LockOutRealm extends CombinedRealm {
/** * The number of times in a row a user has to fail authentication to be locked out. Defaults to 5.
*/ protectedint failureCount = 5;
/** * The time (in seconds) a user is locked out for after too many authentication failures. Defaults to 300 (5 * minutes).
*/ protectedint 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.
*/ protectedint 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).
*/ protectedint 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;
@Override protectedsynchronizedvoid startInternal() throws LifecycleException { /* * Configure the list of failed users to delete the oldest entry once it exceeds the specified size. This is an * LRU cache so if the cache size is exceeded the users who most recently failed authentication will be * retained.
*/
failedUsers = new LinkedHashMap<>(cacheSize, 0.75f, true) { privatestaticfinallong serialVersionUID = 1L;
@Override protectedboolean 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;
/* * Filters authenticated principals to ensure that <code>null</code> is returned for any user that is currently * locked out.
*/ private Principal filterLockedAccounts(String username, Principal authenticatedUser) { // Register all failed authentications if (authenticatedUser == null && isAvailable()) {
registerAuthFailure(username);
}
if (isLocked(username)) { // If the user is currently locked, authentication will always fail
log.warn(sm.getString("lockOutRealm.authLockedUser", username)); returnnull;
}
if (authenticatedUser != null) {
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
*/ publicvoid 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.
*/ publicboolean isLocked(String username) {
LockRecord lockRecord = null; synchronized (this) {
lockRecord = failedUsers.get(username);
}
// No lock record means user can't be locked if (lockRecord == null) { returnfalse;
}
// Check to see if user is locked if (lockRecord.getFailures() >= failureCount &&
(System.currentTimeMillis() - lockRecord.getLastFailureTime()) / 1000 < lockOutTime) { returntrue;
}
// User has not, yet, exceeded lock thresholds returnfalse;
}
/* * After successful authentication, any record of previous authentication failure is removed.
*/ privatesynchronizedvoid 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.
*/ privatevoid 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
*/ publicint getFailureCount() { return failureCount;
}
/** * Set the number of failed authentication attempts required to lock the user account. * * @param failureCount the failureCount to set
*/ publicvoid setFailureCount(int failureCount) { this.failureCount = failureCount;
}
/** * Get the period for which an account will be locked. * * @return the lockOutTime
*/ publicint getLockOutTime() { return lockOutTime;
}
/** * Set the period for which an account will be locked. * * @param lockOutTime the lockOutTime to set
*/ publicvoid 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
*/ publicint 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
*/ publicvoid 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
*/ publicint 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
*/ publicvoid setCacheRemovalWarningTime(int cacheRemovalWarningTime) { this.cacheRemovalWarningTime = cacheRemovalWarningTime;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.