From 75f74eec94a2e8d0bfd1f04267669f5de6a0c2f0 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 20 Jul 2016 13:42:57 -0700 Subject: [PATCH] GUACAMOLE-5: Extract common base class for AuthenticatedUser. --- .../auth/jdbc/user/AuthenticatedUser.java | 103 +------------ .../jdbc/user/RemoteAuthenticatedUser.java | 141 ++++++++++++++++++ 2 files changed, 143 insertions(+), 101 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/AuthenticatedUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/AuthenticatedUser.java index 0696c8801..d58c2e316 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/AuthenticatedUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/AuthenticatedUser.java @@ -22,9 +22,6 @@ package org.apache.guacamole.auth.jdbc.user; import java.util.Collections; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.servlet.http.HttpServletRequest; import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.Credentials; @@ -33,49 +30,13 @@ import org.apache.guacamole.net.auth.Credentials; * * @author Michael Jumper */ -public class AuthenticatedUser implements org.apache.guacamole.net.auth.AuthenticatedUser { +public class AuthenticatedUser extends RemoteAuthenticatedUser { /** * The user that authenticated. */ private final ModeledUser user; - /** - * The credentials given when this user authenticated. - */ - private final Credentials credentials; - - /** - * The AuthenticationProvider that authenticated this user. - */ - private final AuthenticationProvider authenticationProvider; - - /** - * The host from which this user authenticated. - */ - private final String remoteHost; - - /** - * Regular expression which matches any IPv4 address. - */ - private static final String IPV4_ADDRESS_REGEX = "([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})"; - - /** - * Regular expression which matches any IPv6 address. - */ - private static final String IPV6_ADDRESS_REGEX = "([0-9a-fA-F]*(:[0-9a-fA-F]*){0,7})"; - - /** - * Regular expression which matches any IP address, regardless of version. - */ - private static final String IP_ADDRESS_REGEX = "(" + IPV4_ADDRESS_REGEX + "|" + IPV6_ADDRESS_REGEX + ")"; - - /** - * Pattern which matches valid values of the de-facto standard - * "X-Forwarded-For" header. - */ - private static final Pattern X_FORWARDED_FOR = Pattern.compile("^" + IP_ADDRESS_REGEX + "(, " + IP_ADDRESS_REGEX + ")*$"); - /** * The connections which have been committed for use by this user in the * context of a balancing connection group. Balancing connection groups @@ -87,38 +48,6 @@ public class AuthenticatedUser implements org.apache.guacamole.net.auth.Authenti private final Set preferredConnections = Collections.newSetFromMap(new ConcurrentHashMap()); - /** - * Derives the remote host of the authenticating user from the given - * credentials object. The remote host is derived from X-Forwarded-For - * in addition to the actual source IP of the request, and thus is not - * trusted. The derived remote host is really only useful for logging, - * unless the server is configured such that X-Forwarded-For is guaranteed - * to be trustworthy. - * - * @param credentials - * The credentials to derive the remote host from. - * - * @return - * The remote host from which the user with the given credentials is - * authenticating. - */ - private static String getRemoteHost(Credentials credentials) { - - HttpServletRequest request = credentials.getRequest(); - - // Use X-Forwarded-For, if present and valid - String header = request.getHeader("X-Forwarded-For"); - if (header != null) { - Matcher matcher = X_FORWARDED_FOR.matcher(header); - if (matcher.matches()) - return matcher.group(1); - } - - // If header absent or invalid, just use source IP - return request.getRemoteAddr(); - - } - /** * Creates a new AuthenticatedUser associating the given user with their * corresponding credentials. @@ -134,10 +63,8 @@ public class AuthenticatedUser implements org.apache.guacamole.net.auth.Authenti */ public AuthenticatedUser(AuthenticationProvider authenticationProvider, ModeledUser user, Credentials credentials) { - this.authenticationProvider = authenticationProvider; + super(authenticationProvider, credentials); this.user = user; - this.credentials = credentials; - this.remoteHost = getRemoteHost(credentials); } /** @@ -150,27 +77,6 @@ public class AuthenticatedUser implements org.apache.guacamole.net.auth.Authenti return user; } - /** - * Returns the credentials given during authentication by this user. - * - * @return - * The credentials given during authentication by this user. - */ - @Override - public Credentials getCredentials() { - return credentials; - } - - /** - * Returns the host from which this user authenticated. - * - * @return - * The host from which this user authenticated. - */ - public String getRemoteHost() { - return remoteHost; - } - /** * Returns whether the connection having the given identifier has been * marked as preferred for this user's current Guacamole session. A @@ -201,11 +107,6 @@ public class AuthenticatedUser implements org.apache.guacamole.net.auth.Authenti preferredConnections.add(identifier); } - @Override - public AuthenticationProvider getAuthenticationProvider() { - return authenticationProvider; - } - @Override public String getIdentifier() { return user.getIdentifier(); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java new file mode 100644 index 000000000..cb89b50b8 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java @@ -0,0 +1,141 @@ +/* + * 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.jdbc.user; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.servlet.http.HttpServletRequest; +import org.apache.guacamole.net.auth.AuthenticatedUser; +import org.apache.guacamole.net.auth.AuthenticationProvider; +import org.apache.guacamole.net.auth.Credentials; + +/** + * An AuthenticatedUser that has an associated remote host. + * + * @author Michael Jumper + */ +public abstract class RemoteAuthenticatedUser implements AuthenticatedUser { + + /** + * The credentials given when this user authenticated. + */ + private final Credentials credentials; + + /** + * The AuthenticationProvider that authenticated this user. + */ + private final AuthenticationProvider authenticationProvider; + + /** + * The host from which this user authenticated. + */ + private final String remoteHost; + + /** + * Regular expression which matches any IPv4 address. + */ + private static final String IPV4_ADDRESS_REGEX = "([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})"; + + /** + * Regular expression which matches any IPv6 address. + */ + private static final String IPV6_ADDRESS_REGEX = "([0-9a-fA-F]*(:[0-9a-fA-F]*){0,7})"; + + /** + * Regular expression which matches any IP address, regardless of version. + */ + private static final String IP_ADDRESS_REGEX = "(" + IPV4_ADDRESS_REGEX + "|" + IPV6_ADDRESS_REGEX + ")"; + + /** + * Pattern which matches valid values of the de-facto standard + * "X-Forwarded-For" header. + */ + private static final Pattern X_FORWARDED_FOR = Pattern.compile("^" + IP_ADDRESS_REGEX + "(, " + IP_ADDRESS_REGEX + ")*$"); + + /** + * Derives the remote host of the authenticating user from the given + * credentials object. The remote host is derived from X-Forwarded-For + * in addition to the actual source IP of the request, and thus is not + * trusted. The derived remote host is really only useful for logging, + * unless the server is configured such that X-Forwarded-For is guaranteed + * to be trustworthy. + * + * @param credentials + * The credentials to derive the remote host from. + * + * @return + * The remote host from which the user with the given credentials is + * authenticating. + */ + private static String getRemoteHost(Credentials credentials) { + + HttpServletRequest request = credentials.getRequest(); + + // Use X-Forwarded-For, if present and valid + String header = request.getHeader("X-Forwarded-For"); + if (header != null) { + Matcher matcher = X_FORWARDED_FOR.matcher(header); + if (matcher.matches()) + return matcher.group(1); + } + + // If header absent or invalid, just use source IP + return request.getRemoteAddr(); + + } + + /** + * Creates a new RemoteAuthenticatedUser, deriving the associated remote + * host from the given credentials. + * + * @param authenticationProvider + * The AuthenticationProvider that has authenticated the given user. + * + * @param credentials + * The credentials given by the user when they authenticated. + */ + public RemoteAuthenticatedUser(AuthenticationProvider authenticationProvider, + Credentials credentials) { + this.authenticationProvider = authenticationProvider; + this.credentials = credentials; + this.remoteHost = getRemoteHost(credentials); + } + + @Override + public Credentials getCredentials() { + return credentials; + } + + /** + * Returns the host from which this user authenticated. + * + * @return + * The host from which this user authenticated. + */ + public String getRemoteHost() { + return remoteHost; + } + + @Override + public AuthenticationProvider getAuthenticationProvider() { + return authenticationProvider; + } + +}