From 4bbe2c986368b5b1dcd98f122485d0f25808fccc Mon Sep 17 00:00:00 2001 From: James Muehlner Date: Thu, 21 Feb 2013 22:56:43 -0800 Subject: [PATCH] Ticket #269: Connection implementation completed. Testing and styling remain. --- .../net/auth/mysql/ConnectionDirectory.java | 109 ++++++++-- .../mysql/GuacamolePermissionException.java | 2 +- .../mysql/MySQLAuthenticationProvider.java | 13 +- .../net/auth/mysql/MySQLConnection.java | 86 ++++++-- .../net/auth/mysql/MySQLConnectionRecord.java | 14 +- .../guacamole/net/auth/mysql/MySQLUser.java | 44 ++-- .../net/auth/mysql/MySQLUserContext.java | 12 +- .../net/auth/mysql/UserDirectory.java | 131 ++++++------ .../properties/MySQLGuacamoleProperties.java | 23 +- .../mysql/utility/PermissionCheckUtility.java | 198 +++++++++--------- .../auth/mysql/utility/ProviderUtility.java | 21 +- .../Sha256PasswordEncryptionUtility.java | 7 - 12 files changed, 405 insertions(+), 255 deletions(-) diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/ConnectionDirectory.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/ConnectionDirectory.java index f99e14e99..b98e00653 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/ConnectionDirectory.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/ConnectionDirectory.java @@ -35,7 +35,7 @@ * ***** END LICENSE BLOCK ***** */ package net.sourceforge.guacamole.net.auth.mysql; -import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; import com.google.inject.Inject; import java.util.ArrayList; import java.util.HashMap; @@ -51,6 +51,7 @@ import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionParameterMapper; import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionPermissionMapper; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionParameter; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionParameterExample; +import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionExample; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionKey; import net.sourceforge.guacamole.net.auth.mysql.utility.PermissionCheckUtility; import net.sourceforge.guacamole.net.auth.mysql.utility.ProviderUtility; @@ -68,30 +69,30 @@ public class ConnectionDirectory implements Directory{ * Access is based on his/her permission settings. */ private MySQLUser user; - + @Inject PermissionCheckUtility permissionCheckUtility; - + @Inject ProviderUtility providerUtility; - + @Inject ConnectionMapper connectionDAO; - + @Inject ConnectionPermissionMapper connectionPermissionDAO; - + @Inject ConnectionParameterMapper connectionParameterDAO; - + /** * Set the user for this directory. - * @param user + * @param user */ void init(MySQLUser user) { this.user = user; } - + @Transactional @Override public Connection get(String identifier) throws GuacamoleException { @@ -113,14 +114,13 @@ public class ConnectionDirectory implements Directory{ @Transactional @Override public void add(Connection object) throws GuacamoleException { - Preconditions.checkNotNull(object); permissionCheckUtility.verifyCreateConnectionPermission(this.user.getUserID()); - + MySQLConnection mySQLConnection = providerUtility.getNewMySQLConnection(object); connectionDAO.insert(mySQLConnection.getConnection()); - + updateConfigurationValues(mySQLConnection); - + //finally, give the current user full access to the newly created connection. ConnectionPermissionKey newConnectionPermission = new ConnectionPermissionKey(); newConnectionPermission.setUser_id(this.user.getUserID()); @@ -134,39 +134,104 @@ public class ConnectionDirectory implements Directory{ newConnectionPermission.setPermission(MySQLConstants.USER_ADMINISTER); connectionPermissionDAO.insert(newConnectionPermission); } - + /** * Saves the values of the configuration to the database - * @param connection + * @param connection */ private void updateConfigurationValues(MySQLConnection mySQLConnection) { GuacamoleConfiguration configuration = mySQLConnection.getConfiguration(); Map existingConfiguration = new HashMap(); ConnectionParameterExample example = new ConnectionParameterExample(); + example.createCriteria().andConnection_idEqualTo(mySQLConnection.getConnectionID()); List connectionParameters = connectionParameterDAO.selectByExample(example); for(ConnectionParameter parameter : connectionParameters) existingConfiguration.put(parameter.getParameter_name(), parameter.getParameter_value()); - + List parametersToInsert = new ArrayList(); List parametersToUpdate = new ArrayList(); - + Set parameterNames = configuration.getParameterNames(); - + for(String parameterName : parameterNames) { - + String parameterValue = configuration.getParameter(parameterName); + if(existingConfiguration.containsKey(parameterName)) { + String existingValue = existingConfiguration.get(parameterName); + // the value is different; we'll have to update this one in the database + if(!parameterValue.equals(existingValue)) { + ConnectionParameter parameterToUpdate = new ConnectionParameter(); + parameterToUpdate.setConnection_id(mySQLConnection.getConnectionID()); + parameterToUpdate.setParameter_name(parameterName); + parameterToUpdate.setParameter_value(parameterValue); + parametersToUpdate.add(parameterToUpdate); + } + } else { + // the value is new, we need to insert it + ConnectionParameter parameterToInsert = new ConnectionParameter(); + parameterToInsert.setConnection_id(mySQLConnection.getConnectionID()); + parameterToInsert.setParameter_name(parameterName); + parameterToInsert.setParameter_value(parameterValue); + parametersToInsert.add(parameterToInsert); + } + } + + // First, delete all parameters that are not in the new configuration. + example.clear(); + example.createCriteria(). + andConnection_idEqualTo(mySQLConnection.getConnectionID()). + andParameter_nameNotIn(Lists.newArrayList(existingConfiguration.keySet())); + + //Second, update all the parameters that need to be modified. + for(ConnectionParameter parameter : parametersToUpdate) { + example.clear(); + example.createCriteria(). + andConnection_idEqualTo(mySQLConnection.getConnectionID()). + andParameter_nameEqualTo(parameter.getParameter_name()); + + connectionParameterDAO.updateByExample(parameter, example); + } + + //Finally, insert any new parameters. + for(ConnectionParameter parameter : parametersToInsert) { + example.clear(); + example.createCriteria(). + andConnection_idEqualTo(mySQLConnection.getConnectionID()). + andParameter_nameEqualTo(parameter.getParameter_name()); + + connectionParameterDAO.insert(parameter); } } @Transactional @Override public void update(Connection object) throws GuacamoleException { - throw new UnsupportedOperationException("Not supported yet."); + permissionCheckUtility.verifyConnectionUpdateAccess(this.user.getUserID(), object.getIdentifier()); + + MySQLConnection mySQLConnection = providerUtility.getExistingMySQLConnection(object); + connectionDAO.updateByPrimaryKey(mySQLConnection.getConnection()); + + updateConfigurationValues(mySQLConnection); } @Transactional @Override public void remove(String identifier) throws GuacamoleException { - throw new UnsupportedOperationException("Not supported yet."); + permissionCheckUtility.verifyConnectionDeleteAccess(this.user.getUserID(), identifier); + + MySQLConnection mySQLConnection = providerUtility.getExistingMySQLConnection(identifier); + + // delete all configuration values + ConnectionParameterExample connectionParameterExample = new ConnectionParameterExample(); + connectionParameterExample.createCriteria().andConnection_idEqualTo(mySQLConnection.getConnectionID()); + connectionParameterDAO.deleteByExample(connectionParameterExample); + + // delete all permissions that refer to this connection + ConnectionPermissionExample connectionPermissionExample = new ConnectionPermissionExample(); + connectionPermissionExample.createCriteria().andConnection_idEqualTo(mySQLConnection.getConnectionID()); + connectionPermissionDAO.deleteByExample(connectionPermissionExample); + + // delete the connection itself + connectionDAO.deleteByPrimaryKey(mySQLConnection.getConnectionID()); } - + } diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/GuacamolePermissionException.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/GuacamolePermissionException.java index 44502bf0a..98df8f749 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/GuacamolePermissionException.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/GuacamolePermissionException.java @@ -74,5 +74,5 @@ public class GuacamolePermissionException extends GuacamoleException { super(cause); } - + } diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java index 5cd9ca423..22a00e7e4 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java @@ -52,6 +52,7 @@ import net.sourceforge.guacamole.net.auth.mysql.dao.SystemPermissionMapper; import net.sourceforge.guacamole.net.auth.mysql.dao.UserMapper; import net.sourceforge.guacamole.net.auth.mysql.dao.UserPermissionMapper; import net.sourceforge.guacamole.net.auth.mysql.properties.MySQLGuacamoleProperties; +import net.sourceforge.guacamole.net.auth.mysql.utility.ConfigurationTranslationUtility; import net.sourceforge.guacamole.net.auth.mysql.utility.PasswordEncryptionUtility; import net.sourceforge.guacamole.net.auth.mysql.utility.PermissionCheckUtility; import net.sourceforge.guacamole.net.auth.mysql.utility.ProviderUtility; @@ -73,18 +74,21 @@ import org.slf4j.LoggerFactory; public class MySQLAuthenticationProvider implements AuthenticationProvider { private Logger logger = LoggerFactory.getLogger(MySQLUserContext.class); - + + private ActiveConnectionSet activeConnectionSet = new ActiveConnectionSet(); + private Injector injector; - + @Override public UserContext getUserContext(Credentials credentials) throws GuacamoleException { MySQLUserContext context = injector.getInstance(MySQLUserContext.class); context.init(credentials); return context; } - + public MySQLAuthenticationProvider() throws GuacamoleException { final Properties myBatisProperties = new Properties(); + //set the mysql properties for MyBatis. myBatisProperties.setProperty("mybatis.environment.id", "guacamole"); myBatisProperties.setProperty("JDBC.host", GuacamoleProperties.getRequiredProperty(MySQLGuacamoleProperties.MYSQL_HOSTNAME)); myBatisProperties.setProperty("JDBC.port", String.valueOf(GuacamoleProperties.getRequiredProperty(MySQLGuacamoleProperties.MYSQL_PORT))); @@ -93,6 +97,7 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider { myBatisProperties.setProperty("JDBC.password", GuacamoleProperties.getRequiredProperty(MySQLGuacamoleProperties.MYSQL_PASSWORD)); myBatisProperties.setProperty("JDBC.autoCommit", "false"); + // Set up Guice injector. injector = Guice.createInjector( JdbcHelper.MySQL, new Module() { @@ -117,6 +122,8 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider { bind(PasswordEncryptionUtility.class).to(Sha256PasswordEncryptionUtility.class); bind(PermissionCheckUtility.class); bind(ProviderUtility.class); + bind(ConfigurationTranslationUtility.class); + bind(ActiveConnectionSet.class).toInstance(activeConnectionSet); } } ); diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnection.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnection.java index d34bce987..6dabae6cb 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnection.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnection.java @@ -39,11 +39,19 @@ import com.google.inject.Inject; import java.util.List; import net.sourceforge.guacamole.GuacamoleException; import net.sourceforge.guacamole.net.GuacamoleSocket; +import net.sourceforge.guacamole.net.InetGuacamoleSocket; import net.sourceforge.guacamole.net.auth.Connection; import net.sourceforge.guacamole.net.auth.ConnectionRecord; import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionMapper; +import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionParameterMapper; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionExample; +import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionParameter; +import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionParameterExample; +import net.sourceforge.guacamole.net.auth.mysql.properties.MySQLGuacamoleProperties; +import net.sourceforge.guacamole.net.auth.mysql.utility.ConfigurationTranslationUtility; import net.sourceforge.guacamole.net.auth.mysql.utility.ProviderUtility; +import net.sourceforge.guacamole.properties.GuacamoleProperties; +import net.sourceforge.guacamole.protocol.ConfiguredGuacamoleSocket; import net.sourceforge.guacamole.protocol.GuacamoleClientInformation; import net.sourceforge.guacamole.protocol.GuacamoleConfiguration; @@ -52,24 +60,34 @@ import net.sourceforge.guacamole.protocol.GuacamoleConfiguration; * @author James Muehlner */ public class MySQLConnection implements Connection { - + @Inject ConnectionMapper connectionDAO; - + + @Inject + ConnectionParameterMapper connectionParameterDAO; + @Inject ProviderUtility providerUtility; - + + @Inject + ActiveConnectionSet activeConnectionSet; + + @Inject + ConfigurationTranslationUtility configurationTranslationUtility; + private net.sourceforge.guacamole.net.auth.mysql.model.Connection connection; - + private GuacamoleConfiguration configuration; - + /** * Create a default, empty connection. */ MySQLConnection() { connection = new net.sourceforge.guacamole.net.auth.mysql.model.Connection(); + configuration = new GuacamoleConfiguration(); } - + /** * Get the ID of the underlying connection record. * @return the ID of the underlying connection @@ -77,7 +95,7 @@ public class MySQLConnection implements Connection { public int getConnectionID() { return connection.getConnection_id(); } - + /** * Get the underlying connection database record. * @return the underlying connection record. @@ -85,19 +103,31 @@ public class MySQLConnection implements Connection { public net.sourceforge.guacamole.net.auth.mysql.model.Connection getConnection() { return connection; } - + /** * Create a new MySQLConnection from this new connection. This is a connection that has not yet been inserted. - * @param connection + * @param connection */ public void initNew(Connection connection) { this.connection.setConnection_name(connection.getIdentifier()); this.configuration = connection.getConfiguration(); } - + + /** + * Initializes the GuacamoleConfiguration based on the ConnectionParameter values in the database. + */ + private void initConfiguration() { + ConnectionParameterExample connectionParameterExample = new ConnectionParameterExample(); + connectionParameterExample.createCriteria().andConnection_idEqualTo(connection.getConnection_id()); + + List connectionParameters = connectionParameterDAO.selectByExample(connectionParameterExample); + + configuration = configurationTranslationUtility.getConfiguration(connection.getProtocol(), connectionParameters); + } + /** * Load an existing connection by name. - * @param connectionName + * @param connectionName */ public void initExisting(String connectionName) throws GuacamoleException { ConnectionExample example = new ConnectionExample(); @@ -108,16 +138,19 @@ public class MySQLConnection implements Connection { throw new GuacamoleException("Multiple connections found named '" + connectionName + "'."); else if(connections.isEmpty()) throw new GuacamoleException("No connection found named '" + connectionName + "'."); - + connection = connections.get(0); + + initConfiguration(); } - + /** - * Initialize from a database record. - * @param connection + * Initialize from a database record. This also initializes the configuration values. + * @param connection */ public void init(net.sourceforge.guacamole.net.auth.mysql.model.Connection connection) { this.connection = connection; + initConfiguration(); } @Override @@ -138,13 +171,30 @@ public class MySQLConnection implements Connection { @Override public void setConfiguration(GuacamoleConfiguration config) { this.configuration = config; + } @Override public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException { - throw new UnsupportedOperationException("Not supported yet."); + // If the current connection is active, and multiple simultaneous connections are not allowed. + if(GuacamoleProperties.getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS, false) + && activeConnectionSet.contains(getConnectionID())) + throw new GuacamoleException("Cannot connect. This connection is in use."); + + String host = GuacamoleProperties.getProperty(GuacamoleProperties.GUACD_HOSTNAME); + int port = GuacamoleProperties.getProperty(GuacamoleProperties.GUACD_PORT); + + InetGuacamoleSocket inetSocket = new InetGuacamoleSocket(host, port); + ConfiguredGuacamoleSocket configuredSocket = new ConfiguredGuacamoleSocket(inetSocket, configuration); + + MySQLGuacamoleSocket mySQLSocket = providerUtility.getMySQLGuacamoleSocket(configuredSocket, getConnectionID()); + + // mark this connection as active + activeConnectionSet.add(getConnectionID()); + + return mySQLSocket; } - + @Override public boolean equals(Object other) { if(!(other instanceof MySQLConnection)) @@ -163,7 +213,7 @@ public class MySQLConnection implements Connection { hash = 73 * hash + getIdentifier().hashCode(); return hash; } - + @Override public List getHistory() throws GuacamoleException { return providerUtility.getExistingMySQLConnectionRecords(connection.getConnection_id()); diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnectionRecord.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnectionRecord.java index 099f5a482..ec47b4556 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnectionRecord.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnectionRecord.java @@ -55,24 +55,24 @@ public class MySQLConnectionRecord implements ConnectionRecord { * The database record that this ConnectionRecord represents. */ private ConnectionHistory connectionHistory; - + @Inject UserMapper userDAO; - + @Inject ConnectionMapper connectionDAO; - + @Inject ProviderUtility providerUtility; - + /** * Initialize this MySQLConnectionRecord with the database record it represents. - * @param connectionHistory + * @param connectionHistory */ public void init(ConnectionHistory connectionHistory) { this.connectionHistory = connectionHistory; } - + @Override public Date getStartDate() { return connectionHistory.getStart_date(); @@ -98,5 +98,5 @@ public class MySQLConnectionRecord implements ConnectionRecord { // if the end date hasn't been stored yet, the connection is still open. return connectionHistory.getEnd_date() == null; } - + } diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUser.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUser.java index 92975ee87..be69486b3 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUser.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUser.java @@ -58,21 +58,21 @@ import net.sourceforge.guacamole.net.auth.permission.Permission; public class MySQLUser implements User { private UserWithBLOBs user; - + @Inject UserMapper userDAO; - + @Inject PasswordEncryptionUtility passwordUtility; - + @Inject SaltUtility saltUtility; - + @Inject PermissionCheckUtility permissionCheckUtility; - + Set permissions; - + /** * Create a default, empty user. */ @@ -80,11 +80,11 @@ public class MySQLUser implements User { user = new UserWithBLOBs(); permissions = new HashSet(); } - + /** * Create the user, throwing an exception if the credentials do not match what's in the database. * @param credentials - * @throws GuacamoleException + * @throws GuacamoleException */ void init (Credentials credentials) throws GuacamoleException { UserExample userExample = new UserExample(); @@ -98,25 +98,25 @@ public class MySQLUser implements User { // check password if(!passwordUtility.checkCredentials(credentials, user.getPassword_hash(), user.getUsername(), user.getPassword_salt())) throw new GuacamoleException("No user found with the supplied credentials"); - + this.permissions = permissionCheckUtility.getAllPermissions(user.getUser_id()); } - + /** * Create a new user from the provided information. This represents a user that has not yet been inserted. * @param user - * @throws GuacamoleException + * @throws GuacamoleException */ public void initNew (User user) throws GuacamoleException { this.setPassword(user.getPassword()); this.setUsername(user.getUsername()); this.permissions = user.getPermissions(); } - + /** * Loads a user by username. * @param userName - * @throws GuacamoleException + * @throws GuacamoleException */ public void initExisting (String username) throws GuacamoleException { UserExample example = new UserExample(); @@ -126,36 +126,36 @@ public class MySQLUser implements User { throw new GuacamoleException("Multiple users found with username '" + username + "'."); if(userList.isEmpty()) throw new GuacamoleException("No user found with username '" + username + "'."); - + this.user = userList.get(0); this.permissions = permissionCheckUtility.getAllPermissions(user.getUser_id()); } - + /** * Initialize from a database record. - * @param user + * @param user */ public void init(UserWithBLOBs user) { this.user = user; this.permissions = permissionCheckUtility.getAllPermissions(user.getUser_id()); } - + /** * Get the user id. - * @return + * @return */ public int getUserID() { return user.getUser_id(); } - + /** * Return the database record held by this object. - * @return + * @return */ public UserWithBLOBs getUser() { return user; } - + @Override public String getUsername() { return user.getUsername(); @@ -202,7 +202,7 @@ public class MySQLUser implements User { public void removePermission(Permission permission) throws GuacamoleException { permissions.remove(permission); } - + @Override public boolean equals(Object other) { if(!(other instanceof MySQLUser)) diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUserContext.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUserContext.java index fc55da470..2ca81af11 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUserContext.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUserContext.java @@ -50,18 +50,18 @@ import org.slf4j.LoggerFactory; * @author James Muehlner */ public class MySQLUserContext implements UserContext { - + private Logger logger = LoggerFactory.getLogger(MySQLUserContext.class); - + @Inject private MySQLUser user; - + @Inject private UserDirectory userDirectory; - + @Inject private ConnectionDirectory connectionDirectory; - + void init(Credentials credentials) throws GuacamoleException { user.init(credentials); userDirectory.init(user); @@ -82,5 +82,5 @@ public class MySQLUserContext implements UserContext { public Directory getConnectionDirectory() throws GuacamoleException { return connectionDirectory; } - + } diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/UserDirectory.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/UserDirectory.java index 92dd7d22f..1cc339d42 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/UserDirectory.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/UserDirectory.java @@ -74,42 +74,42 @@ import org.mybatis.guice.transactional.Transactional; * @author James Muehlner */ public class UserDirectory implements Directory { - + /** * The user who this user directory belongs to. * Access is based on his/her permission settings. */ private MySQLUser user; - + @Inject UserMapper userDAO; - + @Inject ConnectionMapper connectionDAO; - + @Inject UserPermissionMapper userPermissionDAO; - + @Inject ConnectionPermissionMapper connectionPermissionDAO; - + @Inject SystemPermissionMapper systemPermissionDAO; - + @Inject PermissionCheckUtility permissionCheckUtility; - + @Inject ProviderUtility providerUtility; - + /** * Set the user for this directory. - * @param user + * @param user */ void init(MySQLUser user) { this.user = user; } - + @Transactional @Override public User get(String identifier) throws GuacamoleException { @@ -133,14 +133,14 @@ public class UserDirectory implements Directory { public void add(User object) throws GuacamoleException { permissionCheckUtility.verifyCreateUserPermission(this.user.getUserID()); Preconditions.checkNotNull(object); - + //create user in database MySQLUser mySQLUser = providerUtility.getNewMySQLUser(object); userDAO.insert(mySQLUser.getUser()); - + //create permissions in database updatePermissions(mySQLUser); - + //finally, give the current user full access to the newly created user. UserPermissionKey newUserPermission = new UserPermissionKey(); newUserPermission.setUser_id(this.user.getUserID()); @@ -154,24 +154,24 @@ public class UserDirectory implements Directory { newUserPermission.setPermission(MySQLConstants.USER_ADMINISTER); userPermissionDAO.insert(newUserPermission); } - + /** * Update all the permissions for a given user to be only those specified in the user object. * Delete any permissions not in the list, and create any in the list that do not exist * in the database. * @param user - * @throws GuacamoleException + * @throws GuacamoleException */ private void updatePermissions(MySQLUser user) throws GuacamoleException { List userPermissions = new ArrayList(); List connectionPermissions = new ArrayList(); List systemPermissions = new ArrayList(); - + // Get the list of all the users and connections that the user performing the user save action has. // Need to make sure the user saving this user has permission to administrate all the objects in the permission list. Set administerableUsers = permissionCheckUtility.getAdministerableUserIDs(this.user.getUserID()); Set administerableConnections = permissionCheckUtility.getAdministerableConnectionIDs(this.user.getUserID()); - + for(Permission permission : user.getPermissions()) { if(permission instanceof UserPermission) userPermissions.add((UserPermission)permission); @@ -180,36 +180,36 @@ public class UserDirectory implements Directory { else if(permission instanceof SystemPermission) systemPermissions.add((SystemPermission)permission); } - + updateUserPermissions(userPermissions, user, administerableUsers); updateConnectionPermissions(connectionPermissions, user, administerableConnections); updateSystemPermissions(systemPermissions, user); } - + /** * Update all the permissions having to do with users for a given user. * @param permissions - * @param user + * @param user */ private void updateUserPermissions(Iterable permissions, MySQLUser user, Set administerableUsers) throws GuacamoleException { - + List usernames = new ArrayList(); for(UserPermission permission : permissions) { usernames.add(permission.getObjectIdentifier()); } - + // find all the users by username UserExample userExample = new UserExample(); userExample.createCriteria().andUsernameIn(usernames); List dbUsers = userDAO.selectByExample(userExample); List userIDs = new ArrayList(); - + Map dbUserMap = new HashMap(); for(net.sourceforge.guacamole.net.auth.mysql.model.User dbUser : dbUsers) { dbUserMap.put(dbUser.getUsername(), dbUser); userIDs.add(dbUser.getUser_id()); } - + // find any user permissions that may already exist UserPermissionExample userPermissionExample = new UserPermissionExample(); userPermissionExample.createCriteria().andAffected_user_idIn(userIDs); @@ -218,35 +218,35 @@ public class UserDirectory implements Directory { for(UserPermissionKey userPermission : existingPermissions) { existingUserIDs.add(userPermission.getAffected_user_id()); } - + // delete any permissions that are not in the provided list userPermissionExample.clear(); userPermissionExample.createCriteria().andAffected_user_idNotIn(userIDs); List permissionsToDelete = userPermissionDAO.selectByExample(userPermissionExample); - + // verify that the user actually has permission to administrate every one of these users for(UserPermissionKey permissionToDelete : permissionsToDelete) { if(!administerableUsers.contains(permissionToDelete.getAffected_user_id())) throw new GuacamolePermissionException("User '" + this.user.getUsername() + "' does not have permission to administrate user " + permissionToDelete.getAffected_user_id()); } - + userPermissionDAO.deleteByExample(userPermissionExample); - + // finally, insert the new permissions for(UserPermission permission : permissions) { net.sourceforge.guacamole.net.auth.mysql.model.User dbAffectedUser = dbUserMap.get(permission.getObjectIdentifier()); if(dbAffectedUser == null) throw new GuacamoleException("User '" + permission.getObjectIdentifier() + "' not found."); - + // the permission for this user already exists, we don't need to create it again if(existingUserIDs.contains(dbAffectedUser.getUser_id())) continue; - - + + // verify that the user actually has permission to administrate every one of these users if(!administerableUsers.contains(dbAffectedUser.getUser_id())) throw new GuacamolePermissionException("User '" + this.user.getUsername() + "' does not have permission to administrate user " + dbAffectedUser.getUser_id()); - + UserPermissionKey newPermission = new UserPermissionKey(); newPermission.setAffected_user_id(dbAffectedUser.getUser_id()); newPermission.setPermission(permission.getType().name()); @@ -254,31 +254,31 @@ public class UserDirectory implements Directory { userPermissionDAO.insert(newPermission); } } - + /** * Update all the permissions having to do with connections for a given user. * @param permissions - * @param user + * @param user */ private void updateConnectionPermissions(Iterable permissions, MySQLUser user, Set administerableConnections) throws GuacamoleException { - + List connectionnames = new ArrayList(); for(ConnectionPermission permission : permissions) { connectionnames.add(permission.getObjectIdentifier()); } - + // find all the connections by connectionname ConnectionExample connectionExample = new ConnectionExample(); connectionExample.createCriteria().andConnection_nameIn(connectionnames); List dbConnections = connectionDAO.selectByExample(connectionExample); List connectionIDs = new ArrayList(); - + Map dbConnectionMap = new HashMap(); for(net.sourceforge.guacamole.net.auth.mysql.model.Connection dbConnection : dbConnections) { dbConnectionMap.put(dbConnection.getConnection_name(), dbConnection); connectionIDs.add(dbConnection.getConnection_id()); } - + // find any connection permissions that may already exist ConnectionPermissionExample connectionPermissionExample = new ConnectionPermissionExample(); connectionPermissionExample.createCriteria().andConnection_idIn(connectionIDs); @@ -287,35 +287,35 @@ public class UserDirectory implements Directory { for(ConnectionPermissionKey connectionPermission : existingPermissions) { existingConnectionIDs.add(connectionPermission.getConnection_id()); } - + // delete any permissions that are not in the provided list connectionPermissionExample.clear(); connectionPermissionExample.createCriteria().andConnection_idNotIn(connectionIDs); - + //make sure the user has permission to administrate each of these connections List connectionPermissionsToDelete = connectionPermissionDAO.selectByExample(connectionPermissionExample); - + for(ConnectionPermissionKey connectionPermissionToDelete : connectionPermissionsToDelete) { if(!administerableConnections.contains(connectionPermissionToDelete.getConnection_id())) throw new GuacamolePermissionException("User '" + this.user.getUsername() + "' does not have permission to administrate connection " + connectionPermissionToDelete.getConnection_id()); } - + connectionPermissionDAO.deleteByExample(connectionPermissionExample); - + // finally, insert the new permissions for(ConnectionPermission permission : permissions) { net.sourceforge.guacamole.net.auth.mysql.model.Connection dbConnection = dbConnectionMap.get(permission.getObjectIdentifier()); if(dbConnection == null) throw new GuacamoleException("Connection '" + permission.getObjectIdentifier() + "' not found."); - + // the permission for this connection already exists, we don't need to create it again if(existingConnectionIDs.contains(dbConnection.getConnection_id())) continue; - + if(!administerableConnections.contains(dbConnection.getConnection_id())) throw new GuacamolePermissionException("User '" + this.user.getUsername() + "' does not have permission to administrate connection " + dbConnection.getConnection_id()); - - + + ConnectionPermissionKey newPermission = new ConnectionPermissionKey(); newPermission.setConnection_id(dbConnection.getConnection_id()); newPermission.setPermission(permission.getType().name()); @@ -323,11 +323,11 @@ public class UserDirectory implements Directory { connectionPermissionDAO.insert(newPermission); } } - + /** * Update all system permissions for a given user. * @param permissions - * @param user + * @param user */ private void updateSystemPermissions(Iterable permissions, MySQLUser user) { List systemPermissionTypes = new ArrayList(); @@ -338,12 +338,12 @@ public class UserDirectory implements Directory { else if(permission instanceof UserDirectoryPermission) systemPermissionTypes.add(operation + "_USER"); } - + //delete all system permissions not in the list SystemPermissionExample systemPermissionExample = new SystemPermissionExample(); systemPermissionExample.createCriteria().andUser_idEqualTo(user.getUserID()).andPermissionNotIn(systemPermissionTypes); systemPermissionDAO.deleteByExample(systemPermissionExample); - + // find all existing system permissions systemPermissionExample.clear(); systemPermissionExample.createCriteria().andUser_idEqualTo(user.getUserID()).andPermissionIn(systemPermissionTypes); @@ -352,13 +352,13 @@ public class UserDirectory implements Directory { for(SystemPermissionKey existingPermission : existingPermissions) { existingPermissionTypes.add(existingPermission.getPermission()); } - + // finally, insert any new system permissions for this user for(String systemPermissionType : systemPermissionTypes) { - //do not insert the permission if it already exists + //do not insert the permission if it already exists if(existingPermissionTypes.contains(systemPermissionType)) continue; - + SystemPermissionKey newSystemPermission = new SystemPermissionKey(); newSystemPermission.setUser_id(user.getUserID()); newSystemPermission.setPermission(systemPermissionType); @@ -373,7 +373,7 @@ public class UserDirectory implements Directory { //update the user in the database MySQLUser mySQLUser = providerUtility.getExistingMySQLUser(object); userDAO.updateByPrimaryKey(mySQLUser.getUser()); - + //update permissions in database updatePermissions(mySQLUser); } @@ -382,34 +382,39 @@ public class UserDirectory implements Directory { @Transactional public void remove(String identifier) throws GuacamoleException { permissionCheckUtility.verifyUserDeleteAccess(this.user.getUserID(), identifier); - + MySQLUser mySQLUser = providerUtility.getExistingMySQLUser(identifier); - + //delete all the user permissions in the database deleteAllPermissions(mySQLUser); - + //delete the user in the database userDAO.deleteByPrimaryKey(mySQLUser.getUserID()); } - + /** * Delete all permissions associated with the provided user. This is only used when deleting a user. - * @param user + * @param user */ private void deleteAllPermissions(MySQLUser user) throws GuacamolePermissionException { //delete all user permissions UserPermissionExample userPermissionExample = new UserPermissionExample(); userPermissionExample.createCriteria().andUser_idEqualTo(user.getUserID()); userPermissionDAO.deleteByExample(userPermissionExample); - + //delete all connection permissions ConnectionPermissionExample connectionPermissionExample = new ConnectionPermissionExample(); connectionPermissionExample.createCriteria().andUser_idEqualTo(user.getUserID()); connectionPermissionDAO.deleteByExample(connectionPermissionExample); - + //delete all system permissions SystemPermissionExample systemPermissionExample = new SystemPermissionExample(); systemPermissionExample.createCriteria().andUser_idEqualTo(user.getUserID()); systemPermissionDAO.deleteByExample(systemPermissionExample); + + //delete all permissions that refer to this user + userPermissionExample.createCriteria(); + userPermissionExample.createCriteria().andAffected_user_idEqualTo(user.getUserID()); + userPermissionDAO.deleteByExample(userPermissionExample); } } diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/MySQLGuacamoleProperties.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/MySQLGuacamoleProperties.java index b37856a6c..10ca5525f 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/MySQLGuacamoleProperties.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/MySQLGuacamoleProperties.java @@ -35,6 +35,7 @@ * ***** END LICENSE BLOCK ***** */ package net.sourceforge.guacamole.net.auth.mysql.properties; +import net.sourceforge.guacamole.properties.BooleanGuacamoleProperty; import net.sourceforge.guacamole.properties.IntegerGuacamoleProperty; import net.sourceforge.guacamole.properties.StringGuacamoleProperty; @@ -43,12 +44,12 @@ import net.sourceforge.guacamole.properties.StringGuacamoleProperty; * @author James Muehlner */ public class MySQLGuacamoleProperties { - + /** * This class should not be instantiated. */ private MySQLGuacamoleProperties() {} - + /** * The URL of the MySQL server hosting the guacamole authentication tables. */ @@ -58,7 +59,7 @@ public class MySQLGuacamoleProperties { public String getName() { return "mysql-hostname"; } }; - + /** * The port of the MySQL server hosting the guacamole authentication tables. */ @@ -68,7 +69,7 @@ public class MySQLGuacamoleProperties { public String getName() { return "mysql-port"; } }; - + /** * The name of the MySQL database containing the guacamole authentication tables. */ @@ -78,7 +79,7 @@ public class MySQLGuacamoleProperties { public String getName() { return "mysql-database"; } }; - + /** * The username used to authenticate to the MySQL database containing the guacamole authentication tables. */ @@ -88,7 +89,7 @@ public class MySQLGuacamoleProperties { public String getName() { return "mysql-username"; } }; - + /** * The password used to authenticate to the MySQL database containing the guacamole authentication tables. */ @@ -98,4 +99,14 @@ public class MySQLGuacamoleProperties { public String getName() { return "mysql-password"; } }; + + /** + * 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() { + + @Override + public String getName() { return "mysql-disallow-simultaneous-connections"; } + + }; } diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/utility/PermissionCheckUtility.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/utility/PermissionCheckUtility.java index 07745c098..8d43206e1 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/utility/PermissionCheckUtility.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/utility/PermissionCheckUtility.java @@ -76,28 +76,28 @@ import net.sourceforge.guacamole.net.auth.permission.UserPermission; * @author James Muehlner */ public class PermissionCheckUtility { - + @Inject UserMapper userDAO; - + @Inject ConnectionMapper connectionDAO; - + @Inject UserPermissionMapper userPermissionDAO; - + @Inject ConnectionPermissionMapper connectionPermissionDAO; - + @Inject SystemPermissionMapper systemPermissionDAO; - + @Inject Provider mySQLUserProvider; - + @Inject Provider mySQLConnectionProvider; - + /** * Verifies that the user has read access to the given user. If not, throws a GuacamolePermissionException. * @param userID @@ -108,7 +108,7 @@ public class PermissionCheckUtility { if(!checkUserReadAccess(userID, affectedUserID)) throw new GuacamolePermissionException("User " + userID + " does not have read access to user " + affectedUserID); } - + /** * Verifies that the user has update access to the given user. If not, throws a GuacamolePermissionException. * @param userID @@ -119,7 +119,7 @@ public class PermissionCheckUtility { if(!checkUserUpdateAccess(userID, affectedUserID)) throw new GuacamolePermissionException("User " + userID + " does not have update access to user " + affectedUserID); } - + /** * Verifies that the user has delete access to the given user. If not, throws a GuacamolePermissionException. * @param userID @@ -130,7 +130,7 @@ public class PermissionCheckUtility { if(!checkUserDeleteAccess(userID, affectedUserID)) throw new GuacamolePermissionException("User " + userID + " does not have delete access to user " + affectedUserID); } - + /** * Verifies that the user has administer access to the given user. If not, throws a GuacamolePermissionException. * @param userID @@ -141,7 +141,7 @@ public class PermissionCheckUtility { if(!checkUserAdministerAccess(userID, affectedUserID)) throw new GuacamolePermissionException("User " + userID + " does not have administer access to user " + affectedUserID); } - + /** * Verifies that the user has read access to the given user. If not, throws a GuacamolePermissionException. * @param userID @@ -152,7 +152,7 @@ public class PermissionCheckUtility { if(!checkUserReadAccess(userID, affectedUsername)) throw new GuacamolePermissionException("User " + userID + " does not have read access to user '" + affectedUsername + "'"); } - + /** * Verifies that the user has update access to the given user. If not, throws a GuacamolePermissionException. * @param userID @@ -163,7 +163,7 @@ public class PermissionCheckUtility { if(!checkUserUpdateAccess(userID, affectedUsername)) throw new GuacamolePermissionException("User " + userID + " does not have update access to user '" + affectedUsername + "'"); } - + /** * Verifies that the user has delete access to the given user. If not, throws a GuacamolePermissionException. * @param userID @@ -174,7 +174,7 @@ public class PermissionCheckUtility { if(!checkUserDeleteAccess(userID, affectedUsername)) throw new GuacamolePermissionException("User " + userID + " does not have delete access to user '" + affectedUsername + "'"); } - + /** * Verifies that the user has administer access to the given user. If not, throws a GuacamolePermissionException. * @param userID @@ -185,7 +185,7 @@ public class PermissionCheckUtility { if(!checkUserAdministerAccess(userID, affectedUsername)) throw new GuacamolePermissionException("User " + userID + " does not have administer access to user '" + affectedUsername + "'"); } - + /** * Checks if the user has read access to the given user. * @param userID @@ -195,7 +195,7 @@ public class PermissionCheckUtility { public boolean checkUserReadAccess(int userID, int affectedUserID) { return checkUserAccess(userID, affectedUserID, MySQLConstants.USER_READ); } - + /** * Checks if the user has update access to the given user. * @param userID @@ -205,7 +205,7 @@ public class PermissionCheckUtility { public boolean checkUserUpdateAccess(int userID, int affectedUserID) { return checkUserAccess(userID, affectedUserID, MySQLConstants.USER_UPDATE); } - + /** * Checks if the user has delete access to the given user. * @param userID @@ -215,7 +215,7 @@ public class PermissionCheckUtility { public boolean checkUserDeleteAccess(int userID, int affectedUserID) { return checkUserAccess(userID, affectedUserID, MySQLConstants.USER_DELETE); } - + /** * Checks if the user has administer access to the given user. * @param userID @@ -225,7 +225,7 @@ public class PermissionCheckUtility { public boolean checkUserAdministerAccess(int userID, int affectedUserID) { return checkUserAccess(userID, affectedUserID, MySQLConstants.USER_ADMINISTER); } - + /** * Checks if the user has read access to the given user. * @param userID @@ -235,7 +235,7 @@ public class PermissionCheckUtility { public boolean checkUserReadAccess(int userID, String affectedUsername) { return checkUserAccess(userID, affectedUsername, MySQLConstants.USER_READ); } - + /** * Checks if the user has update access to the given user. * @param userID @@ -245,7 +245,7 @@ public class PermissionCheckUtility { public boolean checkUserUpdateAccess(int userID, String affectedUsername) { return checkUserAccess(userID, affectedUsername, MySQLConstants.USER_UPDATE); } - + /** * Checks if the user has delete access to the given user. * @param userID @@ -255,7 +255,7 @@ public class PermissionCheckUtility { public boolean checkUserDeleteAccess(int userID, String affectedUsername) { return checkUserAccess(userID, affectedUsername, MySQLConstants.USER_DELETE); } - + /** * Checks if the user has administer access to the given user. * @param userID @@ -265,28 +265,28 @@ public class PermissionCheckUtility { public boolean checkUserAdministerAccess(int userID, String affectedUsername) { return checkUserAccess(userID, affectedUsername, MySQLConstants.USER_ADMINISTER); } - + /** * Check if the user has the selected type of access to the affected user. * @param userID * @param affectedUsername * @param permissionType - * @return + * @return */ private boolean checkUserAccess(int userID, String affectedUsername, String permissionType) { User affectedUser = getUser(affectedUsername); if(affectedUser != null) return checkUserAccess(userID, affectedUser.getUser_id(), permissionType); - + return false; } - + /** * Check if the user has the selected type of access to the affected user. * @param userID * @param affectedUserID * @param permissionType - * @return + * @return */ private boolean checkUserAccess(int userID, Integer affectedUserID, String permissionType) { UserPermissionExample example = new UserPermissionExample(); @@ -294,7 +294,7 @@ public class PermissionCheckUtility { int count = userPermissionDAO.countByExample(example); return count > 0; } - + /** * Find the list of all user IDs a user has permission to administer. * @param userID @@ -303,7 +303,7 @@ public class PermissionCheckUtility { public Set getAdministerableUserIDs(int userID) { return getUserIDs(userID, MySQLConstants.USER_ADMINISTER); } - + /** * Find the list of all user IDs a user has permission to delete. * @param userID @@ -312,7 +312,7 @@ public class PermissionCheckUtility { public Set getDeletableUserIDs(int userID) { return getUserIDs(userID, MySQLConstants.USER_DELETE); } - + /** * Find the list of all user IDs a user has permission to write. * @param userID @@ -321,7 +321,7 @@ public class PermissionCheckUtility { public Set getUpdateableUserIDs(int userID) { return getUserIDs(userID, MySQLConstants.USER_UPDATE); } - + /** * Find the list of all user IDs a user has permission to read. * @param userID @@ -330,7 +330,7 @@ public class PermissionCheckUtility { public Set getReadableUserIDs(int userID) { return getUserIDs(userID, MySQLConstants.USER_READ); } - + /** * Find the list of all users a user has permission to administer. * @param userID @@ -339,7 +339,7 @@ public class PermissionCheckUtility { public Set getAdministerableUsers(int userID) { return getUsers(userID, MySQLConstants.USER_ADMINISTER); } - + /** * Find the list of all users a user has permission to delete. * @param userID @@ -348,7 +348,7 @@ public class PermissionCheckUtility { public Set getDeletableUsers(int userID) { return getUsers(userID, MySQLConstants.USER_DELETE); } - + /** * Find the list of all users a user has permission to write. * @param userID @@ -357,7 +357,7 @@ public class PermissionCheckUtility { public Set getUpdateableUsers(int userID) { return getUsers(userID, MySQLConstants.USER_UPDATE); } - + /** * Find the list of all users a user has permission to read. * @param userID @@ -366,7 +366,7 @@ public class PermissionCheckUtility { public Set getReadableUsers(int userID) { return getUsers(userID, MySQLConstants.USER_READ); } - + /** * Find the list of all users a user has permission to. * The access type is defined by permissionType. @@ -385,10 +385,10 @@ public class PermissionCheckUtility { mySQLUser.init(affectedUser); affectedUsers.add(mySQLUser); } - + return affectedUsers; } - + /** * Find the list of the IDs of all users a user has permission to. * The access type is defined by permissionType. @@ -403,10 +403,10 @@ public class PermissionCheckUtility { List userPermissions = userPermissionDAO.selectByExample(example); for(UserPermissionKey permission : userPermissions) userIDs.add(permission.getAffected_user_id()); - + return userIDs; } - + /** * Verifies that the user has read access to the given connection. If not, throws a GuacamolePermissionException. * @param userID @@ -417,7 +417,7 @@ public class PermissionCheckUtility { if(!checkConnectionReadAccess(userID, affectedConnectionID)) throw new GuacamolePermissionException("User " + userID + " does not have read access to connection " + affectedConnectionID); } - + /** * Verifies that the user has update access to the given connection. If not, throws a GuacamolePermissionException. * @param userID @@ -428,7 +428,7 @@ public class PermissionCheckUtility { if(!checkConnectionUpdateAccess(userID, affectedConnectionID)) throw new GuacamolePermissionException("User " + userID + " does not have update access to connection " + affectedConnectionID); } - + /** * Verifies that the user has delete access to the given connection. If not, throws a GuacamolePermissionException. * @param userID @@ -439,7 +439,7 @@ public class PermissionCheckUtility { if(!checkConnectionDeleteAccess(userID, affectedConnectionID)) throw new GuacamolePermissionException("User " + userID + " does not have delete access to connection " + affectedConnectionID); } - + /** * Verifies that the user has administer access to the given connection. If not, throws a GuacamolePermissionException. * @param userID @@ -450,7 +450,7 @@ public class PermissionCheckUtility { if(!checkConnectionAdministerAccess(userID, affectedConnectionID)) throw new GuacamolePermissionException("User " + userID + " does not have administer access to connection " + affectedConnectionID); } - + /** * Verifies that the user has read access to the given connection. If not, throws a GuacamolePermissionException. * @param userID @@ -461,7 +461,7 @@ public class PermissionCheckUtility { if(!checkConnectionReadAccess(userID, affectedConnectionName)) throw new GuacamolePermissionException("User " + userID + " does not have read access to connection '" + affectedConnectionName + "'"); } - + /** * Verifies that the user has update access to the given connection. If not, throws a GuacamolePermissionException. * @param userID @@ -472,7 +472,7 @@ public class PermissionCheckUtility { if(!checkConnectionUpdateAccess(userID, affectedConnectionName)) throw new GuacamolePermissionException("User " + userID + " does not have update access to connection '" + affectedConnectionName + "'"); } - + /** * Verifies that the user has delete access to the given connection. If not, throws a GuacamolePermissionException. * @param userID @@ -483,7 +483,7 @@ public class PermissionCheckUtility { if(!checkConnectionDeleteAccess(userID, affectedConnectionName)) throw new GuacamolePermissionException("User " + userID + " does not have delete access to connection '" + affectedConnectionName + "'"); } - + /** * Verifies that the user has administer access to the given connection. If not, throws a GuacamolePermissionException. * @param userID @@ -494,7 +494,7 @@ public class PermissionCheckUtility { if(!checkConnectionAdministerAccess(userID, affectedConnectionName)) throw new GuacamolePermissionException("User " + userID + " does not have administer access to connection '" + affectedConnectionName + "'"); } - + /** * Checks if the user has read access to the given connection. * @param userID @@ -504,7 +504,7 @@ public class PermissionCheckUtility { public boolean checkConnectionReadAccess(int userID, int affectedConnectionID) { return checkConnectionAccess(userID, affectedConnectionID, MySQLConstants.CONNECTION_READ); } - + /** * Checks if the user has update access to the given connection. * @param userID @@ -514,7 +514,7 @@ public class PermissionCheckUtility { public boolean checkConnectionUpdateAccess(int userID, int affectedConnectionID) { return checkConnectionAccess(userID, affectedConnectionID, MySQLConstants.CONNECTION_UPDATE); } - + /** * Checks if the user has delete access to the given connection. * @param userID @@ -524,7 +524,7 @@ public class PermissionCheckUtility { public boolean checkConnectionDeleteAccess(int userID, int affectedConnectionID) { return checkConnectionAccess(userID, affectedConnectionID, MySQLConstants.CONNECTION_DELETE); } - + /** * Checks if the user has administer access to the given connection. * @param userID @@ -534,7 +534,7 @@ public class PermissionCheckUtility { public boolean checkConnectionAdministerAccess(int userID, int affectedConnectionID) { return checkConnectionAccess(userID, affectedConnectionID, MySQLConstants.CONNECTION_ADMINISTER); } - + /** * Checks if the user has read access to the given connection. * @param userID @@ -544,7 +544,7 @@ public class PermissionCheckUtility { public boolean checkConnectionReadAccess(int userID, String affectedConnectionName) { return checkConnectionAccess(userID, affectedConnectionName, MySQLConstants.CONNECTION_READ); } - + /** * Checks if the user has update access to the given connection. * @param userID @@ -554,7 +554,7 @@ public class PermissionCheckUtility { public boolean checkConnectionUpdateAccess(int userID, String affectedConnectionName) { return checkConnectionAccess(userID, affectedConnectionName, MySQLConstants.CONNECTION_UPDATE); } - + /** * Checks if the user has delete access to the given connection. * @param userID @@ -564,7 +564,7 @@ public class PermissionCheckUtility { public boolean checkConnectionDeleteAccess(int userID, String affectedConnectionname) { return checkConnectionAccess(userID, affectedConnectionname, MySQLConstants.CONNECTION_DELETE); } - + /** * Checks if the user has administer access to the given connection. * @param userID @@ -574,28 +574,28 @@ public class PermissionCheckUtility { public boolean checkConnectionAdministerAccess(int userID, String affectedConnectionName) { return checkConnectionAccess(userID, affectedConnectionName, MySQLConstants.CONNECTION_ADMINISTER); } - + /** * Check if the user has the selected type of access to the affected connection. * @param connectionID * @param affectedConnectionname * @param permissionType - * @return + * @return */ private boolean checkConnectionAccess(int userID, String affectedConnectionName, String permissionType) { Connection connection = getConnection(affectedConnectionName); if(connection != null) return checkConnectionAccess(userID, connection.getConnection_id(), permissionType); - + return false; } - + /** * Check if the user has the selected type of access to the affected connection. * @param connectionID * @param affectedConnectionID * @param permissionType - * @return + * @return */ private boolean checkConnectionAccess(int userID, Integer affectedConnectionID, String permissionType) { ConnectionPermissionExample example = new ConnectionPermissionExample(); @@ -603,7 +603,7 @@ public class PermissionCheckUtility { int count = connectionPermissionDAO.countByExample(example); return count > 0; } - + /** * Find the list of all connection IDs a user has permission to administer. * @param userID @@ -612,7 +612,7 @@ public class PermissionCheckUtility { public Set getAdministerableConnectionIDs(int userID) { return getConnectionIDs(userID, MySQLConstants.CONNECTION_ADMINISTER); } - + /** * Find the list of all connection IDs a user has permission to delete. * @param userID @@ -621,7 +621,7 @@ public class PermissionCheckUtility { public Set getDeletableConnectionIDs(int userID) { return getConnectionIDs(userID, MySQLConstants.CONNECTION_DELETE); } - + /** * Find the list of all connection IDs a user has permission to write. * @param userID @@ -630,7 +630,7 @@ public class PermissionCheckUtility { public Set getUpdateableConnectionIDs(int userID) { return getConnectionIDs(userID, MySQLConstants.CONNECTION_UPDATE); } - + /** * Find the list of all connection IDs a user has permission to read. * @param userID @@ -639,7 +639,7 @@ public class PermissionCheckUtility { public Set getReadableConnectionIDs(int userID) { return getConnectionIDs(userID, MySQLConstants.CONNECTION_READ); } - + /** * Find the list of all connections a user has permission to administer. * @param userID @@ -648,7 +648,7 @@ public class PermissionCheckUtility { public Set getAdministerableConnections(int userID) { return getConnections(userID, MySQLConstants.CONNECTION_ADMINISTER); } - + /** * Find the list of all connections a user has permission to delete. * @param userID @@ -657,7 +657,7 @@ public class PermissionCheckUtility { public Set getDeletableConnections(int userID) { return getConnections(userID, MySQLConstants.CONNECTION_DELETE); } - + /** * Find the list of all connections a user has permission to write. * @param userID @@ -666,7 +666,7 @@ public class PermissionCheckUtility { public Set getUpdateableConnections(int userID) { return getConnections(userID, MySQLConstants.CONNECTION_UPDATE); } - + /** * Find the list of all connections a user has permission to read. * @param userID @@ -675,7 +675,7 @@ public class PermissionCheckUtility { public Set getReadableConnections(int userID) { return getConnections(userID, MySQLConstants.CONNECTION_READ); } - + /** * Find the list of all connections a user has permission to. * The access type is defined by permissionType. @@ -694,10 +694,10 @@ public class PermissionCheckUtility { mySQLConnection.init(affectedConnection); affectedConnections.add(mySQLConnection); } - + return affectedConnections; } - + /** * Find the list of the IDs of all connections a user has permission to. * The access type is defined by permissionType. @@ -712,43 +712,43 @@ public class PermissionCheckUtility { List connectionPermissions = connectionPermissionDAO.selectByExample(example); for(ConnectionPermissionKey permission : connectionPermissions) connectionIDs.add(permission.getConnection_id()); - + return connectionIDs; } - + public void verifyCreateUserPermission(int userID) throws GuacamolePermissionException { if(!checkCreateUserPermission(userID)) throw new GuacamolePermissionException("User " + userID + " does not have permission to create users."); } - + public void verifyCreateConnectionPermission(int userID) throws GuacamolePermissionException { if(!checkCreateConnectionPermission(userID)) throw new GuacamolePermissionException("User " + userID + " does not have permission to create connections."); } - + /** * Check if the user has the permission to create users. * @param userID - * @return + * @return */ public boolean checkCreateUserPermission(int userID) { return checkSystemPermission(userID, MySQLConstants.SYSTEM_USER_CREATE); } - + /** * Check if the user has the permission to create connections. * @param userID - * @return + * @return */ public boolean checkCreateConnectionPermission(int userID) { return checkSystemPermission(userID, MySQLConstants.SYSTEM_CONNECTION_CREATE); } - + /** * Check if the user has the selected system permission. * @param userID - * @param systemPermissionType - * @return + * @param systemPermissionType + * @return */ private boolean checkSystemPermission(int userID, String systemPermissionType) { SystemPermissionExample example = new SystemPermissionExample(); @@ -756,11 +756,11 @@ public class PermissionCheckUtility { int count = systemPermissionDAO.countByExample(example); return count > 0; } - + /** * Get a connection object by name. * @param name - * @return + * @return */ private Connection getConnection(String name) { ConnectionExample example = new ConnectionExample(); @@ -768,14 +768,14 @@ public class PermissionCheckUtility { List connections = connectionDAO.selectByExample(example); if(connections.isEmpty()) return null; - + return connections.get(0); } - + /** * Get a user object by username. * @param userName - * @return + * @return */ private User getUser(String username) { UserExample example = new UserExample(); @@ -783,18 +783,18 @@ public class PermissionCheckUtility { List users = userDAO.selectByExample(example); if(users.isEmpty()) return null; - + return users.get(0); } - + /** * Get all permissions a given user has. * @param userID - * @return all permissions a user has. + * @return all permissions a user has. */ public Set getAllPermissions(int userID) { Set allPermissions = new HashSet(); - + // first, user permissions UserPermissionExample userPermissionExample = new UserPermissionExample(); userPermissionExample.createCriteria().andUser_idEqualTo(userID); @@ -803,7 +803,7 @@ public class PermissionCheckUtility { for(UserPermissionKey userPermission : userPermissions) { affectedUserIDs.add(userPermission.getAffected_user_id()); } - + UserExample userExample = new UserExample(); userExample.createCriteria().andUser_idIn(affectedUserIDs); List users = userDAO.selectByExample(userExample); @@ -811,7 +811,7 @@ public class PermissionCheckUtility { for(User user : users) { userMap.put(user.getUser_id(), user); } - + for(UserPermissionKey userPermission : userPermissions) { User affectedUser = userMap.get(userPermission.getAffected_user_id()); UserPermission newPermission = new UserPermission( @@ -820,7 +820,7 @@ public class PermissionCheckUtility { ); allPermissions.add(newPermission); } - + //secondly, connection permissions ConnectionPermissionExample connectionPermissionExample = new ConnectionPermissionExample(); connectionPermissionExample.createCriteria().andUser_idEqualTo(userID); @@ -829,7 +829,7 @@ public class PermissionCheckUtility { for(ConnectionPermissionKey connectionPermission : connectionPermissions) { affectedConnectionIDs.add(connectionPermission.getConnection_id()); } - + ConnectionExample connectionExample = new ConnectionExample(); connectionExample.createCriteria().andConnection_idIn(affectedConnectionIDs); List connections = connectionDAO.selectByExample(connectionExample); @@ -837,7 +837,7 @@ public class PermissionCheckUtility { for(Connection connection : connections) { connectionMap.put(connection.getConnection_id(), connection); } - + for(ConnectionPermissionKey connectionPermission : connectionPermissions) { Connection affectedConnection = connectionMap.get(connectionPermission.getConnection_id()); ConnectionPermission newPermission = new ConnectionPermission( @@ -846,7 +846,7 @@ public class PermissionCheckUtility { ); allPermissions.add(newPermission); } - + //and finally, system permissions SystemPermissionExample systemPermissionExample = new SystemPermissionExample(); systemPermissionExample.createCriteria().andUser_idEqualTo(userID); @@ -857,11 +857,11 @@ public class PermissionCheckUtility { newPermission = new UserDirectoryPermission(UserDirectoryPermission.Type.CREATE); else if(systemPermission.getPermission().equals(MySQLConstants.SYSTEM_CONNECTION_CREATE)) newPermission = new ConnectionDirectoryPermission(ConnectionDirectoryPermission.Type.CREATE); - + if(newPermission != null) allPermissions.add(newPermission); } - + return allPermissions; } } diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/utility/ProviderUtility.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/utility/ProviderUtility.java index f2b91428f..a449e7154 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/utility/ProviderUtility.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/utility/ProviderUtility.java @@ -44,6 +44,7 @@ import net.sourceforge.guacamole.net.auth.Connection; import net.sourceforge.guacamole.net.auth.User; import net.sourceforge.guacamole.net.auth.mysql.MySQLConnection; import net.sourceforge.guacamole.net.auth.mysql.MySQLConnectionRecord; +import net.sourceforge.guacamole.net.auth.mysql.MySQLGuacamoleSocket; import net.sourceforge.guacamole.net.auth.mysql.MySQLUser; import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionHistoryMapper; import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionMapper; @@ -53,9 +54,10 @@ import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionHistory; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionHistoryExample; import net.sourceforge.guacamole.net.auth.mysql.model.UserExample; import net.sourceforge.guacamole.net.auth.mysql.model.UserWithBLOBs; +import net.sourceforge.guacamole.protocol.ConfiguredGuacamoleSocket; /** - * Provides convenient provider methods for MySQLUser, MySQLConnection, and MySQLConnctionRecord objects. + * Provides convenient provider methods for MySQL specific implementations. * @author James Muehlner */ public class ProviderUtility { @@ -77,6 +79,9 @@ public class ProviderUtility { @Inject Provider mySQLConnectionRecordProvider; + @Inject + Provider mySQLGuacamoleSocketProvider; + /** * Create a new user based on the provided object. * @param user @@ -205,6 +210,8 @@ public class ProviderUtility { public List getExistingMySQLConnectionRecords(Integer connectionID) { ConnectionHistoryExample example = new ConnectionHistoryExample(); example.createCriteria().andConnection_idEqualTo(connectionID); + // we want to return the newest records first + example.setOrderByClause("start_date DESC"); List connectionHistories = connectionHistoryDAO.selectByExample(example); List connectionRecords = new ArrayList(); for(ConnectionHistory history : connectionHistories) { @@ -223,4 +230,16 @@ public class ProviderUtility { record.init(history); return record; } + + /** + * Create a MySQLGuacamoleSocket using the provided ConfiguredGuacamoleSocket and connection ID. + * @param socket + * @param connectionID + * @return + */ + public MySQLGuacamoleSocket getMySQLGuacamoleSocket(ConfiguredGuacamoleSocket socket, int connectionID) { + MySQLGuacamoleSocket mySQLGuacamoleSocket = mySQLGuacamoleSocketProvider.get(); + mySQLGuacamoleSocket.init(socket, connectionID); + return mySQLGuacamoleSocket; + } } diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/utility/Sha256PasswordEncryptionUtility.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/utility/Sha256PasswordEncryptionUtility.java index a46485695..c191f60ca 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/utility/Sha256PasswordEncryptionUtility.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/utility/Sha256PasswordEncryptionUtility.java @@ -35,7 +35,6 @@ * ***** END LICENSE BLOCK ***** */ package net.sourceforge.guacamole.net.auth.mysql.utility; -import com.google.common.base.Preconditions; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -51,18 +50,12 @@ public class Sha256PasswordEncryptionUtility implements PasswordEncryptionUtilit @Override public boolean checkCredentials(Credentials credentials, byte[] dbPasswordHash, String dbUsername, byte[] dbSalt) { - Preconditions.checkNotNull(credentials); - Preconditions.checkNotNull(dbPasswordHash); - Preconditions.checkNotNull(dbUsername); - Preconditions.checkNotNull(dbSalt); byte[] passwordBytes = createPasswordHash(credentials.getPassword(), dbSalt); return Arrays.equals(passwordBytes, dbPasswordHash); } @Override public byte[] createPasswordHash(String password, byte[] salt) { - Preconditions.checkNotNull(password); - Preconditions.checkNotNull(salt); try { MessageDigest md = MessageDigest.getInstance("SHA-256");