From 920ce67beebd3d1635c9b41bb0842c6402c0c15f Mon Sep 17 00:00:00 2001 From: James Muehlner Date: Wed, 11 Nov 2015 22:52:53 -0800 Subject: [PATCH 1/7] GUAC-1373: Partly refactored JDBC property loading. --- .../JDBCAuthenticationProviderModule.java | 20 +- .../guacamole/auth/jdbc/JDBCEnvironment.java | 106 ++++++ .../AbstractGuacamoleTunnelService.java | 3 +- .../ConfigurableGuacamoleTunnelService.java | 75 +---- .../mysql/MySQLAuthenticationProvider.java | 122 +------ .../MySQLAuthenticationProviderModule.java | 13 +- .../net/auth/mysql/MySQLEnvironment.java | 304 ++++++++++++++++++ .../auth/mysql/MySQLGuacamoleProperties.java | 22 +- 8 files changed, 449 insertions(+), 216 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCEnvironment.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java index 0ffc7edd1..883e58986 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java @@ -62,7 +62,6 @@ import org.glyptodon.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermis import org.glyptodon.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionSet; import org.glyptodon.guacamole.auth.jdbc.activeconnection.ActiveConnectionService; import org.glyptodon.guacamole.auth.jdbc.activeconnection.TrackedActiveConnection; -import org.glyptodon.guacamole.environment.Environment; import org.glyptodon.guacamole.net.auth.AuthenticationProvider; import org.mybatis.guice.MyBatisModule; import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider; @@ -80,12 +79,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { /** * The environment of the Guacamole server. */ - private final Environment environment; - - /** - * The service to use to provide GuacamoleTunnels for each connection. - */ - private final GuacamoleTunnelService tunnelService; + private final JDBCEnvironment environment; /** * The AuthenticationProvider which is using this module to configure @@ -104,16 +98,11 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { * * @param environment * The environment to use to configure injected classes. - * - * @param tunnelService - * The tunnel service to use to provide tunnels sockets for connections. */ public JDBCAuthenticationProviderModule(AuthenticationProvider authProvider, - Environment environment, - GuacamoleTunnelService tunnelService) { + JDBCEnvironment environment) { this.authProvider = authProvider; this.environment = environment; - this.tunnelService = tunnelService; } @Override @@ -140,7 +129,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { bind(ActiveConnectionDirectory.class); bind(ActiveConnectionPermissionSet.class); bind(AuthenticationProvider.class).toInstance(authProvider); - bind(Environment.class).toInstance(environment); + bind(JDBCEnvironment.class).toInstance(environment); bind(ConnectionDirectory.class); bind(ConnectionGroupDirectory.class); bind(ConnectionGroupPermissionSet.class); @@ -169,9 +158,6 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { bind(UserPermissionService.class); bind(UserService.class); - // Bind provided tunnel service - bind(GuacamoleTunnelService.class).toInstance(tunnelService); - } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCEnvironment.java new file mode 100644 index 000000000..f7a3a6fbe --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCEnvironment.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * 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. + */ + +package org.glyptodon.guacamole.auth.jdbc; + +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.environment.LocalEnvironment; + +/** + * A JDBC-specific implementation of Environment that defines generic properties + * intended for use within JDBC based authentication providers. + * + * @author James Muehlner + */ +public abstract class JDBCEnvironment extends LocalEnvironment { + + /** + * Constructs a new JDBCEnvironment using an underlying LocalEnviroment to + * read properties from the file system. + * + * @throws GuacamoleException + * If an error occurs while setting up the underlying LocalEnvironment. + */ + public JDBCEnvironment() throws GuacamoleException { + super(); + } + + /** + * Returns the default maximum number of concurrent connections to allow to + * any one connection, unless specified differently on an individual + * connection. Zero denotes unlimited. + * + * @return + * The default maximum allowable number of concurrent connections + * to any connection. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property. + */ + public abstract int getDefaultMaxConnections() throws GuacamoleException; + + /** + * Returns the default maximum number of concurrent connections to allow to + * any one connection group, unless specified differently on an individual + * connection group. Zero denotes unlimited. + * + * @return + * The default maximum allowable number of concurrent connections + * to any connection group. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property. + */ + public abstract int getDefaultMaxGroupConnections() + throws GuacamoleException; + + /** + * Returns the default maximum number of concurrent connections to allow to + * any one connection by an individual user, unless specified differently on + * an individual connection. Zero denotes unlimited. + * + * @return + * The default maximum allowable number of concurrent connections to + * any connection by an individual user. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property. + */ + public abstract int getDefaultMaxConnectionsPerUser() + throws GuacamoleException; + + /** + * Returns the default maximum number of concurrent connections to allow to + * any one connection group by an individual user, unless specified + * differently on an individual connection group. Zero denotes unlimited. + * + * @return + * The default maximum allowable number of concurrent connections to + * any connection group by an individual user. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property. + */ + public abstract int getDefaultMaxGroupConnectionsPerUser() + throws GuacamoleException; + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java index 94a5753d7..667be3329 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java @@ -45,6 +45,7 @@ import org.glyptodon.guacamole.auth.jdbc.connection.ParameterModel; import org.glyptodon.guacamole.auth.jdbc.user.UserModel; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleSecurityException; +import org.glyptodon.guacamole.auth.jdbc.JDBCEnvironment; import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionMapper; import org.glyptodon.guacamole.environment.Environment; import org.glyptodon.guacamole.net.GuacamoleSocket; @@ -72,7 +73,7 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS * The environment of the Guacamole server. */ @Inject - private Environment environment; + private JDBCEnvironment environment; /** * Mapper for accessing connections. diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ConfigurableGuacamoleTunnelService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ConfigurableGuacamoleTunnelService.java index 3b5e8b54d..0f9bf15f0 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ConfigurableGuacamoleTunnelService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ConfigurableGuacamoleTunnelService.java @@ -23,6 +23,7 @@ package org.glyptodon.guacamole.auth.jdbc.tunnel; import com.google.common.collect.ConcurrentHashMultiset; +import com.google.inject.Inject; import com.google.inject.Singleton; import java.util.Arrays; import java.util.Comparator; @@ -32,6 +33,7 @@ import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleResourceConflictException; +import org.glyptodon.guacamole.auth.jdbc.JDBCEnvironment; import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; @@ -46,6 +48,11 @@ import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; @Singleton public class ConfigurableGuacamoleTunnelService extends AbstractGuacamoleTunnelService { + + /** + * The configuration for the current JDBC environment. + */ + @Inject JDBCEnvironment jdbcEnvironment; /** * Set of all currently-active user/connection pairs (seats). @@ -67,66 +74,6 @@ public class ConfigurableGuacamoleTunnelService */ private final ConcurrentHashMultiset activeGroups = ConcurrentHashMultiset.create(); - /** - * The maximum number of connections allowed per connection by default, or - * zero if no default limit applies. - */ - private final int connectionDefaultMaxConnections; - - /** - * The maximum number of connections a user may have to any one connection - * by default, or zero if no default limit applies. - */ - private final int connectionDefaultMaxConnectionsPerUser; - - /** - * The maximum number of connections allowed per connection group by - * default, or zero if no default limit applies. - */ - private final int connectionGroupDefaultMaxConnections; - - /** - * The maximum number of connections a user may have to any one connection - * group by default, or zero if no default limit applies. - */ - private final int connectionGroupDefaultMaxConnectionsPerUser; - - /** - * Creates a new ConfigurableGuacamoleTunnelService which applies the given - * limitations when new connections are acquired. - * - * @param connectionDefaultMaxConnections - * The maximum number of connections allowed per connection by default, - * or zero if no default limit applies. - * - * @param connectionDefaultMaxConnectionsPerUser - * The maximum number of connections a user may have to any one - * connection by default, or zero if no default limit applies. - * - * @param connectionGroupDefaultMaxConnections - * The maximum number of connections allowed per connection group by - * default, or zero if no default limit applies. - * - * @param connectionGroupDefaultMaxConnectionsPerUser - * The maximum number of connections a user may have to any one - * connection group by default, or zero if no default limit applies. - */ - public ConfigurableGuacamoleTunnelService( - int connectionDefaultMaxConnections, - int connectionDefaultMaxConnectionsPerUser, - int connectionGroupDefaultMaxConnections, - int connectionGroupDefaultMaxConnectionsPerUser) { - - // Set default connection limits - this.connectionDefaultMaxConnections = connectionDefaultMaxConnections; - this.connectionDefaultMaxConnectionsPerUser = connectionDefaultMaxConnectionsPerUser; - - // Set default connection group limits - this.connectionGroupDefaultMaxConnections = connectionGroupDefaultMaxConnections; - this.connectionGroupDefaultMaxConnectionsPerUser = connectionGroupDefaultMaxConnectionsPerUser; - - } - /** * Attempts to add a single instance of the given value to the given * multiset without exceeding the specified maximum number of values. If @@ -203,12 +150,12 @@ public class ConfigurableGuacamoleTunnelService // Determine per-user limits on this connection Integer connectionMaxConnectionsPerUser = connection.getModel().getMaxConnectionsPerUser(); if (connectionMaxConnectionsPerUser == null) - connectionMaxConnectionsPerUser = connectionDefaultMaxConnectionsPerUser; + connectionMaxConnectionsPerUser = jdbcEnvironment.getDefaultMaxConnectionsPerUser(); // Determine overall limits on this connection Integer connectionMaxConnections = connection.getModel().getMaxConnections(); if (connectionMaxConnections == null) - connectionMaxConnections = connectionDefaultMaxConnections; + connectionMaxConnections = jdbcEnvironment.getDefaultMaxConnections(); // Attempt to aquire connection according to per-user limits Seat seat = new Seat(username, connection.getIdentifier()); @@ -255,12 +202,12 @@ public class ConfigurableGuacamoleTunnelService // Determine per-user limits on this connection group Integer connectionGroupMaxConnectionsPerUser = connectionGroup.getModel().getMaxConnectionsPerUser(); if (connectionGroupMaxConnectionsPerUser == null) - connectionGroupMaxConnectionsPerUser = connectionGroupDefaultMaxConnectionsPerUser; + connectionGroupMaxConnectionsPerUser = jdbcEnvironment.getDefaultMaxGroupConnectionsPerUser(); // Determine overall limits on this connection group Integer connectionGroupMaxConnections = connectionGroup.getModel().getMaxConnections(); if (connectionGroupMaxConnections == null) - connectionGroupMaxConnections = connectionGroupDefaultMaxConnections; + connectionGroupMaxConnections = jdbcEnvironment.getDefaultMaxGroupConnections(); // Attempt to aquire connection group according to per-user limits Seat seat = new Seat(username, connectionGroup.getIdentifier()); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java index ed4f60c87..303401b60 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java @@ -29,14 +29,8 @@ import org.glyptodon.guacamole.net.auth.AuthenticationProvider; import org.glyptodon.guacamole.net.auth.Credentials; import org.glyptodon.guacamole.net.auth.UserContext; import org.glyptodon.guacamole.auth.jdbc.JDBCAuthenticationProviderModule; -import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; -import org.glyptodon.guacamole.auth.jdbc.tunnel.ConfigurableGuacamoleTunnelService; import org.glyptodon.guacamole.auth.jdbc.user.AuthenticationProviderService; -import org.glyptodon.guacamole.environment.Environment; -import org.glyptodon.guacamole.environment.LocalEnvironment; import org.glyptodon.guacamole.net.auth.AuthenticatedUser; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Provides a MySQL based implementation of the AuthenticationProvider @@ -47,123 +41,12 @@ import org.slf4j.LoggerFactory; */ public class MySQLAuthenticationProvider implements AuthenticationProvider { - /** - * Logger for this class. - */ - private static final Logger logger = LoggerFactory.getLogger(MySQLAuthenticationProvider.class); - /** * Injector which will manage the object graph of this authentication * provider. */ private final Injector injector; - /** - * Returns the appropriate tunnel service given the Guacamole environment. - * The service is configured based on configuration options that dictate - * the default concurrent usage policy. - * - * @param environment - * The environment of the Guacamole server. - * - * @return - * A tunnel service implementation configured according to the - * concurrent usage policy options set in the Guacamole environment. - * - * @throws GuacamoleException - * If an error occurs while reading the configuration options. - */ - private GuacamoleTunnelService getTunnelService(Environment environment) - throws GuacamoleException { - - // Tunnel service default configuration - int connectionDefaultMaxConnections; - int connectionDefaultMaxConnectionsPerUser; - int connectionGroupDefaultMaxConnections; - int connectionGroupDefaultMaxConnectionsPerUser; - - // Read legacy concurrency-related properties - Boolean disallowSimultaneous = environment.getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS); - Boolean disallowDuplicate = environment.getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS); - - // Legacy "simultaneous" property dictates only the maximum number of - // connections per connection - if (disallowSimultaneous != null) { - - // Translate legacy property - if (disallowSimultaneous) { - connectionDefaultMaxConnections = 1; - connectionGroupDefaultMaxConnections = 0; - } - else { - connectionDefaultMaxConnections = 0; - connectionGroupDefaultMaxConnections = 0; - } - - // Warn of deprecation - logger.warn("The \"{}\" property is deprecated. Use \"{}\" and \"{}\" instead.", - MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS.getName(), - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS.getName(), - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName()); - - // Inform of new equivalent - logger.info("To achieve the same result of setting \"{}\" to \"{}\", set \"{}\" to \"{}\" and \"{}\" to \"{}\".", - MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS.getName(), disallowSimultaneous, - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS.getName(), connectionDefaultMaxConnections, - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName(), connectionGroupDefaultMaxConnections); - - } - - // If legacy property is not specified, use new property - else { - connectionDefaultMaxConnections = environment.getProperty(MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS, 0); - connectionGroupDefaultMaxConnections = environment.getProperty(MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS, 0); - } - - // Legacy "duplicate" property dictates whether connections and groups - // may be used concurrently only by different users - if (disallowDuplicate != null) { - - // Translate legacy property - if (disallowDuplicate) { - connectionDefaultMaxConnectionsPerUser = 1; - connectionGroupDefaultMaxConnectionsPerUser = 1; - } - else { - connectionDefaultMaxConnectionsPerUser = 0; - connectionGroupDefaultMaxConnectionsPerUser = 0; - } - - // Warn of deprecation - logger.warn("The \"{}\" property is deprecated. Use \"{}\" and \"{}\" instead.", - MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS.getName(), - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS_PER_USER.getName(), - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName()); - - // Inform of new equivalent - logger.info("To achieve the same result of setting \"{}\" to \"{}\", set \"{}\" to \"{}\" and \"{}\" to \"{}\".", - MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS.getName(), disallowDuplicate, - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS_PER_USER.getName(), connectionDefaultMaxConnectionsPerUser, - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER.getName(), connectionGroupDefaultMaxConnectionsPerUser); - - } - - // If legacy property is not specified, use new property - else { - connectionDefaultMaxConnectionsPerUser = environment.getProperty(MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS_PER_USER, 1); - connectionGroupDefaultMaxConnectionsPerUser = environment.getProperty(MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER, 1); - } - - // Return service configured for specified default limits - return new ConfigurableGuacamoleTunnelService( - connectionDefaultMaxConnections, - connectionDefaultMaxConnectionsPerUser, - connectionGroupDefaultMaxConnections, - connectionGroupDefaultMaxConnectionsPerUser - ); - - } - /** * Creates a new MySQLAuthenticationProvider that reads and writes * authentication data to a MySQL database defined by properties in @@ -176,7 +59,7 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider { public MySQLAuthenticationProvider() throws GuacamoleException { // Get local environment - Environment environment = new LocalEnvironment(); + MySQLEnvironment environment = new MySQLEnvironment(); // Set up Guice injector. injector = Guice.createInjector( @@ -185,8 +68,7 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider { new MySQLAuthenticationProviderModule(environment), // Configure JDBC authentication core - new JDBCAuthenticationProviderModule(this, environment, - getTunnelService(environment)) + new JDBCAuthenticationProviderModule(this, environment) ); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProviderModule.java index e5af46928..a11c525db 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProviderModule.java @@ -27,7 +27,6 @@ import com.google.inject.Module; import com.google.inject.name.Names; import java.util.Properties; import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.environment.Environment; import org.mybatis.guice.datasource.helper.JdbcHelper; /** @@ -59,16 +58,16 @@ public class MySQLAuthenticationProviderModule implements Module { * If a required property is missing, or an error occurs while parsing * a property. */ - public MySQLAuthenticationProviderModule(Environment environment) + public MySQLAuthenticationProviderModule(MySQLEnvironment environment) throws GuacamoleException { // Set the MySQL-specific properties for MyBatis. myBatisProperties.setProperty("mybatis.environment.id", "guacamole"); - myBatisProperties.setProperty("JDBC.host", environment.getRequiredProperty(MySQLGuacamoleProperties.MYSQL_HOSTNAME)); - myBatisProperties.setProperty("JDBC.port", String.valueOf(environment.getRequiredProperty(MySQLGuacamoleProperties.MYSQL_PORT))); - myBatisProperties.setProperty("JDBC.schema", environment.getRequiredProperty(MySQLGuacamoleProperties.MYSQL_DATABASE)); - myBatisProperties.setProperty("JDBC.username", environment.getRequiredProperty(MySQLGuacamoleProperties.MYSQL_USERNAME)); - myBatisProperties.setProperty("JDBC.password", environment.getRequiredProperty(MySQLGuacamoleProperties.MYSQL_PASSWORD)); + myBatisProperties.setProperty("JDBC.host", environment.getMySQLHostname()); + myBatisProperties.setProperty("JDBC.port", String.valueOf(environment.getMySQLPort())); + myBatisProperties.setProperty("JDBC.schema", environment.getMySQLDatabase()); + myBatisProperties.setProperty("JDBC.username", environment.getMySQLUsername()); + myBatisProperties.setProperty("JDBC.password", environment.getMySQLPassword()); myBatisProperties.setProperty("JDBC.autoCommit", "false"); myBatisProperties.setProperty("mybatis.pooled.pingEnabled", "true"); myBatisProperties.setProperty("mybatis.pooled.pingQuery", "SELECT 1"); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java new file mode 100644 index 000000000..d058414e1 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * 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. + */ + +package net.sourceforge.guacamole.net.auth.mysql; + +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.auth.jdbc.JDBCEnvironment; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A MySQL-specific implementation of JDBCEnvironment provides database + * properties specifically for MySQL. + * + * @author James Muehlner + */ +public class MySQLEnvironment extends JDBCEnvironment { + + /** + * Logger for this class. + */ + private static final Logger logger = LoggerFactory.getLogger(MySQLEnvironment.class); + + /** + * Constructs a new MysqlEnvironment. + * + * @throws GuacamoleException + * If an error occurs while setting up the underlying JDBCEnvironment. + */ + public MySQLEnvironment() throws GuacamoleException { + super(); + } + + /** + * Log a warning about the usage of the deprecated + * MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS property, and the appropriate + * replacements for it. + * + * @param disallowSimultaneous + * Whether simultaneous connections have been disabled. + */ + private void warnOfSimultaneousPropertyDeprecation(boolean disallowSimultaneous) { + + // Warn of deprecation + logger.warn("The \"{}\" property is deprecated. Use \"{}\" and \"{}\" instead.", + MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS.getName(), + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS.getName(), + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName()); + + // Inform of new equivalent + logger.info("To achieve the same result of setting \"{}\" to \"{}\", set \"{}\" to \"{}\" and \"{}\" to \"{}\".", + MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS.getName(), disallowSimultaneous, + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS.getName(), disallowSimultaneous ? 1 : 0, + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName(), 0); + + } + + /** + * Log a warning about the usage of the deprecated + * MYSQL_DISALLOW_DUPLICATE_CONNECTIONS property, and the appropriate + * replacements for it. + * + * @param disallowDuplicate + * Whether duplicate connections have been disabled. + */ + private void warnOfDuplicatePropertyDeprecation(boolean disallowDuplicate) { + + // Warn of deprecation + logger.warn("The \"{}\" property is deprecated. Use \"{}\" and \"{}\" instead.", + MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS.getName(), + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS_PER_USER.getName(), + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName()); + + // Inform of new equivalent + logger.info("To achieve the same result of setting \"{}\" to \"{}\", set \"{}\" to \"{}\" and \"{}\" to \"{}\".", + MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS.getName(), disallowDuplicate, + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS_PER_USER.getName(), disallowDuplicate ? 1 :0, + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER.getName(), disallowDuplicate ? 1 :0); + + } + + @Override + public int getDefaultMaxConnections() throws GuacamoleException { + + // Tunnel service default configuration + int connectionDefaultMaxConnections; + + // Read legacy concurrency-related property + Boolean disallowSimultaneous = getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS); + + // Legacy "simultaneous" property dictates only the maximum number of + // connections per connection + if (disallowSimultaneous != null) { + + // Translate legacy property + if (disallowSimultaneous) { + connectionDefaultMaxConnections = 1; + } + else { + connectionDefaultMaxConnections = 0; + } + + // Warn that a different property should be used going forward + warnOfSimultaneousPropertyDeprecation(disallowSimultaneous); + + } + + // If legacy property is not specified, use new property + else { + connectionDefaultMaxConnections = getProperty(MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS, 0); + } + + return connectionDefaultMaxConnections; + } + + @Override + public int getDefaultMaxGroupConnections() throws GuacamoleException { + + int connectionGroupDefaultMaxConnections; + + // Read legacy concurrency-related property + Boolean disallowSimultaneous = getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS); + + // Legacy "simultaneous" property dictates only the maximum number of + // connections per connection + if (disallowSimultaneous != null) { + + // Translate legacy property + connectionGroupDefaultMaxConnections = 0; + + // Warn that a different property should be used going forward + warnOfSimultaneousPropertyDeprecation(disallowSimultaneous); + + } + + // If legacy property is not specified, use new property + else { + connectionGroupDefaultMaxConnections = getProperty(MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS, 0); + } + + return connectionGroupDefaultMaxConnections; + } + + @Override + public int getDefaultMaxConnectionsPerUser() throws GuacamoleException { + + int connectionDefaultMaxConnectionsPerUser; + + // Read legacy concurrency-related properties + Boolean disallowDuplicate = getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS); + + // Legacy "duplicate" property dictates whether connections and groups + // may be used concurrently only by different users + if (disallowDuplicate != null) { + + // Translate legacy property + if (disallowDuplicate) { + connectionDefaultMaxConnectionsPerUser = 1; + } + else { + connectionDefaultMaxConnectionsPerUser = 0; + } + + // Warn that a different property should be used going forward + warnOfDuplicatePropertyDeprecation(disallowDuplicate); + + } + + // If legacy property is not specified, use new property + else { + connectionDefaultMaxConnectionsPerUser = getProperty(MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS_PER_USER, 1); + } + + return connectionDefaultMaxConnectionsPerUser; + } + + @Override + public int getDefaultMaxGroupConnectionsPerUser() throws GuacamoleException { + + int connectionGroupDefaultMaxConnectionsPerUser; + + // Read legacy concurrency-related property + Boolean disallowDuplicate = getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS); + + // Legacy "duplicate" property dictates whether connections and groups + // may be used concurrently only by different users + if (disallowDuplicate != null) { + + // Translate legacy property + if (disallowDuplicate) { + connectionGroupDefaultMaxConnectionsPerUser = 1; + } + else { + connectionGroupDefaultMaxConnectionsPerUser = 0; + } + + // Warn that a different property should be used going forward + warnOfDuplicatePropertyDeprecation(disallowDuplicate); + + } + + // If legacy property is not specified, use new property + else { + connectionGroupDefaultMaxConnectionsPerUser = getProperty(MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER, 1); + } + + return connectionGroupDefaultMaxConnectionsPerUser; + + } + + /** + * Returns the hostname of the MySQL server hosting the Guacamole + * authentication tables. If unspecified, this will be "localhost". + * + * @return + * The URL of the MySQL server. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property value. + */ + public String getMySQLHostname() throws GuacamoleException { + return getProperty(MySQLGuacamoleProperties.MYSQL_HOSTNAME, "localhost"); + } + + /** + * Returns the port number of the MySQL server hosting the Guacamole + * authentication tables. If unspecified, this will be the default MySQL + * port of 3306. + * + * @return + * The port number of the MySQL server. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property value. + */ + public int getMySQLPort() throws GuacamoleException { + return getProperty(MySQLGuacamoleProperties.MYSQL_PORT, 3306); + } + + /** + * Returns the name of the MySQL database containing the Guacamole + * authentication tables. + * + * @return + * The name of the MySQL database. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property value, or if the + * value was not set, as this property is required. + */ + public String getMySQLDatabase() throws GuacamoleException { + return getRequiredProperty(MySQLGuacamoleProperties.MYSQL_DATABASE); + } + + /** + * Returns the username that should be used when authenticating with the + * MySQL database containing the Guacamole authentication tables. + * + * @return + * The username for the MySQL database. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property value, or if the + * value was not set, as this property is required. + */ + public String getMySQLUsername() throws GuacamoleException { + return getRequiredProperty(MySQLGuacamoleProperties.MYSQL_USERNAME); + } + + /** + * Returns the password that should be used when authenticating with the + * MySQL database containing the Guacamole authentication tables. + * + * @return + * The password for the MySQL database. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property value, or if the + * value was not set, as this property is required. + */ + public String getMySQLPassword() throws GuacamoleException { + return getRequiredProperty(MySQLGuacamoleProperties.MYSQL_PASSWORD); + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleProperties.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleProperties.java index 369f2ef89..cb0c35bed 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleProperties.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleProperties.java @@ -28,6 +28,7 @@ import org.glyptodon.guacamole.properties.StringGuacamoleProperty; /** * Properties used by the MySQL Authentication plugin. + * * @author James Muehlner */ public class MySQLGuacamoleProperties { @@ -38,7 +39,8 @@ public class MySQLGuacamoleProperties { private MySQLGuacamoleProperties() {} /** - * The URL of the MySQL server hosting the guacamole authentication tables. + * The hostname of the MySQL server hosting the Guacamole authentication + * tables. */ public static final StringGuacamoleProperty MYSQL_HOSTNAME = new StringGuacamoleProperty() { @@ -48,7 +50,8 @@ public class MySQLGuacamoleProperties { }; /** - * The port of the MySQL server hosting the guacamole authentication tables. + * The port number of the MySQL server hosting the Guacamole authentication + * tables. */ public static final IntegerGuacamoleProperty MYSQL_PORT = new IntegerGuacamoleProperty() { @@ -58,7 +61,8 @@ public class MySQLGuacamoleProperties { }; /** - * The name of the MySQL database containing the guacamole authentication tables. + * The name of the MySQL database containing the Guacamole authentication + * tables. */ public static final StringGuacamoleProperty MYSQL_DATABASE = new StringGuacamoleProperty() { @@ -68,7 +72,8 @@ public class MySQLGuacamoleProperties { }; /** - * The username used to authenticate to the MySQL database containing the guacamole authentication tables. + * The username that should be used when authenticating with the MySQL + * database containing the Guacamole authentication tables. */ public static final StringGuacamoleProperty MYSQL_USERNAME = new StringGuacamoleProperty() { @@ -78,7 +83,8 @@ public class MySQLGuacamoleProperties { }; /** - * The password used to authenticate to the MySQL database containing the guacamole authentication tables. + * The password that should be used when authenticating with the MySQL + * database containing the Guacamole authentication tables. */ public static final StringGuacamoleProperty MYSQL_PASSWORD = new StringGuacamoleProperty() { @@ -88,7 +94,8 @@ public class MySQLGuacamoleProperties { }; /** - * Whether or not multiple users accessing the same connection at the same time should be disallowed. + * Whether or not multiple users accessing the same connection at the same + * time should be disallowed. */ public static final BooleanGuacamoleProperty MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS = new BooleanGuacamoleProperty() { @@ -98,7 +105,8 @@ public class MySQLGuacamoleProperties { }; /** - * Whether or not the same user accessing the same connection or connection group at the same time should be disallowed. + * Whether or not the same user accessing the same connection or connection + * group at the same time should be disallowed. */ public static final BooleanGuacamoleProperty MYSQL_DISALLOW_DUPLICATE_CONNECTIONS = new BooleanGuacamoleProperty() { From 5cb228391c1ce0aab7b127a3a7c23a36d0753819 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 12 Nov 2015 11:13:44 -0800 Subject: [PATCH 2/7] GUAC-1373: Add default constants. Clean up. --- .../net/auth/mysql/MySQLEnvironment.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java index d058414e1..c4cd78e29 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java @@ -41,7 +41,18 @@ public class MySQLEnvironment extends JDBCEnvironment { private static final Logger logger = LoggerFactory.getLogger(MySQLEnvironment.class); /** - * Constructs a new MysqlEnvironment. + * The default host to connect to, if MYSQL_HOSTNAME is not specified. + */ + private static final String DEFAULT_HOSTNAME = "localhost"; + + /** + * The default port to connect to, if MYSQL_PORT is not specified. + */ + private static final int DEFAULT_PORT = 3306; + + /** + * Constructs a new MySQLEnvironment, providing access to MySQL-specific + * configuration options. * * @throws GuacamoleException * If an error occurs while setting up the underlying JDBCEnvironment. @@ -238,7 +249,10 @@ public class MySQLEnvironment extends JDBCEnvironment { * If an error occurs while retrieving the property value. */ public String getMySQLHostname() throws GuacamoleException { - return getProperty(MySQLGuacamoleProperties.MYSQL_HOSTNAME, "localhost"); + return getProperty( + MySQLGuacamoleProperties.MYSQL_HOSTNAME, + DEFAULT_HOSTNAME + ); } /** @@ -253,7 +267,7 @@ public class MySQLEnvironment extends JDBCEnvironment { * If an error occurs while retrieving the property value. */ public int getMySQLPort() throws GuacamoleException { - return getProperty(MySQLGuacamoleProperties.MYSQL_PORT, 3306); + return getProperty(MySQLGuacamoleProperties.MYSQL_PORT, DEFAULT_PORT); } /** From ea871348795ad703b9b1a7ec1102049b2e95063b Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 12 Nov 2015 11:35:59 -0800 Subject: [PATCH 3/7] GUAC-1373: Clean up logic surrounding legacy concurrency properties. --- .../net/auth/mysql/MySQLEnvironment.java | 254 ++++++++---------- 1 file changed, 106 insertions(+), 148 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java index c4cd78e29..90a42afd9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java @@ -32,6 +32,7 @@ import org.slf4j.LoggerFactory; * properties specifically for MySQL. * * @author James Muehlner + * @author Michael Jumper */ public class MySQLEnvironment extends JDBCEnvironment { @@ -50,73 +51,60 @@ public class MySQLEnvironment extends JDBCEnvironment { */ private static final int DEFAULT_PORT = 3306; + /** + * The default value for the default maximum number of connections to be + * allowed per user to any one connection. Note that, as long as the + * legacy "disallow duplicate" and "disallow simultaneous" properties are + * still supported, these cannot be constants, as the legacy properties + * dictate the values that should be used in the absence of the correct + * properties. + */ + private int DEFAULT_MAX_CONNECTIONS_PER_USER = 1; + + /** + * The default value for the default maximum number of connections to be + * allowed per user to any one connection group. Note that, as long as the + * legacy "disallow duplicate" and "disallow simultaneous" properties are + * still supported, these cannot be constants, as the legacy properties + * dictate the values that should be used in the absence of the correct + * properties. + */ + private int DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER = 1; + + /** + * The default value for the default maximum number of connections to be + * allowed to any one connection. Note that, as long as the legacy + * "disallow duplicate" and "disallow simultaneous" properties are still + * supported, these cannot be constants, as the legacy properties dictate + * the values that should be used in the absence of the correct properties. + */ + private int DEFAULT_MAX_CONNECTIONS = 0; + + /** + * The default value for the default maximum number of connections to be + * allowed to any one connection group. Note that, as long as the legacy + * "disallow duplicate" and "disallow simultaneous" properties are still + * supported, these cannot be constants, as the legacy properties dictate + * the values that should be used in the absence of the correct properties. + */ + private int DEFAULT_MAX_GROUP_CONNECTIONS = 0; + /** * Constructs a new MySQLEnvironment, providing access to MySQL-specific * configuration options. * * @throws GuacamoleException - * If an error occurs while setting up the underlying JDBCEnvironment. + * If an error occurs while setting up the underlying JDBCEnvironment + * or while parsing legacy MySQL configuration options. */ public MySQLEnvironment() throws GuacamoleException { + + // Init underlying JDBC environment super(); - } - - /** - * Log a warning about the usage of the deprecated - * MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS property, and the appropriate - * replacements for it. - * - * @param disallowSimultaneous - * Whether simultaneous connections have been disabled. - */ - private void warnOfSimultaneousPropertyDeprecation(boolean disallowSimultaneous) { - - // Warn of deprecation - logger.warn("The \"{}\" property is deprecated. Use \"{}\" and \"{}\" instead.", - MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS.getName(), - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS.getName(), - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName()); - // Inform of new equivalent - logger.info("To achieve the same result of setting \"{}\" to \"{}\", set \"{}\" to \"{}\" and \"{}\" to \"{}\".", - MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS.getName(), disallowSimultaneous, - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS.getName(), disallowSimultaneous ? 1 : 0, - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName(), 0); - - } - - /** - * Log a warning about the usage of the deprecated - * MYSQL_DISALLOW_DUPLICATE_CONNECTIONS property, and the appropriate - * replacements for it. - * - * @param disallowDuplicate - * Whether duplicate connections have been disabled. - */ - private void warnOfDuplicatePropertyDeprecation(boolean disallowDuplicate) { - - // Warn of deprecation - logger.warn("The \"{}\" property is deprecated. Use \"{}\" and \"{}\" instead.", - MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS.getName(), - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS_PER_USER.getName(), - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName()); - - // Inform of new equivalent - logger.info("To achieve the same result of setting \"{}\" to \"{}\", set \"{}\" to \"{}\" and \"{}\" to \"{}\".", - MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS.getName(), disallowDuplicate, - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS_PER_USER.getName(), disallowDuplicate ? 1 :0, - MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER.getName(), disallowDuplicate ? 1 :0); - - } - - @Override - public int getDefaultMaxConnections() throws GuacamoleException { - - // Tunnel service default configuration - int connectionDefaultMaxConnections; - // Read legacy concurrency-related property Boolean disallowSimultaneous = getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS); + Boolean disallowDuplicate = getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS); // Legacy "simultaneous" property dictates only the maximum number of // connections per connection @@ -124,118 +112,88 @@ public class MySQLEnvironment extends JDBCEnvironment { // Translate legacy property if (disallowSimultaneous) { - connectionDefaultMaxConnections = 1; + DEFAULT_MAX_CONNECTIONS = 1; + DEFAULT_MAX_GROUP_CONNECTIONS = 0; } else { - connectionDefaultMaxConnections = 0; + DEFAULT_MAX_CONNECTIONS = 0; + DEFAULT_MAX_GROUP_CONNECTIONS = 0; } - // Warn that a different property should be used going forward - warnOfSimultaneousPropertyDeprecation(disallowSimultaneous); + // Warn of deprecation + logger.warn("The \"{}\" property is deprecated. Use \"{}\" and \"{}\" instead.", + MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS.getName(), + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS.getName(), + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName()); + + // Inform of new equivalent + logger.info("To achieve the same result of setting \"{}\" to \"{}\", set \"{}\" to \"{}\" and \"{}\" to \"{}\".", + MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS.getName(), disallowSimultaneous, + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS.getName(), DEFAULT_MAX_CONNECTIONS, + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName(), DEFAULT_MAX_GROUP_CONNECTIONS); } - // If legacy property is not specified, use new property - else { - connectionDefaultMaxConnections = getProperty(MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS, 0); + // Legacy "duplicate" property dictates whether connections and groups + // may be used concurrently only by different users + if (disallowDuplicate != null) { + + // Translate legacy property + if (disallowDuplicate) { + DEFAULT_MAX_CONNECTIONS_PER_USER = 1; + DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER = 1; + } + else { + DEFAULT_MAX_CONNECTIONS_PER_USER = 0; + DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER = 0; + } + + // Warn of deprecation + logger.warn("The \"{}\" property is deprecated. Use \"{}\" and \"{}\" instead.", + MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS.getName(), + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS_PER_USER.getName(), + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName()); + + // Inform of new equivalent + logger.info("To achieve the same result of setting \"{}\" to \"{}\", set \"{}\" to \"{}\" and \"{}\" to \"{}\".", + MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS.getName(), disallowDuplicate, + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS_PER_USER.getName(), DEFAULT_MAX_CONNECTIONS_PER_USER, + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER.getName(), DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER); + } - - return connectionDefaultMaxConnections; + + } + + @Override + public int getDefaultMaxConnections() throws GuacamoleException { + return getProperty( + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS, + DEFAULT_MAX_CONNECTIONS + ); } @Override public int getDefaultMaxGroupConnections() throws GuacamoleException { - - int connectionGroupDefaultMaxConnections; - - // Read legacy concurrency-related property - Boolean disallowSimultaneous = getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS); - - // Legacy "simultaneous" property dictates only the maximum number of - // connections per connection - if (disallowSimultaneous != null) { - - // Translate legacy property - connectionGroupDefaultMaxConnections = 0; - - // Warn that a different property should be used going forward - warnOfSimultaneousPropertyDeprecation(disallowSimultaneous); - - } - - // If legacy property is not specified, use new property - else { - connectionGroupDefaultMaxConnections = getProperty(MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS, 0); - } - - return connectionGroupDefaultMaxConnections; + return getProperty( + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS, + DEFAULT_MAX_GROUP_CONNECTIONS + ); } @Override public int getDefaultMaxConnectionsPerUser() throws GuacamoleException { - - int connectionDefaultMaxConnectionsPerUser; - - // Read legacy concurrency-related properties - Boolean disallowDuplicate = getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS); - - // Legacy "duplicate" property dictates whether connections and groups - // may be used concurrently only by different users - if (disallowDuplicate != null) { - - // Translate legacy property - if (disallowDuplicate) { - connectionDefaultMaxConnectionsPerUser = 1; - } - else { - connectionDefaultMaxConnectionsPerUser = 0; - } - - // Warn that a different property should be used going forward - warnOfDuplicatePropertyDeprecation(disallowDuplicate); - - } - - // If legacy property is not specified, use new property - else { - connectionDefaultMaxConnectionsPerUser = getProperty(MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS_PER_USER, 1); - } - - return connectionDefaultMaxConnectionsPerUser; + return getProperty( + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS_PER_USER, + DEFAULT_MAX_CONNECTIONS_PER_USER + ); } @Override public int getDefaultMaxGroupConnectionsPerUser() throws GuacamoleException { - - int connectionGroupDefaultMaxConnectionsPerUser; - - // Read legacy concurrency-related property - Boolean disallowDuplicate = getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS); - - // Legacy "duplicate" property dictates whether connections and groups - // may be used concurrently only by different users - if (disallowDuplicate != null) { - - // Translate legacy property - if (disallowDuplicate) { - connectionGroupDefaultMaxConnectionsPerUser = 1; - } - else { - connectionGroupDefaultMaxConnectionsPerUser = 0; - } - - // Warn that a different property should be used going forward - warnOfDuplicatePropertyDeprecation(disallowDuplicate); - - } - - // If legacy property is not specified, use new property - else { - connectionGroupDefaultMaxConnectionsPerUser = getProperty(MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER, 1); - } - - return connectionGroupDefaultMaxConnectionsPerUser; - + return getProperty( + MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER, + DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER + ); } /** From c22d22f99b48774bd30c8531c7cf98e0994fd095 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 12 Nov 2015 11:45:37 -0800 Subject: [PATCH 4/7] GUAC-1373: Refactor PostgreSQL auth to support new JDBCEnvironment. --- .../PostgreSQLAuthenticationProvider.java | 116 +------- ...ostgreSQLAuthenticationProviderModule.java | 13 +- .../postgresql/PostgreSQLEnvironment.java | 278 ++++++++++++++++++ 3 files changed, 287 insertions(+), 120 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLEnvironment.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java index db0fe1b08..602784bae 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java @@ -29,11 +29,8 @@ import org.glyptodon.guacamole.net.auth.AuthenticationProvider; import org.glyptodon.guacamole.net.auth.Credentials; import org.glyptodon.guacamole.net.auth.UserContext; import org.glyptodon.guacamole.auth.jdbc.JDBCAuthenticationProviderModule; -import org.glyptodon.guacamole.auth.jdbc.tunnel.ConfigurableGuacamoleTunnelService; -import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; +import org.glyptodon.guacamole.auth.jdbc.JDBCEnvironment; import org.glyptodon.guacamole.auth.jdbc.user.AuthenticationProviderService; -import org.glyptodon.guacamole.environment.Environment; -import org.glyptodon.guacamole.environment.LocalEnvironment; import org.glyptodon.guacamole.net.auth.AuthenticatedUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,112 +55,6 @@ public class PostgreSQLAuthenticationProvider implements AuthenticationProvider */ private final Injector injector; - /** - * Returns the appropriate tunnel service given the Guacamole environment. - * The service is configured based on configuration options that dictate - * the default concurrent usage policy. - * - * @param environment - * The environment of the Guacamole server. - * - * @return - * A tunnel service implementation configured according to the - * concurrent usage policy options set in the Guacamole environment. - * - * @throws GuacamoleException - * If an error occurs while reading the configuration options. - */ - private GuacamoleTunnelService getTunnelService(Environment environment) - throws GuacamoleException { - - // Tunnel service default configuration - int connectionDefaultMaxConnections; - int connectionDefaultMaxConnectionsPerUser; - int connectionGroupDefaultMaxConnections; - int connectionGroupDefaultMaxConnectionsPerUser; - - // Read legacy concurrency-related properties - Boolean disallowSimultaneous = environment.getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_SIMULTANEOUS_CONNECTIONS); - Boolean disallowDuplicate = environment.getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_DUPLICATE_CONNECTIONS); - - // Legacy "simultaneous" property dictates only the maximum number of - // connections per connection - if (disallowSimultaneous != null) { - - // Translate legacy property - if (disallowSimultaneous) { - connectionDefaultMaxConnections = 1; - connectionGroupDefaultMaxConnections = 0; - } - else { - connectionDefaultMaxConnections = 0; - connectionGroupDefaultMaxConnections = 0; - } - - // Warn of deprecation - logger.warn("The \"{}\" property is deprecated. Use \"{}\" and \"{}\" instead.", - PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_SIMULTANEOUS_CONNECTIONS.getName(), - PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_CONNECTIONS.getName(), - PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName()); - - // Inform of new equivalent - logger.info("To achieve the same result of setting \"{}\" to \"{}\", set \"{}\" to \"{}\" and \"{}\" to \"{}\".", - PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_SIMULTANEOUS_CONNECTIONS.getName(), disallowSimultaneous, - PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_CONNECTIONS.getName(), connectionDefaultMaxConnections, - PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName(), connectionGroupDefaultMaxConnections); - - } - - // If legacy property is not specified, use new property - else { - connectionDefaultMaxConnections = environment.getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_CONNECTIONS, 0); - connectionGroupDefaultMaxConnections = environment.getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_GROUP_CONNECTIONS, 0); - } - - // Legacy "duplicate" property dictates whether connections and groups - // may be used concurrently only by different users - if (disallowDuplicate != null) { - - // Translate legacy property - if (disallowDuplicate) { - connectionDefaultMaxConnectionsPerUser = 1; - connectionGroupDefaultMaxConnectionsPerUser = 1; - } - else { - connectionDefaultMaxConnectionsPerUser = 0; - connectionGroupDefaultMaxConnectionsPerUser = 0; - } - - // Warn of deprecation - logger.warn("The \"{}\" property is deprecated. Use \"{}\" and \"{}\" instead.", - PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_DUPLICATE_CONNECTIONS.getName(), - PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_CONNECTIONS_PER_USER.getName(), - PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName()); - - // Inform of new equivalent - logger.info("To achieve the same result of setting \"{}\" to \"{}\", set \"{}\" to \"{}\" and \"{}\" to \"{}\".", - PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_DUPLICATE_CONNECTIONS.getName(), disallowDuplicate, - PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_CONNECTIONS_PER_USER.getName(), connectionDefaultMaxConnectionsPerUser, - PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER.getName(), connectionGroupDefaultMaxConnectionsPerUser); - - } - - // If legacy property is not specified, use new property - else { - connectionDefaultMaxConnectionsPerUser = environment.getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_CONNECTIONS_PER_USER, 1); - connectionGroupDefaultMaxConnectionsPerUser = environment.getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER, 1); - } - - // Return service configured for specified default limits - return new ConfigurableGuacamoleTunnelService( - connectionDefaultMaxConnections, - connectionDefaultMaxConnectionsPerUser, - connectionGroupDefaultMaxConnections, - connectionGroupDefaultMaxConnectionsPerUser - ); - - } - /** * Creates a new PostgreSQLAuthenticationProvider that reads and writes * authentication data to a PostgreSQL database defined by properties in @@ -176,7 +67,7 @@ public class PostgreSQLAuthenticationProvider implements AuthenticationProvider public PostgreSQLAuthenticationProvider() throws GuacamoleException { // Get local environment - Environment environment = new LocalEnvironment(); + PostgreSQLEnvironment environment = new PostgreSQLEnvironment(); // Set up Guice injector. injector = Guice.createInjector( @@ -185,8 +76,7 @@ public class PostgreSQLAuthenticationProvider implements AuthenticationProvider new PostgreSQLAuthenticationProviderModule(environment), // Configure JDBC authentication core - new JDBCAuthenticationProviderModule(this, environment, - getTunnelService(environment)) + new JDBCAuthenticationProviderModule(this, environment) ); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java index 2decdf9a6..efd7b9f4f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java @@ -27,7 +27,6 @@ import com.google.inject.Module; import com.google.inject.name.Names; import java.util.Properties; import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.environment.Environment; import org.mybatis.guice.datasource.helper.JdbcHelper; /** @@ -60,16 +59,16 @@ public class PostgreSQLAuthenticationProviderModule implements Module { * If a required property is missing, or an error occurs while parsing * a property. */ - public PostgreSQLAuthenticationProviderModule(Environment environment) + public PostgreSQLAuthenticationProviderModule(PostgreSQLEnvironment environment) throws GuacamoleException { // Set the PostgreSQL-specific properties for MyBatis. myBatisProperties.setProperty("mybatis.environment.id", "guacamole"); - myBatisProperties.setProperty("JDBC.host", environment.getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_HOSTNAME)); - myBatisProperties.setProperty("JDBC.port", String.valueOf(environment.getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_PORT))); - myBatisProperties.setProperty("JDBC.schema", environment.getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DATABASE)); - myBatisProperties.setProperty("JDBC.username", environment.getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_USERNAME)); - myBatisProperties.setProperty("JDBC.password", environment.getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_PASSWORD)); + myBatisProperties.setProperty("JDBC.host", environment.getPostgreSQLHostname()); + myBatisProperties.setProperty("JDBC.port", String.valueOf(environment.getPostgreSQLPort())); + myBatisProperties.setProperty("JDBC.schema", environment.getPostgreSQLDatabase()); + myBatisProperties.setProperty("JDBC.username", environment.getPostgreSQLUsername()); + myBatisProperties.setProperty("JDBC.password", environment.getPostgreSQLPassword()); myBatisProperties.setProperty("JDBC.autoCommit", "false"); myBatisProperties.setProperty("mybatis.pooled.pingEnabled", "true"); myBatisProperties.setProperty("mybatis.pooled.pingQuery", "SELECT 1"); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLEnvironment.java new file mode 100644 index 000000000..83c139ec5 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLEnvironment.java @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * 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. + */ + +package org.glyptodon.guacamole.auth.postgresql; + +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.auth.jdbc.JDBCEnvironment; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A PostgreSQL-specific implementation of JDBCEnvironment provides database + * properties specifically for PostgreSQL. + * + * @author Michael Jumper + */ +public class PostgreSQLEnvironment extends JDBCEnvironment { + + /** + * Logger for this class. + */ + private static final Logger logger = LoggerFactory.getLogger(PostgreSQLEnvironment.class); + + /** + * The default host to connect to, if POSTGRESQL_HOSTNAME is not specified. + */ + private static final String DEFAULT_HOSTNAME = "localhost"; + + /** + * The default port to connect to, if POSTGRESQL_PORT is not specified. + */ + private static final int DEFAULT_PORT = 5432; + + /** + * The default value for the default maximum number of connections to be + * allowed per user to any one connection. Note that, as long as the + * legacy "disallow duplicate" and "disallow simultaneous" properties are + * still supported, these cannot be constants, as the legacy properties + * dictate the values that should be used in the absence of the correct + * properties. + */ + private int DEFAULT_MAX_CONNECTIONS_PER_USER = 1; + + /** + * The default value for the default maximum number of connections to be + * allowed per user to any one connection group. Note that, as long as the + * legacy "disallow duplicate" and "disallow simultaneous" properties are + * still supported, these cannot be constants, as the legacy properties + * dictate the values that should be used in the absence of the correct + * properties. + */ + private int DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER = 1; + + /** + * The default value for the default maximum number of connections to be + * allowed to any one connection. Note that, as long as the legacy + * "disallow duplicate" and "disallow simultaneous" properties are still + * supported, these cannot be constants, as the legacy properties dictate + * the values that should be used in the absence of the correct properties. + */ + private int DEFAULT_MAX_CONNECTIONS = 0; + + /** + * The default value for the default maximum number of connections to be + * allowed to any one connection group. Note that, as long as the legacy + * "disallow duplicate" and "disallow simultaneous" properties are still + * supported, these cannot be constants, as the legacy properties dictate + * the values that should be used in the absence of the correct properties. + */ + private int DEFAULT_MAX_GROUP_CONNECTIONS = 0; + + /** + * Constructs a new PostgreSQLEnvironment, providing access to PostgreSQL-specific + * configuration options. + * + * @throws GuacamoleException + * If an error occurs while setting up the underlying JDBCEnvironment + * or while parsing legacy PostgreSQL configuration options. + */ + public PostgreSQLEnvironment() throws GuacamoleException { + + // Init underlying JDBC environment + super(); + + // Read legacy concurrency-related property + Boolean disallowSimultaneous = getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_SIMULTANEOUS_CONNECTIONS); + Boolean disallowDuplicate = getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_DUPLICATE_CONNECTIONS); + + // Legacy "simultaneous" property dictates only the maximum number of + // connections per connection + if (disallowSimultaneous != null) { + + // Translate legacy property + if (disallowSimultaneous) { + DEFAULT_MAX_CONNECTIONS = 1; + DEFAULT_MAX_GROUP_CONNECTIONS = 0; + } + else { + DEFAULT_MAX_CONNECTIONS = 0; + DEFAULT_MAX_GROUP_CONNECTIONS = 0; + } + + // Warn of deprecation + logger.warn("The \"{}\" property is deprecated. Use \"{}\" and \"{}\" instead.", + PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_SIMULTANEOUS_CONNECTIONS.getName(), + PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_CONNECTIONS.getName(), + PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName()); + + // Inform of new equivalent + logger.info("To achieve the same result of setting \"{}\" to \"{}\", set \"{}\" to \"{}\" and \"{}\" to \"{}\".", + PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_SIMULTANEOUS_CONNECTIONS.getName(), disallowSimultaneous, + PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_CONNECTIONS.getName(), DEFAULT_MAX_CONNECTIONS, + PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName(), DEFAULT_MAX_GROUP_CONNECTIONS); + + } + + // Legacy "duplicate" property dictates whether connections and groups + // may be used concurrently only by different users + if (disallowDuplicate != null) { + + // Translate legacy property + if (disallowDuplicate) { + DEFAULT_MAX_CONNECTIONS_PER_USER = 1; + DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER = 1; + } + else { + DEFAULT_MAX_CONNECTIONS_PER_USER = 0; + DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER = 0; + } + + // Warn of deprecation + logger.warn("The \"{}\" property is deprecated. Use \"{}\" and \"{}\" instead.", + PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_DUPLICATE_CONNECTIONS.getName(), + PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_CONNECTIONS_PER_USER.getName(), + PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_GROUP_CONNECTIONS.getName()); + + // Inform of new equivalent + logger.info("To achieve the same result of setting \"{}\" to \"{}\", set \"{}\" to \"{}\" and \"{}\" to \"{}\".", + PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_DUPLICATE_CONNECTIONS.getName(), disallowDuplicate, + PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_CONNECTIONS_PER_USER.getName(), DEFAULT_MAX_CONNECTIONS_PER_USER, + PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER.getName(), DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER); + + } + + } + + @Override + public int getDefaultMaxConnections() throws GuacamoleException { + return getProperty( + PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_CONNECTIONS, + DEFAULT_MAX_CONNECTIONS + ); + } + + @Override + public int getDefaultMaxGroupConnections() throws GuacamoleException { + return getProperty( + PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_GROUP_CONNECTIONS, + DEFAULT_MAX_GROUP_CONNECTIONS + ); + } + + @Override + public int getDefaultMaxConnectionsPerUser() throws GuacamoleException { + return getProperty( + PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_CONNECTIONS_PER_USER, + DEFAULT_MAX_CONNECTIONS_PER_USER + ); + } + + @Override + public int getDefaultMaxGroupConnectionsPerUser() throws GuacamoleException { + return getProperty( + PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER, + DEFAULT_MAX_GROUP_CONNECTIONS_PER_USER + ); + } + + /** + * Returns the hostname of the PostgreSQL server hosting the Guacamole + * authentication tables. If unspecified, this will be "localhost". + * + * @return + * The URL of the PostgreSQL server. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property value. + */ + public String getPostgreSQLHostname() throws GuacamoleException { + return getProperty( + PostgreSQLGuacamoleProperties.POSTGRESQL_HOSTNAME, + DEFAULT_HOSTNAME + ); + } + + /** + * Returns the port number of the PostgreSQL server hosting the Guacamole + * authentication tables. If unspecified, this will be the default + * PostgreSQL port of 5432. + * + * @return + * The port number of the PostgreSQL server. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property value. + */ + public int getPostgreSQLPort() throws GuacamoleException { + return getProperty( + PostgreSQLGuacamoleProperties.POSTGRESQL_PORT, + DEFAULT_PORT + ); + } + + /** + * Returns the name of the PostgreSQL database containing the Guacamole + * authentication tables. + * + * @return + * The name of the PostgreSQL database. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property value, or if the + * value was not set, as this property is required. + */ + public String getPostgreSQLDatabase() throws GuacamoleException { + return getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DATABASE); + } + + /** + * Returns the username that should be used when authenticating with the + * PostgreSQL database containing the Guacamole authentication tables. + * + * @return + * The username for the PostgreSQL database. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property value, or if the + * value was not set, as this property is required. + */ + public String getPostgreSQLUsername() throws GuacamoleException { + return getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_USERNAME); + } + + /** + * Returns the password that should be used when authenticating with the + * PostgreSQL database containing the Guacamole authentication tables. + * + * @return + * The password for the PostgreSQL database. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property value, or if the + * value was not set, as this property is required. + */ + public String getPostgreSQLPassword() throws GuacamoleException { + return getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_PASSWORD); + } + +} From 7298cb7bb7f40465f090ecfd18db14f4034de2b5 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 12 Nov 2015 12:43:42 -0800 Subject: [PATCH 5/7] GUAC-1373: Restore bind() for GuacamoleTunnelService. --- .../guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java index 883e58986..414f280a3 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java @@ -62,6 +62,7 @@ import org.glyptodon.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermis import org.glyptodon.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionSet; import org.glyptodon.guacamole.auth.jdbc.activeconnection.ActiveConnectionService; import org.glyptodon.guacamole.auth.jdbc.activeconnection.TrackedActiveConnection; +import org.glyptodon.guacamole.auth.jdbc.tunnel.ConfigurableGuacamoleTunnelService; import org.glyptodon.guacamole.net.auth.AuthenticationProvider; import org.mybatis.guice.MyBatisModule; import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider; @@ -152,6 +153,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { bind(ConnectionGroupService.class); bind(ConnectionPermissionService.class); bind(ConnectionService.class); + bind(GuacamoleTunnelService.class).to(ConfigurableGuacamoleTunnelService.class); bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class); bind(SaltService.class).to(SecureRandomSaltService.class); bind(SystemPermissionService.class); From a7746863115a867cd442b43d3f50d1c5710f2e33 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 12 Nov 2015 12:44:40 -0800 Subject: [PATCH 6/7] GUAC-1373: Injected JDBCEnvironment should be private. --- .../tunnel/ConfigurableGuacamoleTunnelService.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ConfigurableGuacamoleTunnelService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ConfigurableGuacamoleTunnelService.java index 0f9bf15f0..b34a4ff0a 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ConfigurableGuacamoleTunnelService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ConfigurableGuacamoleTunnelService.java @@ -50,9 +50,10 @@ public class ConfigurableGuacamoleTunnelService extends AbstractGuacamoleTunnelService { /** - * The configuration for the current JDBC environment. + * The Guacamole server environment. */ - @Inject JDBCEnvironment jdbcEnvironment; + @Inject + private JDBCEnvironment environment; /** * Set of all currently-active user/connection pairs (seats). @@ -150,12 +151,12 @@ public class ConfigurableGuacamoleTunnelService // Determine per-user limits on this connection Integer connectionMaxConnectionsPerUser = connection.getModel().getMaxConnectionsPerUser(); if (connectionMaxConnectionsPerUser == null) - connectionMaxConnectionsPerUser = jdbcEnvironment.getDefaultMaxConnectionsPerUser(); + connectionMaxConnectionsPerUser = environment.getDefaultMaxConnectionsPerUser(); // Determine overall limits on this connection Integer connectionMaxConnections = connection.getModel().getMaxConnections(); if (connectionMaxConnections == null) - connectionMaxConnections = jdbcEnvironment.getDefaultMaxConnections(); + connectionMaxConnections = environment.getDefaultMaxConnections(); // Attempt to aquire connection according to per-user limits Seat seat = new Seat(username, connection.getIdentifier()); @@ -202,12 +203,12 @@ public class ConfigurableGuacamoleTunnelService // Determine per-user limits on this connection group Integer connectionGroupMaxConnectionsPerUser = connectionGroup.getModel().getMaxConnectionsPerUser(); if (connectionGroupMaxConnectionsPerUser == null) - connectionGroupMaxConnectionsPerUser = jdbcEnvironment.getDefaultMaxGroupConnectionsPerUser(); + connectionGroupMaxConnectionsPerUser = environment.getDefaultMaxGroupConnectionsPerUser(); // Determine overall limits on this connection group Integer connectionGroupMaxConnections = connectionGroup.getModel().getMaxConnections(); if (connectionGroupMaxConnections == null) - connectionGroupMaxConnections = jdbcEnvironment.getDefaultMaxGroupConnections(); + connectionGroupMaxConnections = environment.getDefaultMaxGroupConnections(); // Attempt to aquire connection group according to per-user limits Seat seat = new Seat(username, connectionGroup.getIdentifier()); From 65393adeda06bdce385d2aea55aba515d6de6a55 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 12 Nov 2015 13:00:43 -0800 Subject: [PATCH 7/7] GUAC-1373: Move property/attribute logic into ModeledConnection and ModeledConnectionGroup. --- .../JDBCAuthenticationProviderModule.java | 4 +- .../jdbc/connection/ModeledConnection.java | 56 ++++++++++++++++++ .../ModeledConnectionGroup.java | 58 +++++++++++++++++++ ... => RestrictedGuacamoleTunnelService.java} | 39 ++----------- 4 files changed, 122 insertions(+), 35 deletions(-) rename extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/{ConfigurableGuacamoleTunnelService.java => RestrictedGuacamoleTunnelService.java} (81%) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java index 414f280a3..7a570e0ee 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java @@ -62,7 +62,7 @@ import org.glyptodon.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermis import org.glyptodon.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionSet; import org.glyptodon.guacamole.auth.jdbc.activeconnection.ActiveConnectionService; import org.glyptodon.guacamole.auth.jdbc.activeconnection.TrackedActiveConnection; -import org.glyptodon.guacamole.auth.jdbc.tunnel.ConfigurableGuacamoleTunnelService; +import org.glyptodon.guacamole.auth.jdbc.tunnel.RestrictedGuacamoleTunnelService; import org.glyptodon.guacamole.net.auth.AuthenticationProvider; import org.mybatis.guice.MyBatisModule; import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider; @@ -153,7 +153,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { bind(ConnectionGroupService.class); bind(ConnectionPermissionService.class); bind(ConnectionService.class); - bind(GuacamoleTunnelService.class).to(ConfigurableGuacamoleTunnelService.class); + bind(GuacamoleTunnelService.class).to(RestrictedGuacamoleTunnelService.class); bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class); bind(SaltService.class).to(SecureRandomSaltService.class); bind(SystemPermissionService.class); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnection.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnection.java index 3a1bb2ff5..bb5e020da 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnection.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnection.java @@ -32,6 +32,7 @@ import java.util.List; import java.util.Map; import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.auth.jdbc.JDBCEnvironment; import org.glyptodon.guacamole.auth.jdbc.base.ModeledGroupedDirectoryObject; import org.glyptodon.guacamole.form.Field; import org.glyptodon.guacamole.form.Form; @@ -88,6 +89,12 @@ public class ModeledConnection extends ModeledGroupedDirectoryObject