diff --git a/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/BanningAuthenticationListener.java b/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/BanningAuthenticationListener.java index 38fd575fd..4d8a3bbad 100644 --- a/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/BanningAuthenticationListener.java +++ b/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/BanningAuthenticationListener.java @@ -19,6 +19,7 @@ package org.apache.guacamole.auth.ban; +import org.apache.guacamole.auth.ban.status.AuthenticationFailureTracker; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException; import org.apache.guacamole.net.event.AuthenticationFailureEvent; diff --git a/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/BanningAuthenticationProvider.java b/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/BanningAuthenticationProvider.java index adf54ff0c..a6df43a30 100644 --- a/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/BanningAuthenticationProvider.java +++ b/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/BanningAuthenticationProvider.java @@ -19,8 +19,11 @@ package org.apache.guacamole.auth.ban; +import org.apache.guacamole.auth.ban.status.InMemoryAuthenticationFailureTracker; +import org.apache.guacamole.auth.ban.status.AuthenticationFailureTracker; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; +import org.apache.guacamole.auth.ban.status.NullAuthenticationFailureTracker; import org.apache.guacamole.environment.Environment; import org.apache.guacamole.environment.LocalEnvironment; import org.apache.guacamole.net.auth.AbstractAuthenticationProvider; @@ -29,6 +32,8 @@ import org.apache.guacamole.net.auth.Credentials; import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.properties.IntegerGuacamoleProperty; import org.apache.guacamole.properties.LongGuacamoleProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * AuthenticationProvider implementation that blocks further authentication @@ -37,6 +42,11 @@ import org.apache.guacamole.properties.LongGuacamoleProperty; */ public class BanningAuthenticationProvider extends AbstractAuthenticationProvider { + /** + * Logger for this class. + */ + private static final Logger logger = LoggerFactory.getLogger(BanningAuthenticationProvider.class); + /** * The maximum number of failed authentication attempts allowed before an * address is temporarily banned. @@ -126,7 +136,29 @@ public class BanningAuthenticationProvider extends AbstractAuthenticationProvide + "\"" + MAX_ADDRESSES.getName() + "\" property, must be " + "greater than zero."); - tracker = new AuthenticationFailureTracker(maxAttempts, banDuration, maxAddresses); + // Configure auth failure tracking behavior and inform administrator of + // ultimate result + if (maxAttempts <= 0) { + this.tracker = new NullAuthenticationFailureTracker(); + logger.info("Maximum failed authentication attempts has been set " + + "to {}. Automatic banning of brute-force authentication " + + "attempts will be disabled.", maxAttempts); + } + else if (banDuration <= 0) { + this.tracker = new NullAuthenticationFailureTracker(); + logger.info("Ban duration for addresses that repeatedly fail " + + "authentication has been set to {}. Automatic banning " + + "of brute-force authentication attempts will be " + + "disabled.", banDuration); + } + else { + this.tracker = new InMemoryAuthenticationFailureTracker(maxAttempts, banDuration, maxAddresses); + logger.info("Addresses will be automatically banned for {} " + + "seconds after {} failed authentication attempts. Up " + + "to {} unique addresses will be tracked/banned at any " + + "given time.", banDuration, maxAttempts, maxAddresses); + } + BanningAuthenticationListener.setAuthenticationFailureTracker(tracker); } diff --git a/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/AuthenticationFailureStatus.java b/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/status/AuthenticationFailureStatus.java similarity index 98% rename from extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/AuthenticationFailureStatus.java rename to extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/status/AuthenticationFailureStatus.java index ac4f1efc1..3292d1179 100644 --- a/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/AuthenticationFailureStatus.java +++ b/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/status/AuthenticationFailureStatus.java @@ -17,7 +17,7 @@ * under the License. */ -package org.apache.guacamole.auth.ban; +package org.apache.guacamole.auth.ban.status; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; diff --git a/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/status/AuthenticationFailureTracker.java b/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/status/AuthenticationFailureTracker.java new file mode 100644 index 000000000..9ea7f2c9e --- /dev/null +++ b/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/status/AuthenticationFailureTracker.java @@ -0,0 +1,78 @@ +/* + * 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.guacamole.auth.ban.status; + +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.Credentials; + +/** + * Tracks past authentication results, automatically blocking the IP addresses + * of machines that repeatedly fail to authenticate. + */ +public interface AuthenticationFailureTracker { + + /** + * Reports that an authentication request has been received, but it is + * either not yet known whether the request has succeeded or failed. If the + * associated address is currently being blocked, an exception will be + * thrown. + * + * @param credentials + * The credentials associated with the authentication request. + * + * @throws GuacamoleException + * If the authentication request is being blocked due to brute force + * prevention rules. + */ + void notifyAuthenticationRequestReceived(Credentials credentials) + throws GuacamoleException; + + /** + * Reports that an authentication request has been received and has + * succeeded. If the associated address is currently being blocked, an + * exception will be thrown. + * + * @param credentials + * The credentials associated with the successful authentication + * request. + * + * @throws GuacamoleException + * If the authentication request is being blocked due to brute force + * prevention rules. + */ + void notifyAuthenticationSuccess(Credentials credentials) + throws GuacamoleException; + + /** + * Reports that an authentication request has been received and has + * failed. If the associated address is currently being blocked, an + * exception will be thrown. + * + * @param credentials + * The credentials associated with the failed authentication request. + * + * @throws GuacamoleException + * If the authentication request is being blocked due to brute force + * prevention rules. + */ + void notifyAuthenticationFailed(Credentials credentials) + throws GuacamoleException; + +} diff --git a/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/AuthenticationFailureTracker.java b/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/status/InMemoryAuthenticationFailureTracker.java similarity index 74% rename from extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/AuthenticationFailureTracker.java rename to extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/status/InMemoryAuthenticationFailureTracker.java index 72b4fc8dd..b655168e1 100644 --- a/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/AuthenticationFailureTracker.java +++ b/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/status/InMemoryAuthenticationFailureTracker.java @@ -17,7 +17,7 @@ * under the License. */ -package org.apache.guacamole.auth.ban; +package org.apache.guacamole.auth.ban.status; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; @@ -30,15 +30,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Provides automated tracking and blocking of IP addresses that repeatedly - * fail authentication. + * AuthenticationFailureTracker implementation that tracks the failure status + * of each IP address in memory. The maximum amount of memory consumed is + * bounded by the configured maximum number of addresses tracked. */ -public class AuthenticationFailureTracker { +public class InMemoryAuthenticationFailureTracker implements AuthenticationFailureTracker { /** * Logger for this class. */ - private static final Logger logger = LoggerFactory.getLogger(AuthenticationFailureTracker.class); + private static final Logger logger = LoggerFactory.getLogger(InMemoryAuthenticationFailureTracker.class); /** * All authentication failures currently being tracked, stored by the @@ -74,38 +75,17 @@ public class AuthenticationFailureTracker { * The maximum number of unique IP addresses that should be tracked * before discarding older tracked failures. */ - public AuthenticationFailureTracker(int maxAttempts, int banDuration, + public InMemoryAuthenticationFailureTracker(int maxAttempts, int banDuration, long maxAddresses) { this.maxAttempts = maxAttempts; this.banDuration = banDuration; - // Inform administrator of configured behavior - if (maxAttempts <= 0) { - logger.info("Maximum failed authentication attempts has been set " - + "to {}. Automatic banning of brute-force authentication " - + "attempts will be disabled.", maxAttempts); - } - else if (banDuration <= 0) { - logger.info("Ban duration for addresses that repeatedly fail " - + "authentication has been set to {}. Automatic banning " - + "of brute-force authentication attempts will be " - + "disabled.", banDuration); - } - else { - logger.info("Addresses will be automatically banned for {} " - + "seconds after {} failed authentication attempts.", - 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); - } /** @@ -187,10 +167,6 @@ public class AuthenticationFailureTracker { private void notifyAuthenticationStatus(Credentials credentials, boolean failed) throws GuacamoleException { - // Do not track/ban if tracking or banning are disabled - if (maxAttempts <= 0 || banDuration <= 0) - return; - // Ignore requests that do not contain explicit parameters of any kind if (isEmpty(credentials)) return; @@ -234,54 +210,19 @@ public class AuthenticationFailureTracker { } - /** - * Reports that an authentication request has been received, but it is - * either not yet known whether the request has succeeded or failed. If the - * associated address is currently being blocked, an exception will be - * thrown. - * - * @param credentials - * The credentials associated with the authentication request. - * - * @throws GuacamoleException - * If the authentication request is being blocked due to brute force - * prevention rules. - */ + @Override public void notifyAuthenticationRequestReceived(Credentials credentials) throws GuacamoleException { notifyAuthenticationStatus(credentials, false); } - /** - * Reports that an authentication request has been received and has - * succeeded. If the associated address is currently being blocked, an - * exception will be thrown. - * - * @param credentials - * The credentials associated with the successful authentication - * request. - * - * @throws GuacamoleException - * If the authentication request is being blocked due to brute force - * prevention rules. - */ + @Override public void notifyAuthenticationSuccess(Credentials credentials) throws GuacamoleException { notifyAuthenticationStatus(credentials, false); } - /** - * Reports that an authentication request has been received and has - * failed. If the associated address is currently being blocked, an - * exception will be thrown. - * - * @param credentials - * The credentials associated with the failed authentication request. - * - * @throws GuacamoleException - * If the authentication request is being blocked due to brute force - * prevention rules. - */ + @Override public void notifyAuthenticationFailed(Credentials credentials) throws GuacamoleException { notifyAuthenticationStatus(credentials, true); diff --git a/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/status/NullAuthenticationFailureTracker.java b/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/status/NullAuthenticationFailureTracker.java new file mode 100644 index 000000000..9b50a3022 --- /dev/null +++ b/extensions/guacamole-auth-ban/src/main/java/org/apache/guacamole/auth/ban/status/NullAuthenticationFailureTracker.java @@ -0,0 +1,49 @@ +/* + * 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.guacamole.auth.ban.status; + +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.Credentials; + +/** + * AuthenticationFailureTracker implementation that does nothing. All requests + * are ignored, regardless of status, and no tracking is performed. + */ +public class NullAuthenticationFailureTracker implements AuthenticationFailureTracker { + + @Override + public void notifyAuthenticationRequestReceived(Credentials credentials) + throws GuacamoleException { + // Do nothing + } + + @Override + public void notifyAuthenticationSuccess(Credentials credentials) + throws GuacamoleException { + // Do nothing + } + + @Override + public void notifyAuthenticationFailed(Credentials credentials) + throws GuacamoleException { + // Do nothing + } + +}