mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUACAMOLE-990: Limit maximum number of tracked addresses.
This commit is contained in:
8
doc/licenses/caffeine-2.9.3/README
Normal file
8
doc/licenses/caffeine-2.9.3/README
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Caffeine (https://github.com/ben-manes/caffeine)
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
Version: 2.9.3
|
||||||
|
From: 'Ben Manes' (https://github.com/ben-manes)
|
||||||
|
License(s):
|
||||||
|
Apache v2.0
|
||||||
|
|
1
doc/licenses/caffeine-2.9.3/dep-coordinates.txt
Normal file
1
doc/licenses/caffeine-2.9.3/dep-coordinates.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
com.github.ben-manes.caffeine:caffeine:jar:2.9.3
|
22
doc/licenses/checker-qual-3.19.0/LICENSE.txt
Normal file
22
doc/licenses/checker-qual-3.19.0/LICENSE.txt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Checker Framework qualifiers
|
||||||
|
Copyright 2004-present by the Checker Framework developers
|
||||||
|
|
||||||
|
MIT License:
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
8
doc/licenses/checker-qual-3.19.0/README
Normal file
8
doc/licenses/checker-qual-3.19.0/README
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Checker Framework qualifiers (https://checkerframework.org/)
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Version: 3.19.0
|
||||||
|
From: 'Checker Framework developers' (https://checkerframework.org/)
|
||||||
|
License(s):
|
||||||
|
MIT (bundled/checker-qual-3.19.0/LICENSE.txt)
|
||||||
|
|
1
doc/licenses/checker-qual-3.19.0/dep-coordinates.txt
Normal file
1
doc/licenses/checker-qual-3.19.0/dep-coordinates.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
org.checkerframework:checker-qual:jar:3.19.0
|
8
doc/licenses/error-prone-2.10.0/README
Normal file
8
doc/licenses/error-prone-2.10.0/README
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Error Prone (https://errorprone.info/)
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
Version: 2.10.0
|
||||||
|
From: 'Google Inc.' (http://www.google.com/)
|
||||||
|
License(s):
|
||||||
|
Apache v2.0
|
||||||
|
|
1
doc/licenses/error-prone-2.10.0/dep-coordinates.txt
Normal file
1
doc/licenses/error-prone-2.10.0/dep-coordinates.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
com.google.errorprone:error_prone_annotations:jar:2.10.0
|
@@ -53,6 +53,27 @@
|
|||||||
<artifactId>guacamole-ext</artifactId>
|
<artifactId>guacamole-ext</artifactId>
|
||||||
<version>1.4.0</version>
|
<version>1.4.0</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
|
|
||||||
|
<!-- Exclude transitive dependencies that will be overridden by
|
||||||
|
newer versions required by Caffeine -->
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.checkerframework</groupId>
|
||||||
|
<artifactId>checker-qual</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>com.google.errorprone</groupId>
|
||||||
|
<artifactId>error_prone_annotations</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Guava Base Libraries -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
|
<artifactId>caffeine</artifactId>
|
||||||
|
<version>2.9.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@@ -53,9 +53,9 @@ public class AuthenticationFailureStatus {
|
|||||||
private final long duration;
|
private final long duration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an AuthenticationFailureStatus that represents a single failure
|
* Creates an AuthenticationFailureStatus that is initialized to zero
|
||||||
* and is subject to the given restrictions. Additional failures may be
|
* failures and is subject to the given restrictions. Additional failures
|
||||||
* flagged after creation with {@link #notifyFailed()}.
|
* may be flagged after creation with {@link #notifyFailed()}.
|
||||||
*
|
*
|
||||||
* @param maxAttempts
|
* @param maxAttempts
|
||||||
* The maximum number of failures that may occur before the
|
* The maximum number of failures that may occur before the
|
||||||
@@ -67,7 +67,7 @@ public class AuthenticationFailureStatus {
|
|||||||
*/
|
*/
|
||||||
public AuthenticationFailureStatus(int maxAttempts, int duration) {
|
public AuthenticationFailureStatus(int maxAttempts, int duration) {
|
||||||
this.lastFailure = System.nanoTime();
|
this.lastFailure = System.nanoTime();
|
||||||
this.failureCount = new AtomicInteger(1);
|
this.failureCount = new AtomicInteger(0);
|
||||||
this.maxAttempts = maxAttempts;
|
this.maxAttempts = maxAttempts;
|
||||||
this.duration = TimeUnit.SECONDS.toNanos(duration);
|
this.duration = TimeUnit.SECONDS.toNanos(duration);
|
||||||
}
|
}
|
||||||
|
@@ -19,8 +19,8 @@
|
|||||||
|
|
||||||
package org.apache.guacamole.auth.ban;
|
package org.apache.guacamole.auth.ban;
|
||||||
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.GuacamoleServerException;
|
import org.apache.guacamole.GuacamoleServerException;
|
||||||
@@ -44,8 +44,7 @@ public class AuthenticationFailureTracker {
|
|||||||
* All authentication failures currently being tracked, stored by the
|
* All authentication failures currently being tracked, stored by the
|
||||||
* associated IP address.
|
* associated IP address.
|
||||||
*/
|
*/
|
||||||
private final ConcurrentMap<String, AuthenticationFailureStatus> failures =
|
private final Cache<String, AuthenticationFailureStatus> failures;
|
||||||
new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum number of failed authentication attempts allowed before an
|
* The maximum number of failed authentication attempts allowed before an
|
||||||
@@ -70,8 +69,14 @@ public class AuthenticationFailureTracker {
|
|||||||
* @param banDuration
|
* @param banDuration
|
||||||
* The length of time that each address should be banned after reaching
|
* The length of time that each address should be banned after reaching
|
||||||
* the maximum number of failed authentication attempts, in seconds.
|
* the maximum number of failed authentication attempts, in seconds.
|
||||||
|
*
|
||||||
|
* @param maxAddresses
|
||||||
|
* The maximum number of unique IP addresses that should be tracked
|
||||||
|
* before discarding older tracked failures.
|
||||||
*/
|
*/
|
||||||
public AuthenticationFailureTracker(int maxAttempts, int banDuration) {
|
public AuthenticationFailureTracker(int maxAttempts, int banDuration,
|
||||||
|
long maxAddresses) {
|
||||||
|
|
||||||
this.maxAttempts = maxAttempts;
|
this.maxAttempts = maxAttempts;
|
||||||
this.banDuration = banDuration;
|
this.banDuration = banDuration;
|
||||||
|
|
||||||
@@ -93,6 +98,14 @@ public class AuthenticationFailureTracker {
|
|||||||
banDuration, maxAttempts);
|
banDuration, maxAttempts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Limit maximum number of tracked addresses to configured upper bound
|
||||||
|
this.failures = Caffeine.newBuilder()
|
||||||
|
.maximumSize(maxAddresses)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
logger.info("Up to {} unique addresses will be tracked/banned at any "
|
||||||
|
+ " given time.", maxAddresses);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -147,10 +160,8 @@ public class AuthenticationFailureTracker {
|
|||||||
*/
|
*/
|
||||||
private AuthenticationFailureStatus getAuthenticationFailure(String address) {
|
private AuthenticationFailureStatus getAuthenticationFailure(String address) {
|
||||||
|
|
||||||
AuthenticationFailureStatus newFailure = new AuthenticationFailureStatus(maxAttempts, banDuration);
|
AuthenticationFailureStatus status = failures.get(address,
|
||||||
AuthenticationFailureStatus status = failures.putIfAbsent(address, newFailure);
|
(addr) -> new AuthenticationFailureStatus(maxAttempts, banDuration));
|
||||||
if (status == null)
|
|
||||||
return newFailure;
|
|
||||||
|
|
||||||
status.notifyFailed();
|
status.notifyFailed();
|
||||||
return status;
|
return status;
|
||||||
@@ -199,7 +210,7 @@ public class AuthenticationFailureTracker {
|
|||||||
address, status.getFailures(), maxAttempts);
|
address, status.getFailures(), maxAttempts);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
status = failures.get(address);
|
status = failures.getIfPresent(address);
|
||||||
|
|
||||||
if (status != null) {
|
if (status != null) {
|
||||||
|
|
||||||
@@ -216,7 +227,7 @@ public class AuthenticationFailureTracker {
|
|||||||
// relevant (all failures are sufficiently old)
|
// relevant (all failures are sufficiently old)
|
||||||
else if (!status.isValid()) {
|
else if (!status.isValid()) {
|
||||||
logger.debug("Removing address \"{}\" from tracking as there are no recent authentication failures.", address);
|
logger.debug("Removing address \"{}\" from tracking as there are no recent authentication failures.", address);
|
||||||
failures.remove(address);
|
failures.invalidate(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
package org.apache.guacamole.auth.ban;
|
package org.apache.guacamole.auth.ban;
|
||||||
|
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
|
import org.apache.guacamole.GuacamoleServerException;
|
||||||
import org.apache.guacamole.environment.Environment;
|
import org.apache.guacamole.environment.Environment;
|
||||||
import org.apache.guacamole.environment.LocalEnvironment;
|
import org.apache.guacamole.environment.LocalEnvironment;
|
||||||
import org.apache.guacamole.net.auth.AbstractAuthenticationProvider;
|
import org.apache.guacamole.net.auth.AbstractAuthenticationProvider;
|
||||||
@@ -27,6 +28,7 @@ import org.apache.guacamole.net.auth.AuthenticatedUser;
|
|||||||
import org.apache.guacamole.net.auth.Credentials;
|
import org.apache.guacamole.net.auth.Credentials;
|
||||||
import org.apache.guacamole.net.auth.UserContext;
|
import org.apache.guacamole.net.auth.UserContext;
|
||||||
import org.apache.guacamole.properties.IntegerGuacamoleProperty;
|
import org.apache.guacamole.properties.IntegerGuacamoleProperty;
|
||||||
|
import org.apache.guacamole.properties.LongGuacamoleProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AuthenticationProvider implementation that blocks further authentication
|
* AuthenticationProvider implementation that blocks further authentication
|
||||||
@@ -61,6 +63,20 @@ public class BanningAuthenticationProvider extends AbstractAuthenticationProvide
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of failed authentication attempts tracked at any
|
||||||
|
* given time. Once this number of addresses is exceeded, the oldest
|
||||||
|
* authentication attempts are rotated off on an LRU basis.
|
||||||
|
*/
|
||||||
|
private static final LongGuacamoleProperty MAX_ADDRESSES = new LongGuacamoleProperty() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "ban-max-addresses";
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default maximum number of failed authentication attempts allowed
|
* The default maximum number of failed authentication attempts allowed
|
||||||
* before an address is temporarily banned.
|
* before an address is temporarily banned.
|
||||||
@@ -74,6 +90,13 @@ public class BanningAuthenticationProvider extends AbstractAuthenticationProvide
|
|||||||
*/
|
*/
|
||||||
private static final int DEFAULT_IP_BAN_DURATION = 300;
|
private static final int DEFAULT_IP_BAN_DURATION = 300;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of failed authentication attempts tracked at any
|
||||||
|
* given time. Once this number of addresses is exceeded, the oldest
|
||||||
|
* authentication attempts are rotated off on an LRU basis.
|
||||||
|
*/
|
||||||
|
private static final long DEFAULT_MAX_ADDRESSES = 10485760;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared tracker of addresses that have repeatedly failed authentication.
|
* Shared tracker of addresses that have repeatedly failed authentication.
|
||||||
*/
|
*/
|
||||||
@@ -95,8 +118,15 @@ public class BanningAuthenticationProvider extends AbstractAuthenticationProvide
|
|||||||
Environment environment = LocalEnvironment.getInstance();
|
Environment environment = LocalEnvironment.getInstance();
|
||||||
int maxAttempts = environment.getProperty(MAX_ATTEMPTS, DEFAULT_MAX_ATTEMPTS);
|
int maxAttempts = environment.getProperty(MAX_ATTEMPTS, DEFAULT_MAX_ATTEMPTS);
|
||||||
int banDuration = environment.getProperty(IP_BAN_DURATION, DEFAULT_IP_BAN_DURATION);
|
int banDuration = environment.getProperty(IP_BAN_DURATION, DEFAULT_IP_BAN_DURATION);
|
||||||
|
long maxAddresses = environment.getProperty(MAX_ADDRESSES, DEFAULT_MAX_ADDRESSES);
|
||||||
|
|
||||||
tracker = new AuthenticationFailureTracker(maxAttempts, banDuration);
|
if (maxAddresses <= 0)
|
||||||
|
throw new GuacamoleServerException("The maximum number of "
|
||||||
|
+ "addresses tracked, as specified by the "
|
||||||
|
+ "\"" + MAX_ADDRESSES.getName() + "\" property, must be "
|
||||||
|
+ "greater than zero.");
|
||||||
|
|
||||||
|
tracker = new AuthenticationFailureTracker(maxAttempts, banDuration, maxAddresses);
|
||||||
BanningAuthenticationListener.setAuthenticationFailureTracker(tracker);
|
BanningAuthenticationListener.setAuthenticationFailureTracker(tracker);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user