diff --git a/extensions/guacamole-auth-mysql/LICENSE b/extensions/guacamole-auth-jdbc/LICENSE
similarity index 100%
rename from extensions/guacamole-auth-mysql/LICENSE
rename to extensions/guacamole-auth-jdbc/LICENSE
diff --git a/extensions/guacamole-auth-jdbc/README b/extensions/guacamole-auth-jdbc/README
new file mode 100644
index 000000000..d4fa250aa
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/README
@@ -0,0 +1,102 @@
+
+------------------------------------------------------------
+ About this README
+------------------------------------------------------------
+
+This README is intended to provide quick and to-the-point documentation for
+technical users intending to compile parts of Guacamole themselves.
+
+Distribution-specific packages are available from the files section of the main
+project page:
+
+ http://sourceforge.net/projects/guacamole/files/
+
+Distribution-specific documentation is provided on the Guacamole wiki:
+
+ http://guac-dev.org/
+
+
+------------------------------------------------------------
+ What is guacamole-auth-jdbc?
+------------------------------------------------------------
+
+guacamole-auth-jdbc is a Java library for use with the Guacamole web
+application to provide database-driven authentication.
+
+guacamole-auth-jdbc provides multiple authentication provider implementations
+which each provide a support for a different database. These authentication
+providers can be set in guacamole.properties to allow authentication of
+Guacamole users through that type of database.
+
+Schema files are provided to create the required tables in your database of
+choice.
+
+
+------------------------------------------------------------
+ Compiling and installing guacamole-auth-jdbc
+------------------------------------------------------------
+
+guacamole-auth-jdbc is built using Maven. Building guacamole-auth-jdbc compiles
+all classes and packages them into a redistributable .tar.gz archive. This
+archive contains multiple .jar files, each of this corresponds to a
+database-specific authentication provider implementation that can be installed
+in the library directory configured in guacamole.properties.
+
+1) Run mvn package
+
+ $ mvn package
+
+ Maven will download any needed dependencies for building the .jar file.
+ Once all dependencies have been downloaded, the .jar file will be
+ created in the target/ subdirectory of the current directory.
+
+4) Extract the .tar.gz file now present in the target/ directory, and
+ place the .jar files in the extracted lib/ subdirectory in the library
+ directory specified in guacamole.properties.
+
+ You will likely need to do this as root.
+
+ If you do not have a library directory configured in your
+ guacamole.properties, you will need to specify one. The directory
+ is specified using the "lib-directory" property.
+
+5) Set up your MySQL database to authenticate Guacamole users
+
+ A schema file is provided in the schema directory for creating
+ the guacamole authentication tables in your MySQL database.
+
+ Additionally, a script is provided to create a default admin user
+ with username 'guacadmin' and password 'guacadmin'. This user can
+ be used to set up any other connections and users.
+
+6) Configure guacamole.properties for your database
+
+ There are additional properties required by JDBC drivers which must
+ be added/changed in your guacamole.properties. These parameters are
+ specific to the database being used.
+
+ For MySQL, the following properties are available:
+
+ # Database connection configuration
+ mysql-hostname: database.host.name
+ mysql-port: 3306
+ mysql-database: guacamole.database.name
+ mysql-username: user
+ mysql-password: pass
+
+ Optionally, the authentication provider can be configured
+ not to allow multiple users to use the same connection
+ at the same time:
+
+ mysql-disallow-simultaneous-connections: true
+
+
+------------------------------------------------------------
+ Reporting problems
+------------------------------------------------------------
+
+Please report any bugs encountered by opening a new issue in the JIRA system
+hosted at:
+
+ http://glyptodon.org/jira/
+
diff --git a/extensions/guacamole-auth-mysql/.gitignore b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/.gitignore
similarity index 100%
rename from extensions/guacamole-auth-mysql/.gitignore
rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/.gitignore
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml
new file mode 100644
index 000000000..40ca67bee
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml
@@ -0,0 +1,82 @@
+
+
+ 4.0.0
+ org.glyptodon.guacamole
+ guacamole-auth-jdbc-base
+ jar
+ guacamole-auth-jdbc-base
+ http://guac-dev.org/
+
+
+ UTF-8
+
+
+
+ org.glyptodon.guacamole
+ guacamole-auth-jdbc
+ 0.9.5
+ ../../
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.6
+ 1.6
+
+
+
+
+
+
+
+
+
+
+ org.glyptodon.guacamole
+ guacamole-ext
+ provided
+
+
+
+
+ org.slf4j
+ slf4j-api
+ 1.7.7
+
+
+
+
+ org.mybatis
+ mybatis
+ 3.2.8
+
+
+
+
+ org.mybatis
+ mybatis-guice
+ 3.6
+
+
+
+
+ com.google.inject
+ guice
+ 3.0
+
+
+ com.google.inject.extensions
+ guice-multibindings
+ 3.0
+
+
+
+
+
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
new file mode 100644
index 000000000..31e9c6389
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
@@ -0,0 +1,143 @@
+/*
+ * 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.auth.jdbc.user.UserContext;
+import org.glyptodon.guacamole.auth.jdbc.connectiongroup.RootConnectionGroup;
+import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
+import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ConnectionGroupDirectory;
+import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionDirectory;
+import org.glyptodon.guacamole.auth.jdbc.connection.ModeledGuacamoleConfiguration;
+import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
+import org.glyptodon.guacamole.auth.jdbc.permission.SystemPermissionSet;
+import org.glyptodon.guacamole.auth.jdbc.user.ModeledUser;
+import org.glyptodon.guacamole.auth.jdbc.user.UserDirectory;
+import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ConnectionGroupMapper;
+import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionMapper;
+import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionRecordMapper;
+import org.glyptodon.guacamole.auth.jdbc.connection.ParameterMapper;
+import org.glyptodon.guacamole.auth.jdbc.permission.SystemPermissionMapper;
+import org.glyptodon.guacamole.auth.jdbc.user.UserMapper;
+import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ConnectionGroupService;
+import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionService;
+import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService;
+import org.glyptodon.guacamole.auth.jdbc.security.PasswordEncryptionService;
+import org.glyptodon.guacamole.auth.jdbc.security.SHA256PasswordEncryptionService;
+import org.glyptodon.guacamole.auth.jdbc.security.SaltService;
+import org.glyptodon.guacamole.auth.jdbc.security.SecureRandomSaltService;
+import org.glyptodon.guacamole.auth.jdbc.permission.SystemPermissionService;
+import org.glyptodon.guacamole.auth.jdbc.socket.UnrestrictedGuacamoleSocketService;
+import org.glyptodon.guacamole.auth.jdbc.user.UserService;
+import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
+import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionGroupPermissionMapper;
+import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionGroupPermissionService;
+import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionGroupPermissionSet;
+import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionPermissionMapper;
+import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionPermissionService;
+import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionPermissionSet;
+import org.glyptodon.guacamole.auth.jdbc.permission.UserPermissionMapper;
+import org.glyptodon.guacamole.auth.jdbc.permission.UserPermissionService;
+import org.glyptodon.guacamole.auth.jdbc.permission.UserPermissionSet;
+import org.glyptodon.guacamole.environment.Environment;
+import org.mybatis.guice.MyBatisModule;
+import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider;
+
+/**
+ * Guice module which configures the injections used by the JDBC authentication
+ * provider base. This module MUST be included in the Guice injector, or
+ * authentication providers based on JDBC will not function.
+ *
+ * @author Michael Jumper
+ * @author James Muehlner
+ */
+public class JDBCAuthenticationProviderModule extends MyBatisModule {
+
+ /**
+ * The environment of the Guacamole server.
+ */
+ private final Environment environment;
+
+ /**
+ * Creates a new JDBC authentication provider module that configures the
+ * various injected base classes using the given environment.
+ *
+ * @param environment
+ * The environment to use to configure injected classes.
+ */
+ public JDBCAuthenticationProviderModule(Environment environment) {
+ this.environment = environment;
+ }
+
+ @Override
+ protected void initialize() {
+
+ // Datasource
+ bindDataSourceProviderType(PooledDataSourceProvider.class);
+
+ // Transaction factory
+ bindTransactionFactoryType(JdbcTransactionFactory.class);
+
+ // Add MyBatis mappers
+ addMapperClass(ConnectionMapper.class);
+ addMapperClass(ConnectionGroupMapper.class);
+ addMapperClass(ConnectionGroupPermissionMapper.class);
+ addMapperClass(ConnectionPermissionMapper.class);
+ addMapperClass(ConnectionRecordMapper.class);
+ addMapperClass(ParameterMapper.class);
+ addMapperClass(SystemPermissionMapper.class);
+ addMapperClass(UserMapper.class);
+ addMapperClass(UserPermissionMapper.class);
+
+ // Bind core implementations of guacamole-ext classes
+ bind(Environment.class).toInstance(environment);
+ bind(ConnectionDirectory.class);
+ bind(ConnectionGroupDirectory.class);
+ bind(ConnectionGroupPermissionSet.class);
+ bind(ConnectionPermissionSet.class);
+ bind(ModeledConnection.class);
+ bind(ModeledConnectionGroup.class);
+ bind(ModeledGuacamoleConfiguration.class);
+ bind(ModeledUser.class);
+ bind(RootConnectionGroup.class);
+ bind(SystemPermissionSet.class);
+ bind(UserContext.class);
+ bind(UserDirectory.class);
+ bind(UserPermissionSet.class);
+
+ // Bind services
+ bind(ConnectionGroupPermissionService.class);
+ bind(ConnectionGroupService.class);
+ bind(ConnectionPermissionService.class);
+ bind(ConnectionService.class);
+ bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class);
+ bind(SaltService.class).to(SecureRandomSaltService.class);
+ bind(SystemPermissionService.class);
+ bind(UserPermissionService.class);
+ bind(UserService.class);
+
+ // Bind appropriate socket service based on policy
+ bind(GuacamoleSocketService.class).to(UnrestrictedGuacamoleSocketService.class);
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/DirectoryObject.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/DirectoryObject.java
new file mode 100644
index 000000000..8568d8995
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/DirectoryObject.java
@@ -0,0 +1,49 @@
+/*
+ * 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.base;
+
+import org.glyptodon.guacamole.net.auth.Identifiable;
+
+/**
+ * Common base class for objects that will ultimately be made available through
+ * the Directory class. All such objects will need the same base set of queries
+ * to fulfill the needs of the Directory class.
+ *
+ * @author Michael Jumper
+ * @param
+ * The type of model object that corresponds to this object.
+ */
+public abstract class DirectoryObject
+ extends ModeledObject implements Identifiable {
+
+ @Override
+ public String getIdentifier() {
+ return getModel().getIdentifier();
+ }
+
+ @Override
+ public void setIdentifier(String identifier) {
+ getModel().setIdentifier(identifier);
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/DirectoryObjectMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/DirectoryObjectMapper.java
new file mode 100644
index 000000000..d63cf3814
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/DirectoryObjectMapper.java
@@ -0,0 +1,140 @@
+/*
+ * 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.base;
+
+import java.util.Collection;
+import java.util.Set;
+import org.glyptodon.guacamole.auth.jdbc.user.UserModel;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * Common interface for objects that will ultimately be made available through
+ * the Directory class. All such objects will need the same base set of queries
+ * to fulfill the needs of the Directory class.
+ *
+ * @author Michael Jumper
+ * @param
+ * The type of object contained within the directory whose objects are
+ * mapped by this mapper.
+ */
+public interface DirectoryObjectMapper {
+
+ /**
+ * Selects the identifiers of all objects, regardless of whether they
+ * are readable by any particular user. This should only be called on
+ * behalf of a system administrator. If identifiers are needed by a non-
+ * administrative user who must have explicit read rights, use
+ * selectReadableIdentifiers() instead.
+ *
+ * @return
+ * A Set containing all identifiers of all objects.
+ */
+ Set selectIdentifiers();
+
+ /**
+ * Selects the identifiers of all objects that are explicitly readable by
+ * the given user. If identifiers are needed by a system administrator
+ * (who, by definition, does not need explicit read rights), use
+ * selectIdentifiers() instead.
+ *
+ * @param user
+ * The user whose permissions should determine whether an identifier
+ * is returned.
+ *
+ * @return
+ * A Set containing all identifiers of all readable objects.
+ */
+ Set selectReadableIdentifiers(@Param("user") UserModel user);
+
+ /**
+ * Selects all objects which have the given identifiers. If an identifier
+ * has no corresponding object, it will be ignored. This should only be
+ * called on behalf of a system administrator. If objects are needed by a
+ * non-administrative user who must have explicit read rights, use
+ * selectReadable() instead.
+ *
+ * @param identifiers
+ * The identifiers of the objects to return.
+ *
+ * @return
+ * A Collection of all objects having the given identifiers.
+ */
+ Collection select(@Param("identifiers") Collection identifiers);
+
+ /**
+ * Selects all objects which have the given identifiers and are explicitly
+ * readably by the given user. If an identifier has no corresponding
+ * object, or the corresponding object is unreadable, it will be ignored.
+ * If objects are needed by a system administrator (who, by definition,
+ * does not need explicit read rights), use select() instead.
+ *
+ * @param user
+ * The user whose permissions should determine whether an object
+ * is returned.
+ *
+ * @param identifiers
+ * The identifiers of the objects to return.
+ *
+ * @return
+ * A Collection of all objects having the given identifiers.
+ */
+ Collection selectReadable(@Param("user") UserModel user,
+ @Param("identifiers") Collection identifiers);
+
+ /**
+ * Inserts the given object into the database. If the object already
+ * exists, this will result in an error.
+ *
+ * @param object
+ * The object to insert.
+ *
+ * @return
+ * The number of rows inserted.
+ */
+ int insert(@Param("object") ModelType object);
+
+ /**
+ * Deletes the given object into the database. If the object does not
+ * exist, this operation has no effect.
+ *
+ * @param identifier
+ * The identifier of the object to delete.
+ *
+ * @return
+ * The number of rows deleted.
+ */
+ int delete(@Param("identifier") String identifier);
+
+ /**
+ * Updates the given existing object in the database. If the object does
+ * not actually exist, this operation has no effect.
+ *
+ * @param object
+ * The object to update.
+ *
+ * @return
+ * The number of rows updated.
+ */
+ int update(@Param("object") ModelType object);
+
+}
\ No newline at end of file
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/DirectoryObjectService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/DirectoryObjectService.java
new file mode 100644
index 000000000..fc2bdb331
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/DirectoryObjectService.java
@@ -0,0 +1,490 @@
+/*
+ * Copyright (C) 2013 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.base;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.GuacamoleSecurityException;
+import org.glyptodon.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
+import org.glyptodon.guacamole.auth.jdbc.permission.ObjectPermissionModel;
+import org.glyptodon.guacamole.auth.jdbc.user.UserModel;
+import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
+import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
+
+/**
+ * Service which provides convenience methods for creating, retrieving, and
+ * manipulating users. This service will automatically enforce the
+ * permissions of the current user.
+ *
+ * @author Michael Jumper
+ * @param
+ * The specific internal implementation of the type of object this service
+ * provides access to.
+ *
+ * @param
+ * The external interface or implementation of the type of object this
+ * service provides access to, as defined by the guacamole-ext API.
+ *
+ * @param
+ * The underlying model object used to represent InternalType in the
+ * database.
+ */
+public abstract class DirectoryObjectService,
+ ExternalType, ModelType extends ObjectModel> {
+
+ /**
+ * All object permissions which are implicitly granted upon creation to the
+ * creator of the object.
+ */
+ private static final ObjectPermission.Type[] IMPLICIT_OBJECT_PERMISSIONS = {
+ ObjectPermission.Type.READ,
+ ObjectPermission.Type.UPDATE,
+ ObjectPermission.Type.DELETE,
+ ObjectPermission.Type.ADMINISTER
+ };
+
+ /**
+ * Returns an instance of a mapper for the type of object used by this
+ * service.
+ *
+ * @return
+ * A mapper which provides access to the model objects associated with
+ * the objects used by this service.
+ */
+ protected abstract DirectoryObjectMapper getObjectMapper();
+
+ /**
+ * Returns an instance of a mapper for the type of permissions that affect
+ * the type of object used by this service.
+ *
+ * @return
+ * A mapper which provides access to the model objects associated with
+ * the permissions that affect the objects used by this service.
+ */
+ protected abstract ObjectPermissionMapper getPermissionMapper();
+
+ /**
+ * Returns an instance of an object which is backed by the given model
+ * object.
+ *
+ * @param currentUser
+ * The user for whom this object is being created.
+ *
+ * @param model
+ * The model object to use to back the returned object.
+ *
+ * @return
+ * An object which is backed by the given model object.
+ */
+ protected abstract InternalType getObjectInstance(AuthenticatedUser currentUser,
+ ModelType model);
+
+ /**
+ * Returns an instance of a model object which is based on the given
+ * object.
+ *
+ * @param currentUser
+ * The user for whom this model object is being created.
+ *
+ * @param object
+ * The object to use to produce the returned model object.
+ *
+ * @return
+ * A model object which is based on the given object.
+ */
+ protected abstract ModelType getModelInstance(AuthenticatedUser currentUser,
+ ExternalType object);
+
+ /**
+ * Returns whether the given user has permission to create the type of
+ * objects that this directory object service manages.
+ *
+ * @param user
+ * The user being checked.
+ *
+ * @return
+ * true if the user has object creation permission relevant to this
+ * directory object service, false otherwise.
+ *
+ * @throws GuacamoleException
+ * If permission to read the user's permissions is denied.
+ */
+ protected abstract boolean hasCreatePermission(AuthenticatedUser user)
+ throws GuacamoleException;
+
+ /**
+ * Returns whether the given user has permission to perform a certain
+ * action on a specific object managed by this directory object service.
+ *
+ * @param user
+ * The user being checked.
+ *
+ * @param identifier
+ * The identifier of the object to check.
+ *
+ * @param type
+ * The type of action that will be performed.
+ *
+ * @return
+ * true if the user has object permission relevant described, false
+ * otherwise.
+ *
+ * @throws GuacamoleException
+ * If permission to read the user's permissions is denied.
+ */
+ protected boolean hasObjectPermission(AuthenticatedUser user,
+ String identifier, ObjectPermission.Type type)
+ throws GuacamoleException {
+
+ // Get object permissions
+ ObjectPermissionSet permissionSet = getPermissionSet(user);
+
+ // Return whether permission is granted
+ return user.getUser().isAdministrator()
+ || permissionSet.hasPermission(type, identifier);
+
+ }
+
+ /**
+ * Returns the permission set associated with the given user and related
+ * to the type of objects handled by this directory object service.
+ *
+ * @param user
+ * The user whose permissions are being retrieved.
+ *
+ * @return
+ * A permission set which contains the permissions associated with the
+ * given user and related to the type of objects handled by this
+ * directory object service.
+ *
+ * @throws GuacamoleException
+ * If permission to read the user's permissions is denied.
+ */
+ protected abstract ObjectPermissionSet getPermissionSet(AuthenticatedUser user)
+ throws GuacamoleException;
+
+ /**
+ * Returns a collection of objects which are backed by the models in the
+ * given collection.
+ *
+ * @param currentUser
+ * The user for whom these objects are being created.
+ *
+ * @param models
+ * The model objects to use to back the objects within the returned
+ * collection.
+ *
+ * @return
+ * A collection of objects which are backed by the models in the given
+ * collection.
+ */
+ protected Collection getObjectInstances(AuthenticatedUser currentUser,
+ Collection models) {
+
+ // Create new collection of objects by manually converting each model
+ Collection objects = new ArrayList(models.size());
+ for (ModelType model : models)
+ objects.add(getObjectInstance(currentUser, model));
+
+ return objects;
+
+ }
+
+ /**
+ * Returns whether the contents of the given model are valid and can be
+ * used to create a new object as-is. The object does not yet exist in the
+ * database, but the user desires to create a new object with the given
+ * model. This function will be called prior to any creation operation, and
+ * provides a means for the implementation to abort prior to completion. The
+ * default implementation does nothing.
+ *
+ * @param user
+ * The user creating the object.
+ *
+ * @param model
+ * The model to validate.
+ *
+ * @throws GuacamoleException
+ * If the object is invalid, or an error prevents validating the given
+ * object.
+ */
+ protected void validateNewModel(AuthenticatedUser user,
+ ModelType model) throws GuacamoleException {
+
+ // By default, do nothing.
+
+ }
+
+ /**
+ * Returns whether the given model is valid and can be used to update an
+ * existing object as-is. The object already exists in the database, but the
+ * user desires to update the object to the given model. This function will
+ * be called prior to update operation, and provides a means for the
+ * implementation to abort prior to completion. The default implementation
+ * does nothing.
+ *
+ * @param user
+ * The user updating the existing object.
+ *
+ * @param model
+ * The model to validate.
+ *
+ * @throws GuacamoleException
+ * If the object is invalid, or an error prevents validating the given
+ * object.
+ */
+ protected void validateExistingModel(AuthenticatedUser user,
+ ModelType model) throws GuacamoleException {
+
+ // By default, do nothing.
+
+ }
+
+ /**
+ * Retrieves the single object that has the given identifier, if it exists
+ * and the user has permission to read it.
+ *
+ * @param user
+ * The user retrieving the object.
+ *
+ * @param identifier
+ * The identifier of the object to retrieve.
+ *
+ * @return
+ * The object having the given identifier, or null if no such object
+ * exists.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while retrieving the requested object.
+ */
+ public InternalType retrieveObject(AuthenticatedUser user,
+ String identifier) throws GuacamoleException {
+
+ // Pull objects having given identifier
+ Collection objects = retrieveObjects(user, Collections.singleton(identifier));
+
+ // If no such object, return null
+ if (objects.isEmpty())
+ return null;
+
+ // The object collection will have exactly one element unless the
+ // database has seriously lost integrity
+ assert(objects.size() == 1);
+
+ // Return first and only object
+ return objects.iterator().next();
+
+ }
+
+ /**
+ * Retrieves all objects that have the identifiers in the given collection.
+ * Only objects that the user has permission to read will be returned.
+ *
+ * @param user
+ * The user retrieving the objects.
+ *
+ * @param identifiers
+ * The identifiers of the objects to retrieve.
+ *
+ * @return
+ * The objects having the given identifiers.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while retrieving the requested objects.
+ */
+ public Collection retrieveObjects(AuthenticatedUser user,
+ Collection identifiers) throws GuacamoleException {
+
+ // Do not query if no identifiers given
+ if (identifiers.isEmpty())
+ return Collections.EMPTY_LIST;
+
+ Collection objects;
+
+ // Bypass permission checks if the user is a system admin
+ if (user.getUser().isAdministrator())
+ objects = getObjectMapper().select(identifiers);
+
+ // Otherwise only return explicitly readable identifiers
+ else
+ objects = getObjectMapper().selectReadable(user.getUser().getModel(), identifiers);
+
+ // Return collection of requested objects
+ return getObjectInstances(user, objects);
+
+ }
+
+ /**
+ * Creates the given object within the database. If the object already
+ * exists, an error will be thrown. The internal model object will be
+ * updated appropriately to contain the new database ID.
+ *
+ * @param user
+ * The user creating the object.
+ *
+ * @param object
+ * The object to create.
+ *
+ * @return
+ * The newly-created object.
+ *
+ * @throws GuacamoleException
+ * If the user lacks permission to create the object, or an error
+ * occurs while creating the object.
+ */
+ public InternalType createObject(AuthenticatedUser user, ExternalType object)
+ throws GuacamoleException {
+
+ // Only create object if user has permission to do so
+ if (user.getUser().isAdministrator() || hasCreatePermission(user)) {
+
+ // Validate object prior to creation
+ ModelType model = getModelInstance(user, object);
+ validateNewModel(user, model);
+
+ // Create object
+ getObjectMapper().insert(model);
+
+ // Build list of implicit permissions
+ Collection implicitPermissions =
+ new ArrayList(IMPLICIT_OBJECT_PERMISSIONS.length);
+
+ UserModel userModel = user.getUser().getModel();
+ for (ObjectPermission.Type permission : IMPLICIT_OBJECT_PERMISSIONS) {
+
+ // Create model which grants this permission to the current user
+ ObjectPermissionModel permissionModel = new ObjectPermissionModel();
+ permissionModel.setUserID(userModel.getObjectID());
+ permissionModel.setUsername(userModel.getIdentifier());
+ permissionModel.setType(permission);
+ permissionModel.setObjectIdentifier(model.getIdentifier());
+
+ // Add permission
+ implicitPermissions.add(permissionModel);
+
+ }
+
+ // Add implicit permissions
+ getPermissionMapper().insert(implicitPermissions);
+
+ return getObjectInstance(user, model);
+ }
+
+ // User lacks permission to create
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+ /**
+ * Deletes the object having the given identifier. If no such object
+ * exists, this function has no effect.
+ *
+ * @param user
+ * The user deleting the object.
+ *
+ * @param identifier
+ * The identifier of the object to delete.
+ *
+ * @throws GuacamoleException
+ * If the user lacks permission to delete the object, or an error
+ * occurs while deleting the object.
+ */
+ public void deleteObject(AuthenticatedUser user, String identifier)
+ throws GuacamoleException {
+
+ // Only delete object if user has permission to do so
+ if (hasObjectPermission(user, identifier, ObjectPermission.Type.DELETE)) {
+ getObjectMapper().delete(identifier);
+ return;
+ }
+
+ // User lacks permission to delete
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+ /**
+ * Updates the given object in the database, applying any changes that have
+ * been made. If no such object exists, this function has no effect.
+ *
+ * @param user
+ * The user updating the object.
+ *
+ * @param object
+ * The object to update.
+ *
+ * @throws GuacamoleException
+ * If the user lacks permission to update the object, or an error
+ * occurs while updating the object.
+ */
+ public void updateObject(AuthenticatedUser user, InternalType object)
+ throws GuacamoleException {
+
+ // Only update object if user has permission to do so
+ if (hasObjectPermission(user, object.getIdentifier(), ObjectPermission.Type.UPDATE)) {
+
+ // Validate object prior to creation
+ ModelType model = object.getModel();
+ validateExistingModel(user, model);
+
+ // Update object
+ getObjectMapper().update(model);
+ return;
+ }
+
+ // User lacks permission to update
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+ /**
+ * Returns the set of all identifiers for all objects in the database that
+ * the user has read access to.
+ *
+ * @param user
+ * The user retrieving the identifiers.
+ *
+ * @return
+ * The set of all identifiers for all objects in the database.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while reading identifiers.
+ */
+ public Set getIdentifiers(AuthenticatedUser user)
+ throws GuacamoleException {
+
+ // Bypass permission checks if the user is a system admin
+ if (user.getUser().isAdministrator())
+ return getObjectMapper().selectIdentifiers();
+
+ // Otherwise only return explicitly readable identifiers
+ else
+ return getObjectMapper().selectReadableIdentifiers(user.getUser().getModel());
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/ModeledObject.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/ModeledObject.java
new file mode 100644
index 000000000..276b0909e
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/ModeledObject.java
@@ -0,0 +1,82 @@
+/*
+ * 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.base;
+
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+
+/**
+ * Common base class for objects have an underlying model. For the purposes of
+ * JDBC-driven authentication providers, all modeled objects are also
+ * restricted.
+ *
+ * @author Michael Jumper
+ * @param
+ * The type of model object which corresponds to this object.
+ */
+public abstract class ModeledObject extends RestrictedObject {
+
+ /**
+ * The internal model object containing the values which represent this
+ * object in the database.
+ */
+ private ModelType model;
+
+ /**
+ * Initializes this object, associating it with the current authenticated
+ * user and populating it with data from the given model object
+ *
+ * @param currentUser
+ * The user that created or retrieved this object.
+ *
+ * @param model
+ * The backing model object.
+ */
+ public void init(AuthenticatedUser currentUser, ModelType model) {
+ super.init(currentUser);
+ setModel(model);
+ }
+
+ /**
+ * Returns the backing model object. Changes to the model object will
+ * affect this object, and changes to this object will affect the model
+ * object.
+ *
+ * @return
+ * The backing model object.
+ */
+ public ModelType getModel() {
+ return model;
+ }
+
+ /**
+ * Sets the backing model object. This will effectively replace all data
+ * contained within this object.
+ *
+ * @param model
+ * The backing model object.
+ */
+ public void setModel(ModelType model) {
+ this.model = model;
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/ObjectModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/ObjectModel.java
new file mode 100644
index 000000000..e936686cd
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/ObjectModel.java
@@ -0,0 +1,90 @@
+/*
+ * 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.base;
+
+/**
+ * Object representation of a Guacamole object, such as a user or connection,
+ * as represented in the database.
+ *
+ * @author Michael Jumper
+ */
+public abstract class ObjectModel {
+
+ /**
+ * The ID of this object in the database, if any.
+ */
+ private Integer objectID;
+
+ /**
+ * The unique identifier which identifies this object.
+ */
+ private String identifier;
+
+ /**
+ * Creates a new, empty object.
+ */
+ public ObjectModel() {
+ }
+
+ /**
+ * Returns the identifier that uniquely identifies this object.
+ *
+ * @return
+ * The identifier that uniquely identifies this object.
+ */
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ * Sets the identifier that uniquely identifies this object.
+ *
+ * @param identifier
+ * The identifier that uniquely identifies this object.
+ */
+ public void setIdentifier(String identifier) {
+ this.identifier = identifier;
+ }
+
+ /**
+ * Returns the ID of this object in the database, if it exists.
+ *
+ * @return
+ * The ID of this object in the database, or null if this object was
+ * not retrieved from the database.
+ */
+ public Integer getObjectID() {
+ return objectID;
+ }
+
+ /**
+ * Sets the ID of this object to the given value.
+ *
+ * @param objectID
+ * The ID to assign to this object.
+ */
+ public void setObjectID(Integer objectID) {
+ this.objectID = objectID;
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/RestrictedObject.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/RestrictedObject.java
new file mode 100644
index 000000000..d8828c43c
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/RestrictedObject.java
@@ -0,0 +1,76 @@
+/*
+ * 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.base;
+
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+
+/**
+ * Common base class for objects that are associated with the users that
+ * obtain them.
+ *
+ * @author Michael Jumper
+ */
+public abstract class RestrictedObject {
+
+ /**
+ * The user this object belongs to. Access is based on his/her permission
+ * settings.
+ */
+ private AuthenticatedUser currentUser;
+
+ /**
+ * Initializes this object, associating it with the current authenticated
+ * user and populating it with data from the given model object
+ *
+ * @param currentUser
+ * The user that created or retrieved this object.
+ */
+ public void init(AuthenticatedUser currentUser) {
+ setCurrentUser(currentUser);
+ }
+
+ /**
+ * Returns the user that created or queried this object. This user's
+ * permissions dictate what operations can be performed on or through this
+ * object.
+ *
+ * @return
+ * The user that created or queried this object.
+ */
+ public AuthenticatedUser getCurrentUser() {
+ return currentUser;
+ }
+
+ /**
+ * Sets the user that created or queried this object. This user's
+ * permissions dictate what operations can be performed on or through this
+ * object.
+ *
+ * @param currentUser
+ * The user that created or queried this object.
+ */
+ public void setCurrentUser(AuthenticatedUser currentUser) {
+ this.currentUser = currentUser;
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/package-info.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/package-info.java
new file mode 100644
index 000000000..122dc3ec9
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+/**
+ * Base classes supporting JDBC-driven authentication providers and defining
+ * the relationships between the model and the implementations of guacamole-ext
+ * classes.
+ */
+package org.glyptodon.guacamole.auth.jdbc.base;
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionDirectory.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionDirectory.java
new file mode 100644
index 000000000..2afc98b28
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionDirectory.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2013 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.connection;
+
+
+import com.google.inject.Inject;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.auth.jdbc.base.RestrictedObject;
+import org.glyptodon.guacamole.net.auth.Connection;
+import org.glyptodon.guacamole.net.auth.Directory;
+import org.mybatis.guice.transactional.Transactional;
+
+/**
+ * Implementation of the Connection Directory which is driven by an underlying,
+ * arbitrary database.
+ *
+ * @author James Muehlner
+ * @author Michael Jumper
+ */
+public class ConnectionDirectory extends RestrictedObject
+ implements Directory {
+
+ /**
+ * Service for managing connection objects.
+ */
+ @Inject
+ private ConnectionService connectionService;
+
+ @Override
+ public Connection get(String identifier) throws GuacamoleException {
+ return connectionService.retrieveObject(getCurrentUser(), identifier);
+ }
+
+ @Override
+ @Transactional
+ public Collection getAll(Collection identifiers) throws GuacamoleException {
+ Collection objects = connectionService.retrieveObjects(getCurrentUser(), identifiers);
+ return Collections.unmodifiableCollection(objects);
+ }
+
+ @Override
+ @Transactional
+ public Set getIdentifiers() throws GuacamoleException {
+ return connectionService.getIdentifiers(getCurrentUser());
+ }
+
+ @Override
+ @Transactional
+ public void add(Connection object) throws GuacamoleException {
+ connectionService.createObject(getCurrentUser(), object);
+ }
+
+ @Override
+ @Transactional
+ public void update(Connection object) throws GuacamoleException {
+ ModeledConnection connection = (ModeledConnection) object;
+ connectionService.updateObject(getCurrentUser(), connection);
+ }
+
+ @Override
+ @Transactional
+ public void remove(String identifier) throws GuacamoleException {
+ connectionService.deleteObject(getCurrentUser(), identifier);
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.java
new file mode 100644
index 000000000..faa7f21d1
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.java
@@ -0,0 +1,92 @@
+/*
+ * 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.connection;
+
+import java.util.Set;
+import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectMapper;
+import org.glyptodon.guacamole.auth.jdbc.user.UserModel;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * Mapper for connection objects.
+ *
+ * @author Michael Jumper
+ */
+public interface ConnectionMapper extends DirectoryObjectMapper {
+
+ /**
+ * Selects the identifiers of all connections within the given parent
+ * connection group, regardless of whether they are readable by any
+ * particular user. This should only be called on behalf of a system
+ * administrator. If identifiers are needed by a non-administrative user
+ * who must have explicit read rights, use
+ * selectReadableIdentifiersWithin() instead.
+ *
+ * @param parentIdentifier
+ * The identifier of the parent connection group, or null if the root
+ * connection group is to be queried.
+ *
+ * @return
+ * A Set containing all identifiers of all objects.
+ */
+ Set selectIdentifiersWithin(@Param("parentIdentifier") String parentIdentifier);
+
+ /**
+ * Selects the identifiers of all connections within the given parent
+ * connection group that are explicitly readable by the given user. If
+ * identifiers are needed by a system administrator (who, by definition,
+ * does not need explicit read rights), use selectIdentifiersWithin()
+ * instead.
+ *
+ * @param user
+ * The user whose permissions should determine whether an identifier
+ * is returned.
+ *
+ * @param parentIdentifier
+ * The identifier of the parent connection group, or null if the root
+ * connection group is to be queried.
+ *
+ * @return
+ * A Set containing all identifiers of all readable objects.
+ */
+ Set selectReadableIdentifiersWithin(@Param("user") UserModel user,
+ @Param("parentIdentifier") String parentIdentifier);
+
+ /**
+ * Selects the connection within the given parent group and having the
+ * given name. If no such connection exists, null is returned.
+ *
+ * @param parentIdentifier
+ * The identifier of the parent group to search within.
+ *
+ * @param name
+ * The name of the connection to find.
+ *
+ * @return
+ * The connection having the given name within the given parent group,
+ * or null if no such connection exists.
+ */
+ ConnectionModel selectOneByName(@Param("parentIdentifier") String parentIdentifier,
+ @Param("name") String name);
+
+}
\ No newline at end of file
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionModel.java
new file mode 100644
index 000000000..b4ef2e907
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionModel.java
@@ -0,0 +1,139 @@
+/*
+ * 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.connection;
+
+import org.glyptodon.guacamole.auth.jdbc.base.ObjectModel;
+
+/**
+ * Object representation of a Guacamole connection, as represented in the
+ * database.
+ *
+ * @author Michael Jumper
+ */
+public class ConnectionModel extends ObjectModel {
+
+ /**
+ * The identifier of the parent connection group in the database, or null
+ * if the parent connection group is the root group.
+ */
+ private String parentIdentifier;
+
+ /**
+ * The human-readable name associated with this connection.
+ */
+ private String name;
+
+ /**
+ * The name of the protocol to use when connecting to this connection.
+ */
+ private String protocol;
+
+ /**
+ * Creates a new, empty connection.
+ */
+ public ConnectionModel() {
+ }
+
+ /**
+ * Returns the name associated with this connection.
+ *
+ * @return
+ * The name associated with this connection.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name associated with this connection.
+ *
+ * @param name
+ * The name to associate with this connection.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the name of the protocol to use when connecting to this
+ * connection.
+ *
+ * @return
+ * The name of the protocol to use when connecting to this connection.
+ */
+ public String getProtocol() {
+ return protocol;
+ }
+
+ /**
+ * Sets the name of the protocol to use when connecting to this connection.
+ *
+ * @param protocol
+ * The name of the protocol to use when connecting to this connection.
+ */
+ public void setProtocol(String protocol) {
+ this.protocol = protocol;
+ }
+
+ /**
+ * Returns the identifier of the parent connection group, or null if the
+ * parent connection group is the root connection group.
+ *
+ * @return
+ * The identifier of the parent connection group, or null if the parent
+ * connection group is the root connection group.
+ */
+ public String getParentIdentifier() {
+ return parentIdentifier;
+ }
+
+ /**
+ * Sets the identifier of the parent connection group.
+ *
+ * @param parentIdentifier
+ * The identifier of the parent connection group, or null if the parent
+ * connection group is the root connection group.
+ */
+ public void setParentIdentifier(String parentIdentifier) {
+ this.parentIdentifier = parentIdentifier;
+ }
+
+ @Override
+ public String getIdentifier() {
+
+ // If no associated ID, then no associated identifier
+ Integer id = getObjectID();
+ if (id == null)
+ return null;
+
+ // Otherwise, the identifier is the ID as a string
+ return id.toString();
+
+ }
+
+ @Override
+ public void setIdentifier(String identifier) {
+ throw new UnsupportedOperationException("Connection identifiers are derived from IDs. They cannot be set.");
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java
new file mode 100644
index 000000000..8816fb69c
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java
@@ -0,0 +1,60 @@
+/*
+ * 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.connection;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * Mapper for connection record objects.
+ *
+ * @author Michael Jumper
+ */
+public interface ConnectionRecordMapper {
+
+ /**
+ * Returns a collection of all connection records associated with the
+ * connection having the given identifier.
+ *
+ * @param identifier
+ * The identifier of the connection whose records are to be retrieved.
+ *
+ * @return
+ * A collection of all connection records associated with the
+ * connection having the given identifier. This collection will be
+ * empty if no such connection exists.
+ */
+ List select(@Param("identifier") String identifier);
+
+ /**
+ * Inserts the given connection record.
+ *
+ * @param record
+ * The connection record to insert.
+ *
+ * @return
+ * The number of rows inserted.
+ */
+ int insert(@Param("record") ConnectionRecordModel record);
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordModel.java
new file mode 100644
index 000000000..aa35fb27c
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordModel.java
@@ -0,0 +1,170 @@
+/*
+ * 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.connection;
+
+import java.util.Date;
+
+/**
+ * A single connection record representing a past usage of a particular
+ * connection.
+ *
+ * @author Michael Jumper
+ */
+public class ConnectionRecordModel {
+
+ /**
+ * The identifier of the connection associated with this connection record.
+ */
+ private String connectionIdentifier;
+
+ /**
+ * The database ID of the user associated with this connection record.
+ */
+ private Integer userID;
+
+ /**
+ * The username of the user associated with this connection record.
+ */
+ private String username;
+
+ /**
+ * The time the connection was initiated by the associated user.
+ */
+ private Date startDate;
+
+ /**
+ * The time the connection ended, or null if the end time is not known or
+ * the connection is still running.
+ */
+ private Date endDate;
+
+ /**
+ * Returns the identifier of the connection associated with this connection
+ * record.
+ *
+ * @return
+ * The identifier of the connection associated with this connection
+ * record.
+ */
+ public String getConnectionIdentifier() {
+ return connectionIdentifier;
+ }
+
+ /**
+ * Sets the identifier of the connection associated with this connection
+ * record.
+ *
+ * @param connectionIdentifier
+ * The identifier of the connection to associate with this connection
+ * record.
+ */
+ public void setConnectionIdentifier(String connectionIdentifier) {
+ this.connectionIdentifier = connectionIdentifier;
+ }
+
+ /**
+ * Returns the database ID of the user associated with this connection
+ * record.
+ *
+ * @return
+ * The database ID of the user associated with this connection record.
+ */
+ public Integer getUserID() {
+ return userID;
+ }
+
+ /**
+ * Sets the database ID of the user associated with this connection record.
+ *
+ * @param userID
+ * The database ID of the user to associate with this connection
+ * record.
+ */
+ public void setUserID(Integer userID) {
+ this.userID = userID;
+ }
+
+ /**
+ * Returns the username of the user associated with this connection record.
+ *
+ * @return
+ * The username of the user associated with this connection record.
+ */
+ public String getUsername() {
+ return username;
+ }
+
+ /**
+ * Sets the username of the user associated with this connection record.
+ *
+ * @param username
+ * The username of the user to associate with this connection record.
+ */
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ /**
+ * Returns the date that the associated connection was established.
+ *
+ * @return
+ * The date the associated connection was established.
+ */
+ public Date getStartDate() {
+ return startDate;
+ }
+
+ /**
+ * Sets the date that the associated connection was established.
+ *
+ * @param startDate
+ * The date that the associated connection was established.
+ */
+ public void setStartDate(Date startDate) {
+ this.startDate = startDate;
+ }
+
+ /**
+ * Returns the date that the associated connection ended, or null if no
+ * end date was recorded. The lack of an end date does not necessarily
+ * mean that the connection is still active.
+ *
+ * @return
+ * The date the associated connection ended, or null if no end date was
+ * recorded.
+ */
+ public Date getEndDate() {
+ return endDate;
+ }
+
+ /**
+ * Sets the date that the associated connection ended.
+ *
+ * @param endDate
+ * The date that the associated connection ended.
+ */
+ public void setEndDate(Date endDate) {
+ this.endDate = endDate;
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionService.java
new file mode 100644
index 000000000..f7d0b5ac5
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionService.java
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2013 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.connection;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectMapper;
+import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectService;
+import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService;
+import org.glyptodon.guacamole.GuacamoleClientException;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.GuacamoleSecurityException;
+import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionPermissionMapper;
+import org.glyptodon.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
+import org.glyptodon.guacamole.net.GuacamoleSocket;
+import org.glyptodon.guacamole.net.auth.Connection;
+import org.glyptodon.guacamole.net.auth.ConnectionRecord;
+import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
+import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
+import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
+import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
+import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
+
+/**
+ * Service which provides convenience methods for creating, retrieving, and
+ * manipulating connections.
+ *
+ * @author Michael Jumper, James Muehlner
+ */
+public class ConnectionService extends DirectoryObjectService {
+
+ /**
+ * Mapper for accessing connections.
+ */
+ @Inject
+ private ConnectionMapper connectionMapper;
+
+ /**
+ * Mapper for manipulating connection permissions.
+ */
+ @Inject
+ private ConnectionPermissionMapper connectionPermissionMapper;
+
+ /**
+ * Mapper for accessing connection parameters.
+ */
+ @Inject
+ private ParameterMapper parameterMapper;
+
+ /**
+ * Mapper for accessing connection history.
+ */
+ @Inject
+ private ConnectionRecordMapper connectionRecordMapper;
+
+ /**
+ * Provider for creating connections.
+ */
+ @Inject
+ private Provider connectionProvider;
+
+ /**
+ * Service for creating and tracking sockets.
+ */
+ @Inject
+ private GuacamoleSocketService socketService;
+
+ @Override
+ protected DirectoryObjectMapper getObjectMapper() {
+ return connectionMapper;
+ }
+
+ @Override
+ protected ObjectPermissionMapper getPermissionMapper() {
+ return connectionPermissionMapper;
+ }
+
+ @Override
+ protected ModeledConnection getObjectInstance(AuthenticatedUser currentUser,
+ ConnectionModel model) {
+ ModeledConnection connection = connectionProvider.get();
+ connection.init(currentUser, model);
+ return connection;
+ }
+
+ @Override
+ protected ConnectionModel getModelInstance(AuthenticatedUser currentUser,
+ final Connection object) {
+
+ // Create new ModeledConnection backed by blank model
+ ConnectionModel model = new ConnectionModel();
+ ModeledConnection connection = getObjectInstance(currentUser, model);
+
+ // Set model contents through ModeledConnection, copying the provided connection
+ connection.setParentIdentifier(object.getParentIdentifier());
+ connection.setName(object.getName());
+ connection.setConfiguration(object.getConfiguration());
+
+ return model;
+
+ }
+
+ @Override
+ protected boolean hasCreatePermission(AuthenticatedUser user)
+ throws GuacamoleException {
+
+ // Return whether user has explicit connection creation permission
+ SystemPermissionSet permissionSet = user.getUser().getSystemPermissions();
+ return permissionSet.hasPermission(SystemPermission.Type.CREATE_CONNECTION);
+
+ }
+
+ @Override
+ protected ObjectPermissionSet getPermissionSet(AuthenticatedUser user)
+ throws GuacamoleException {
+
+ // Return permissions related to connections
+ return user.getUser().getConnectionPermissions();
+
+ }
+
+ @Override
+ protected void validateNewModel(AuthenticatedUser user,
+ ConnectionModel model) throws GuacamoleException {
+
+ // Name must not be blank
+ if (model.getName().trim().isEmpty())
+ throw new GuacamoleClientException("Connection names must not be blank.");
+
+ // Do not attempt to create duplicate connections
+ ConnectionModel existing = connectionMapper.selectOneByName(model.getParentIdentifier(), model.getName());
+ if (existing != null)
+ throw new GuacamoleClientException("The connection \"" + model.getName() + "\" already exists.");
+
+ }
+
+ @Override
+ protected void validateExistingModel(AuthenticatedUser user,
+ ConnectionModel model) throws GuacamoleException {
+
+ // Name must not be blank
+ if (model.getName().trim().isEmpty())
+ throw new GuacamoleClientException("Connection names must not be blank.");
+
+ // Check whether such a connection is already present
+ ConnectionModel existing = connectionMapper.selectOneByName(model.getParentIdentifier(), model.getName());
+ if (existing != null) {
+
+ // If the specified name matches a DIFFERENT existing connection, the update cannot continue
+ if (!existing.getObjectID().equals(model.getObjectID()))
+ throw new GuacamoleClientException("The connection \"" + model.getName() + "\" already exists.");
+
+ }
+
+ }
+
+ /**
+ * Given an arbitrary Guacamole connection, produces a collection of
+ * parameter model objects containing the name/value pairs of that
+ * connection's parameters.
+ *
+ * @param connection
+ * The connection whose configuration should be used to produce the
+ * collection of parameter models.
+ *
+ * @return
+ * A collection of parameter models containing the name/value pairs
+ * of the given connection's parameters.
+ */
+ private Collection getParameterModels(ModeledConnection connection) {
+
+ Map parameters = connection.getConfiguration().getParameters();
+
+ // Convert parameters to model objects
+ Collection parameterModels = new ArrayList(parameters.size());
+ for (Map.Entry parameterEntry : parameters.entrySet()) {
+
+ // Get parameter name and value
+ String name = parameterEntry.getKey();
+ String value = parameterEntry.getValue();
+
+ // There is no need to insert empty parameters
+ if (value.isEmpty())
+ continue;
+
+ // Produce model object from parameter
+ ParameterModel model = new ParameterModel();
+ model.setConnectionIdentifier(connection.getIdentifier());
+ model.setName(name);
+ model.setValue(value);
+
+ // Add model to list
+ parameterModels.add(model);
+
+ }
+
+ return parameterModels;
+
+ }
+
+ @Override
+ public ModeledConnection createObject(AuthenticatedUser user, Connection object)
+ throws GuacamoleException {
+
+ // Create connection
+ ModeledConnection connection = super.createObject(user, object);
+ connection.setConfiguration(object.getConfiguration());
+
+ // Insert new parameters, if any
+ Collection parameterModels = getParameterModels(connection);
+ if (!parameterModels.isEmpty())
+ parameterMapper.insert(parameterModels);
+
+ return connection;
+
+ }
+
+ @Override
+ public void updateObject(AuthenticatedUser user, ModeledConnection object)
+ throws GuacamoleException {
+
+ // Update connection
+ super.updateObject(user, object);
+
+ // Replace existing parameters with new parameters, if any
+ Collection parameterModels = getParameterModels(object);
+ parameterMapper.delete(object.getIdentifier());
+ if (!parameterModels.isEmpty())
+ parameterMapper.insert(parameterModels);
+
+ }
+
+ /**
+ * Returns the set of all identifiers for all connections within the
+ * connection group having the given identifier. Only connections that the
+ * user has read access to will be returned.
+ *
+ * Permission to read the connection group having the given identifier is
+ * NOT checked.
+ *
+ * @param user
+ * The user retrieving the identifiers.
+ *
+ * @param identifier
+ * The identifier of the parent connection group, or null to check the
+ * root connection group.
+ *
+ * @return
+ * The set of all identifiers for all connections in the connection
+ * group having the given identifier that the user has read access to.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while reading identifiers.
+ */
+ public Set getIdentifiersWithin(AuthenticatedUser user,
+ String identifier)
+ throws GuacamoleException {
+
+ // Bypass permission checks if the user is a system admin
+ if (user.getUser().isAdministrator())
+ return connectionMapper.selectIdentifiersWithin(identifier);
+
+ // Otherwise only return explicitly readable identifiers
+ else
+ return connectionMapper.selectReadableIdentifiersWithin(user.getUser().getModel(), identifier);
+
+ }
+
+ /**
+ * Retrieves all parameters visible to the given user and associated with
+ * the connection having the given identifier. If the given user has no
+ * access to such parameters, or no such connection exists, the returned
+ * map will be empty.
+ *
+ * @param user
+ * The user retrieving connection parameters.
+ *
+ * @param identifier
+ * The identifier of the connection whose parameters are being
+ * retrieved.
+ *
+ * @return
+ * A new map of all parameter name/value pairs that the given user has
+ * access to.
+ */
+ public Map retrieveParameters(AuthenticatedUser user,
+ String identifier) {
+
+ Map parameterMap = new HashMap();
+
+ // Determine whether we have permission to read parameters
+ boolean canRetrieveParameters;
+ try {
+ canRetrieveParameters = hasObjectPermission(user, identifier,
+ ObjectPermission.Type.UPDATE);
+ }
+
+ // Provide empty (but mutable) map if unable to check permissions
+ catch (GuacamoleException e) {
+ return parameterMap;
+ }
+
+ // Populate parameter map if we have permission to do so
+ if (canRetrieveParameters) {
+ for (ParameterModel parameter : parameterMapper.select(identifier))
+ parameterMap.put(parameter.getName(), parameter.getValue());
+ }
+
+ return parameterMap;
+
+ }
+
+ /**
+ * Retrieves the connection history of the given connection, including any
+ * active connections.
+ *
+ * @param user
+ * The user retrieving the connection history.
+ *
+ * @param connection
+ * The connection whose history is being retrieved.
+ *
+ * @return
+ * The connection history of the given connection, including any
+ * active connections.
+ *
+ * @throws GuacamoleException
+ * If permission to read the connection history is denied.
+ */
+ public List retrieveHistory(AuthenticatedUser user,
+ ModeledConnection connection) throws GuacamoleException {
+
+ String identifier = connection.getIdentifier();
+
+ // Retrieve history only if READ permission is granted
+ if (hasObjectPermission(user, identifier, ObjectPermission.Type.READ)) {
+
+ // Retrieve history
+ List models = connectionRecordMapper.select(identifier);
+
+ // Get currently-active connections
+ List records = new ArrayList(socketService.getActiveConnections(connection));
+
+ // Add past connections from model objects
+ for (ConnectionRecordModel model : models)
+ records.add(new ModeledConnectionRecord(model));
+
+ // Return converted history list
+ return records;
+
+ }
+
+ // The user does not have permission to read the history
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+ /**
+ * Connects to the given connection as the given user, using the given
+ * client information. If the user does not have permission to read the
+ * connection, permission will be denied.
+ *
+ * @param user
+ * The user connecting to the connection.
+ *
+ * @param connection
+ * The connection being connected to.
+ *
+ * @param info
+ * Information associated with the connecting client.
+ *
+ * @return
+ * A connected GuacamoleSocket associated with a newly-established
+ * connection.
+ *
+ * @throws GuacamoleException
+ * If permission to connect to this connection is denied.
+ */
+ public GuacamoleSocket connect(AuthenticatedUser user,
+ ModeledConnection connection, GuacamoleClientInformation info)
+ throws GuacamoleException {
+
+ // Connect only if READ permission is granted
+ if (hasObjectPermission(user, connection.getIdentifier(), ObjectPermission.Type.READ))
+ return socketService.getGuacamoleSocket(user, connection, info);
+
+ // The user does not have permission to connect
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+}
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
new file mode 100644
index 000000000..64cb1232c
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnection.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2013 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.connection;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.util.List;
+import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObject;
+import org.glyptodon.guacamole.auth.jdbc.connectiongroup.RootConnectionGroup;
+import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.net.GuacamoleSocket;
+import org.glyptodon.guacamole.net.auth.Connection;
+import org.glyptodon.guacamole.net.auth.ConnectionRecord;
+import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
+import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
+
+/**
+ * An implementation of the Connection object which is backed by a database
+ * model.
+ *
+ * @author James Muehlner
+ * @author Michael Jumper
+ */
+public class ModeledConnection extends DirectoryObject
+ implements Connection {
+
+ /**
+ * Service for managing connections.
+ */
+ @Inject
+ private ConnectionService connectionService;
+
+ /**
+ * Service for creating and tracking sockets.
+ */
+ @Inject
+ private GuacamoleSocketService socketService;
+
+ /**
+ * Provider for lazy-loaded, permission-controlled configurations.
+ */
+ @Inject
+ private Provider configProvider;
+
+ /**
+ * The manually-set GuacamoleConfiguration, if any.
+ */
+ private GuacamoleConfiguration config = null;
+
+ /**
+ * Creates a new, empty ModeledConnection.
+ */
+ public ModeledConnection() {
+ }
+
+ @Override
+ public String getName() {
+ return getModel().getName();
+ }
+
+ @Override
+ public void setName(String name) {
+ getModel().setName(name);
+ }
+
+ @Override
+ public String getParentIdentifier() {
+
+ // Translate null parent to proper identifier
+ String parentIdentifier = getModel().getParentIdentifier();
+ if (parentIdentifier == null)
+ return RootConnectionGroup.IDENTIFIER;
+
+ return parentIdentifier;
+
+ }
+
+ @Override
+ public void setParentIdentifier(String parentIdentifier) {
+
+ // Translate root identifier back into null
+ if (parentIdentifier != null
+ && parentIdentifier.equals(RootConnectionGroup.IDENTIFIER))
+ parentIdentifier = null;
+
+ getModel().setParentIdentifier(parentIdentifier);
+
+ }
+
+ @Override
+ public GuacamoleConfiguration getConfiguration() {
+
+ // If configuration has been manually set, return that
+ if (config != null)
+ return config;
+
+ // Otherwise, return permission-controlled configuration
+ ModeledGuacamoleConfiguration restrictedConfig = configProvider.get();
+ restrictedConfig.init(getCurrentUser(), getModel());
+ return restrictedConfig;
+
+ }
+
+ @Override
+ public void setConfiguration(GuacamoleConfiguration config) {
+
+ // Store manually-set configuration internally
+ this.config = config;
+
+ // Update model
+ getModel().setProtocol(config.getProtocol());
+
+ }
+
+ @Override
+ public List extends ConnectionRecord> getHistory() throws GuacamoleException {
+ return connectionService.retrieveHistory(getCurrentUser(), this);
+ }
+
+ @Override
+ public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
+ return connectionService.connect(getCurrentUser(), this, info);
+ }
+
+ @Override
+ public int getActiveConnections() {
+ return socketService.getActiveConnections(this).size();
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java
new file mode 100644
index 000000000..c86e46588
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 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.connection;
+
+
+import java.util.Date;
+import org.glyptodon.guacamole.net.auth.ConnectionRecord;
+
+/**
+ * A ConnectionRecord which is backed by a database model.
+ *
+ * @author James Muehlner
+ * @author Michael Jumper
+ */
+public class ModeledConnectionRecord implements ConnectionRecord {
+
+ /**
+ * The model object backing this connection record.
+ */
+ private final ConnectionRecordModel model;
+
+ /**
+ * Creates a new ModeledConnectionRecord backed by the given model object.
+ * Changes to this record will affect the backing model object, and changes
+ * to the backing model object will affect this record.
+ *
+ * @param model
+ * The model object to use to back this connection record.
+ */
+ public ModeledConnectionRecord(ConnectionRecordModel model) {
+ this.model = model;
+ }
+
+ @Override
+ public Date getStartDate() {
+ return model.getStartDate();
+ }
+
+ @Override
+ public Date getEndDate() {
+ return model.getEndDate();
+ }
+
+ @Override
+ public String getUsername() {
+ return model.getUsername();
+ }
+
+ @Override
+ public boolean isActive() {
+ return false;
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledGuacamoleConfiguration.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledGuacamoleConfiguration.java
new file mode 100644
index 000000000..b88a936e7
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledGuacamoleConfiguration.java
@@ -0,0 +1,120 @@
+/*
+ * 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.connection;
+
+import com.google.inject.Inject;
+import java.util.Map;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
+
+/**
+ * Implementation of GuacamoleConfiguration which loads parameter values only
+ * if necessary, and only if allowed.
+ *
+ * @author Michael Jumper
+ */
+public class ModeledGuacamoleConfiguration extends GuacamoleConfiguration {
+
+ /**
+ * The user this configuration belongs to. Access is based on his/her
+ * permission settings.
+ */
+ private AuthenticatedUser currentUser;
+
+ /**
+ * The internal model object containing the values which represent the
+ * connection associated with this configuration.
+ */
+ private ConnectionModel connectionModel;
+
+ /**
+ * Service for managing connection parameters.
+ */
+ @Inject
+ private ConnectionService connectionService;
+
+ /**
+ * The manually-set parameter map, if any.
+ */
+ private Map parameters = null;
+
+ /**
+ * Creates a new, empty ModelGuacamoleConfiguration.
+ */
+ public ModeledGuacamoleConfiguration() {
+ }
+
+ /**
+ * Initializes this configuration, associating it with the current
+ * authenticated user and populating it with data from the given model
+ * object.
+ *
+ * @param currentUser
+ * The user that created or retrieved this configuration.
+ *
+ * @param connectionModel
+ * The model object backing this configuration.
+ */
+ public void init(AuthenticatedUser currentUser, ConnectionModel connectionModel) {
+ this.currentUser = currentUser;
+ this.connectionModel = connectionModel;
+ }
+
+ @Override
+ public String getProtocol() {
+ return connectionModel.getProtocol();
+ }
+
+ @Override
+ public void setProtocol(String protocol) {
+ super.setProtocol(protocol);
+ connectionModel.setProtocol(protocol);
+ }
+
+
+ @Override
+ public void setParameters(Map parameters) {
+ this.parameters = parameters;
+ super.setParameters(parameters);
+ }
+
+ @Override
+ public Map getParameters() {
+
+ // Retrieve visible parameters, if not overridden by setParameters()
+ if (parameters == null) {
+
+ // Retrieve all visible parameters
+ Map visibleParameters =
+ connectionService.retrieveParameters(currentUser, connectionModel.getIdentifier());
+
+ // Use retrieved parameters to back future operations
+ super.setParameters(visibleParameters);
+
+ }
+
+ return super.getParameters();
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.java
new file mode 100644
index 000000000..b8bb26fb5
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.java
@@ -0,0 +1,75 @@
+/*
+ * 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.connection;
+
+import java.util.Collection;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * Mapper for connection parameter objects.
+ *
+ * @author Michael Jumper
+ */
+public interface ParameterMapper {
+
+ /**
+ * Returns a collection of all parameters associated with the connection
+ * having the given identifier.
+ *
+ * @param identifier
+ * The identifier of the connection whose parameters are to be
+ * retrieved.
+ *
+ * @return
+ * A collection of all parameters associated with the connection
+ * having the given identifier. This collection will be empty if no
+ * such connection exists.
+ */
+ Collection select(@Param("identifier") String identifier);
+
+ /**
+ * Inserts each of the parameter model objects in the given collection as
+ * new connection parameters.
+ *
+ * @param parameters
+ * The connection parameters to insert.
+ *
+ * @return
+ * The number of rows inserted.
+ */
+ int insert(@Param("parameters") Collection parameters);
+
+ /**
+ * Deletes all parameters associated with the connection having the given
+ * identifier.
+ *
+ * @param identifier
+ * The identifier of the connection whose parameters should be
+ * deleted.
+ *
+ * @return
+ * The number of rows deleted.
+ */
+ int delete(@Param("identifier") String identifier);
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ParameterModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ParameterModel.java
new file mode 100644
index 000000000..103bdae49
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ParameterModel.java
@@ -0,0 +1,107 @@
+/*
+ * 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.connection;
+
+/**
+ * A single parameter name/value pair belonging to a connection.
+ *
+ * @author Michael Jumper
+ */
+public class ParameterModel {
+
+ /**
+ * The identifier of the connection associated with this parameter.
+ */
+ private String connectionIdentifier;
+
+ /**
+ * The name of the parameter.
+ */
+ private String name;
+
+ /**
+ * The value the parameter is set to.
+ */
+ private String value;
+
+ /**
+ * Returns the identifier of the connection associated with this parameter.
+ *
+ * @return
+ * The identifier of the connection associated with this parameter.
+ */
+ public String getConnectionIdentifier() {
+ return connectionIdentifier;
+ }
+
+ /**
+ * Sets the identifier of the connection associated with this parameter.
+ *
+ * @param connectionIdentifier
+ * The identifier of the connection to associate with this parameter.
+ */
+ public void setConnectionIdentifier(String connectionIdentifier) {
+ this.connectionIdentifier = connectionIdentifier;
+ }
+
+ /**
+ * Returns the name of this parameter.
+ *
+ * @return
+ * The name of this parameter.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name of this parameter.
+ *
+ * @param name
+ * The name of this parameter.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the value of this parameter.
+ *
+ * @return
+ * The value of this parameter.
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Sets the value of this parameter.
+ *
+ * @param value
+ * The value of this parameter.
+ */
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/package-info.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/package-info.java
similarity index 85%
rename from extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/package-info.java
rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/package-info.java
index d665bbc7d..6507c59b9 100644
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/package-info.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Glyptodon LLC
+ * 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
@@ -21,8 +21,6 @@
*/
/**
- * Service classes which help fill the needs of the MySQL authentication
- * provider.
+ * Classes related to connections and their parameters and history.
*/
-package net.sourceforge.guacamole.net.auth.mysql.service;
-
+package org.glyptodon.guacamole.auth.jdbc.connection;
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupDirectory.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupDirectory.java
new file mode 100644
index 000000000..6f76dd7c6
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupDirectory.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2013 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.connectiongroup;
+
+
+import com.google.inject.Inject;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.auth.jdbc.base.RestrictedObject;
+import org.glyptodon.guacamole.net.auth.ConnectionGroup;
+import org.glyptodon.guacamole.net.auth.Directory;
+import org.mybatis.guice.transactional.Transactional;
+
+/**
+ * Implementation of the ConnectionGroup Directory which is driven by an
+ * underlying, arbitrary database.
+ *
+ * @author James Muehlner
+ * @author Michael Jumper
+ */
+public class ConnectionGroupDirectory extends RestrictedObject
+ implements Directory {
+
+ /**
+ * Service for managing connection group objects.
+ */
+ @Inject
+ private ConnectionGroupService connectionGroupService;
+
+ @Override
+ public ConnectionGroup get(String identifier) throws GuacamoleException {
+ return connectionGroupService.retrieveObject(getCurrentUser(), identifier);
+ }
+
+ @Override
+ @Transactional
+ public Collection getAll(Collection identifiers) throws GuacamoleException {
+ Collection objects = connectionGroupService.retrieveObjects(getCurrentUser(), identifiers);
+ return Collections.unmodifiableCollection(objects);
+ }
+
+ @Override
+ @Transactional
+ public Set getIdentifiers() throws GuacamoleException {
+ return connectionGroupService.getIdentifiers(getCurrentUser());
+ }
+
+ @Override
+ @Transactional
+ public void add(ConnectionGroup object) throws GuacamoleException {
+ connectionGroupService.createObject(getCurrentUser(), object);
+ }
+
+ @Override
+ @Transactional
+ public void update(ConnectionGroup object) throws GuacamoleException {
+ ModeledConnectionGroup connectionGroup = (ModeledConnectionGroup) object;
+ connectionGroupService.updateObject(getCurrentUser(), connectionGroup);
+ }
+
+ @Override
+ @Transactional
+ public void remove(String identifier) throws GuacamoleException {
+ connectionGroupService.deleteObject(getCurrentUser(), identifier);
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.java
new file mode 100644
index 000000000..a08ef7c20
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.java
@@ -0,0 +1,92 @@
+/*
+ * 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.connectiongroup;
+
+import java.util.Set;
+import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectMapper;
+import org.glyptodon.guacamole.auth.jdbc.user.UserModel;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * Mapper for connection group objects.
+ *
+ * @author Michael Jumper
+ */
+public interface ConnectionGroupMapper extends DirectoryObjectMapper {
+
+ /**
+ * Selects the identifiers of all connection groups within the given parent
+ * connection group, regardless of whether they are readable by any
+ * particular user. This should only be called on behalf of a system
+ * administrator. If identifiers are needed by a non-administrative user
+ * who must have explicit read rights, use
+ * selectReadableIdentifiersWithin() instead.
+ *
+ * @param parentIdentifier
+ * The identifier of the parent connection group, or null if the root
+ * connection group is to be queried.
+ *
+ * @return
+ * A Set containing all identifiers of all objects.
+ */
+ Set selectIdentifiersWithin(@Param("parentIdentifier") String parentIdentifier);
+
+ /**
+ * Selects the identifiers of all connection groups within the given parent
+ * connection group that are explicitly readable by the given user. If
+ * identifiers are needed by a system administrator (who, by definition,
+ * does not need explicit read rights), use selectIdentifiersWithin()
+ * instead.
+ *
+ * @param user
+ * The user whose permissions should determine whether an identifier
+ * is returned.
+ *
+ * @param parentIdentifier
+ * The identifier of the parent connection group, or null if the root
+ * connection group is to be queried.
+ *
+ * @return
+ * A Set containing all identifiers of all readable objects.
+ */
+ Set selectReadableIdentifiersWithin(@Param("user") UserModel user,
+ @Param("parentIdentifier") String parentIdentifier);
+
+ /**
+ * Selects the connection group within the given parent group and having
+ * the given name. If no such connection group exists, null is returned.
+ *
+ * @param parentIdentifier
+ * The identifier of the parent group to search within.
+ *
+ * @param name
+ * The name of the connection group to find.
+ *
+ * @return
+ * The connection group having the given name within the given parent
+ * group, or null if no such connection group exists.
+ */
+ ConnectionGroupModel selectOneByName(@Param("parentIdentifier") String parentIdentifier,
+ @Param("name") String name);
+
+}
\ No newline at end of file
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupModel.java
new file mode 100644
index 000000000..68845df9c
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupModel.java
@@ -0,0 +1,141 @@
+/*
+ * 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.connectiongroup;
+
+import org.glyptodon.guacamole.auth.jdbc.base.ObjectModel;
+import org.glyptodon.guacamole.net.auth.ConnectionGroup;
+
+/**
+ * Object representation of a Guacamole connection group, as represented in the
+ * database.
+ *
+ * @author Michael Jumper
+ */
+public class ConnectionGroupModel extends ObjectModel {
+
+ /**
+ * The identifier of the parent connection group in the database, or null
+ * if the parent connection group is the root group.
+ */
+ private String parentIdentifier;
+
+ /**
+ * The human-readable name associated with this connection group.
+ */
+ private String name;
+
+ /**
+ * The type of this connection group, such as organizational or balancing.
+ */
+ private ConnectionGroup.Type type;
+
+ /**
+ * Creates a new, empty connection group.
+ */
+ public ConnectionGroupModel() {
+ }
+
+ /**
+ * Returns the name associated with this connection group.
+ *
+ * @return
+ * The name associated with this connection group.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name associated with this connection group.
+ *
+ * @param name
+ * The name to associate with this connection group.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the identifier of the parent connection group, or null if the
+ * parent connection group is the root connection group.
+ *
+ * @return
+ * The identifier of the parent connection group, or null if the parent
+ * connection group is the root connection group.
+ */
+ public String getParentIdentifier() {
+ return parentIdentifier;
+ }
+
+ /**
+ * Sets the identifier of the parent connection group.
+ *
+ * @param parentIdentifier
+ * The identifier of the parent connection group, or null if the parent
+ * connection group is the root connection group.
+ */
+ public void setParentIdentifier(String parentIdentifier) {
+ this.parentIdentifier = parentIdentifier;
+ }
+
+ /**
+ * Returns the type of this connection group, such as organizational or
+ * balancing.
+ *
+ * @return
+ * The type of this connection group.
+ */
+ public ConnectionGroup.Type getType() {
+ return type;
+ }
+
+ /**
+ * Sets the type of this connection group, such as organizational or
+ * balancing.
+ *
+ * @param type
+ * The type of this connection group.
+ */
+ public void setType(ConnectionGroup.Type type) {
+ this.type = type;
+ }
+
+ @Override
+ public String getIdentifier() {
+
+ // If no associated ID, then no associated identifier
+ Integer id = getObjectID();
+ if (id == null)
+ return null;
+
+ // Otherwise, the identifier is the ID as a string
+ return id.toString();
+
+ }
+
+ @Override
+ public void setIdentifier(String identifier) {
+ throw new UnsupportedOperationException("Connection group identifiers are derived from IDs. They cannot be set.");
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java
new file mode 100644
index 000000000..cfed2edd0
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2013 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.connectiongroup;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.util.Set;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectMapper;
+import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectService;
+import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService;
+import org.glyptodon.guacamole.GuacamoleClientException;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.GuacamoleSecurityException;
+import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionGroupPermissionMapper;
+import org.glyptodon.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
+import org.glyptodon.guacamole.net.GuacamoleSocket;
+import org.glyptodon.guacamole.net.auth.ConnectionGroup;
+import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
+import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
+import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
+import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
+import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
+
+/**
+ * Service which provides convenience methods for creating, retrieving, and
+ * manipulating connection groups.
+ *
+ * @author Michael Jumper, James Muehlner
+ */
+public class ConnectionGroupService extends DirectoryObjectService {
+
+ /**
+ * Mapper for accessing connection groups.
+ */
+ @Inject
+ private ConnectionGroupMapper connectionGroupMapper;
+
+ /**
+ * Mapper for manipulating connection group permissions.
+ */
+ @Inject
+ private ConnectionGroupPermissionMapper connectionGroupPermissionMapper;
+
+ /**
+ * Provider for creating connection groups.
+ */
+ @Inject
+ private Provider connectionGroupProvider;
+
+ /**
+ * Service for creating and tracking sockets.
+ */
+ @Inject
+ private GuacamoleSocketService socketService;
+
+ @Override
+ protected DirectoryObjectMapper getObjectMapper() {
+ return connectionGroupMapper;
+ }
+
+ @Override
+ protected ObjectPermissionMapper getPermissionMapper() {
+ return connectionGroupPermissionMapper;
+ }
+
+ @Override
+ protected ModeledConnectionGroup getObjectInstance(AuthenticatedUser currentUser,
+ ConnectionGroupModel model) {
+ ModeledConnectionGroup connectionGroup = connectionGroupProvider.get();
+ connectionGroup.init(currentUser, model);
+ return connectionGroup;
+ }
+
+ @Override
+ protected ConnectionGroupModel getModelInstance(AuthenticatedUser currentUser,
+ final ConnectionGroup object) {
+
+ // Create new ModeledConnectionGroup backed by blank model
+ ConnectionGroupModel model = new ConnectionGroupModel();
+ ModeledConnectionGroup connectionGroup = getObjectInstance(currentUser, model);
+
+ // Set model contents through ModeledConnectionGroup, copying the provided connection group
+ connectionGroup.setParentIdentifier(object.getParentIdentifier());
+ connectionGroup.setName(object.getName());
+ connectionGroup.setType(object.getType());
+
+ return model;
+
+ }
+
+ @Override
+ protected boolean hasCreatePermission(AuthenticatedUser user)
+ throws GuacamoleException {
+
+ // Return whether user has explicit connection group creation permission
+ SystemPermissionSet permissionSet = user.getUser().getSystemPermissions();
+ return permissionSet.hasPermission(SystemPermission.Type.CREATE_CONNECTION_GROUP);
+
+ }
+
+ @Override
+ protected ObjectPermissionSet getPermissionSet(AuthenticatedUser user)
+ throws GuacamoleException {
+
+ // Return permissions related to connection groups
+ return user.getUser().getConnectionGroupPermissions();
+
+ }
+
+ @Override
+ protected void validateNewModel(AuthenticatedUser user,
+ ConnectionGroupModel model) throws GuacamoleException {
+
+ // Name must not be blank
+ if (model.getName().trim().isEmpty())
+ throw new GuacamoleClientException("Connection group names must not be blank.");
+
+ // Do not attempt to create duplicate connection groups
+ ConnectionGroupModel existing = connectionGroupMapper.selectOneByName(model.getParentIdentifier(), model.getName());
+ if (existing != null)
+ throw new GuacamoleClientException("The connection group \"" + model.getName() + "\" already exists.");
+
+ }
+
+ @Override
+ protected void validateExistingModel(AuthenticatedUser user,
+ ConnectionGroupModel model) throws GuacamoleException {
+
+ // Name must not be blank
+ if (model.getName().trim().isEmpty())
+ throw new GuacamoleClientException("Connection group names must not be blank.");
+
+ // Check whether such a connection group is already present
+ ConnectionGroupModel existing = connectionGroupMapper.selectOneByName(model.getParentIdentifier(), model.getName());
+ if (existing != null) {
+
+ // If the specified name matches a DIFFERENT existing connection group, the update cannot continue
+ if (!existing.getObjectID().equals(model.getObjectID()))
+ throw new GuacamoleClientException("The connection group \"" + model.getName() + "\" already exists.");
+
+ }
+
+ }
+
+ /**
+ * Returns the set of all identifiers for all connection groups within the
+ * connection group having the given identifier. Only connection groups
+ * that the user has read access to will be returned.
+ *
+ * Permission to read the connection group having the given identifier is
+ * NOT checked.
+ *
+ * @param user
+ * The user retrieving the identifiers.
+ *
+ * @param identifier
+ * The identifier of the parent connection group, or null to check the
+ * root connection group.
+ *
+ * @return
+ * The set of all identifiers for all connection groups in the
+ * connection group having the given identifier that the user has read
+ * access to.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while reading identifiers.
+ */
+ public Set getIdentifiersWithin(AuthenticatedUser user,
+ String identifier)
+ throws GuacamoleException {
+
+ // Bypass permission checks if the user is a system admin
+ if (user.getUser().isAdministrator())
+ return connectionGroupMapper.selectIdentifiersWithin(identifier);
+
+ // Otherwise only return explicitly readable identifiers
+ else
+ return connectionGroupMapper.selectReadableIdentifiersWithin(user.getUser().getModel(), identifier);
+
+ }
+
+ /**
+ * Connects to the given connection group as the given user, using the
+ * given client information. If the user does not have permission to read
+ * the connection group, permission will be denied.
+ *
+ * @param user
+ * The user connecting to the connection group.
+ *
+ * @param connectionGroup
+ * The connectionGroup being connected to.
+ *
+ * @param info
+ * Information associated with the connecting client.
+ *
+ * @return
+ * A connected GuacamoleSocket associated with a newly-established
+ * connection.
+ *
+ * @throws GuacamoleException
+ * If permission to connect to this connection is denied.
+ */
+ public GuacamoleSocket connect(AuthenticatedUser user,
+ ModeledConnectionGroup connectionGroup, GuacamoleClientInformation info)
+ throws GuacamoleException {
+
+ // Connect only if READ permission is granted
+ if (hasObjectPermission(user, connectionGroup.getIdentifier(), ObjectPermission.Type.READ))
+ return socketService.getGuacamoleSocket(user, connectionGroup, info);
+
+ // The user does not have permission to connect
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ModeledConnectionGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ModeledConnectionGroup.java
new file mode 100644
index 000000000..cad15286c
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ModeledConnectionGroup.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2013 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.connectiongroup;
+
+import com.google.inject.Inject;
+import java.util.Set;
+import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObject;
+import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionService;
+import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.net.GuacamoleSocket;
+import org.glyptodon.guacamole.net.auth.ConnectionGroup;
+import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
+
+/**
+ * An implementation of the ConnectionGroup object which is backed by a
+ * database model.
+ *
+ * @author James Muehlner
+ */
+public class ModeledConnectionGroup extends DirectoryObject
+ implements ConnectionGroup {
+
+ /**
+ * Service for managing connections.
+ */
+ @Inject
+ private ConnectionService connectionService;
+
+ /**
+ * Service for managing connection groups.
+ */
+ @Inject
+ private ConnectionGroupService connectionGroupService;
+
+ /**
+ * Service for creating and tracking sockets.
+ */
+ @Inject
+ private GuacamoleSocketService socketService;
+
+ /**
+ * Creates a new, empty ModeledConnectionGroup.
+ */
+ public ModeledConnectionGroup() {
+ }
+
+ @Override
+ public String getName() {
+ return getModel().getName();
+ }
+
+ @Override
+ public void setName(String name) {
+ getModel().setName(name);
+ }
+
+ @Override
+ public String getParentIdentifier() {
+
+ // Translate null parent to proper identifier
+ String parentIdentifier = getModel().getParentIdentifier();
+ if (parentIdentifier == null)
+ return RootConnectionGroup.IDENTIFIER;
+
+ return parentIdentifier;
+
+ }
+
+ @Override
+ public void setParentIdentifier(String parentIdentifier) {
+
+ // Translate root identifier back into null
+ if (parentIdentifier != null
+ && parentIdentifier.equals(RootConnectionGroup.IDENTIFIER))
+ parentIdentifier = null;
+
+ getModel().setParentIdentifier(parentIdentifier);
+
+ }
+
+ @Override
+ public GuacamoleSocket connect(GuacamoleClientInformation info)
+ throws GuacamoleException {
+ return connectionGroupService.connect(getCurrentUser(), this, info);
+ }
+
+ @Override
+ public int getActiveConnections() {
+ return socketService.getActiveConnections(this).size();
+ }
+
+ @Override
+ public void setType(Type type) {
+ getModel().setType(type);
+ }
+
+ @Override
+ public Type getType() {
+ return getModel().getType();
+ }
+
+ @Override
+ public Set getConnectionIdentifiers()
+ throws GuacamoleException {
+ return connectionService.getIdentifiersWithin(getCurrentUser(), getIdentifier());
+ }
+
+ @Override
+ public Set getConnectionGroupIdentifiers()
+ throws GuacamoleException {
+ return connectionGroupService.getIdentifiersWithin(getCurrentUser(), getIdentifier());
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/RootConnectionGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/RootConnectionGroup.java
new file mode 100644
index 000000000..93b61275b
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/RootConnectionGroup.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2013 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.connectiongroup;
+
+import com.google.inject.Inject;
+import java.util.Set;
+import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionService;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.GuacamoleSecurityException;
+import org.glyptodon.guacamole.auth.jdbc.base.RestrictedObject;
+import org.glyptodon.guacamole.net.GuacamoleSocket;
+import org.glyptodon.guacamole.net.auth.ConnectionGroup;
+import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
+
+/**
+ * The root connection group, here represented as its own dedicated object as
+ * the database does not contain an actual root group.
+ *
+ * @author Michael Jumper
+ */
+public class RootConnectionGroup extends RestrictedObject
+ implements ConnectionGroup {
+
+ /**
+ * The identifier used to represent the root connection group. There is no
+ * corresponding entry in the database, thus a reserved identifier that
+ * cannot collide with database-generated identifiers is needed.
+ */
+ public static final String IDENTIFIER = "ROOT";
+
+ /**
+ * The human-readable name of this connection group. The name of the root
+ * group is not normally visible, and may even be replaced by the web
+ * interface for the sake of translation.
+ */
+ public static final String NAME = "ROOT";
+
+ /**
+ * Service for managing connection objects.
+ */
+ @Inject
+ private ConnectionService connectionService;
+
+ /**
+ * Service for managing connection group objects.
+ */
+ @Inject
+ private ConnectionGroupService connectionGroupService;
+
+ /**
+ * Creates a new, empty RootConnectionGroup.
+ */
+ public RootConnectionGroup() {
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ @Override
+ public void setName(String name) {
+ throw new UnsupportedOperationException("The root connection group cannot be modified.");
+ }
+
+ @Override
+ public String getParentIdentifier() {
+ return null;
+ }
+
+ @Override
+ public void setParentIdentifier(String parentIdentifier) {
+ throw new UnsupportedOperationException("The root connection group cannot be modified.");
+ }
+
+ @Override
+ public Type getType() {
+ return ConnectionGroup.Type.ORGANIZATIONAL;
+ }
+
+ @Override
+ public void setType(Type type) {
+ throw new UnsupportedOperationException("The root connection group cannot be modified.");
+ }
+
+ @Override
+ public Set getConnectionIdentifiers() throws GuacamoleException {
+ return connectionService.getIdentifiersWithin(getCurrentUser(), null);
+ }
+
+ @Override
+ public Set getConnectionGroupIdentifiers()
+ throws GuacamoleException {
+ return connectionGroupService.getIdentifiersWithin(getCurrentUser(), null);
+ }
+
+ @Override
+ public String getIdentifier() {
+ return IDENTIFIER;
+ }
+
+ @Override
+ public void setIdentifier(String identifier) {
+ throw new UnsupportedOperationException("The root connection group cannot be modified.");
+ }
+
+ @Override
+ public GuacamoleSocket connect(GuacamoleClientInformation info)
+ throws GuacamoleException {
+ throw new GuacamoleSecurityException("Permission denied.");
+ }
+
+ @Override
+ public int getActiveConnections() {
+ return 0;
+ }
+
+}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/package-info.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/package-info.java
similarity index 85%
rename from extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/package-info.java
rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/package-info.java
index cf3a32372..a1d0bd250 100644
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/package-info.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Glyptodon LLC
+ * 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
@@ -21,8 +21,6 @@
*/
/**
- * Properties which control the configuration of the MySQL authentication
- * provider.
+ * Classes related to connection groups.
*/
-package net.sourceforge.guacamole.net.auth.mysql.properties;
-
+package org.glyptodon.guacamole.auth.jdbc.connectiongroup;
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/package-info.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/package-info.java
new file mode 100644
index 000000000..e4d12fca9
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/package-info.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+/**
+ * The base JDBC authentication provider. This authentication provider serves
+ * as a basis for other JDBC authentication provider implementations which are
+ * driven by relatively-common schemas. The only difference between such
+ * implementations are maintained within database-specific MyBatis mappings.
+ */
+package org.glyptodon.guacamole.auth.jdbc;
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.java
new file mode 100644
index 000000000..cc791d628
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.java
@@ -0,0 +1,30 @@
+/*
+ * 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.permission;
+
+/**
+ * Mapper for connection group permissions.
+ *
+ * @author Michael Jumper
+ */
+public interface ConnectionGroupPermissionMapper extends ObjectPermissionMapper {}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java
new file mode 100644
index 000000000..e64d6c71f
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java
@@ -0,0 +1,69 @@
+/*
+ * 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.permission;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.auth.jdbc.user.ModeledUser;
+
+/**
+ * Service which provides convenience methods for creating, retrieving, and
+ * deleting connection group permissions. This service will automatically
+ * enforce the permissions of the current user.
+ *
+ * @author Michael Jumper
+ */
+public class ConnectionGroupPermissionService extends ObjectPermissionService {
+
+ /**
+ * Mapper for connection group permissions.
+ */
+ @Inject
+ private ConnectionGroupPermissionMapper connectionGroupPermissionMapper;
+
+ /**
+ * Provider for connection group permission sets.
+ */
+ @Inject
+ private Provider connectionGroupPermissionSetProvider;
+
+ @Override
+ protected ObjectPermissionMapper getPermissionMapper() {
+ return connectionGroupPermissionMapper;
+ }
+
+ @Override
+ public ObjectPermissionSet getPermissionSet(AuthenticatedUser user,
+ ModeledUser targetUser) throws GuacamoleException {
+
+ // Create permission set for requested user
+ ObjectPermissionSet permissionSet = connectionGroupPermissionSetProvider.get();
+ permissionSet.init(user, targetUser);
+
+ return permissionSet;
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionSet.java
new file mode 100644
index 000000000..5f057dc2d
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionSet.java
@@ -0,0 +1,47 @@
+/*
+ * 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.permission;
+
+import com.google.inject.Inject;
+
+/**
+ * A database implementation of ObjectPermissionSet which uses an injected
+ * service to query and manipulate the connection group permissions associated
+ * with a particular user.
+ *
+ * @author Michael Jumper
+ */
+public class ConnectionGroupPermissionSet extends ObjectPermissionSet {
+
+ /**
+ * Service for querying and manipulating connection group permissions.
+ */
+ @Inject
+ private ConnectionGroupPermissionService connectionGroupPermissionService;
+
+ @Override
+ protected ObjectPermissionService getObjectPermissionService() {
+ return connectionGroupPermissionService;
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.java
new file mode 100644
index 000000000..5dfdd07cd
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.java
@@ -0,0 +1,30 @@
+/*
+ * 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.permission;
+
+/**
+ * Mapper for connection permissions.
+ *
+ * @author Michael Jumper
+ */
+public interface ConnectionPermissionMapper extends ObjectPermissionMapper {}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionService.java
new file mode 100644
index 000000000..0903f71ab
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionService.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 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.permission;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.auth.jdbc.user.ModeledUser;
+
+/**
+ * Service which provides convenience methods for creating, retrieving, and
+ * deleting connection permissions. This service will automatically enforce the
+ * permissions of the current user.
+ *
+ * @author Michael Jumper
+ */
+public class ConnectionPermissionService extends ObjectPermissionService {
+
+ /**
+ * Mapper for connection permissions.
+ */
+ @Inject
+ private ConnectionPermissionMapper connectionPermissionMapper;
+
+ /**
+ * Provider for connection permission sets.
+ */
+ @Inject
+ private Provider connectionPermissionSetProvider;
+
+ @Override
+ protected ObjectPermissionMapper getPermissionMapper() {
+ return connectionPermissionMapper;
+ }
+
+ @Override
+ public ObjectPermissionSet getPermissionSet(AuthenticatedUser user,
+ ModeledUser targetUser) throws GuacamoleException {
+
+ // Create permission set for requested user
+ ObjectPermissionSet permissionSet = connectionPermissionSetProvider.get();
+ permissionSet.init(user, targetUser);
+
+ return permissionSet;
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionSet.java
new file mode 100644
index 000000000..6ed57ebbd
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionSet.java
@@ -0,0 +1,47 @@
+/*
+ * 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.permission;
+
+import com.google.inject.Inject;
+
+/**
+ * A database implementation of ObjectPermissionSet which uses an injected
+ * service to query and manipulate the connection permissions associated with
+ * a particular user.
+ *
+ * @author Michael Jumper
+ */
+public class ConnectionPermissionSet extends ObjectPermissionSet {
+
+ /**
+ * Service for querying and manipulating connection permissions.
+ */
+ @Inject
+ private ConnectionPermissionService connectionPermissionService;
+
+ @Override
+ protected ObjectPermissionService getObjectPermissionService() {
+ return connectionPermissionService;
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java
new file mode 100644
index 000000000..fcd54b17f
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java
@@ -0,0 +1,83 @@
+/*
+ * 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.permission;
+
+import java.util.Collection;
+import org.apache.ibatis.annotations.Param;
+import org.glyptodon.guacamole.auth.jdbc.user.UserModel;
+import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
+
+/**
+ * Mapper for object-related permissions.
+ *
+ * @author Michael Jumper
+ */
+public interface ObjectPermissionMapper extends PermissionMapper {
+
+ /**
+ * Retrieve the permission of the given type associated with the given
+ * user and object, if it exists. If no such permission exists, null is
+ * returned.
+ *
+ * @param user
+ * The user to retrieve permissions for.
+ *
+ * @param type
+ * The type of permission to return.
+ *
+ * @param identifier
+ * The identifier of the object affected by the permission to return.
+ *
+ * @return
+ * The requested permission, or null if no such permission is granted
+ * to the given user for the given object.
+ */
+ ObjectPermissionModel selectOne(@Param("user") UserModel user,
+ @Param("type") ObjectPermission.Type type,
+ @Param("identifier") String identifier);
+
+ /**
+ * Retrieves the subset of the given identifiers for which the given user
+ * has at least one of the given permissions.
+ *
+ * @param user
+ * The user to check permissions of.
+ *
+ * @param permissions
+ * The permissions to check. An identifier will be included in the
+ * resulting collection if at least one of these permissions is granted
+ * for the associated object
+ *
+ * @param identifiers
+ * The identifiers of the objects affected by the permissions being
+ * checked.
+ *
+ * @return
+ * A collection containing the subset of identifiers for which at least
+ * one of the specified permissions is granted.
+ */
+ Collection selectAccessibleIdentifiers(@Param("user") UserModel user,
+ @Param("permissions") Collection permissions,
+ @Param("identifiers") Collection identifiers);
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionModel.java
new file mode 100644
index 000000000..0a00081ab
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionModel.java
@@ -0,0 +1,66 @@
+/*
+ * 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.permission;
+
+import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
+
+/**
+ * Object representation of an object-related Guacamole permission, as
+ * represented in the database.
+ *
+ * @author Michael Jumper
+ */
+public class ObjectPermissionModel extends PermissionModel {
+
+ /**
+ * The unique identifier of the object affected by this permission.
+ */
+ private String objectIdentifier;
+
+ /**
+ * Creates a new, empty object permission.
+ */
+ public ObjectPermissionModel() {
+ }
+
+ /**
+ * Returns the unique identifier of the object affected by this permission.
+ *
+ * @return
+ * The unique identifier of the object affected by this permission.
+ */
+ public String getObjectIdentifier() {
+ return objectIdentifier;
+ }
+
+ /**
+ * Sets the unique identifier of the object affected by this permission.
+ *
+ * @param objectIdentifier
+ * The unique identifier of the object affected by this permission.
+ */
+ public void setObjectIdentifier(String objectIdentifier) {
+ this.objectIdentifier = objectIdentifier;
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionService.java
new file mode 100644
index 000000000..79ce6407e
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionService.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2013 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.permission;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.auth.jdbc.user.ModeledUser;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.GuacamoleSecurityException;
+import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
+import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
+
+/**
+ * Service which provides convenience methods for creating, retrieving, and
+ * deleting object permissions. This service will automatically enforce the
+ * permissions of the current user.
+ *
+ * @author Michael Jumper
+ */
+public abstract class ObjectPermissionService
+ extends PermissionService {
+
+ @Override
+ protected abstract ObjectPermissionMapper getPermissionMapper();
+
+ @Override
+ protected ObjectPermission getPermissionInstance(ObjectPermissionModel model) {
+ return new ObjectPermission(model.getType(), model.getObjectIdentifier());
+ }
+
+ @Override
+ protected ObjectPermissionModel getModelInstance(ModeledUser targetUser,
+ ObjectPermission permission) {
+
+ ObjectPermissionModel model = new ObjectPermissionModel();
+
+ // Populate model object with data from user and permission
+ model.setUserID(targetUser.getModel().getObjectID());
+ model.setUsername(targetUser.getModel().getIdentifier());
+ model.setType(permission.getType());
+ model.setObjectIdentifier(permission.getObjectIdentifier());
+
+ return model;
+
+ }
+
+ /**
+ * Determines whether the current user has permission to update the given
+ * target user, adding or removing the given permissions. Such permission
+ * depends on whether the current user is a system administrator, whether
+ * they have explicit UPDATE permission on the target user, and whether
+ * they have explicit ADMINISTER permission on all affected objects.
+ *
+ * @param user
+ * The user who is changing permissions.
+ *
+ * @param targetUser
+ * The user whose permissions are being changed.
+ *
+ * @param permissions
+ * The permissions that are being added or removed from the target
+ * user.
+ *
+ * @return
+ * true if the user has permission to change the target users
+ * permissions as specified, false otherwise.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while checking permission status, or if
+ * permission is denied to read the current user's permissions.
+ */
+ protected boolean canAlterPermissions(AuthenticatedUser user, ModeledUser targetUser,
+ Collection permissions)
+ throws GuacamoleException {
+
+ // A system adminstrator can do anything
+ if (user.getUser().isAdministrator())
+ return true;
+
+ // Verify user has update permission on the target user
+ ObjectPermissionSet userPermissionSet = user.getUser().getUserPermissions();
+ if (!userPermissionSet.hasPermission(ObjectPermission.Type.UPDATE, targetUser.getIdentifier()))
+ return false;
+
+ // Produce collection of affected identifiers
+ Collection affectedIdentifiers = new HashSet(permissions.size());
+ for (ObjectPermission permission : permissions)
+ affectedIdentifiers.add(permission.getObjectIdentifier());
+
+ // Determine subset of affected identifiers that we have admin access to
+ ObjectPermissionSet affectedPermissionSet = getPermissionSet(user, user.getUser());
+ Collection allowedSubset = affectedPermissionSet.getAccessibleObjects(
+ Collections.singleton(ObjectPermission.Type.ADMINISTER),
+ affectedIdentifiers
+ );
+
+ // The permissions can be altered if and only if the set of objects we
+ // are allowed to administer is equal to the set of objects we will be
+ // affecting.
+
+ return affectedIdentifiers.size() == allowedSubset.size();
+
+ }
+
+ @Override
+ public void createPermissions(AuthenticatedUser user, ModeledUser targetUser,
+ Collection permissions)
+ throws GuacamoleException {
+
+ // Create permissions only if user has permission to do so
+ if (canAlterPermissions(user, targetUser, permissions)) {
+ Collection models = getModelInstances(targetUser, permissions);
+ getPermissionMapper().insert(models);
+ return;
+ }
+
+ // User lacks permission to create object permissions
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+ @Override
+ public void deletePermissions(AuthenticatedUser user, ModeledUser targetUser,
+ Collection permissions)
+ throws GuacamoleException {
+
+ // Delete permissions only if user has permission to do so
+ if (canAlterPermissions(user, targetUser, permissions)) {
+ Collection models = getModelInstances(targetUser, permissions);
+ getPermissionMapper().delete(models);
+ return;
+ }
+
+ // User lacks permission to delete object permissions
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+ /**
+ * Retrieves the permission of the given type associated with the given
+ * user and object, if it exists. If no such permission exists, null is
+ *
+ * @param user
+ * The user retrieving the permission.
+ *
+ * @param targetUser
+ * The user associated with the permission to be retrieved.
+ *
+ * @param type
+ * The type of permission to retrieve.
+ *
+ * @param identifier
+ * The identifier of the object affected by the permission to return.
+ *
+ * @return
+ * The permission of the given type associated with the given user and
+ * object, or null if no such permission exists.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while retrieving the requested permission.
+ */
+ public ObjectPermission retrievePermission(AuthenticatedUser user,
+ ModeledUser targetUser, ObjectPermission.Type type,
+ String identifier) throws GuacamoleException {
+
+ // Only an admin can read permissions that aren't his own
+ if (user.getUser().getIdentifier().equals(targetUser.getIdentifier())
+ || user.getUser().isAdministrator()) {
+
+ // Read permission from database, return null if not found
+ ObjectPermissionModel model = getPermissionMapper().selectOne(targetUser.getModel(), type, identifier);
+ if (model == null)
+ return null;
+
+ return getPermissionInstance(model);
+
+ }
+
+ // User cannot read this user's permissions
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+ /**
+ * Retrieves the subset of the given identifiers for which the given user
+ * has at least one of the given permissions.
+ *
+ * @param user
+ * The user checking the permissions.
+ *
+ * @param targetUser
+ * The user to check permissions of.
+ *
+ * @param permissions
+ * The permissions to check. An identifier will be included in the
+ * resulting collection if at least one of these permissions is granted
+ * for the associated object
+ *
+ * @param identifiers
+ * The identifiers of the objects affected by the permissions being
+ * checked.
+ *
+ * @return
+ * A collection containing the subset of identifiers for which at least
+ * one of the specified permissions is granted.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while retrieving permissions.
+ */
+ public Collection retrieveAccessibleIdentifiers(AuthenticatedUser user,
+ ModeledUser targetUser, Collection permissions,
+ Collection identifiers) throws GuacamoleException {
+
+ // Nothing is always accessible
+ if (identifiers.isEmpty())
+ return identifiers;
+
+ // Determine whether the user is an admin
+ boolean isAdmin = user.getUser().isAdministrator();
+
+ // Only an admin can read permissions that aren't his own
+ if (isAdmin || user.getUser().getIdentifier().equals(targetUser.getIdentifier())) {
+
+ // If user is an admin, everything is accessible
+ if (isAdmin)
+ return identifiers;
+
+ // Otherwise, return explicitly-retrievable identifiers
+ return getPermissionMapper().selectAccessibleIdentifiers(targetUser.getModel(), permissions, identifiers);
+
+ }
+
+ // User cannot read this user's permissions
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionSet.java
new file mode 100644
index 000000000..3806f046c
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionSet.java
@@ -0,0 +1,125 @@
+/*
+ * 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.permission;
+
+import org.glyptodon.guacamole.auth.jdbc.user.ModeledUser;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.auth.jdbc.base.RestrictedObject;
+import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
+
+/**
+ * A database implementation of ObjectPermissionSet which uses an injected
+ * service to query and manipulate the object-level permissions associated with
+ * a particular user.
+ *
+ * @author Michael Jumper
+ */
+public abstract class ObjectPermissionSet extends RestrictedObject
+ implements org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet {
+
+ /**
+ * The user associated with this permission set. Each of the permissions in
+ * this permission set is granted to this user.
+ */
+ private ModeledUser user;
+
+ /**
+ * Creates a new ObjectPermissionSet. The resulting permission set
+ * must still be initialized by a call to init(), or the information
+ * necessary to read and modify this set will be missing.
+ */
+ public ObjectPermissionSet() {
+ }
+
+ /**
+ * Initializes this permission set with the current user and the user
+ * to whom the permissions in this set are granted.
+ *
+ * @param currentUser
+ * The user who queried this permission set, and whose permissions
+ * dictate the access level of all operations performed on this set.
+ *
+ * @param user
+ * The user to whom the permissions in this set are granted.
+ */
+ public void init(AuthenticatedUser currentUser, ModeledUser user) {
+ super.init(currentUser);
+ this.user = user;
+ }
+
+ /**
+ * Returns an ObjectPermissionService implementation for manipulating the
+ * type of permissions contained within this permission set.
+ *
+ * @return
+ * An object permission service for manipulating the type of
+ * permissions contained within this permission set.
+ */
+ protected abstract ObjectPermissionService getObjectPermissionService();
+
+ @Override
+ public Set getPermissions() throws GuacamoleException {
+ return getObjectPermissionService().retrievePermissions(getCurrentUser(), user);
+ }
+
+ @Override
+ public boolean hasPermission(ObjectPermission.Type permission,
+ String identifier) throws GuacamoleException {
+ return getObjectPermissionService().retrievePermission(getCurrentUser(), user, permission, identifier) != null;
+ }
+
+ @Override
+ public void addPermission(ObjectPermission.Type permission,
+ String identifier) throws GuacamoleException {
+ addPermissions(Collections.singleton(new ObjectPermission(permission, identifier)));
+ }
+
+ @Override
+ public void removePermission(ObjectPermission.Type permission,
+ String identifier) throws GuacamoleException {
+ removePermissions(Collections.singleton(new ObjectPermission(permission, identifier)));
+ }
+
+ @Override
+ public Collection getAccessibleObjects(Collection permissions,
+ Collection identifiers) throws GuacamoleException {
+ return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), user, permissions, identifiers);
+ }
+
+ @Override
+ public void addPermissions(Set permissions)
+ throws GuacamoleException {
+ getObjectPermissionService().createPermissions(getCurrentUser(), user, permissions);
+ }
+
+ @Override
+ public void removePermissions(Set permissions)
+ throws GuacamoleException {
+ getObjectPermissionService().deletePermissions(getCurrentUser(), user, permissions);
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/PermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/PermissionMapper.java
new file mode 100644
index 000000000..eff35a1ac
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/PermissionMapper.java
@@ -0,0 +1,73 @@
+/*
+ * 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.permission;
+
+import java.util.Collection;
+import org.glyptodon.guacamole.auth.jdbc.user.UserModel;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * Generic base for mappers which handle permissions.
+ *
+ * @author Michael Jumper
+ * @param
+ * The type of permission model object handled by this mapper.
+ */
+public interface PermissionMapper {
+
+ /**
+ * Retrieves all permissions associated with the given user.
+ *
+ * @param user
+ * The user to retrieve permissions for.
+ *
+ * @return
+ * All permissions associated with the given user.
+ */
+ Collection select(@Param("user") UserModel user);
+
+ /**
+ * Inserts the given permissions into the database. If any permissions
+ * already exist, they will be ignored.
+ *
+ * @param permissions
+ * The permissions to insert.
+ *
+ * @return
+ * The number of rows inserted.
+ */
+ int insert(@Param("permissions") Collection permissions);
+
+ /**
+ * Deletes the given permissions from the database. If any permissions do
+ * not exist, they will be ignored.
+ *
+ * @param permissions
+ * The permissions to delete.
+ *
+ * @return
+ * The number of rows deleted.
+ */
+ int delete(@Param("permissions") Collection permissions);
+
+}
\ No newline at end of file
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/PermissionModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/PermissionModel.java
new file mode 100644
index 000000000..d50c9704f
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/PermissionModel.java
@@ -0,0 +1,110 @@
+/*
+ * 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.permission;
+
+/**
+ * Generic base permission model which grants a permission of a particular type
+ * to a specific user.
+ *
+ * @author Michael Jumper
+ * @param
+ * The type of permissions allowed within this model.
+ */
+public abstract class PermissionModel {
+
+ /**
+ * The database ID of the user to whom this permission is granted.
+ */
+ private Integer userID;
+
+ /**
+ * The username of the user to whom this permission is granted.
+ */
+ private String username;
+
+ /**
+ * The type of action granted by this permission.
+ */
+ private PermissionType type;
+
+ /**
+ * Returns the database ID of the user to whom this permission is granted.
+ *
+ * @return
+ * The database ID of the user to whom this permission is granted.
+ */
+ public Integer getUserID() {
+ return userID;
+ }
+
+ /**
+ * Sets the database ID of the user to whom this permission is granted.
+ *
+ * @param userID
+ * The database ID of the user to whom this permission is granted.
+ */
+ public void setUserID(Integer userID) {
+ this.userID = userID;
+ }
+
+ /**
+ * Returns the username of the user to whom this permission is granted.
+ *
+ * @return
+ * The username of the user to whom this permission is granted.
+ */
+ public String getUsername() {
+ return username;
+ }
+
+ /**
+ * Sets the username of the user to whom this permission is granted.
+ *
+ * @param username
+ * The username of the user to whom this permission is granted.
+ */
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ /**
+ * Returns the type of action granted by this permission.
+ *
+ * @return
+ * The type of action granted by this permission.
+ */
+ public PermissionType getType() {
+ return type;
+ }
+
+ /**
+ * Sets the type of action granted by this permission.
+ *
+ * @param type
+ * The type of action granted by this permission.
+ */
+ public void setType(PermissionType type) {
+ this.type = type;
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/PermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/PermissionService.java
new file mode 100644
index 000000000..3207ffc8d
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/PermissionService.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2013 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.permission;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.auth.jdbc.user.ModeledUser;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.GuacamoleSecurityException;
+import org.glyptodon.guacamole.net.auth.permission.Permission;
+import org.glyptodon.guacamole.net.auth.permission.PermissionSet;
+
+/**
+ * Service which provides convenience methods for creating, retrieving, and
+ * deleting permissions, and for obtaining the permission sets that contain
+ * these permissions. This service will automatically enforce the permissions
+ * of the current user.
+ *
+ * @author Michael Jumper
+ * @param
+ * The type of permission sets this service provides access to.
+ *
+ * @param
+ * The type of permission this service provides access to.
+ *
+ * @param
+ * The underlying model object used to represent PermissionType in the
+ * database.
+ */
+public abstract class PermissionService,
+ PermissionType extends Permission, ModelType> {
+
+ /**
+ * Returns an instance of a mapper for the type of permission used by this
+ * service.
+ *
+ * @return
+ * A mapper which provides access to the model objects associated with
+ * the permissions used by this service.
+ */
+ protected abstract PermissionMapper getPermissionMapper();
+
+ /**
+ * Returns an instance of a permission which is based on the given model
+ * object.
+ *
+ * @param model
+ * The model object to use to produce the returned permission.
+ *
+ * @return
+ * A permission which is based on the given model object.
+ */
+ protected abstract PermissionType getPermissionInstance(ModelType model);
+
+ /**
+ * Returns a collection of permissions which are based on the models in
+ * the given collection.
+ *
+ * @param models
+ * The model objects to use to produce the permissions within the
+ * returned set.
+ *
+ * @return
+ * A set of permissions which are based on the models in the given
+ * collection.
+ */
+ protected Set getPermissionInstances(Collection models) {
+
+ // Create new collection of permissions by manually converting each model
+ Set permissions = new HashSet(models.size());
+ for (ModelType model : models)
+ permissions.add(getPermissionInstance(model));
+
+ return permissions;
+
+ }
+
+ /**
+ * Returns an instance of a model object which is based on the given
+ * permission and target user.
+ *
+ * @param targetUser
+ * The user to whom this permission is granted.
+ *
+ * @param permission
+ * The permission to use to produce the returned model object.
+ *
+ * @return
+ * A model object which is based on the given permission and target
+ * user.
+ */
+ protected abstract ModelType getModelInstance(ModeledUser targetUser,
+ PermissionType permission);
+
+ /**
+ * Returns a collection of model objects which are based on the given
+ * permissions and target user.
+ *
+ * @param targetUser
+ * The user to whom this permission is granted.
+ *
+ * @param permissions
+ * The permissions to use to produce the returned model objects.
+ *
+ * @return
+ * A collection of model objects which are based on the given
+ * permissions and target user.
+ */
+ protected Collection getModelInstances(ModeledUser targetUser,
+ Collection permissions) {
+
+ // Create new collection of models by manually converting each permission
+ Collection models = new ArrayList(permissions.size());
+ for (PermissionType permission : permissions)
+ models.add(getModelInstance(targetUser, permission));
+
+ return models;
+
+ }
+
+ /**
+ * Returns a permission set that can be used to retrieve and manipulate the
+ * permissions of the given user.
+ *
+ * @param user
+ * The user who will be retrieving or manipulating permissions through
+ * the returned permission set.
+ *
+ * @param targetUser
+ * The user to whom the permissions in the returned permission set are
+ * granted.
+ *
+ * @return
+ * A permission set that contains all permissions associated with the
+ * given user, and can be used to manipulate that user's permissions.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while retrieving the permissions of the given
+ * user, or if permission to retrieve the permissions of the given
+ * user is denied.
+ */
+ public abstract PermissionSetType getPermissionSet(AuthenticatedUser user,
+ ModeledUser targetUser) throws GuacamoleException;
+
+ /**
+ * Retrieves all permissions associated with the given user.
+ *
+ * @param user
+ * The user retrieving the permissions.
+ *
+ * @param targetUser
+ * The user associated with the permissions to be retrieved.
+ *
+ * @return
+ * The permissions associated with the given user.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while retrieving the requested permissions.
+ */
+ public Set retrievePermissions(AuthenticatedUser user,
+ ModeledUser targetUser) throws GuacamoleException {
+
+ // Only an admin can read permissions that aren't his own
+ if (user.getUser().getIdentifier().equals(targetUser.getIdentifier())
+ || user.getUser().isAdministrator())
+ return getPermissionInstances(getPermissionMapper().select(targetUser.getModel()));
+
+ // User cannot read this user's permissions
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+ /**
+ * Creates the given permissions within the database. If any permissions
+ * already exist, they will be ignored.
+ *
+ * @param user
+ * The user creating the permissions.
+ *
+ * @param targetUser
+ * The user associated with the permissions to be created.
+ *
+ * @param permissions
+ * The permissions to create.
+ *
+ * @throws GuacamoleException
+ * If the user lacks permission to create the permissions, or an error
+ * occurs while creating the permissions.
+ */
+ public abstract void createPermissions(AuthenticatedUser user,
+ ModeledUser targetUser,
+ Collection permissions) throws GuacamoleException;
+
+ /**
+ * Deletes the given permissions. If any permissions do not exist, they
+ * will be ignored.
+ *
+ * @param user
+ * The user deleting the permissions.
+ *
+ * @param targetUser
+ * The user associated with the permissions to be deleted.
+ *
+ * @param permissions
+ * The permissions to delete.
+ *
+ * @throws GuacamoleException
+ * If the user lacks permission to delete the permissions, or an error
+ * occurs while deleting the permissions.
+ */
+ public abstract void deletePermissions(AuthenticatedUser user,
+ ModeledUser targetUser,
+ Collection permissions) throws GuacamoleException;
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.java
new file mode 100644
index 000000000..fdcb63ce9
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.java
@@ -0,0 +1,53 @@
+/*
+ * 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.permission;
+
+import org.glyptodon.guacamole.auth.jdbc.user.UserModel;
+import org.apache.ibatis.annotations.Param;
+import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
+
+/**
+ * Mapper for system-level permissions.
+ *
+ * @author Michael Jumper
+ */
+public interface SystemPermissionMapper extends PermissionMapper {
+
+ /**
+ * Retrieve the permission of the given type associated with the given
+ * user, if it exists. If no such permission exists, null is returned.
+ *
+ * @param user
+ * The user to retrieve permissions for.
+ *
+ * @param type
+ * The type of permission to return.
+ *
+ * @return
+ * The requested permission, or null if no such permission is granted
+ * to the given user.
+ */
+ SystemPermissionModel selectOne(@Param("user") UserModel user,
+ @Param("type") SystemPermission.Type type);
+
+}
\ No newline at end of file
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionModel.java
new file mode 100644
index 000000000..8c1c13ac9
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionModel.java
@@ -0,0 +1,41 @@
+/*
+ * 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.permission;
+
+import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
+
+/**
+ * Object representation of an system-level Guacamole permission, as
+ * represented in the database.
+ *
+ * @author Michael Jumper
+ */
+public class SystemPermissionModel extends PermissionModel {
+
+ /**
+ * Creates a new, empty System permission.
+ */
+ public SystemPermissionModel() {
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionService.java
new file mode 100644
index 000000000..52edda6d0
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionService.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2013 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.permission;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.util.Collection;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.auth.jdbc.user.ModeledUser;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.GuacamoleSecurityException;
+import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
+
+/**
+ * Service which provides convenience methods for creating, retrieving, and
+ * deleting system permissions. This service will automatically enforce
+ * the permissions of the current user.
+ *
+ * @author Michael Jumper
+ */
+public class SystemPermissionService
+ extends PermissionService {
+
+ /**
+ * Mapper for system-level permissions.
+ */
+ @Inject
+ private SystemPermissionMapper systemPermissionMapper;
+
+ /**
+ * Provider for creating system permission sets.
+ */
+ @Inject
+ private Provider systemPermissionSetProvider;
+
+ @Override
+ protected SystemPermissionMapper getPermissionMapper() {
+ return systemPermissionMapper;
+ }
+
+ @Override
+ protected SystemPermission getPermissionInstance(SystemPermissionModel model) {
+ return new SystemPermission(model.getType());
+ }
+
+ @Override
+ protected SystemPermissionModel getModelInstance(final ModeledUser targetUser,
+ final SystemPermission permission) {
+
+ SystemPermissionModel model = new SystemPermissionModel();
+
+ // Populate model object with data from user and permission
+ model.setUserID(targetUser.getModel().getObjectID());
+ model.setUsername(targetUser.getModel().getIdentifier());
+ model.setType(permission.getType());
+
+ return model;
+
+ }
+
+ @Override
+ public SystemPermissionSet getPermissionSet(AuthenticatedUser user,
+ ModeledUser targetUser) throws GuacamoleException {
+
+ // Create permission set for requested user
+ SystemPermissionSet permissionSet = systemPermissionSetProvider.get();
+ permissionSet.init(user, targetUser);
+
+ return permissionSet;
+
+ }
+
+ @Override
+ public void createPermissions(AuthenticatedUser user, ModeledUser targetUser,
+ Collection permissions) throws GuacamoleException {
+
+ // Only an admin can create system permissions
+ if (user.getUser().isAdministrator()) {
+ Collection models = getModelInstances(targetUser, permissions);
+ systemPermissionMapper.insert(models);
+ return;
+ }
+
+ // User lacks permission to create system permissions
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+ @Override
+ public void deletePermissions(AuthenticatedUser user, ModeledUser targetUser,
+ Collection permissions) throws GuacamoleException {
+
+ // Only an admin can delete system permissions
+ if (user.getUser().isAdministrator()) {
+ Collection models = getModelInstances(targetUser, permissions);
+ systemPermissionMapper.delete(models);
+ return;
+ }
+
+ // User lacks permission to delete system permissions
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+ /**
+ * Retrieves the permission of the given type associated with the given
+ * user, if it exists. If no such permission exists, null is returned.
+ *
+ * @param user
+ * The user retrieving the permission.
+ *
+ * @param targetUser
+ * The user associated with the permission to be retrieved.
+ *
+ * @param type
+ * The type of permission to retrieve.
+ *
+ * @return
+ * The permission of the given type associated with the given user, or
+ * null if no such permission exists.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while retrieving the requested permission.
+ */
+ public SystemPermission retrievePermission(AuthenticatedUser user,
+ ModeledUser targetUser, SystemPermission.Type type) throws GuacamoleException {
+
+ // Only an admin can read permissions that aren't his own
+ if (user.getUser().getIdentifier().equals(targetUser.getIdentifier())
+ || user.getUser().isAdministrator()) {
+
+ // Read permission from database, return null if not found
+ SystemPermissionModel model = getPermissionMapper().selectOne(targetUser.getModel(), type);
+ if (model == null)
+ return null;
+
+ return getPermissionInstance(model);
+
+ }
+
+ // User cannot read this user's permissions
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionSet.java
new file mode 100644
index 000000000..485eaecfe
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionSet.java
@@ -0,0 +1,115 @@
+/*
+ * 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.permission;
+
+import org.glyptodon.guacamole.auth.jdbc.user.ModeledUser;
+import com.google.inject.Inject;
+import java.util.Collections;
+import java.util.Set;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.auth.jdbc.base.RestrictedObject;
+import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
+
+/**
+ * A database implementation of SystemPermissionSet which uses an injected
+ * service to query and manipulate the system permissions associated with a
+ * particular user.
+ *
+ * @author Michael Jumper
+ */
+public class SystemPermissionSet extends RestrictedObject
+ implements org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet {
+
+ /**
+ * The user associated with this permission set. Each of the permissions in
+ * this permission set is granted to this user.
+ */
+ private ModeledUser user;
+
+ /**
+ * Service for reading and manipulating system permissions.
+ */
+ @Inject
+ private SystemPermissionService systemPermissionService;
+
+ /**
+ * Creates a new SystemPermissionSet. The resulting permission set
+ * must still be initialized by a call to init(), or the information
+ * necessary to read and modify this set will be missing.
+ */
+ public SystemPermissionSet() {
+ }
+
+ /**
+ * Initializes this permission set with the current user and the user
+ * to whom the permissions in this set are granted.
+ *
+ * @param currentUser
+ * The user who queried this permission set, and whose permissions
+ * dictate the access level of all operations performed on this set.
+ *
+ * @param user
+ * The user to whom the permissions in this set are granted.
+ */
+ public void init(AuthenticatedUser currentUser, ModeledUser user) {
+ super.init(currentUser);
+ this.user = user;
+ }
+
+ @Override
+ public Set getPermissions() throws GuacamoleException {
+ return systemPermissionService.retrievePermissions(getCurrentUser(), user);
+ }
+
+ @Override
+ public boolean hasPermission(SystemPermission.Type permission)
+ throws GuacamoleException {
+ return systemPermissionService.retrievePermission(getCurrentUser(), user, permission) != null;
+ }
+
+ @Override
+ public void addPermission(SystemPermission.Type permission)
+ throws GuacamoleException {
+ addPermissions(Collections.singleton(new SystemPermission(permission)));
+ }
+
+ @Override
+ public void removePermission(SystemPermission.Type permission)
+ throws GuacamoleException {
+ removePermissions(Collections.singleton(new SystemPermission(permission)));
+ }
+
+ @Override
+ public void addPermissions(Set permissions)
+ throws GuacamoleException {
+ systemPermissionService.createPermissions(getCurrentUser(), user, permissions);
+ }
+
+ @Override
+ public void removePermissions(Set permissions)
+ throws GuacamoleException {
+ systemPermissionService.deletePermissions(getCurrentUser(), user, permissions);
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.java
new file mode 100644
index 000000000..a6c3275d9
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.java
@@ -0,0 +1,30 @@
+/*
+ * 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.permission;
+
+/**
+ * Mapper for user permissions.
+ *
+ * @author Michael Jumper
+ */
+public interface UserPermissionMapper extends ObjectPermissionMapper {}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionService.java
new file mode 100644
index 000000000..33497496a
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionService.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 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.permission;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.auth.jdbc.user.ModeledUser;
+
+/**
+ * Service which provides convenience methods for creating, retrieving, and
+ * deleting user permissions. This service will automatically enforce the
+ * permissions of the current user.
+ *
+ * @author Michael Jumper
+ */
+public class UserPermissionService extends ObjectPermissionService {
+
+ /**
+ * Mapper for user permissions.
+ */
+ @Inject
+ private UserPermissionMapper userPermissionMapper;
+
+ /**
+ * Provider for user permission sets.
+ */
+ @Inject
+ private Provider userPermissionSetProvider;
+
+ @Override
+ protected ObjectPermissionMapper getPermissionMapper() {
+ return userPermissionMapper;
+ }
+
+ @Override
+ public ObjectPermissionSet getPermissionSet(AuthenticatedUser user,
+ ModeledUser targetUser) throws GuacamoleException {
+
+ // Create permission set for requested user
+ ObjectPermissionSet permissionSet = userPermissionSetProvider.get();
+ permissionSet.init(user, targetUser);
+
+ return permissionSet;
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionSet.java
new file mode 100644
index 000000000..ca99be759
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionSet.java
@@ -0,0 +1,47 @@
+/*
+ * 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.permission;
+
+import com.google.inject.Inject;
+
+/**
+ * A database implementation of ObjectPermissionSet which uses an injected
+ * service to query and manipulate the user permissions associated with a
+ * particular user.
+ *
+ * @author Michael Jumper
+ */
+public class UserPermissionSet extends ObjectPermissionSet {
+
+ /**
+ * Service for querying and manipulating user permissions.
+ */
+ @Inject
+ private UserPermissionService userPermissionService;
+
+ @Override
+ protected ObjectPermissionService getObjectPermissionService() {
+ return userPermissionService;
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/package-info.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/package-info.java
new file mode 100644
index 000000000..01b820ac1
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/**
+ * Classes related to object- and system-level permissions.
+ */
+package org.glyptodon.guacamole.auth.jdbc.permission;
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/PasswordEncryptionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/PasswordEncryptionService.java
similarity index 71%
rename from extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/PasswordEncryptionService.java
rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/PasswordEncryptionService.java
index 67ea8bab0..ef3099468 100644
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/PasswordEncryptionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/PasswordEncryptionService.java
@@ -20,8 +20,7 @@
* THE SOFTWARE.
*/
-package net.sourceforge.guacamole.net.auth.mysql.service;
-
+package org.glyptodon.guacamole.auth.jdbc.security;
/**
* A service to perform password encryption and checking.
@@ -29,20 +28,6 @@ package net.sourceforge.guacamole.net.auth.mysql.service;
*/
public interface PasswordEncryptionService {
- /**
- * Checks whether the provided, unhashed password matches the given
- * hash/salt pair.
- *
- * @param password The unhashed password to validate.
- * @param hashedPassword The hashed password to compare the given password
- * against.
- * @param salt The salt used when the hashed password given was created.
- * @return true if the provided credentials match the values given, false
- * otherwise.
- */
- public boolean checkPassword(String password, byte[] hashedPassword,
- byte[] salt);
-
/**
* Creates a password hash based on the provided username, password, and
* salt.
@@ -52,4 +37,5 @@ public interface PasswordEncryptionService {
* @return The generated password hash.
*/
public byte[] createPasswordHash(String password, byte[] salt);
+
}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SHA256PasswordEncryptionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/SHA256PasswordEncryptionService.java
similarity index 84%
rename from extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SHA256PasswordEncryptionService.java
rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/SHA256PasswordEncryptionService.java
index aa3043805..cfe5bc45f 100644
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SHA256PasswordEncryptionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/SHA256PasswordEncryptionService.java
@@ -20,12 +20,11 @@
* THE SOFTWARE.
*/
-package net.sourceforge.guacamole.net.auth.mysql.service;
+package org.glyptodon.guacamole.auth.jdbc.security;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
import javax.xml.bind.DatatypeConverter;
/**
@@ -34,16 +33,6 @@ import javax.xml.bind.DatatypeConverter;
*/
public class SHA256PasswordEncryptionService implements PasswordEncryptionService {
- @Override
- public boolean checkPassword(String password, byte[] hashedPassword,
- byte[] salt) {
-
- // Compare bytes of password in credentials against hashed password
- byte[] passwordBytes = createPasswordHash(password, salt);
- return Arrays.equals(passwordBytes, hashedPassword);
-
- }
-
@Override
public byte[] createPasswordHash(String password, byte[] salt) {
@@ -72,4 +61,5 @@ public class SHA256PasswordEncryptionService implements PasswordEncryptionServic
}
}
+
}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SaltService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/SaltService.java
similarity index 96%
rename from extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SaltService.java
rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/SaltService.java
index 823fa93da..7badde447 100644
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SaltService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/SaltService.java
@@ -20,7 +20,7 @@
* THE SOFTWARE.
*/
-package net.sourceforge.guacamole.net.auth.mysql.service;
+package org.glyptodon.guacamole.auth.jdbc.security;
/**
* A service to generate password salts.
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SecureRandomSaltService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/SecureRandomSaltService.java
similarity index 96%
rename from extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SecureRandomSaltService.java
rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/SecureRandomSaltService.java
index e119eb881..608733b5b 100644
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SecureRandomSaltService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/SecureRandomSaltService.java
@@ -20,7 +20,7 @@
* THE SOFTWARE.
*/
-package net.sourceforge.guacamole.net.auth.mysql.service;
+package org.glyptodon.guacamole.auth.jdbc.security;
import java.security.SecureRandom;
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/package-info.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/package-info.java
new file mode 100644
index 000000000..3f1d8b4f7
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/**
+ * Classes related to hashing or encryption.
+ */
+package org.glyptodon.guacamole.auth.jdbc.security;
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/AbstractGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/AbstractGuacamoleSocketService.java
new file mode 100644
index 000000000..5f1b623e6
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/AbstractGuacamoleSocketService.java
@@ -0,0 +1,288 @@
+/*
+ * 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.socket;
+
+import com.google.inject.Inject;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
+import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
+import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionRecordMapper;
+import org.glyptodon.guacamole.auth.jdbc.connection.ParameterMapper;
+import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionModel;
+import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionRecordModel;
+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.environment.Environment;
+import org.glyptodon.guacamole.net.GuacamoleSocket;
+import org.glyptodon.guacamole.net.InetGuacamoleSocket;
+import org.glyptodon.guacamole.net.auth.Connection;
+import org.glyptodon.guacamole.net.auth.ConnectionGroup;
+import org.glyptodon.guacamole.net.auth.ConnectionRecord;
+import org.glyptodon.guacamole.protocol.ConfiguredGuacamoleSocket;
+import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
+import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
+import org.glyptodon.guacamole.token.StandardTokens;
+import org.glyptodon.guacamole.token.TokenFilter;
+
+
+/**
+ * Base implementation of the GuacamoleSocketService, handling retrieval of
+ * connection parameters, load balancing, and connection usage counts. The
+ * implementation of concurrency rules is up to policy-specific subclasses.
+ *
+ * @author Michael Jumper
+ */
+public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketService {
+
+ /**
+ * The environment of the Guacamole server.
+ */
+ @Inject
+ private Environment environment;
+
+ /**
+ * Mapper for accessing connection parameters.
+ */
+ @Inject
+ private ParameterMapper parameterMapper;
+
+ /**
+ * Mapper for accessing connection history.
+ */
+ @Inject
+ private ConnectionRecordMapper connectionRecordMapper;
+
+ /**
+ * The current number of concurrent uses of the connection having a given
+ * identifier.
+ */
+ private final Map> activeConnections =
+ new HashMap>();
+
+ /**
+ * Atomically increments the current usage count for the given connection.
+ *
+ * @param connection
+ * The connection which is being used.
+ */
+ private void addActiveConnection(Connection connection, ConnectionRecord record) {
+ synchronized (activeConnections) {
+
+ String identifier = connection.getIdentifier();
+
+ // Get set of active connection records, creating if necessary
+ LinkedList connections = activeConnections.get(identifier);
+ if (connections == null) {
+ connections = new LinkedList();
+ activeConnections.put(identifier, connections);
+ }
+
+ // Add active connection
+ connections.addFirst(record);
+
+ }
+ }
+
+ /**
+ * Atomically decrements the current usage count for the given connection.
+ * If a combination of incrementUsage() and decrementUsage() calls result
+ * in the usage counter being reduced to zero, it is guaranteed that one
+ * of those decrementUsage() calls will remove the value from the map.
+ *
+ * @param connection
+ * The connection which is no longer being used.
+ */
+ private void removeActiveConnection(Connection connection, ConnectionRecord record) {
+ synchronized (activeConnections) {
+
+ String identifier = connection.getIdentifier();
+
+ // Get set of active connection records
+ LinkedList connections = activeConnections.get(identifier);
+ assert(connections != null);
+
+ // Remove old record
+ connections.remove(record);
+
+ // If now empty, clean the tracking entry
+ if (connections.isEmpty())
+ activeConnections.remove(identifier);
+
+ }
+ }
+
+ /**
+ * Acquires possibly-exclusive access to the given connection on behalf of
+ * the given user. If access is denied for any reason, an exception is
+ * thrown.
+ *
+ * @param user
+ * The user acquiring access.
+ *
+ * @param connection
+ * The connection being accessed.
+ *
+ * @throws GuacamoleException
+ * If access is denied to the given user for any reason.
+ */
+ protected abstract void acquire(AuthenticatedUser user,
+ ModeledConnection connection) throws GuacamoleException;
+
+ /**
+ * Releases possibly-exclusive access to the given connection on behalf of
+ * the given user. If the given user did not already have access, the
+ * behavior of this function is undefined.
+ *
+ * @param user
+ * The user releasing access.
+ *
+ * @param connection
+ * The connection being released.
+ */
+ protected abstract void release(AuthenticatedUser user,
+ ModeledConnection connection);
+
+ @Override
+ public GuacamoleSocket getGuacamoleSocket(final AuthenticatedUser user,
+ final ModeledConnection connection, GuacamoleClientInformation info)
+ throws GuacamoleException {
+
+ // Create record for active connection
+ final ActiveConnectionRecord activeConnection = new ActiveConnectionRecord(user);
+
+ // Generate configuration from available data
+ GuacamoleConfiguration config = new GuacamoleConfiguration();
+
+ // Set protocol from connection
+ ConnectionModel model = connection.getModel();
+ config.setProtocol(model.getProtocol());
+
+ // Set parameters from associated data
+ Collection parameters = parameterMapper.select(connection.getIdentifier());
+ for (ParameterModel parameter : parameters)
+ config.setParameter(parameter.getName(), parameter.getValue());
+
+ // Build token filter containing credential tokens
+ TokenFilter tokenFilter = new TokenFilter();
+ StandardTokens.addStandardTokens(tokenFilter, user.getCredentials());
+
+ // Filter the configuration
+ tokenFilter.filterValues(config.getParameters());
+
+ // Return new socket
+ try {
+
+ // Atomically gain access to connection
+ acquire(user, connection);
+ addActiveConnection(connection, activeConnection);
+
+ // Return newly-reserved connection
+ return new ConfiguredGuacamoleSocket(
+ new InetGuacamoleSocket(
+ environment.getRequiredProperty(Environment.GUACD_HOSTNAME),
+ environment.getRequiredProperty(Environment.GUACD_PORT)
+ ),
+ config
+ ) {
+
+ @Override
+ public void close() throws GuacamoleException {
+
+ // Attempt to close connection
+ super.close();
+
+ // Release connection upon close
+ removeActiveConnection(connection, activeConnection);
+ release(user, connection);
+
+ UserModel userModel = user.getUser().getModel();
+ ConnectionRecordModel recordModel = new ConnectionRecordModel();
+
+ // Copy user information and timestamps into new record
+ recordModel.setUserID(userModel.getObjectID());
+ recordModel.setUsername(userModel.getIdentifier());
+ recordModel.setConnectionIdentifier(connection.getIdentifier());
+ recordModel.setStartDate(activeConnection.getStartDate());
+ recordModel.setEndDate(new Date());
+
+ // Insert connection record
+ connectionRecordMapper.insert(recordModel);
+
+ }
+
+ };
+
+ }
+
+ // Release connection in case of error
+ catch (GuacamoleException e) {
+
+ // Atomically release access to connection
+ removeActiveConnection(connection, activeConnection);
+ release(user, connection);
+
+ throw e;
+
+ }
+
+ }
+
+ @Override
+ public List getActiveConnections(Connection connection) {
+ synchronized (activeConnections) {
+
+ String identifier = connection.getIdentifier();
+
+ // Get set of active connection records
+ LinkedList connections = activeConnections.get(identifier);
+ if (connections != null)
+ return Collections.unmodifiableList(connections);
+
+ return Collections.EMPTY_LIST;
+
+ }
+ }
+
+ @Override
+ public GuacamoleSocket getGuacamoleSocket(AuthenticatedUser user,
+ ModeledConnectionGroup connectionGroup,
+ GuacamoleClientInformation info) throws GuacamoleException {
+ // STUB
+ throw new UnsupportedOperationException("STUB");
+ }
+
+ @Override
+ public List getActiveConnections(ConnectionGroup connectionGroup) {
+ // STUB
+ return Collections.EMPTY_LIST;
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ActiveConnectionRecord.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ActiveConnectionRecord.java
new file mode 100644
index 000000000..f32669446
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ActiveConnectionRecord.java
@@ -0,0 +1,89 @@
+/*
+ * 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.socket;
+
+import java.util.Date;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.net.auth.ConnectionRecord;
+
+
+/**
+ * A connection record implementation that describes an active connection. As
+ * the associated connection has not yet ended, getEndDate() will always return
+ * null, and isActive() will always return true. The associated start date will
+ * be the time of this objects creation.
+ *
+ * @author Michael Jumper
+ */
+public class ActiveConnectionRecord implements ConnectionRecord {
+
+ /**
+ * The user that connected to the connection associated with this connection
+ * record.
+ */
+ private final AuthenticatedUser user;
+
+ /**
+ * The time this connection record was created.
+ */
+ private final Date startDate = new Date();
+
+ /**
+ * Creates a new connection record associated with the given user. The
+ * start date of this connection record will be the time of its creation.
+ *
+ * @param user
+ * The user that connected to the connection associated with this
+ * connection record.
+ */
+ public ActiveConnectionRecord(AuthenticatedUser user) {
+ this.user = user;
+ }
+
+ @Override
+ public Date getStartDate() {
+ return startDate;
+ }
+
+ @Override
+ public Date getEndDate() {
+
+ // Active connections have not yet ended
+ return null;
+
+ }
+
+ @Override
+ public String getUsername() {
+ return user.getUser().getIdentifier();
+ }
+
+ @Override
+ public boolean isActive() {
+
+ // Active connections are active by definition
+ return true;
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/GuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/GuacamoleSocketService.java
new file mode 100644
index 000000000..31e240ba2
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/GuacamoleSocketService.java
@@ -0,0 +1,132 @@
+/*
+ * 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.socket;
+
+import java.util.List;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
+import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.net.GuacamoleSocket;
+import org.glyptodon.guacamole.net.auth.Connection;
+import org.glyptodon.guacamole.net.auth.ConnectionGroup;
+import org.glyptodon.guacamole.net.auth.ConnectionRecord;
+import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
+
+
+/**
+ * Service which creates pre-configured GuacamoleSocket instances for
+ * connections and balancing groups, applying concurrent usage rules.
+ *
+ * @author Michael Jumper
+ */
+public interface GuacamoleSocketService {
+
+ /**
+ * Creates a socket for the given user which connects to the given
+ * connection. The given client information will be passed to guacd when
+ * the connection is established. This function will apply any concurrent
+ * usage rules in effect, but will NOT test object- or system-level
+ * permissions.
+ *
+ * @param user
+ * The user for whom the connection is being established.
+ *
+ * @param connection
+ * The connection the user is connecting to.
+ *
+ * @param info
+ * Information describing the Guacamole client connecting to the given
+ * connection.
+ *
+ * @return
+ * A new GuacamoleSocket which is configured and connected to the given
+ * connection.
+ *
+ * @throws GuacamoleException
+ * If the connection cannot be established due to concurrent usage
+ * rules.
+ */
+ GuacamoleSocket getGuacamoleSocket(AuthenticatedUser user,
+ ModeledConnection connection, GuacamoleClientInformation info)
+ throws GuacamoleException;
+
+ /**
+ * Returns a list containing connection records representing all currently-
+ * active connections using the given connection. These records will have
+ * usernames and start dates, but no end date.
+ *
+ * @param connection
+ * The connection to check.
+ *
+ * @return
+ * A list containing connection records representing all currently-
+ * active connections.
+ */
+ public List getActiveConnections(Connection connection);
+
+ /**
+ * Creates a socket for the given user which connects to the given
+ * connection group. The given client information will be passed to guacd
+ * when the connection is established. This function will apply any
+ * concurrent usage rules in effect, but will NOT test object- or
+ * system-level permissions.
+ *
+ * @param user
+ * The user for whom the connection is being established.
+ *
+ * @param connectionGroup
+ * The connection group the user is connecting to.
+ *
+ * @param info
+ * Information describing the Guacamole client connecting to the given
+ * connection group.
+ *
+ * @return
+ * A new GuacamoleSocket which is configured and connected to the given
+ * connection group.
+ *
+ * @throws GuacamoleException
+ * If the connection cannot be established due to concurrent usage
+ * rules, or if the connection group is not balancing.
+ */
+ GuacamoleSocket getGuacamoleSocket(AuthenticatedUser user,
+ ModeledConnectionGroup connectionGroup,
+ GuacamoleClientInformation info)
+ throws GuacamoleException;
+
+ /**
+ * Returns a list containing connection records representing all currently-
+ * active connections using the given connection group. These records will
+ * have usernames and start dates, but no end date.
+ *
+ * @param connectionGroup
+ * The connection group to check.
+ *
+ * @return
+ * A list containing connection records representing all currently-
+ * active connections.
+ */
+ public List getActiveConnections(ConnectionGroup connectionGroup);
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/UnrestrictedGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/UnrestrictedGuacamoleSocketService.java
new file mode 100644
index 000000000..a1d619378
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/UnrestrictedGuacamoleSocketService.java
@@ -0,0 +1,52 @@
+/*
+ * 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.socket;
+
+import com.google.inject.Singleton;
+import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
+import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
+import org.glyptodon.guacamole.GuacamoleException;
+
+
+/**
+ * GuacamoleSocketService implementation which imposes no restrictions
+ * whatsoever on the number of concurrent or duplicate connections.
+ *
+ * @author Michael Jumper
+ */
+@Singleton
+public class UnrestrictedGuacamoleSocketService
+ extends AbstractGuacamoleSocketService {
+
+ @Override
+ protected void acquire(AuthenticatedUser user, ModeledConnection connection)
+ throws GuacamoleException {
+ // Do nothing
+ }
+
+ @Override
+ protected void release(AuthenticatedUser user, ModeledConnection connection) {
+ // Do nothing
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/package-info.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/package-info.java
new file mode 100644
index 000000000..42c8cc335
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/package-info.java
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/**
+ * Classes related to obtaining/configuring Guacamole sockets, and restricting
+ * access to those sockets.
+ */
+package org.glyptodon.guacamole.auth.jdbc.socket;
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/AuthenticatedUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/AuthenticatedUser.java
similarity index 75%
rename from extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/AuthenticatedUser.java
rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/AuthenticatedUser.java
index a6aab2b15..7b01d4598 100644
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/AuthenticatedUser.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/AuthenticatedUser.java
@@ -20,22 +20,21 @@
* THE SOFTWARE.
*/
-package net.sourceforge.guacamole.net.auth.mysql;
+package org.glyptodon.guacamole.auth.jdbc.user;
import org.glyptodon.guacamole.net.auth.Credentials;
/**
- * Represents an authenticated user via their database ID and corresponding
- * credentials.
+ * Associates a user with the credentials they used to authenticate.
*
* @author Michael Jumper
*/
public class AuthenticatedUser {
/**
- * The database ID of this user.
+ * The user that authenticated.
*/
- private final int userID;
+ private final ModeledUser user;
/**
* The credentials given when this user authenticated.
@@ -43,28 +42,28 @@ public class AuthenticatedUser {
private final Credentials credentials;
/**
- * Creates a new AuthenticatedUser associated with the given database ID
- * and credentials.
+ * Creates a new AuthenticatedUser associating the given user with their
+ * corresponding credentials.
*
- * @param userID
- * The database ID of the user this object should represent.
+ * @param user
+ * The user this object should represent.
*
* @param credentials
* The credentials given by the user when they authenticated.
*/
- public AuthenticatedUser(int userID, Credentials credentials) {
- this.userID = userID;
+ public AuthenticatedUser(ModeledUser user, Credentials credentials) {
+ this.user = user;
this.credentials = credentials;
}
/**
- * Returns the ID of this user.
+ * Returns the user that authenticated.
*
* @return
- * The ID of this user.
+ * The user that authenticated.
*/
- public int getUserID() {
- return userID;
+ public ModeledUser getUser() {
+ return user;
}
/**
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/ModeledUser.java
new file mode 100644
index 000000000..e9f79d2fd
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/ModeledUser.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2013 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.user;
+
+import com.google.inject.Inject;
+import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObject;
+import org.glyptodon.guacamole.auth.jdbc.security.PasswordEncryptionService;
+import org.glyptodon.guacamole.auth.jdbc.security.SaltService;
+import org.glyptodon.guacamole.auth.jdbc.permission.SystemPermissionService;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionGroupPermissionService;
+import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionPermissionService;
+import org.glyptodon.guacamole.auth.jdbc.permission.UserPermissionService;
+import org.glyptodon.guacamole.net.auth.User;
+import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
+import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
+import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
+
+/**
+ * An implementation of the User object which is backed by a database model.
+ *
+ * @author James Muehlner
+ * @author Michael Jumper
+ */
+public class ModeledUser extends DirectoryObject implements User {
+
+ /**
+ * Service for hashing passwords.
+ */
+ @Inject
+ private PasswordEncryptionService encryptionService;
+
+ /**
+ * Service for providing secure, random salts.
+ */
+ @Inject
+ private SaltService saltService;
+
+ /**
+ * Service for retrieving system permissions.
+ */
+ @Inject
+ private SystemPermissionService systemPermissionService;
+
+ /**
+ * Service for retrieving connection permissions.
+ */
+ @Inject
+ private ConnectionPermissionService connectionPermissionService;
+
+ /**
+ * Service for retrieving connection group permissions.
+ */
+ @Inject
+ private ConnectionGroupPermissionService connectionGroupPermissionService;
+
+ /**
+ * Service for retrieving user permissions.
+ */
+ @Inject
+ private UserPermissionService userPermissionService;
+
+ /**
+ * The plaintext password previously set by a call to setPassword(), if
+ * any. The password of a user cannot be retrieved once saved into the
+ * database, so this serves to ensure getPassword() returns a reasonable
+ * value if setPassword() is called. If no password has been set, or the
+ * user was retrieved from the database, this will be null.
+ */
+ private String password = null;
+
+ /**
+ * Creates a new, empty ModeledUser.
+ */
+ public ModeledUser() {
+ }
+
+ @Override
+ public String getPassword() {
+ return password;
+ }
+
+ @Override
+ public void setPassword(String password) {
+
+ UserModel userModel = getModel();
+
+ // Store plaintext password internally
+ this.password = password;
+
+ // If no password provided, clear password salt and hash
+ if (password == null) {
+ userModel.setPasswordSalt(null);
+ userModel.setPasswordHash(null);
+ }
+
+ // Otherwise generate new salt and hash given password using newly-generated salt
+ else {
+ byte[] salt = saltService.generateSalt();
+ byte[] hash = encryptionService.createPasswordHash(password, salt);
+
+ // Set stored salt and hash
+ userModel.setPasswordSalt(salt);
+ userModel.setPasswordHash(hash);
+ }
+
+ }
+
+ /**
+ * Returns whether this user is a system administrator, and thus is not
+ * restricted by permissions.
+ *
+ * @return
+ * true if this user is a system administrator, false otherwise.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while determining the user's system administrator
+ * status.
+ */
+ public boolean isAdministrator() throws GuacamoleException {
+ SystemPermissionSet systemPermissionSet = getSystemPermissions();
+ return systemPermissionSet.hasPermission(SystemPermission.Type.ADMINISTER);
+ }
+
+ @Override
+ public SystemPermissionSet getSystemPermissions()
+ throws GuacamoleException {
+ return systemPermissionService.getPermissionSet(getCurrentUser(), this);
+ }
+
+ @Override
+ public ObjectPermissionSet getConnectionPermissions()
+ throws GuacamoleException {
+ return connectionPermissionService.getPermissionSet(getCurrentUser(), this);
+ }
+
+ @Override
+ public ObjectPermissionSet getConnectionGroupPermissions()
+ throws GuacamoleException {
+ return connectionGroupPermissionService.getPermissionSet(getCurrentUser(), this);
+ }
+
+ @Override
+ public ObjectPermissionSet getUserPermissions()
+ throws GuacamoleException {
+ return userPermissionService.getPermissionSet(getCurrentUser(), this);
+ }
+
+}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUserContext.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserContext.java
similarity index 50%
rename from extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUserContext.java
rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserContext.java
index 43f0728bb..fac5b9af9 100644
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUserContext.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserContext.java
@@ -20,29 +20,30 @@
* THE SOFTWARE.
*/
-package net.sourceforge.guacamole.net.auth.mysql;
+package org.glyptodon.guacamole.auth.jdbc.user;
+import org.glyptodon.guacamole.auth.jdbc.connectiongroup.RootConnectionGroup;
+import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ConnectionGroupDirectory;
+import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionDirectory;
import com.google.inject.Inject;
+import com.google.inject.Provider;
import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.auth.jdbc.base.RestrictedObject;
+import org.glyptodon.guacamole.net.auth.Connection;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.net.auth.Directory;
import org.glyptodon.guacamole.net.auth.User;
-import org.glyptodon.guacamole.net.auth.UserContext;
-import net.sourceforge.guacamole.net.auth.mysql.service.UserService;
-import org.glyptodon.guacamole.net.auth.Credentials;
/**
- * The MySQL representation of a UserContext.
+ * UserContext implementation which is driven by an arbitrary, underlying
+ * database.
+ *
* @author James Muehlner
+ * @author Michael Jumper
*/
-public class MySQLUserContext implements UserContext {
-
- /**
- * The the user owning this context. The permissions of this user dictate
- * the access given via the user and connection directories.
- */
- private AuthenticatedUser currentUser;
+public class UserContext extends RestrictedObject
+ implements org.glyptodon.guacamole.net.auth.UserContext {
/**
* User directory restricted by the permissions of the user associated
@@ -50,47 +51,67 @@ public class MySQLUserContext implements UserContext {
*/
@Inject
private UserDirectory userDirectory;
-
+
/**
- * The root connection group.
+ * Connection directory restricted by the permissions of the user
+ * associated with this context.
*/
@Inject
- private MySQLConnectionGroup rootConnectionGroup;
+ private ConnectionDirectory connectionDirectory;
/**
- * Service for accessing users.
+ * Connection group directory restricted by the permissions of the user
+ * associated with this context.
*/
@Inject
- private UserService userService;
+ private ConnectionGroupDirectory connectionGroupDirectory;
/**
- * Initializes the user and directories associated with this context.
- *
- * @param currentUser
- * The user owning this context.
+ * Provider for creating the root group.
*/
+ @Inject
+ private Provider rootGroupProvider;
+
+ @Override
public void init(AuthenticatedUser currentUser) {
- this.currentUser = currentUser;
+
+ super.init(currentUser);
+
+ // Init directories
userDirectory.init(currentUser);
- rootConnectionGroup.init(null, null,
- MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER,
- MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER,
- ConnectionGroup.Type.ORGANIZATIONAL, currentUser);
+ connectionDirectory.init(currentUser);
+ connectionGroupDirectory.init(currentUser);
+
}
@Override
public User self() {
- return userService.retrieveUser(currentUser.getUserID());
+ return getCurrentUser().getUser();
}
@Override
- public Directory getUserDirectory() throws GuacamoleException {
+ public Directory getUserDirectory() throws GuacamoleException {
return userDirectory;
}
+ @Override
+ public Directory getConnectionDirectory() throws GuacamoleException {
+ return connectionDirectory;
+ }
+
+ @Override
+ public Directory getConnectionGroupDirectory() throws GuacamoleException {
+ return connectionGroupDirectory;
+ }
+
@Override
public ConnectionGroup getRootConnectionGroup() throws GuacamoleException {
- return rootConnectionGroup;
+
+ // Build and return a root group for the current user
+ RootConnectionGroup rootGroup = rootGroupProvider.get();
+ rootGroup.init(getCurrentUser());
+ return rootGroup;
+
}
}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserContextService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserContextService.java
new file mode 100644
index 000000000..c0a31074f
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserContextService.java
@@ -0,0 +1,84 @@
+/*
+ * 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.user;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.net.auth.Credentials;
+
+/**
+ * Service which creates new UserContext instances for valid users based on
+ * credentials.
+ *
+ * @author Michael Jumper
+ */
+public class UserContextService {
+
+ /**
+ * Service for accessing users.
+ */
+ @Inject
+ private UserService userService;
+
+ /**
+ * Provider for retrieving UserContext instances.
+ */
+ @Inject
+ private Provider userContextProvider;
+
+ /**
+ * Authenticates the user having the given credentials, returning a new
+ * UserContext instance if the credentials are valid.
+ *
+ * @param credentials
+ * The credentials to use to produce the UserContext.
+ *
+ * @return
+ * A new UserContext instance for the user identified by the given
+ * credentials, or null if the credentials are not valid.
+ *
+ * @throws GuacamoleException
+ * If an error occurs during authentication.
+ */
+ public org.glyptodon.guacamole.net.auth.UserContext
+ getUserContext(Credentials credentials)
+ throws GuacamoleException {
+
+ // Authenticate user
+ ModeledUser user = userService.retrieveUser(credentials);
+ if (user != null) {
+
+ // Upon successful authentication, return new user context
+ UserContext context = userContextProvider.get();
+ context.init(user.getCurrentUser());
+ return context;
+
+ }
+
+ // Otherwise, unauthorized
+ return null;
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserDirectory.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserDirectory.java
new file mode 100644
index 000000000..826957b89
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserDirectory.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2013 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.user;
+
+
+import com.google.inject.Inject;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.auth.jdbc.base.RestrictedObject;
+import org.glyptodon.guacamole.net.auth.Directory;
+import org.glyptodon.guacamole.net.auth.User;
+import org.mybatis.guice.transactional.Transactional;
+
+/**
+ * Implementation of the User Directory which is driven by an underlying,
+ * arbitrary database.
+ *
+ * @author James Muehlner
+ * @author Michael Jumper
+ */
+public class UserDirectory extends RestrictedObject
+ implements Directory {
+
+ /**
+ * Service for managing user objects.
+ */
+ @Inject
+ private UserService userService;
+
+ @Override
+ public User get(String identifier) throws GuacamoleException {
+ return userService.retrieveObject(getCurrentUser(), identifier);
+ }
+
+ @Override
+ @Transactional
+ public Collection getAll(Collection identifiers) throws GuacamoleException {
+ Collection objects = userService.retrieveObjects(getCurrentUser(), identifiers);
+ return Collections.unmodifiableCollection(objects);
+ }
+
+ @Override
+ @Transactional
+ public Set getIdentifiers() throws GuacamoleException {
+ return userService.getIdentifiers(getCurrentUser());
+ }
+
+ @Override
+ @Transactional
+ public void add(User object) throws GuacamoleException {
+ userService.createObject(getCurrentUser(), object);
+ }
+
+ @Override
+ @Transactional
+ public void update(User object) throws GuacamoleException {
+ ModeledUser user = (ModeledUser) object;
+ userService.updateObject(getCurrentUser(), user);
+ }
+
+ @Override
+ @Transactional
+ public void remove(String identifier) throws GuacamoleException {
+ userService.deleteObject(getCurrentUser(), identifier);
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.java
new file mode 100644
index 000000000..0563196de
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.java
@@ -0,0 +1,64 @@
+/*
+ * 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.user;
+
+import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectMapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * Mapper for user objects.
+ *
+ * @author Michael Jumper
+ */
+public interface UserMapper extends DirectoryObjectMapper {
+
+ /**
+ * Returns the user having the given username and password, if any. If no
+ * such user exists, null is returned.
+ *
+ * @param username
+ * The username of the user to return.
+ *
+ * @param password
+ * The password of the user to return.
+ *
+ * @return
+ * The user having the given username and password, or null if no such
+ * user exists.
+ */
+ UserModel selectOneByCredentials(@Param("username") String username,
+ @Param("password") String password);
+
+ /**
+ * Returns the user having the given username, if any. If no such user
+ * exists, null is returned.
+ *
+ * @param username
+ * The username of the user to return.
+ *
+ * @return
+ * The user having the given username, or null if no such user exists.
+ */
+ UserModel selectOne(@Param("username") String username);
+
+}
\ No newline at end of file
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserModel.java
new file mode 100644
index 000000000..546b1927a
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserModel.java
@@ -0,0 +1,100 @@
+/*
+ * 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.user;
+
+import org.glyptodon.guacamole.auth.jdbc.base.ObjectModel;
+
+/**
+ * Object representation of a Guacamole user, as represented in the database.
+ *
+ * @author Michael Jumper
+ */
+public class UserModel extends ObjectModel {
+
+ /**
+ * The SHA-256 hash of the password and salt.
+ */
+ private byte[] passwordHash;
+
+ /**
+ * The 32-byte random binary password salt that was appended to the
+ * password prior to hashing.
+ */
+ private byte[] passwordSalt;
+
+ /**
+ * Creates a new, empty user.
+ */
+ public UserModel() {
+ }
+
+ /**
+ * Returns the hash of this user's password and password salt. This may be
+ * null if the user was not retrieved from the database, and setPassword()
+ * has not yet been called.
+ *
+ * @return
+ * The hash of this user's password and password salt.
+ */
+ public byte[] getPasswordHash() {
+ return passwordHash;
+ }
+
+ /**
+ * Sets the hash of this user's password and password salt. This is
+ * normally only set upon retrieval from the database, or through a call
+ * to the higher-level setPassword() function.
+ *
+ * @param passwordHash
+ * The hash of this user's password and password salt.
+ */
+ public void setPasswordHash(byte[] passwordHash) {
+ this.passwordHash = passwordHash;
+ }
+
+ /**
+ * Returns the random salt that was used when generating this user's
+ * password hash. This may be null if the user was not retrieved from the
+ * database, and setPassword() has not yet been called.
+ *
+ * @return
+ * The random salt that was used when generating this user's password
+ * hash.
+ */
+ public byte[] getPasswordSalt() {
+ return passwordSalt;
+ }
+
+ /**
+ * Sets the random salt that was used when generating this user's password
+ * hash. This is normally only set upon retrieval from the database, or
+ * through a call to the higher-level setPassword() function.
+ *
+ * @param passwordSalt
+ * The random salt used when generating this user's password hash.
+ */
+ public void setPasswordSalt(byte[] passwordSalt) {
+ this.passwordSalt = passwordSalt;
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserService.java
new file mode 100644
index 000000000..1fd24dc54
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserService.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2013 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.user;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.util.Collection;
+import java.util.Collections;
+import org.glyptodon.guacamole.net.auth.Credentials;
+import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectMapper;
+import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectService;
+import org.glyptodon.guacamole.GuacamoleClientException;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
+import org.glyptodon.guacamole.auth.jdbc.permission.UserPermissionMapper;
+import org.glyptodon.guacamole.net.auth.User;
+import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
+import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
+import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
+
+/**
+ * Service which provides convenience methods for creating, retrieving, and
+ * manipulating users.
+ *
+ * @author Michael Jumper, James Muehlner
+ */
+public class UserService extends DirectoryObjectService {
+
+ /**
+ * Mapper for accessing users.
+ */
+ @Inject
+ private UserMapper userMapper;
+
+ /**
+ * Mapper for manipulating user permissions.
+ */
+ @Inject
+ private UserPermissionMapper userPermissionMapper;
+
+ /**
+ * Provider for creating users.
+ */
+ @Inject
+ private Provider userProvider;
+
+ @Override
+ protected DirectoryObjectMapper getObjectMapper() {
+ return userMapper;
+ }
+
+ @Override
+ protected ObjectPermissionMapper getPermissionMapper() {
+ return userPermissionMapper;
+ }
+
+ @Override
+ protected ModeledUser getObjectInstance(AuthenticatedUser currentUser,
+ UserModel model) {
+ ModeledUser user = userProvider.get();
+ user.init(currentUser, model);
+ return user;
+ }
+
+ @Override
+ protected UserModel getModelInstance(AuthenticatedUser currentUser,
+ final User object) {
+
+ // Create new ModeledUser backed by blank model
+ UserModel model = new UserModel();
+ ModeledUser user = getObjectInstance(currentUser, model);
+
+ // Set model contents through ModeledUser, copying the provided user
+ user.setIdentifier(object.getIdentifier());
+ user.setPassword(object.getPassword());
+
+ return model;
+
+ }
+
+ @Override
+ protected boolean hasCreatePermission(AuthenticatedUser user)
+ throws GuacamoleException {
+
+ // Return whether user has explicit user creation permission
+ SystemPermissionSet permissionSet = user.getUser().getSystemPermissions();
+ return permissionSet.hasPermission(SystemPermission.Type.CREATE_USER);
+
+ }
+
+ @Override
+ protected ObjectPermissionSet getPermissionSet(AuthenticatedUser user)
+ throws GuacamoleException {
+
+ // Return permissions related to users
+ return user.getUser().getUserPermissions();
+
+ }
+
+ @Override
+ protected void validateNewModel(AuthenticatedUser user, UserModel model)
+ throws GuacamoleException {
+
+ // Username must not be blank
+ if (model.getIdentifier().trim().isEmpty())
+ throw new GuacamoleClientException("The username must not be blank.");
+
+ // Do not create duplicate users
+ Collection existing = userMapper.select(Collections.singleton(model.getIdentifier()));
+ if (!existing.isEmpty())
+ throw new GuacamoleClientException("User \"" + model.getIdentifier() + "\" already exists.");
+
+ }
+
+ @Override
+ protected void validateExistingModel(AuthenticatedUser user,
+ UserModel model) throws GuacamoleException {
+
+ // Username must not be blank
+ if (model.getIdentifier().trim().isEmpty())
+ throw new GuacamoleClientException("The username must not be blank.");
+
+ // Check whether such a user is already present
+ UserModel existing = userMapper.selectOne(model.getIdentifier());
+ if (existing != null) {
+
+ // Do not rename to existing user
+ if (!existing.getObjectID().equals(model.getObjectID()))
+ throw new GuacamoleClientException("User \"" + model.getIdentifier() + "\" already exists.");
+
+ }
+
+ }
+
+ /**
+ * Retrieves the user corresponding to the given credentials from the
+ * database.
+ *
+ * @param credentials
+ * The credentials to use when locating the user.
+ *
+ * @return
+ * The existing ModeledUser object if the credentials given are valid,
+ * null otherwise.
+ */
+ public ModeledUser retrieveUser(Credentials credentials) {
+
+ // Get username and password
+ String username = credentials.getUsername();
+ String password = credentials.getPassword();
+
+ // Retrieve user model, if the user exists
+ UserModel userModel = userMapper.selectOneByCredentials(username, password);
+ if (userModel == null)
+ return null;
+
+ // Return corresponding user, set up cyclic reference
+ ModeledUser user = getObjectInstance(null, userModel);
+ user.setCurrentUser(new AuthenticatedUser(user, credentials));
+ return user;
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/package-info.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/package-info.java
new file mode 100644
index 000000000..e5c15703f
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/**
+ * Classes related to Guacamole users.
+ */
+package org.glyptodon.guacamole.auth.jdbc.user;
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/.gitignore b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/.gitignore
new file mode 100644
index 000000000..42f4a1a64
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/.gitignore
@@ -0,0 +1,2 @@
+target/
+*~
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/pom.xml
new file mode 100644
index 000000000..47dbf1797
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/pom.xml
@@ -0,0 +1,78 @@
+
+
+ 4.0.0
+ org.glyptodon.guacamole
+ guacamole-auth-jdbc-mysql
+ jar
+ guacamole-auth-jdbc-mysql
+ http://guac-dev.org/
+
+
+ UTF-8
+
+
+
+ org.glyptodon.guacamole
+ guacamole-auth-jdbc
+ 0.9.5
+ ../../
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.6
+ 1.6
+
+
+
+
+
+ maven-assembly-plugin
+ 2.2-beta-5
+
+
+ jar-with-dependencies
+ package
+
+ single
+
+
+ extension/${project.artifactId}-${project.version}
+ false
+
+ jar-with-dependencies
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.glyptodon.guacamole
+ guacamole-ext
+ provided
+
+
+
+
+ org.glyptodon.guacamole
+ guacamole-auth-jdbc-base
+ 0.9.5
+
+
+
+
+
diff --git a/extensions/guacamole-auth-mysql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql
similarity index 100%
rename from extensions/guacamole-auth-mysql/schema/001-create-schema.sql
rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql
diff --git a/extensions/guacamole-auth-mysql/schema/002-create-admin-user.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/002-create-admin-user.sql
similarity index 100%
rename from extensions/guacamole-auth-mysql/schema/002-create-admin-user.sql
rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/002-create-admin-user.sql
diff --git a/extensions/guacamole-auth-mysql/schema/upgrade/upgrade-pre-0.8.2.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.8.2.sql
similarity index 100%
rename from extensions/guacamole-auth-mysql/schema/upgrade/upgrade-pre-0.8.2.sql
rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.8.2.sql
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
new file mode 100644
index 000000000..8547fcf3d
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2013 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 com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.glyptodon.guacamole.GuacamoleException;
+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.user.UserContextService;
+import org.glyptodon.guacamole.environment.Environment;
+import org.glyptodon.guacamole.environment.LocalEnvironment;
+
+/**
+ * Provides a MySQL based implementation of the AuthenticationProvider
+ * functionality.
+ *
+ * @author James Muehlner
+ * @author Michael Jumper
+ */
+public class MySQLAuthenticationProvider implements AuthenticationProvider {
+
+ /**
+ * Injector which will manage the object graph of this authentication
+ * provider.
+ */
+ private final Injector injector;
+
+ /**
+ * Creates a new MySQLAuthenticationProvider that reads and writes
+ * authentication data to a MySQL database defined by properties in
+ * guacamole.properties.
+ *
+ * @throws GuacamoleException
+ * If a required property is missing, or an error occurs while parsing
+ * a property.
+ */
+ public MySQLAuthenticationProvider() throws GuacamoleException {
+
+ // Get local environment
+ Environment environment = new LocalEnvironment();
+
+ // Set up Guice injector.
+ injector = Guice.createInjector(
+
+ // Configure MySQL-specific authentication
+ new MySQLAuthenticationProviderModule(environment),
+
+ // Configure JDBC authentication core
+ new JDBCAuthenticationProviderModule(environment)
+
+ );
+
+ }
+
+ @Override
+ public UserContext getUserContext(Credentials credentials)
+ throws GuacamoleException {
+
+ // Create UserContext based on credentials, if valid
+ UserContextService userContextService = injector.getInstance(UserContextService.class);
+ return userContextService.getUserContext(credentials);
+
+ }
+
+ @Override
+ public UserContext updateUserContext(UserContext context,
+ Credentials credentials) throws GuacamoleException {
+
+ // No need to update the context
+ return context;
+
+ }
+
+}
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
new file mode 100644
index 000000000..e5af46928
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProviderModule.java
@@ -0,0 +1,98 @@
+/*
+ * 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 com.google.inject.Binder;
+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;
+
+/**
+ * Guice module which configures MySQL-specific injections.
+ *
+ * @author James Muehlner
+ */
+public class MySQLAuthenticationProviderModule implements Module {
+
+ /**
+ * MyBatis-specific configuration properties.
+ */
+ private final Properties myBatisProperties = new Properties();
+
+ /**
+ * MySQL-specific driver configuration properties.
+ */
+ private final Properties driverProperties = new Properties();
+
+ /**
+ * Creates a new MySQL authentication provider module that configures
+ * driver and MyBatis properties using the given environment.
+ *
+ * @param environment
+ * The environment to use when configuring MyBatis and the underlying
+ * JDBC driver.
+ *
+ * @throws GuacamoleException
+ * If a required property is missing, or an error occurs while parsing
+ * a property.
+ */
+ public MySQLAuthenticationProviderModule(Environment 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.autoCommit", "false");
+ myBatisProperties.setProperty("mybatis.pooled.pingEnabled", "true");
+ myBatisProperties.setProperty("mybatis.pooled.pingQuery", "SELECT 1");
+
+ // Use UTF-8 in database
+ driverProperties.setProperty("characterEncoding","UTF-8");
+
+
+ }
+
+ @Override
+ public void configure(Binder binder) {
+
+ // Bind MySQL-specific properties
+ JdbcHelper.MySQL.configure(binder);
+
+ // Bind MyBatis properties
+ Names.bindProperties(binder, myBatisProperties);
+
+ // Bing JDBC driver properties
+ binder.bind(Properties.class)
+ .annotatedWith(Names.named("JDBC.driverProperties"))
+ .toInstance(driverProperties);
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/MySQLGuacamoleProperties.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleProperties.java
similarity index 98%
rename from extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/MySQLGuacamoleProperties.java
rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleProperties.java
index a4e7ef044..3a599fc93 100644
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/MySQLGuacamoleProperties.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleProperties.java
@@ -20,7 +20,7 @@
* THE SOFTWARE.
*/
-package net.sourceforge.guacamole.net.auth.mysql.properties;
+package net.sourceforge.guacamole.net.auth.mysql;
import org.glyptodon.guacamole.properties.BooleanGuacamoleProperty;
import org.glyptodon.guacamole.properties.IntegerGuacamoleProperty;
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/package-info.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/package-info.java
similarity index 91%
rename from extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/package-info.java
rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/package-info.java
index b21abfcae..65dc294e6 100644
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/package-info.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/package-info.java
@@ -21,8 +21,7 @@
*/
/**
- * Base classes which support the MySQL authentication provider, including
- * the authentication provider itself.
+ * The MySQL authentication provider. This package exists outside of
+ * org.glyptodon for backwards-compatibility.
*/
package net.sourceforge.guacamole.net.auth.mysql;
-
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.xml
new file mode 100644
index 000000000..2211da069
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -0,0 +1,158 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DELETE FROM guacamole_connection
+ WHERE connection_id = #{identifier,jdbcType=VARCHAR}
+
+
+
+
+
+ INSERT INTO guacamole_connection (
+ connection_name,
+ parent_id,
+ protocol
+ )
+ VALUES (
+ #{object.name,jdbcType=VARCHAR},
+ #{object.parentIdentifier,jdbcType=VARCHAR},
+ #{object.protocol,jdbcType=VARCHAR}
+ )
+
+
+
+
+
+ UPDATE guacamole_connection
+ SET connection_name = #{object.name,jdbcType=VARCHAR},
+ parent_id = #{object.parentIdentifier,jdbcType=VARCHAR},
+ protocol = #{object.protocol,jdbcType=VARCHAR}
+ WHERE connection_id = #{object.objectID,jdbcType=INTEGER}
+
+
+
\ No newline at end of file
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
new file mode 100644
index 000000000..b5775f607
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO guacamole_connection_history (
+ connection_id,
+ user_id,
+ start_date,
+ end_date
+ )
+ VALUES (
+ #{record.connectionIdentifier,jdbcType=VARCHAR},
+ #{record.userID,jdbcType=INTEGER},
+ #{record.startDate,jdbcType=TIMESTAMP},
+ #{record.endDate,jdbcType=TIMESTAMP}
+ )
+
+
+
+
\ No newline at end of file
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.xml
new file mode 100644
index 000000000..ccd386c14
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DELETE FROM guacamole_connection_parameter
+ WHERE connection_id = #{identifier,jdbcType=VARCHAR}
+
+
+
+
+
+ INSERT INTO guacamole_connection_parameter (
+ connection_id,
+ parameter_name,
+ parameter_value
+ )
+ VALUES
+
+ (#{parameter.connectionIdentifier,jdbcType=VARCHAR},
+ #{parameter.name,jdbcType=VARCHAR},
+ #{parameter.value,jdbcType=VARCHAR})
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
new file mode 100644
index 000000000..4eb20da1c
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DELETE FROM guacamole_connection_group
+ WHERE connection_group_id = #{identifier,jdbcType=VARCHAR}
+
+
+
+
+
+ INSERT INTO guacamole_connection_group (
+ connection_group_name,
+ parent_id,
+ type
+ )
+ VALUES (
+ #{object.name,jdbcType=VARCHAR},
+ #{object.parentIdentifier,jdbcType=VARCHAR},
+ #{object.type,jdbcType=VARCHAR}
+ )
+
+
+
+
+
+ UPDATE guacamole_connection_group
+ SET connection_group_name = #{object.name,jdbcType=VARCHAR},
+ parent_id = #{object.parentIdentifier,jdbcType=VARCHAR},
+ type = #{object.type,jdbcType=VARCHAR}
+ WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER}
+
+
+
\ No newline at end of file
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
new file mode 100644
index 000000000..40ada12a5
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DELETE FROM guacamole_connection_group_permission
+ WHERE (user_id, permission, connection_group_id) IN
+
+ (#{permission.userID,jdbcType=INTEGER},
+ #{permission.type,jdbcType=VARCHAR},
+ #{permission.objectIdentifier,jdbcType=VARCHAR})
+
+
+
+
+
+
+
+ INSERT IGNORE INTO guacamole_connection_group_permission (
+ user_id,
+ permission,
+ connection_group_id
+ )
+ VALUES
+
+ (#{permission.userID,jdbcType=INTEGER},
+ #{permission.type,jdbcType=VARCHAR},
+ #{permission.objectIdentifier,jdbcType=VARCHAR})
+
+
+
+
+
\ No newline at end of file
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
new file mode 100644
index 000000000..9935f3cfd
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DELETE FROM guacamole_connection_permission
+ WHERE (user_id, permission, connection_id) IN
+
+ (#{permission.userID,jdbcType=INTEGER},
+ #{permission.type,jdbcType=VARCHAR},
+ #{permission.objectIdentifier,jdbcType=VARCHAR})
+
+
+
+
+
+
+
+ INSERT IGNORE INTO guacamole_connection_permission (
+ user_id,
+ permission,
+ connection_id
+ )
+ VALUES
+
+ (#{permission.userID,jdbcType=INTEGER},
+ #{permission.type,jdbcType=VARCHAR},
+ #{permission.objectIdentifier,jdbcType=VARCHAR})
+
+
+
+
+
\ No newline at end of file
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
new file mode 100644
index 000000000..55eacd072
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DELETE FROM guacamole_system_permission
+ WHERE (user_id, permission) IN
+
+ (#{permission.userID,jdbcType=INTEGER},
+ #{permission.type,jdbcType=VARCHAR})
+
+
+
+
+
+
+
+ INSERT IGNORE INTO guacamole_system_permission (
+ user_id,
+ permission
+ )
+ VALUES
+
+ (#{permission.userID,jdbcType=INTEGER},
+ #{permission.type,jdbcType=VARCHAR})
+
+
+
+
+
\ No newline at end of file
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
new file mode 100644
index 000000000..038bb814f
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DELETE FROM guacamole_user_permission
+ USING guacamole_user_permission
+ JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id
+ WHERE
+ (guacamole_user_permission.user_id, permission, affected.username) IN
+
+ (#{permission.userID,jdbcType=INTEGER},
+ #{permission.type,jdbcType=VARCHAR},
+ #{permission.objectIdentifier,jdbcType=VARCHAR})
+
+
+
+
+
+
+
+ INSERT IGNORE INTO guacamole_user_permission (
+ user_id,
+ permission,
+ affected_user_id
+ )
+ SELECT permissions.user_id, permissions.permission, guacamole_user.user_id FROM
+
+ SELECT #{permission.userID,jdbcType=INTEGER} AS user_id,
+ #{permission.type,jdbcType=VARCHAR} AS permission,
+ #{permission.objectIdentifier,jdbcType=VARCHAR} AS username
+
+ AS permissions
+ JOIN guacamole_user ON guacamole_user.username = permissions.username;
+
+
+
+
\ No newline at end of file
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml
new file mode 100644
index 000000000..fb7e6ff55
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml
@@ -0,0 +1,148 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DELETE FROM guacamole_user
+ WHERE username = #{identifier,jdbcType=VARCHAR}
+
+
+
+
+
+ INSERT INTO guacamole_user (
+ username,
+ password_hash,
+ password_salt
+ )
+ VALUES (
+ #{object.identifier,jdbcType=VARCHAR},
+ #{object.passwordHash,jdbcType=BINARY},
+ #{object.passwordSalt,jdbcType=BINARY}
+ )
+
+
+
+
+
+ UPDATE guacamole_user
+ SET password_hash = #{object.passwordHash,jdbcType=BINARY},
+ password_salt = #{object.passwordSalt,jdbcType=BINARY}
+ WHERE user_id = #{object.objectID,jdbcType=VARCHAR}
+
+
+
\ No newline at end of file
diff --git a/extensions/guacamole-auth-jdbc/pom.xml b/extensions/guacamole-auth-jdbc/pom.xml
new file mode 100644
index 000000000..c6c622994
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/pom.xml
@@ -0,0 +1,71 @@
+
+
+ 4.0.0
+ org.glyptodon.guacamole
+ guacamole-auth-jdbc
+ pom
+ 0.9.5
+ guacamole-auth-jdbc
+ http://guac-dev.org/
+
+
+ UTF-8
+
+
+
+
+
+ modules/guacamole-auth-jdbc-base
+
+
+ modules/guacamole-auth-jdbc-mysql
+
+
+
+
+
+
+
+
+ maven-assembly-plugin
+ 2.2-beta-5
+ false
+
+
+ make-dist-archive
+ package
+
+ single
+
+
+ ${project.artifactId}-${project.version}
+ false
+
+ src/main/assembly/dist.xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.glyptodon.guacamole
+ guacamole-ext
+ 0.9.5
+ provided
+
+
+
+
+
+
diff --git a/extensions/guacamole-auth-jdbc/src/main/assembly/dist.xml b/extensions/guacamole-auth-jdbc/src/main/assembly/dist.xml
new file mode 100644
index 000000000..2d20b63a0
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/src/main/assembly/dist.xml
@@ -0,0 +1,32 @@
+
+
+ dist
+ ${project.artifactId}-${project.version}
+
+
+
+ tar.gz
+
+
+
+
+
+
+
+ /mysql/schema
+ modules/guacamole-auth-jdbc-mysql/schema
+
+
+ modules/guacamole-auth-jdbc-mysql/target/extension
+ /mysql
+
+ *.jar
+
+
+
+
+
+
diff --git a/extensions/guacamole-auth-mysql/README b/extensions/guacamole-auth-mysql/README
deleted file mode 100644
index 5543c124f..000000000
--- a/extensions/guacamole-auth-mysql/README
+++ /dev/null
@@ -1,171 +0,0 @@
-
-------------------------------------------------------------
- About this README
-------------------------------------------------------------
-
-This README is intended to provide quick and to-the-point documentation for
-technical users intending to compile parts of Guacamole themselves.
-
-Distribution-specific packages are available from the files section of the main
-project page:
-
- http://sourceforge.net/projects/guacamole/files/
-
-Distribution-specific documentation is provided on the Guacamole wiki:
-
- http://guac-dev.org/
-
-
-------------------------------------------------------------
- What is guacamole-auth-mysql?
-------------------------------------------------------------
-
-guacamole-auth-ldap is a Java library for use with the Guacamole web
-application to provide MySQL based authentication.
-
-guacamole-auth-mysql provides an authentication provider which can be
-set in guacamole.properties to allow MySQL authentication of Guacamole
-users. Additional properties are required to configure the mysql
-connection parameters.
-
-A schema file are provided to create the required tables in your
-mysql database.
-
-
-------------------------------------------------------------
- Compiling and installing guacamole-auth-mysql
-------------------------------------------------------------
-
-guacamole-auth-mysql is built using Maven. Building guacamole-auth-mysql
-compiles all classes and packages them into a redistributable .jar file. This
-.jar file can be installed in the library directory configured in
-guacamole.properties such that the authentication provider is available.
-
-1) Set up a MySQL database with the Guacamole schema.
-
- When guacamole-auth-mysql is compiling, it needs to generate source
- based on a database schema. Because the source generator uses a
- connection to an actual database to do this, you must have a MySQL
- database running with the Guacamole schema set up.
-
- First, create a database. For the sake of these instructions, we will
- call the database "guacamole", and will run all scripts as the root user:
-
- $ mysql -u root -p
- Enter password:
- mysql> CREATE DATABASE guacamole;
- Query OK, 1 row affected (0.00 sec)
-
- mysql> exit
- Bye
-
- The schema files are in the schema/ subdirectory of the source. If run
- in order, they will create the schema and a default user:
-
- $ cat schema/*.sql | mysql -u root -p guacamole
-
-2) Set up your ~/.m2/settings.xml
-
- Once the database is set up, Maven will need to have the credentials
- required to connect to it and query the schema. This information is
- specified in properties inside your ~/.m2/settings.xml file. If this
- file does not exist yet, simply create it.
-
- For ease of compilation, we've included an example settings.xml
- defining the required properties in doc/example/settings.xml. You can
- simply copy this file into ~/.m2 and edit as necessary.
-
- If you wish to write the file yourself, the file should look like this in
- general:
-
-
-
- ...profiles...
-
-
-
- We need to add a profile which defines the required properties by
- placing a section like the following within the "profiles" section of your
- settings.xml:
-
-
- guacamole-mybatis
-
- DATABASE
- USERNAME
- PASSWORD
-
-
-
- Obviously, the DATABASE, USERNAME, and PASSWORD placeholders above must
- be replaced with the appropriate values for your system.
-
- Finally, to make the profile available to the build, it must be activated.
- Place a section like the following at the bottom of your settings.xml,
- right after the profiles section:
-
-
- guacamole-mybatis
-
-
- Maven's documentation has more details on writing the settings.xml file
- if you have different needs or the above directions are not clear.
-
-3) Run mvn package
-
- $ mvn package
-
- Maven will download any needed dependencies for building the .jar file.
- Once all dependencies have been downloaded, the .jar file will be
- created in the target/ subdirectory of the current directory.
-
- If this process fails, check the build errors, and verify that the
- contents of your settings.xml file is correct.
-
-4) Extract the .tar.gz file now present in the target/ directory, and
- place the .jar files in the extracted lib/ subdirectory in the library
- directory specified in guacamole.properties.
-
- You will likely need to do this as root.
-
- If you do not have a library directory configured in your
- guacamole.properties, you will need to specify one. The directory
- is specified using the "lib-directory" property.
-
-5) Set up your MySQL database to authenticate Guacamole users
-
- A schema file is provided in the schema directory for creating
- the guacamole authentication tables in your MySQL database.
-
- Additionally, a script is provided to create a default admin user
- with username 'guacadmin' and password 'guacadmin'. This user can
- be used to set up any other connections and users.
-
-6) Configure guacamole.properties for MySQL
-
- There are additional properties required by the MySQL JDBC driver
- which must be added/changed in your guacamole.properties:
-
- # Configuration for MySQL connection
- mysql-hostname: mysql.host.name
- mysql-port: 3306
- mysql-database: guacamole.database.name
- mysql-username: user
- mysql-password: pass
-
- Optionally, the authentication provider can be configured
- not to allow multiple users to use the same connection
- at the same time:
-
- mysql-disallow-simultaneous-connections: true
-
-
-------------------------------------------------------------
- Reporting problems
-------------------------------------------------------------
-
-Please report any bugs encountered by opening a new ticket at the Trac system
-hosted at:
-
- http://guac-dev.org/trac/
-
diff --git a/extensions/guacamole-auth-mysql/doc/example/settings.xml b/extensions/guacamole-auth-mysql/doc/example/settings.xml
deleted file mode 100644
index d0fb6d5bd..000000000
--- a/extensions/guacamole-auth-mysql/doc/example/settings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
- guacamole-mybatis
-
- SCHEMA
- DATABASE
- USER
- PASS
-
-
-
-
-
-
- guacamole-mybatis
-
-
-
diff --git a/extensions/guacamole-auth-mysql/pom.xml b/extensions/guacamole-auth-mysql/pom.xml
deleted file mode 100644
index e4a4f6544..000000000
--- a/extensions/guacamole-auth-mysql/pom.xml
+++ /dev/null
@@ -1,125 +0,0 @@
-
-
- 4.0.0
- org.glyptodon.guacamole
- guacamole-auth-mysql
- jar
- 0.9.5
- guacamole-auth-mysql
- http://guac-dev.org/
-
-
- UTF-8
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
-
- 1.6
- 1.6
-
-
-
-
-
- maven-assembly-plugin
- 2.2-beta-5
-
- ${project.artifactId}-${project.version}
- false
-
- src/main/assembly/dist.xml
-
-
-
-
- make-dist-archive
- package
-
- single
-
-
-
-
-
-
-
- org.mybatis.generator
- mybatis-generator-maven-plugin
- 1.3.2
-
-
-
- Generate MyBatis Artifacts
-
- generate
-
-
-
-
-
-
-
- mysql
- mysql-connector-java
- 5.1.23
-
-
-
-
-
-
-
-
-
-
-
-
- org.glyptodon.guacamole
- guacamole-common
- 0.9.4
-
-
-
-
- org.glyptodon.guacamole
- guacamole-ext
- 0.9.5
-
-
-
-
- org.slf4j
- slf4j-api
- 1.7.7
-
-
-
-
- org.mybatis
- mybatis
- 3.1.1
-
-
-
-
- org.mybatis
- mybatis-guice
- 3.2
-
-
-
-
- com.google.collections
- google-collections
- 1.0
-
-
-
-
diff --git a/extensions/guacamole-auth-mysql/src/main/assembly/dist.xml b/extensions/guacamole-auth-mysql/src/main/assembly/dist.xml
deleted file mode 100644
index 0628ad61c..000000000
--- a/extensions/guacamole-auth-mysql/src/main/assembly/dist.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
- dist
- ${project.artifactId}-${project.version}
-
-
-
- tar.gz
-
-
-
-
-
-
-
- /
- doc
-
-
-
-
- /schema
- schema
-
-
-
-
-
-
-
-
- /lib
- runtime
- false
- true
- true
-
-
-
-
- org.glyptodon.guacamole:guacamole-common
-
-
- org.glyptodon.guacamole:guacamole-ext
-
-
-
-
-
-
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/ActiveConnectionMap.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/ActiveConnectionMap.java
deleted file mode 100644
index 272434aa9..000000000
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/ActiveConnectionMap.java
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * Copyright (C) 2013 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 com.google.inject.Inject;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import org.glyptodon.guacamole.GuacamoleException;
-import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionHistoryMapper;
-import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionHistory;
-import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
-
-/**
- * Represents the map of currently active Connections to the count of the number
- * of current users. Whenever a socket is opened, the connection count should be
- * incremented, and whenever a socket is closed, the connection count should be
- * decremented.
- *
- * @author James Muehlner
- */
-public class ActiveConnectionMap {
-
- /**
- * Represents the count of users currently using a MySQL connection.
- */
- public class Connection {
-
- /**
- * The ID of the MySQL connection that this Connection represents.
- */
- private int connectionID;
-
- /**
- * The number of users currently using this connection.
- */
- private int currentUserCount;
-
- /**
- * Returns the ID of the MySQL connection that this Connection
- * represents.
- *
- * @return the ID of the MySQL connection that this Connection
- * represents.
- */
- public int getConnectionID() {
- return connectionID;
- }
-
- /**
- * Returns the number of users currently using this connection.
- *
- * @return the number of users currently using this connection.
- */
- public int getCurrentUserCount() {
- return currentUserCount;
- }
-
- /**
- * Set the current user count for this connection.
- *
- * @param currentUserCount The new user count for this Connection.
- */
- public void setCurrentUserCount(int currentUserCount) {
- this.currentUserCount = currentUserCount;
- }
-
- /**
- * Create a new Connection for the given connectionID with a zero
- * current user count.
- *
- * @param connectionID The ID of the MySQL connection that this
- * Connection represents.
- */
- public Connection(int connectionID) {
- this.connectionID = connectionID;
- this.currentUserCount = 0;
- }
- }
-
- /*
- * Represents a user connected to a connection or BALANCING connection group.
- */
- public class ConnectionUser {
- /**
- * The ID of the connection or connection group that this ConnectionUser refers to.
- */
- private int identifier;
-
- /**
- * The user that this ConnectionUser refers to.
- */
- private int userID;
-
- /**
- * Returns ID of the connection or connection group that this ConnectionUser refers to.
- * @return ID of the connection or connection group that this ConnectionUser refers to.
- */
- public int getIdentifier() {
- return identifier;
- }
-
- /**
- * Returns the user ID that this ConnectionUser refers to.
- * @return the user ID that this ConnectionUser refers to.
- */
- public int getUserID() {
- return userID;
- }
-
- /**
- * Create a ConnectionUser with the given connection or connection group
- * ID and user ID.
- *
- * @param identifier The connection or connection group ID that this
- * ConnectionUser refers to.
- * @param userID The user ID that this ConnectionUser refers to.
- */
- public ConnectionUser(int identifier, int userID) {
- this.identifier = identifier;
- this.userID = userID;
- }
-
- @Override
- public boolean equals(Object other) {
-
- // Only another ConnectionUser can equal this ConnectionUser
- if(!(other instanceof ConnectionUser))
- return false;
-
- ConnectionUser otherConnectionGroupUser =
- (ConnectionUser)other;
-
- /*
- * Two ConnectionGroupUsers are equal iff they represent the exact
- * same pairing of connection or connection group and user.
- */
- return this.identifier == otherConnectionGroupUser.identifier
- && this.userID == otherConnectionGroupUser.userID;
- }
-
- @Override
- public int hashCode() {
- int hash = 3;
- hash = 23 * hash + this.identifier;
- hash = 23 * hash + this.userID;
- return hash;
- }
- }
-
- /**
- * DAO for accessing connection history.
- */
- @Inject
- private ConnectionHistoryMapper connectionHistoryDAO;
-
- /**
- * Map of all the connections that are currently active to the
- * count of current users.
- */
- private Map activeConnectionMap =
- new HashMap();
-
- /**
- * Map of all the connection group users to the count of current usages.
- */
- private Map activeConnectionGroupUserMap =
- new HashMap();
-
- /**
- * Map of all the connection users to the count of current usages.
- */
- private Map activeConnectionUserMap =
- new HashMap();
-
- /**
- * Returns the number of connections opened by the given user using
- * the given ConnectionGroup.
- *
- * @param connectionGroupID The connection group ID that this
- * ConnectionUser refers to.
- * @param userID The user ID that this ConnectionUser refers to.
- *
- * @return The number of connections opened by the given user to the given
- * ConnectionGroup.
- */
- public int getConnectionGroupUserCount(int connectionGroupID, int userID) {
- Integer count = activeConnectionGroupUserMap.get
- (new ConnectionUser(connectionGroupID, userID));
-
- // No ConnectionUser found means this combination was never used
- if(count == null)
- return 0;
-
- return count;
- }
-
- /**
- * Checks if the given user is currently connected to the given BALANCING
- * connection group.
- *
- * @param connectionGroupID The connection group ID that this
- * ConnectionUser refers to.
- * @param userID The user ID that this ConnectionUser refers to.
- *
- * @return True if the given user is currently connected to the given
- * BALANCING connection group, false otherwise.
- */
- public boolean isConnectionGroupUserActive(int connectionGroupID, int userID) {
- Integer count = activeConnectionGroupUserMap.get
- (new ConnectionUser(connectionGroupID, userID));
-
- // The connection group is in use if the ConnectionUser count > 0
- return count != null && count > 0;
- }
-
- /**
- * Increment the count of the number of connections opened by the given user
- * to the given ConnectionGroup.
- *
- * @param connectionGroupID The connection group ID that this
- * ConnectionUser refers to.
- * @param userID The user ID that this ConnectionUser refers to.
- */
- private void incrementConnectionGroupUserCount(int connectionGroupID, int userID) {
- int currentCount = getConnectionGroupUserCount(connectionGroupID, userID);
-
- activeConnectionGroupUserMap.put
- (new ConnectionUser(connectionGroupID, userID), currentCount + 1);
- }
-
- /**
- * Decrement the count of the number of connections opened by the given user
- * to the given ConnectionGroup.
- *
- * @param connectionGroupID The connection group ID that this
- * ConnectionUser refers to.
- * @param userID The user ID that this ConnectionUser refers to.
- */
- private void decrementConnectionGroupUserCount(int connectionGroupID, int userID) {
- int currentCount = getConnectionGroupUserCount(connectionGroupID, userID);
-
- activeConnectionGroupUserMap.put
- (new ConnectionUser(connectionGroupID, userID), currentCount - 1);
- }
-
- /**
- * Returns the number of connections opened by the given user using
- * the given Connection.
- *
- * @param connectionID The connection ID that this ConnectionUser refers to.
- * @param userID The user ID that this ConnectionUser refers to.
- *
- * @return The number of connections opened by the given user to the given
- * connection.
- */
- public int getConnectionUserCount(int connectionID, int userID) {
- Integer count = activeConnectionUserMap.get
- (new ConnectionUser(connectionID, userID));
-
- // No ConnectionUser found means this combination was never used
- if(count == null)
- return 0;
-
- return count;
- }
-
- /**
- * Checks if the given user is currently connected to the given connection.
- *
- * @param connectionID The connection ID that this ConnectionUser refers to.
- * @param userID The user ID that this ConnectionUser refers to.
- *
- * @return True if the given user is currently connected to the given
- * connection, false otherwise.
- */
- public boolean isConnectionUserActive(int connectionID, int userID) {
- Integer count = activeConnectionUserMap.get
- (new ConnectionUser(connectionID, userID));
-
- // The connection is in use if the ConnectionUser count > 0
- return count != null && count > 0;
- }
-
- /**
- * Increment the count of the number of connections opened by the given user
- * to the given Connection.
- *
- * @param connectionID The connection ID that this ConnectionUser refers to.
- * @param userID The user ID that this ConnectionUser refers to.
- */
- private void incrementConnectionUserCount(int connectionID, int userID) {
- int currentCount = getConnectionUserCount(connectionID, userID);
-
- activeConnectionUserMap.put
- (new ConnectionUser(connectionID, userID), currentCount + 1);
- }
-
- /**
- * Decrement the count of the number of connections opened by the given user
- * to the given Connection.
- *
- * @param connectionID The connection ID that this ConnectionUser refers to.
- * @param userID The user ID that this ConnectionUser refers to.
- */
- private void decrementConnectionUserCount(int connectionID, int userID) {
- int currentCount = getConnectionUserCount(connectionID, userID);
-
- activeConnectionUserMap.put
- (new ConnectionUser(connectionID, userID), currentCount - 1);
- }
-
- /**
- * Returns the ID of the connection with the lowest number of current
- * active users, if found.
- *
- * @param connectionIDs The subset of connection IDs to find the least
- * used connection within.
- *
- * @return The ID of the connection with the lowest number of current
- * active users, if found.
- */
- public Integer getLeastUsedConnection(Collection connectionIDs) {
-
- if(connectionIDs.isEmpty())
- return null;
-
- int minUserCount = Integer.MAX_VALUE;
- Integer minConnectionID = null;
-
- for(Integer connectionID : connectionIDs) {
- Connection connection = activeConnectionMap.get(connectionID);
-
- /*
- * If the connection is not found in the map, it has not been used,
- * and therefore will be count 0.
- */
- if(connection == null) {
- minUserCount = 0;
- minConnectionID = connectionID;
- }
- // If this is the least active connection
- else if(connection.getCurrentUserCount() < minUserCount) {
- minUserCount = connection.getCurrentUserCount();
- minConnectionID = connection.getConnectionID();
- }
- }
-
- return minConnectionID;
- }
-
- /**
- * Returns the count of currently active users for the given connectionID.
- * @return the count of currently active users for the given connectionID.
- */
- public int getCurrentUserCount(int connectionID) {
- Connection connection = activeConnectionMap.get(connectionID);
-
- if(connection == null)
- return 0;
-
- return connection.getCurrentUserCount();
- }
-
- /**
- * Decrement the current user count for this Connection.
- *
- * @param connectionID The ID of the MySQL connection that this
- * Connection represents.
- *
- * @throws GuacamoleException If the connection is not found.
- */
- private void decrementUserCount(int connectionID)
- throws GuacamoleException {
- Connection connection = activeConnectionMap.get(connectionID);
-
- if(connection == null)
- throw new GuacamoleResourceNotFoundException
- ("Connection to decrement does not exist.");
-
- // Decrement the current user count
- connection.setCurrentUserCount(connection.getCurrentUserCount() - 1);
- }
-
- /**
- * Increment the current user count for this Connection.
- *
- * @param connectionID The ID of the MySQL connection that this
- * Connection represents.
- *
- * @throws GuacamoleException If the connection is not found.
- */
- private void incrementUserCount(int connectionID) {
- Connection connection = activeConnectionMap.get(connectionID);
-
- // If the Connection does not exist, it should be created
- if(connection == null) {
- connection = new Connection(connectionID);
- activeConnectionMap.put(connectionID, connection);
- }
-
- // Increment the current user count
- connection.setCurrentUserCount(connection.getCurrentUserCount() + 1);
- }
-
- /**
- * Check if a connection is currently in use.
- * @param connectionID The connection to check the status of.
- * @return true if the connection is currently in use.
- */
- public boolean isActive(int connectionID) {
- return getCurrentUserCount(connectionID) > 0;
- }
-
- /**
- * Set a connection as open.
- * @param connectionID The ID of the connection that is being opened.
- * @param userID The ID of the user who is opening the connection.
- * @param connectionGroupID The ID of the BALANCING connection group that is
- * being connected to; null if not used.
- * @return The ID of the history record created for this open connection.
- */
- public int openConnection(int connectionID, int userID, Integer connectionGroupID) {
-
- // Create the connection history record
- ConnectionHistory connectionHistory = new ConnectionHistory();
- connectionHistory.setConnection_id(connectionID);
- connectionHistory.setUser_id(userID);
- connectionHistory.setStart_date(new Date());
- connectionHistoryDAO.insert(connectionHistory);
-
- // Increment the user count
- incrementUserCount(connectionID);
-
- // Increment the connection user count
- incrementConnectionUserCount(connectionID, userID);
-
- // If this is a connection to a BALANCING ConnectionGroup, increment the count
- if(connectionGroupID != null)
- incrementConnectionGroupUserCount(connectionGroupID, userID);
-
- return connectionHistory.getHistory_id();
- }
-
- /**
- * Set a connection as closed.
- * @param historyID The ID of the history record about the open connection.
- * @param connectionGroupID The ID of the BALANCING connection group that is
- * being connected to; null if not used.
- * @throws GuacamoleException If the open connection history is not found.
- */
- public void closeConnection(int historyID, Integer connectionGroupID)
- throws GuacamoleException {
-
- // Get the existing history record
- ConnectionHistory connectionHistory =
- connectionHistoryDAO.selectByPrimaryKey(historyID);
-
- if(connectionHistory == null)
- throw new GuacamoleResourceNotFoundException("History record not found.");
-
- // Get the connection and user IDs
- int connectionID = connectionHistory.getConnection_id();
- int userID = connectionHistory.getUser_id();
-
- // Update the connection history record to mark that it is now closed
- connectionHistory.setEnd_date(new Date());
- connectionHistoryDAO.updateByPrimaryKey(connectionHistory);
-
- // Decrement the user count.
- decrementUserCount(connectionID);
-
- // Decrement the connection user count
- decrementConnectionUserCount(connectionID, userID);
-
- // If this is a connection to a BALANCING ConnectionGroup, decrement the count
- if(connectionGroupID != null)
- decrementConnectionGroupUserCount(connectionGroupID, userID);
- }
-}
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
deleted file mode 100644
index e9fde29dc..000000000
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/ConnectionDirectory.java
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (C) 2013 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 com.google.inject.Inject;
-import java.util.Set;
-import org.glyptodon.guacamole.GuacamoleClientException;
-import org.glyptodon.guacamole.GuacamoleException;
-import org.glyptodon.guacamole.net.auth.Connection;
-import org.glyptodon.guacamole.net.auth.Directory;
-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.ConnectionPermissionKey;
-import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionGroupService;
-import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionService;
-import net.sourceforge.guacamole.net.auth.mysql.service.PermissionCheckService;
-import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
-import org.glyptodon.guacamole.GuacamoleUnsupportedException;
-import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
-import org.mybatis.guice.transactional.Transactional;
-
-/**
- * A MySQL-based implementation of the connection directory.
- *
- * @author James Muehlner
- */
-public class ConnectionDirectory implements Directory{
-
- /**
- * The user who this connection directory belongs to. Access is based on
- * his/her permission settings.
- */
- private AuthenticatedUser currentUser;
-
- /**
- * The ID of the parent connection group.
- */
- private Integer parentID;
-
- /**
- * Service for checking permissions.
- */
- @Inject
- private PermissionCheckService permissionCheckService;
-
- /**
- * Service managing connections.
- */
- @Inject
- private ConnectionService connectionService;
-
- /**
- * Service managing connection groups.
- */
- @Inject
- private ConnectionGroupService connectionGroupService;
-
- /**
- * Service for manipulating connection permissions in the database.
- */
- @Inject
- private ConnectionPermissionMapper connectionPermissionDAO;
-
- /**
- * Service for manipulating connection parameters in the database.
- */
- @Inject
- private ConnectionParameterMapper connectionParameterDAO;
-
- /**
- * Set the user and parentID for this directory.
- *
- * @param currentUser
- * The user owning this connection directory.
- *
- * @param parentID
- * The ID of the parent connection group.
- */
- public void init(AuthenticatedUser currentUser, Integer parentID) {
- this.currentUser = currentUser;
- this.parentID = parentID;
- }
-
- @Transactional
- @Override
- public Connection get(String identifier) throws GuacamoleException {
-
- // Get connection
- MySQLConnection connection =
- connectionService.retrieveConnection(identifier, currentUser);
-
- if(connection == null)
- return null;
-
- // Verify permission to use the parent connection group for organizational purposes
- permissionCheckService.verifyConnectionGroupUsageAccess
- (connection.getParentID(), currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
-
- // Verify access is granted
- permissionCheckService.verifyConnectionAccess(
- currentUser,
- connection.getConnectionID(),
- MySQLConstants.CONNECTION_READ);
-
- // Return connection
- return connection;
-
- }
-
- @Transactional
- @Override
- public Set getIdentifiers() throws GuacamoleException {
-
- // Verify permission to use the connection group for organizational purposes
- permissionCheckService.verifyConnectionGroupUsageAccess
- (parentID, currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
-
- return permissionCheckService.retrieveConnectionIdentifiers(currentUser,
- parentID, MySQLConstants.CONNECTION_READ);
- }
-
- @Transactional
- @Override
- public void add(Connection object) throws GuacamoleException {
-
- String name = object.getName().trim();
- if(name.isEmpty())
- throw new GuacamoleClientException("The connection name cannot be blank.");
-
- // Verify permission to create
- permissionCheckService.verifySystemAccess(currentUser,
- MySQLConstants.SYSTEM_CONNECTION_CREATE);
-
- // Verify permission to edit the connection group
- permissionCheckService.verifyConnectionGroupAccess(currentUser,
- this.parentID, MySQLConstants.CONNECTION_GROUP_UPDATE);
-
- // Verify permission to use the connection group for organizational purposes
- permissionCheckService.verifyConnectionGroupUsageAccess
- (parentID, currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
-
- // Verify that no connection already exists with this name.
- MySQLConnection previousConnection =
- connectionService.retrieveConnection(name, parentID, currentUser);
- if(previousConnection != null)
- throw new GuacamoleClientException("That connection name is already in use.");
-
- // Create connection
- MySQLConnection connection = connectionService.createConnection(
- name, object.getConfiguration().getProtocol(), currentUser, parentID);
-
- // Set the connection ID
- object.setIdentifier(connection.getIdentifier());
-
- // Add connection parameters
- createConfigurationValues(connection.getConnectionID(),
- object.getConfiguration());
-
- // Finally, give the current user full access to the newly created
- // connection.
- ConnectionPermissionKey newConnectionPermission = new ConnectionPermissionKey();
- newConnectionPermission.setUser_id(currentUser.getUserID());
- newConnectionPermission.setConnection_id(connection.getConnectionID());
-
- // Read permission
- newConnectionPermission.setPermission(MySQLConstants.CONNECTION_READ);
- connectionPermissionDAO.insert(newConnectionPermission);
-
- // Update permission
- newConnectionPermission.setPermission(MySQLConstants.CONNECTION_UPDATE);
- connectionPermissionDAO.insert(newConnectionPermission);
-
- // Delete permission
- newConnectionPermission.setPermission(MySQLConstants.CONNECTION_DELETE);
- connectionPermissionDAO.insert(newConnectionPermission);
-
- // Administer permission
- newConnectionPermission.setPermission(MySQLConstants.CONNECTION_ADMINISTER);
- connectionPermissionDAO.insert(newConnectionPermission);
-
- }
-
- /**
- * Inserts all parameter values from the given configuration into the
- * database, associating them with the connection having the givenID.
- *
- * @param connection_id The ID of the connection to associate all
- * parameters with.
- * @param config The GuacamoleConfiguration to read parameters from.
- */
- private void createConfigurationValues(int connection_id,
- GuacamoleConfiguration config) {
-
- // Insert new parameters for each parameter in the config
- for (String name : config.getParameterNames()) {
-
- // Create a ConnectionParameter based on the current parameter
- ConnectionParameter parameter = new ConnectionParameter();
- parameter.setConnection_id(connection_id);
- parameter.setParameter_name(name);
- parameter.setParameter_value(config.getParameter(name));
-
- // Insert connection parameter
- connectionParameterDAO.insert(parameter);
- }
-
- }
-
- @Transactional
- @Override
- public void update(Connection object) throws GuacamoleException {
-
- // If connection not actually from this auth provider, we can't handle
- // the update
- if (!(object instanceof MySQLConnection))
- throw new GuacamoleUnsupportedException("Connection not from database.");
-
- MySQLConnection mySQLConnection = (MySQLConnection) object;
-
- // Verify permission to update
- permissionCheckService.verifyConnectionAccess(currentUser,
- mySQLConnection.getConnectionID(),
- MySQLConstants.CONNECTION_UPDATE);
-
- // Perform update
- connectionService.updateConnection(mySQLConnection);
-
- // Delete old connection parameters
- ConnectionParameterExample parameterExample = new ConnectionParameterExample();
- parameterExample.createCriteria().andConnection_idEqualTo(mySQLConnection.getConnectionID());
- connectionParameterDAO.deleteByExample(parameterExample);
-
- // Add connection parameters
- createConfigurationValues(mySQLConnection.getConnectionID(),
- object.getConfiguration());
-
- }
-
- @Transactional
- @Override
- public void remove(String identifier) throws GuacamoleException {
-
- // Get connection
- MySQLConnection mySQLConnection =
- connectionService.retrieveConnection(identifier, currentUser);
-
- if(mySQLConnection == null)
- throw new GuacamoleResourceNotFoundException("Connection not found.");
-
- // Verify permission to use the parent connection group for organizational purposes
- permissionCheckService.verifyConnectionGroupUsageAccess
- (mySQLConnection.getParentID(), currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
-
- // Verify permission to delete
- permissionCheckService.verifyConnectionAccess(currentUser,
- mySQLConnection.getConnectionID(),
- MySQLConstants.CONNECTION_DELETE);
-
- // Delete the connection itself
- connectionService.deleteConnection(mySQLConnection.getConnectionID());
-
- }
-
- @Override
- public void move(String identifier, Directory directory)
- throws GuacamoleException {
-
- if(!(directory instanceof ConnectionDirectory))
- throw new GuacamoleUnsupportedException("Directory not from database");
-
- Integer toConnectionGroupID = ((ConnectionDirectory)directory).parentID;
-
- // Get connection
- MySQLConnection mySQLConnection =
- connectionService.retrieveConnection(identifier, currentUser);
-
- if(mySQLConnection == null)
- throw new GuacamoleResourceNotFoundException("Connection not found.");
-
- // Verify permission to update the connection
- permissionCheckService.verifyConnectionAccess(currentUser,
- mySQLConnection.getConnectionID(),
- MySQLConstants.CONNECTION_UPDATE);
-
- // Verify permission to use the from connection group for organizational purposes
- permissionCheckService.verifyConnectionGroupUsageAccess
- (mySQLConnection.getParentID(), currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
-
- // Verify permission to update the from connection group
- permissionCheckService.verifyConnectionGroupAccess(currentUser,
- mySQLConnection.getParentID(), MySQLConstants.CONNECTION_GROUP_UPDATE);
-
- // Verify permission to use the to connection group for organizational purposes
- permissionCheckService.verifyConnectionGroupUsageAccess
- (toConnectionGroupID, currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
-
- // Verify permission to update the to connection group
- permissionCheckService.verifyConnectionGroupAccess(currentUser,
- toConnectionGroupID, MySQLConstants.CONNECTION_GROUP_UPDATE);
-
- // Verify that no connection already exists with this name.
- MySQLConnection previousConnection =
- connectionService.retrieveConnection(mySQLConnection.getName(),
- toConnectionGroupID, currentUser);
- if(previousConnection != null)
- throw new GuacamoleClientException("That connection name is already in use.");
-
- // Update the connection
- mySQLConnection.setParentID(toConnectionGroupID);
- connectionService.updateConnection(mySQLConnection);
- }
-
-}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/ConnectionGroupDirectory.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/ConnectionGroupDirectory.java
deleted file mode 100644
index 0064b7708..000000000
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/ConnectionGroupDirectory.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (C) 2013 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 com.google.inject.Inject;
-import java.util.Set;
-import org.glyptodon.guacamole.GuacamoleClientException;
-import org.glyptodon.guacamole.GuacamoleException;
-import org.glyptodon.guacamole.net.auth.ConnectionGroup;
-import org.glyptodon.guacamole.net.auth.ConnectionGroup.Type;
-import org.glyptodon.guacamole.net.auth.Directory;
-import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionGroupPermissionMapper;
-import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupPermissionKey;
-import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionGroupService;
-import net.sourceforge.guacamole.net.auth.mysql.service.PermissionCheckService;
-import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
-import org.glyptodon.guacamole.GuacamoleUnsupportedException;
-import org.mybatis.guice.transactional.Transactional;
-
-/**
- * A MySQL-based implementation of the connection group directory.
- *
- * @author James Muehlner
- */
-public class ConnectionGroupDirectory implements Directory{
-
- /**
- * The user who this connection directory belongs to. Access is based on
- * his/her permission settings.
- */
- private AuthenticatedUser currentUser;
-
- /**
- * The ID of the parent connection group.
- */
- private Integer parentID;
-
- /**
- * Service for checking permissions.
- */
- @Inject
- private PermissionCheckService permissionCheckService;
-
- /**
- * Service managing connection groups.
- */
- @Inject
- private ConnectionGroupService connectionGroupService;
-
- /**
- * Service for manipulating connection group permissions in the database.
- */
- @Inject
- private ConnectionGroupPermissionMapper connectionGroupPermissionDAO;
-
- /**
- * Set the user and parentID for this directory.
- *
- * @param currentUser
- * The user owning this connection group directory.
- *
- * @param parentID
- * The ID of the parent connection group.
- */
- public void init(AuthenticatedUser currentUser, Integer parentID) {
- this.parentID = parentID;
- this.currentUser = currentUser;
- }
-
- @Transactional
- @Override
- public ConnectionGroup get(String identifier) throws GuacamoleException {
-
- // Get connection
- MySQLConnectionGroup connectionGroup =
- connectionGroupService.retrieveConnectionGroup(identifier, currentUser);
-
- if(connectionGroup == null)
- return null;
-
- // Verify permission to use the parent connection group for organizational purposes
- permissionCheckService.verifyConnectionGroupUsageAccess
- (connectionGroup.getParentID(), currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
-
- // Verify access is granted
- permissionCheckService.verifyConnectionGroupAccess(
- currentUser,
- connectionGroup.getConnectionGroupID(),
- MySQLConstants.CONNECTION_GROUP_READ);
-
- // Return connection group
- return connectionGroup;
-
- }
-
- @Transactional
- @Override
- public Set getIdentifiers() throws GuacamoleException {
-
- // Verify permission to use the connection group for organizational purposes
- permissionCheckService.verifyConnectionGroupUsageAccess
- (parentID, currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
-
- return permissionCheckService.retrieveConnectionGroupIdentifiers(currentUser,
- parentID, MySQLConstants.CONNECTION_GROUP_READ);
- }
-
- @Transactional
- @Override
- public void add(ConnectionGroup object) throws GuacamoleException {
-
- String name = object.getName().trim();
- if(name.isEmpty())
- throw new GuacamoleClientException("The connection group name cannot be blank.");
-
- Type type = object.getType();
-
- String mySQLType = MySQLConstants.getConnectionGroupTypeConstant(type);
-
- // Verify permission to create
- permissionCheckService.verifySystemAccess(currentUser,
- MySQLConstants.SYSTEM_CONNECTION_GROUP_CREATE);
-
- // Verify permission to edit the parent connection group
- permissionCheckService.verifyConnectionGroupAccess(currentUser,
- this.parentID, MySQLConstants.CONNECTION_GROUP_UPDATE);
-
- // Verify permission to use the parent connection group for organizational purposes
- permissionCheckService.verifyConnectionGroupUsageAccess
- (parentID, currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
-
- // Verify that no connection already exists with this name.
- MySQLConnectionGroup previousConnectionGroup =
- connectionGroupService.retrieveConnectionGroup(name, parentID, currentUser);
- if(previousConnectionGroup != null)
- throw new GuacamoleClientException("That connection group name is already in use.");
-
- // Create connection group
- MySQLConnectionGroup connectionGroup = connectionGroupService
- .createConnectionGroup(name, currentUser, parentID, mySQLType);
-
- // Set the connection group ID
- object.setIdentifier(connectionGroup.getIdentifier());
-
- // Finally, give the current user full access to the newly created
- // connection group.
- ConnectionGroupPermissionKey newConnectionGroupPermission = new ConnectionGroupPermissionKey();
- newConnectionGroupPermission.setUser_id(currentUser.getUserID());
- newConnectionGroupPermission.setConnection_group_id(connectionGroup.getConnectionGroupID());
-
- // Read permission
- newConnectionGroupPermission.setPermission(MySQLConstants.CONNECTION_GROUP_READ);
- connectionGroupPermissionDAO.insert(newConnectionGroupPermission);
-
- // Update permission
- newConnectionGroupPermission.setPermission(MySQLConstants.CONNECTION_GROUP_UPDATE);
- connectionGroupPermissionDAO.insert(newConnectionGroupPermission);
-
- // Delete permission
- newConnectionGroupPermission.setPermission(MySQLConstants.CONNECTION_GROUP_DELETE);
- connectionGroupPermissionDAO.insert(newConnectionGroupPermission);
-
- // Administer permission
- newConnectionGroupPermission.setPermission(MySQLConstants.CONNECTION_GROUP_ADMINISTER);
- connectionGroupPermissionDAO.insert(newConnectionGroupPermission);
-
- }
-
- @Transactional
- @Override
- public void update(ConnectionGroup object) throws GuacamoleException {
-
- // If connection not actually from this auth provider, we can't handle
- // the update
- if (!(object instanceof MySQLConnectionGroup))
- throw new GuacamoleUnsupportedException("Connection not from database.");
-
- MySQLConnectionGroup mySQLConnectionGroup = (MySQLConnectionGroup) object;
-
- // Verify permission to update
- permissionCheckService.verifyConnectionGroupAccess(currentUser,
- mySQLConnectionGroup.getConnectionGroupID(),
- MySQLConstants.CONNECTION_GROUP_UPDATE);
-
- // Perform update
- connectionGroupService.updateConnectionGroup(mySQLConnectionGroup);
- }
-
- @Transactional
- @Override
- public void remove(String identifier) throws GuacamoleException {
-
- // Get connection
- MySQLConnectionGroup mySQLConnectionGroup =
- connectionGroupService.retrieveConnectionGroup(identifier, currentUser);
-
- if(mySQLConnectionGroup == null)
- throw new GuacamoleResourceNotFoundException("Connection group not found.");
-
- // Verify permission to use the parent connection group for organizational purposes
- permissionCheckService.verifyConnectionGroupUsageAccess
- (mySQLConnectionGroup.getParentID(), currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
-
- // Verify permission to delete
- permissionCheckService.verifyConnectionGroupAccess(currentUser,
- mySQLConnectionGroup.getConnectionGroupID(),
- MySQLConstants.CONNECTION_GROUP_DELETE);
-
- // Delete the connection group itself
- connectionGroupService.deleteConnectionGroup
- (mySQLConnectionGroup.getConnectionGroupID());
-
- }
-
- @Override
- public void move(String identifier, Directory directory)
- throws GuacamoleException {
-
- if(MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER.equals(identifier))
- throw new GuacamoleUnsupportedException("The root connection group cannot be moved.");
-
- if(!(directory instanceof ConnectionGroupDirectory))
- throw new GuacamoleUnsupportedException("Directory not from database");
-
- Integer toConnectionGroupID = ((ConnectionGroupDirectory)directory).parentID;
-
- // Get connection group
- MySQLConnectionGroup mySQLConnectionGroup =
- connectionGroupService.retrieveConnectionGroup(identifier, currentUser);
-
- if(mySQLConnectionGroup == null)
- throw new GuacamoleResourceNotFoundException("Connection group not found.");
-
- // Verify permission to update the connection group
- permissionCheckService.verifyConnectionGroupAccess(currentUser,
- mySQLConnectionGroup.getConnectionGroupID(),
- MySQLConstants.CONNECTION_GROUP_UPDATE);
-
- // Verify permission to use the from connection group for organizational purposes
- permissionCheckService.verifyConnectionGroupUsageAccess
- (mySQLConnectionGroup.getParentID(), currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
-
- // Verify permission to update the from connection group
- permissionCheckService.verifyConnectionGroupAccess(currentUser,
- mySQLConnectionGroup.getParentID(), MySQLConstants.CONNECTION_GROUP_UPDATE);
-
- // Verify permission to use the to connection group for organizational purposes
- permissionCheckService.verifyConnectionGroupUsageAccess
- (toConnectionGroupID, currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
-
- // Verify permission to update the to connection group
- permissionCheckService.verifyConnectionGroupAccess(currentUser,
- toConnectionGroupID, MySQLConstants.CONNECTION_GROUP_UPDATE);
-
- // Verify that no connection already exists with this name.
- MySQLConnectionGroup previousConnectionGroup =
- connectionGroupService.retrieveConnectionGroup(mySQLConnectionGroup.getName(),
- toConnectionGroupID, currentUser);
- if(previousConnectionGroup != null)
- throw new GuacamoleClientException("That connection group name is already in use.");
-
- // Verify that moving this connectionGroup would not cause a cycle
- Integer relativeParentID = toConnectionGroupID;
- while(relativeParentID != null) {
- if(relativeParentID == mySQLConnectionGroup.getConnectionGroupID())
- throw new GuacamoleUnsupportedException("Connection group cycle detected.");
-
- MySQLConnectionGroup relativeParentGroup = connectionGroupService.
- retrieveConnectionGroup(relativeParentID, currentUser);
-
- relativeParentID = relativeParentGroup.getParentID();
- }
-
- // Update the connection
- mySQLConnectionGroup.setParentID(toConnectionGroupID);
- connectionGroupService.updateConnectionGroup(mySQLConnectionGroup);
- }
-
-}
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
deleted file mode 100644
index 2a0080325..000000000
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2013 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 com.google.inject.Binder;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Module;
-import com.google.inject.name.Names;
-import java.util.Properties;
-import org.glyptodon.guacamole.GuacamoleException;
-import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
-import org.glyptodon.guacamole.net.auth.Credentials;
-import org.glyptodon.guacamole.net.auth.UserContext;
-import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionGroupMapper;
-import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionGroupPermissionMapper;
-import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionHistoryMapper;
-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.dao.ConnectionPermissionMapper;
-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.service.ConnectionGroupService;
-import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionService;
-import net.sourceforge.guacamole.net.auth.mysql.service.PasswordEncryptionService;
-import net.sourceforge.guacamole.net.auth.mysql.service.PermissionCheckService;
-import net.sourceforge.guacamole.net.auth.mysql.service.SHA256PasswordEncryptionService;
-import net.sourceforge.guacamole.net.auth.mysql.service.SaltService;
-import net.sourceforge.guacamole.net.auth.mysql.service.SecureRandomSaltService;
-import net.sourceforge.guacamole.net.auth.mysql.service.UserService;
-import org.glyptodon.guacamole.properties.GuacamoleProperties;
-import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
-import org.mybatis.guice.MyBatisModule;
-import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider;
-import org.mybatis.guice.datasource.helper.JdbcHelper;
-
-/**
- * Provides a MySQL based implementation of the AuthenticationProvider
- * functionality.
- *
- * @author James Muehlner
- */
-public class MySQLAuthenticationProvider implements AuthenticationProvider {
-
- /**
- * Set of all active connections.
- */
- private ActiveConnectionMap activeConnectionMap = new ActiveConnectionMap();
-
- /**
- * Injector which will manage the object graph of this authentication
- * provider.
- */
- private Injector injector;
-
- @Override
- public UserContext getUserContext(Credentials credentials) throws GuacamoleException {
-
- // Get user service
- UserService userService = injector.getInstance(UserService.class);
-
- // Get user
- MySQLUser authenticatedUser = userService.retrieveUser(credentials);
- if (authenticatedUser != null) {
- MySQLUserContext context = injector.getInstance(MySQLUserContext.class);
- context.init(new AuthenticatedUser(authenticatedUser.getUserID(), credentials));
- return context;
- }
-
- // Otherwise, unauthorized
- return null;
-
- }
-
- /**
- * Creates a new MySQLAuthenticationProvider that reads and writes
- * authentication data to a MySQL database defined by properties in
- * guacamole.properties.
- *
- * @throws GuacamoleException If a required property is missing, or
- * an error occurs while parsing a property.
- */
- public MySQLAuthenticationProvider() throws GuacamoleException {
-
- final Properties myBatisProperties = new Properties();
- final Properties driverProperties = 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)));
- myBatisProperties.setProperty("JDBC.schema", GuacamoleProperties.getRequiredProperty(MySQLGuacamoleProperties.MYSQL_DATABASE));
- myBatisProperties.setProperty("JDBC.username", GuacamoleProperties.getRequiredProperty(MySQLGuacamoleProperties.MYSQL_USERNAME));
- myBatisProperties.setProperty("JDBC.password", GuacamoleProperties.getRequiredProperty(MySQLGuacamoleProperties.MYSQL_PASSWORD));
- myBatisProperties.setProperty("JDBC.autoCommit", "false");
- myBatisProperties.setProperty("mybatis.pooled.pingEnabled", "true");
- myBatisProperties.setProperty("mybatis.pooled.pingQuery", "SELECT 1");
- driverProperties.setProperty("characterEncoding","UTF-8");
-
- // Set up Guice injector.
- injector = Guice.createInjector(
- JdbcHelper.MySQL,
-
- new Module() {
- @Override
- public void configure(Binder binder) {
- Names.bindProperties(binder, myBatisProperties);
- binder.bind(Properties.class)
- .annotatedWith(Names.named("JDBC.driverProperties"))
- .toInstance(driverProperties);
- }
- },
-
- new MyBatisModule() {
- @Override
- protected void initialize() {
-
- // Datasource
- bindDataSourceProviderType(PooledDataSourceProvider.class);
-
- // Transaction factory
- bindTransactionFactoryType(JdbcTransactionFactory.class);
-
- // Add MyBatis mappers
- addMapperClass(ConnectionHistoryMapper.class);
- addMapperClass(ConnectionMapper.class);
- addMapperClass(ConnectionGroupMapper.class);
- addMapperClass(ConnectionGroupPermissionMapper.class);
- addMapperClass(ConnectionParameterMapper.class);
- addMapperClass(ConnectionPermissionMapper.class);
- addMapperClass(SystemPermissionMapper.class);
- addMapperClass(UserMapper.class);
- addMapperClass(UserPermissionMapper.class);
-
- // Bind interfaces
- bind(MySQLUserContext.class);
- bind(UserDirectory.class);
- bind(MySQLUser.class);
- bind(SaltService.class).to(SecureRandomSaltService.class);
- bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class);
- bind(PermissionCheckService.class);
- bind(ConnectionService.class);
- bind(ConnectionGroupService.class);
- bind(UserService.class);
- bind(ActiveConnectionMap.class).toInstance(activeConnectionMap);
-
- }
- } // end of mybatis module
-
- );
- } // end of constructor
-
- @Override
- public UserContext updateUserContext(UserContext context,
- Credentials credentials) throws GuacamoleException {
-
- // No need to update the context
- return context;
-
- }
-
-}
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
deleted file mode 100644
index c685f7eaa..000000000
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnection.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2013 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 com.google.inject.Inject;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import org.glyptodon.guacamole.GuacamoleException;
-import org.glyptodon.guacamole.net.GuacamoleSocket;
-import org.glyptodon.guacamole.net.auth.AbstractConnection;
-import org.glyptodon.guacamole.net.auth.ConnectionRecord;
-import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionService;
-import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
-import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
-
-/**
- * A MySQL based implementation of the Connection object.
- * @author James Muehlner
- */
-public class MySQLConnection extends AbstractConnection {
-
- /**
- * The ID associated with this connection in the database.
- */
- private Integer connectionID;
-
- /**
- * The ID of the parent connection group for this connection.
- */
- private Integer parentID;
-
- /**
- * The user who queried or created this connection.
- */
- private AuthenticatedUser currentUser;
-
- /**
- * History of this connection.
- */
- private List history = new ArrayList();
-
- /**
- * Service for managing connections.
- */
- @Inject
- private ConnectionService connectionService;
-
- /**
- * Create a default, empty connection.
- */
- public MySQLConnection() {
- }
-
- /**
- * Get the ID of the corresponding connection record.
- * @return The ID of the corresponding connection, if any.
- */
- public Integer getConnectionID() {
- return connectionID;
- }
-
- /**
- * Sets the ID of the corresponding connection record.
- * @param connectionID The ID to assign to this connection.
- */
- public void setConnectionID(Integer connectionID) {
- this.connectionID = connectionID;
- }
-
- /**
- * Get the ID of the parent connection group for this connection, if any.
- * @return The ID of the parent connection group for this connection, if any.
- */
- public Integer getParentID() {
- return parentID;
- }
-
- /**
- * Sets the ID of the parent connection group for this connection.
- * @param parentID The ID of the parent connection group for this connection.
- */
- public void setParentID(Integer parentID) {
- this.parentID = parentID;
-
- // Translate to string identifier
- if (parentID != null)
- this.setParentIdentifier(String.valueOf(parentID));
- else
- this.setParentIdentifier(MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER);
-
- }
-
- /**
- * Initialize from explicit values.
- *
- * @param connectionID
- * The ID of the associated database record, if any.
- *
- * @param parentID
- * The ID of the parent connection group for this connection, if any.
- *
- * @param name
- * The human-readable name associated with this connection.
- *
- * @param identifier
- * The unique identifier associated with this connection.
- *
- * @param config
- * The GuacamoleConfiguration associated with this connection.
- *
- * @param history
- * All ConnectionRecords associated with this connection.
- *
- * @param currentUser
- * The user who queried this connection.
- */
- public void init(Integer connectionID, Integer parentID, String name,
- String identifier, GuacamoleConfiguration config,
- List extends ConnectionRecord> history,
- AuthenticatedUser currentUser) {
-
- this.connectionID = connectionID;
- this.setParentID(parentID);
- setName(name);
- setIdentifier(identifier);
- setConfiguration(config);
- this.history.addAll(history);
- this.currentUser = currentUser;
-
- }
-
- @Override
- public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
- return connectionService.connect(this, info, currentUser, null);
- }
-
- @Override
- public List extends ConnectionRecord> getHistory() throws GuacamoleException {
- return Collections.unmodifiableList(history);
- }
-
-}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnectionGroup.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnectionGroup.java
deleted file mode 100644
index 53380bb5c..000000000
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnectionGroup.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2013 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 com.google.inject.Inject;
-import com.google.inject.Provider;
-import org.glyptodon.guacamole.GuacamoleException;
-import org.glyptodon.guacamole.net.GuacamoleSocket;
-import org.glyptodon.guacamole.net.auth.AbstractConnectionGroup;
-import org.glyptodon.guacamole.net.auth.Connection;
-import org.glyptodon.guacamole.net.auth.ConnectionGroup;
-import org.glyptodon.guacamole.net.auth.Directory;
-import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionGroupService;
-import net.sourceforge.guacamole.net.auth.mysql.service.PermissionCheckService;
-import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
-
-/**
- * A MySQL based implementation of the ConnectionGroup object.
- * @author James Muehlner
- */
-public class MySQLConnectionGroup extends AbstractConnectionGroup {
-
- /**
- * The ID associated with this connection group in the database.
- */
- private Integer connectionGroupID;
-
- /**
- * The ID of the parent connection group for this connection group.
- */
- private Integer parentID;
-
- /**
- * The user who queried or created this connection group.
- */
- private AuthenticatedUser currentUser;
-
- /**
- * A Directory of connections that have this connection group as a parent.
- */
- private ConnectionDirectory connectionDirectory = null;
-
- /**
- * A Directory of connection groups that have this connection group as a parent.
- */
- private ConnectionGroupDirectory connectionGroupDirectory = null;
-
- /**
- * Service managing connection groups.
- */
- @Inject
- private ConnectionGroupService connectionGroupService;
-
- /**
- * Service for checking permissions.
- */
- @Inject
- private PermissionCheckService permissionCheckService;
-
- /**
- * Service for creating new ConnectionDirectory objects.
- */
- @Inject Provider connectionDirectoryProvider;
-
- /**
- * Service for creating new ConnectionGroupDirectory objects.
- */
- @Inject Provider connectionGroupDirectoryProvider;
-
- /**
- * Create a default, empty connection group.
- */
- public MySQLConnectionGroup() {
- }
-
- /**
- * Get the ID of the corresponding connection group record.
- * @return The ID of the corresponding connection group, if any.
- */
- public Integer getConnectionGroupID() {
- return connectionGroupID;
- }
-
- /**
- * Sets the ID of the corresponding connection group record.
- * @param connectionGroupID The ID to assign to this connection group.
- */
- public void setConnectionID(Integer connectionGroupID) {
- this.connectionGroupID = connectionGroupID;
- }
-
- /**
- * Get the ID of the parent connection group for this connection group, if any.
- * @return The ID of the parent connection group for this connection group, if any.
- */
- public Integer getParentID() {
- return parentID;
- }
-
- /**
- * Sets the ID of the parent connection group for this connection group.
- * @param parentID The ID of the parent connection group for this connection group.
- */
- public void setParentID(Integer parentID) {
- this.parentID = parentID;
-
- // Translate to string identifier
- if (parentID != null)
- this.setParentIdentifier(String.valueOf(parentID));
- else
- this.setParentIdentifier(MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER);
-
- }
-
- /**
- * Initialize from explicit values.
- *
- * @param connectionGroupID
- * The ID of the associated database record, if any.
- *
- * @param parentID
- * The ID of the parent connection group for this connection group, if
- * any.
- *
- * @param name
- * The name of this connection group.
- *
- * @param identifier
- * The unique identifier associated with this connection group.
- *
- * @param type
- * The type of this connection group.
- *
- * @param currentUser
- * The user who queried this connection.
- */
- public void init(Integer connectionGroupID, Integer parentID, String name,
- String identifier, ConnectionGroup.Type type, AuthenticatedUser currentUser) {
- this.connectionGroupID = connectionGroupID;
- this.setParentID(parentID);
- setName(name);
- setIdentifier(identifier);
- setType(type);
- this.currentUser = currentUser;
-
- connectionDirectory = connectionDirectoryProvider.get();
- connectionDirectory.init(currentUser, connectionGroupID);
-
- connectionGroupDirectory = connectionGroupDirectoryProvider.get();
- connectionGroupDirectory.init(currentUser, connectionGroupID);
- }
-
- @Override
- public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
-
- // Verify permission to use the connection group for balancing purposes
- permissionCheckService.verifyConnectionGroupUsageAccess
- (this.connectionGroupID, currentUser, MySQLConstants.CONNECTION_GROUP_BALANCING);
-
- // Verify permission to delete
- permissionCheckService.verifyConnectionGroupAccess(currentUser,
- this.connectionGroupID,
- MySQLConstants.CONNECTION_GROUP_READ);
-
- return connectionGroupService.connect(this, info, currentUser);
- }
-
- @Override
- public Directory getConnectionDirectory() throws GuacamoleException {
- return connectionDirectory;
- }
-
- @Override
- public Directory getConnectionGroupDirectory() throws GuacamoleException {
- return connectionGroupDirectory;
- }
-
-}
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
deleted file mode 100644
index e723f89b6..000000000
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnectionRecord.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2013 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 java.util.Date;
-import org.glyptodon.guacamole.net.auth.ConnectionRecord;
-
-/**
- * A ConnectionRecord which is based on data stored in MySQL.
- *
- * @author James Muehlner
- */
-public class MySQLConnectionRecord implements ConnectionRecord {
-
- /**
- * The start date of the ConnectionRecord.
- */
- private Date startDate;
-
- /**
- * The end date of the ConnectionRecord.
- */
- private Date endDate;
-
- /**
- * The name of the user that is associated with this ConnectionRecord.
- */
- private String username;
-
- /**
- * Whether this connection is currently active.
- */
- private boolean active;
-
- /**
- * Initialize this MySQLConnectionRecord with the start/end dates,
- * and the name of the user it represents.
- *
- * @param startDate The start date of the connection history.
- * @param endDate The end date of the connection history.
- * @param username The name of the user that used the connection.
- * @param active Whether the connection is currently active.
- */
- public MySQLConnectionRecord(Date startDate, Date endDate,
- String username, boolean active) {
- if (startDate != null) this.startDate = new Date(startDate.getTime());
- if (endDate != null) this.endDate = new Date(endDate.getTime());
- this.username = username;
- this.active = active;
- }
-
- @Override
- public Date getStartDate() {
- if (startDate == null) return null;
- return new Date(startDate.getTime());
- }
-
- @Override
- public Date getEndDate() {
- if (endDate == null) return null;
- return new Date(endDate.getTime());
- }
-
- @Override
- public String getUsername() {
- return username;
- }
-
- @Override
- public boolean isActive() {
- return active;
- }
-
-}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConstants.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConstants.java
deleted file mode 100644
index 532c49f29..000000000
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConstants.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2013 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.net.auth.ConnectionGroup;
-import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
-import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
-
-
-/**
- * A set of constants that are useful for the MySQL-based authentication provider.
- * @author James Muehlner
- */
-public final class MySQLConstants {
-
- /**
- * This class should not be instantiated.
- */
- private MySQLConstants() {}
-
- /**
- * The string stored in the database to represent READ access to a user.
- */
- public static final String USER_READ = "READ";
-
- /**
- * The string stored in the database to represent UPDATE access to a user.
- */
- public static final String USER_UPDATE = "UPDATE";
-
- /**
- * The string stored in the database to represent DELETE access to a user.
- */
- public static final String USER_DELETE = "DELETE";
-
- /**
- * The string stored in the database to represent ADMINISTER access to a
- * user.
- */
- public static final String USER_ADMINISTER = "ADMINISTER";
-
- /**
- * The string stored in the database to represent READ access to a
- * connection.
- */
- public static final String CONNECTION_READ = "READ";
-
- /**
- * The string stored in the database to represent UPDATE access to a
- * connection.
- */
- public static final String CONNECTION_UPDATE = "UPDATE";
-
- /**
- * The string stored in the database to represent DELETE access to a
- * connection.
- */
- public static final String CONNECTION_DELETE = "DELETE";
-
- /**
- * The string stored in the database to represent ADMINISTER access to a
- * connection.
- */
- public static final String CONNECTION_ADMINISTER = "ADMINISTER";
-
- /**
- * The string stored in the database to represent READ access to a
- * connection.
- */
- public static final String CONNECTION_GROUP_READ = "READ";
-
- /**
- * The string stored in the database to represent UPDATE access to a
- * connection group.
- */
- public static final String CONNECTION_GROUP_UPDATE = "UPDATE";
-
- /**
- * The string stored in the database to represent DELETE access to a
- * connection group.
- */
- public static final String CONNECTION_GROUP_DELETE = "DELETE";
-
- /**
- * The string stored in the database to represent ADMINISTER access to a
- * connection group.
- */
- public static final String CONNECTION_GROUP_ADMINISTER = "ADMINISTER";
-
- /**
- * The string stored in the database to represent a BALANCING
- * connection group.
- */
- public static final String CONNECTION_GROUP_BALANCING = "BALANCING";
-
- /**
- * The string stored in the database to represent an ORGANIZATIONAL
- * connection group.
- */
- public static final String CONNECTION_GROUP_ORGANIZATIONAL =
- "ORGANIZATIONAL";
-
- /**
- * The identifier used to mark the root connection group.
- */
- public static final String CONNECTION_GROUP_ROOT_IDENTIFIER = "ROOT";
-
- /**
- * The string stored in the database to represent permission to create
- * users.
- */
- public static final String SYSTEM_USER_CREATE = "CREATE_USER";
-
- /**
- * The string stored in the database to represent permission to create
- * connections.
- */
- public static final String SYSTEM_CONNECTION_CREATE = "CREATE_CONNECTION";
-
- /**
- * The string stored in the database to represent permission to create
- * connection groups.
- */
- public static final String SYSTEM_CONNECTION_GROUP_CREATE = "CREATE_CONNECTION_GROUP";
-
- /**
- * The string stored in the database to represent permission to administer
- * the system as a whole.
- */
- public static final String SYSTEM_ADMINISTER = "ADMINISTER";
-
- /**
- * Given the type of a permission affecting a user, returns the MySQL
- * constant representing that permission type.
- *
- * @param type The type of permission to look up.
- * @return The MySQL constant corresponding to the given permission type.
- */
- public static String getUserConstant(ObjectPermission.Type type) {
-
- // Convert permission type to MySQL constant
- switch (type) {
- case READ: return USER_READ;
- case UPDATE: return USER_UPDATE;
- case ADMINISTER: return USER_ADMINISTER;
- case DELETE: return USER_DELETE;
- }
-
- // If we get here, permission support was not properly implemented
- throw new UnsupportedOperationException(
- "Unsupported permission type: " + type);
-
- }
-
- /**
- * Given the type of a permission affecting a connection, returns the MySQL
- * constant representing that permission type.
- *
- * @param type The type of permission to look up.
- * @return The MySQL constant corresponding to the given permission type.
- */
- public static String getConnectionConstant(ObjectPermission.Type type) {
-
- // Convert permission type to MySQL constant
- switch (type) {
- case READ: return CONNECTION_READ;
- case UPDATE: return CONNECTION_UPDATE;
- case ADMINISTER: return CONNECTION_ADMINISTER;
- case DELETE: return CONNECTION_DELETE;
- }
-
- // If we get here, permission support was not properly implemented
- throw new UnsupportedOperationException(
- "Unsupported permission type: " + type);
-
- }
-
- /**
- * Given the type of a permission affecting a connection group,
- * returns the MySQL constant representing that permission type.
- *
- * @param type The type of permission to look up.
- * @return The MySQL constant corresponding to the given permission type.
- */
- public static String getConnectionGroupConstant(ObjectPermission.Type type) {
-
- // Convert permission type to MySQL constant
- switch (type) {
- case READ: return CONNECTION_GROUP_READ;
- case UPDATE: return CONNECTION_GROUP_UPDATE;
- case ADMINISTER: return CONNECTION_GROUP_ADMINISTER;
- case DELETE: return CONNECTION_GROUP_DELETE;
- }
-
- // If we get here, permission support was not properly implemented
- throw new UnsupportedOperationException(
- "Unsupported permission type: " + type);
-
- }
-
- /**
- * Given the type of a connection group, returns the MySQL constant
- * representing that type.
- *
- * @param type The connection group type to look up.
- * @return The MySQL constant corresponding to the given type.
- */
- public static String getConnectionGroupTypeConstant(ConnectionGroup.Type type) {
-
- // Convert permission type to MySQL constant
- switch (type) {
- case ORGANIZATIONAL: return CONNECTION_GROUP_ORGANIZATIONAL;
- case BALANCING: return CONNECTION_GROUP_BALANCING;
- }
-
- // If we get here, permission support was not properly implemented
- throw new UnsupportedOperationException(
- "Unsupported connection group type: " + type);
-
- }
-
- /**
- * Given the type of a permission affecting the system, returns the MySQL
- * constant representing that permission type.
- *
- * @param type The type of permission to look up.
- * @return The MySQL constant corresponding to the given permission type.
- */
- public static String getSystemConstant(SystemPermission.Type type) {
-
- // Convert permission type to MySQL constant
- switch (type) {
- case CREATE_USER: return SYSTEM_USER_CREATE;
- case CREATE_CONNECTION: return SYSTEM_CONNECTION_CREATE;
- case CREATE_CONNECTION_GROUP: return SYSTEM_CONNECTION_GROUP_CREATE;
- case ADMINISTER: return SYSTEM_ADMINISTER;
- }
-
- // If we get here, permission support was not properly implemented
- throw new UnsupportedOperationException(
- "Unsupported permission type: " + type);
-
- }
-
-}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleSocket.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleSocket.java
deleted file mode 100644
index 4200bfe5d..000000000
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleSocket.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2013 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 com.google.inject.Inject;
-import org.glyptodon.guacamole.GuacamoleException;
-import org.glyptodon.guacamole.io.GuacamoleReader;
-import org.glyptodon.guacamole.io.GuacamoleWriter;
-import org.glyptodon.guacamole.net.GuacamoleSocket;
-
-/**
- * A MySQL specific wrapper around a ConfiguredGuacamoleSocket.
- * @author James Muehlner
- */
-public class MySQLGuacamoleSocket implements GuacamoleSocket {
-
- /**
- * Injected ActiveConnectionMap which will contain all active connections.
- */
- @Inject
- private ActiveConnectionMap activeConnectionMap;
-
- /**
- * The wrapped socket.
- */
- private GuacamoleSocket socket;
-
- /**
- * The ID of the history record associated with this instance of the
- * connection.
- */
- private int historyID;
-
- /**
- * The ID of the balancing connection group that is being connected to;
- * null if not used.
- */
- private Integer connectionGroupID;
-
- /**
- * Initialize this MySQLGuacamoleSocket with the provided GuacamoleSocket.
- *
- * @param socket The ConfiguredGuacamoleSocket to wrap.
- * @param historyID The ID of the history record associated with this
- * instance of the connection.
- * @param connectionGroupID The ID of the balancing connection group that is
- * being connected to; null if not used.
- */
- public void init(GuacamoleSocket socket,
- int historyID, Integer connectionGroupID) {
- this.socket = socket;
- this.historyID = historyID;
- this.connectionGroupID = connectionGroupID;
- }
-
- @Override
- public GuacamoleReader getReader() {
- return socket.getReader();
- }
-
- @Override
- public GuacamoleWriter getWriter() {
- return socket.getWriter();
- }
-
- @Override
- public void close() throws GuacamoleException {
-
- // Mark this connection as inactive
- synchronized (activeConnectionMap) {
-
- if (isOpen())
- activeConnectionMap.closeConnection(historyID, connectionGroupID);
-
- // Close socket
- socket.close();
-
- }
-
- }
-
- @Override
- public boolean isOpen() {
- return socket.isOpen();
- }
-}
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
deleted file mode 100644
index 25b07f123..000000000
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUser.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2013 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 java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import org.glyptodon.guacamole.GuacamoleException;
-import org.glyptodon.guacamole.net.auth.AbstractUser;
-import org.glyptodon.guacamole.net.auth.User;
-import org.glyptodon.guacamole.net.auth.permission.Permission;
-
-/**
- * A MySQL based implementation of the User object.
- * @author James Muehlner
- */
-public class MySQLUser extends AbstractUser {
-
- /**
- * The ID of this user in the database, if any.
- */
- private Integer userID;
-
- /**
- * The set of current permissions a user has.
- */
- private Set permissions = new HashSet();
-
- /**
- * Any newly added permissions that have yet to be committed.
- */
- private Set newPermissions = new HashSet();
-
- /**
- * Any newly deleted permissions that have yet to be deleted.
- */
- private Set removedPermissions = new HashSet();
-
- /**
- * Creates a new, empty MySQLUser.
- */
- public MySQLUser() {
- }
-
- /**
- * Initializes a new MySQLUser having the given username.
- *
- * @param name The name to assign to this MySQLUser.
- */
- public void init(String name) {
- init(null, name, null, Collections.EMPTY_SET);
- }
-
- /**
- * Initializes a new MySQLUser, copying all data from the given user
- * object.
- *
- * @param user The user object to copy.
- * @throws GuacamoleException If an error occurs while reading the user
- * data in the given object.
- */
- public void init(User user) throws GuacamoleException {
- init(null, user.getUsername(), user.getPassword(), user.getPermissions());
- }
-
- /**
- * Initializes a new MySQLUser initialized from the given data from the
- * database.
- *
- * @param userID The ID of the user in the database, if any.
- * @param username The username of this user.
- * @param password The password to assign to this user.
- * @param permissions The permissions to assign to this user, as
- * retrieved from the database.
- */
- public void init(Integer userID, String username, String password,
- Set permissions) {
- this.userID = userID;
- setUsername(username);
- setPassword(password);
- this.permissions.addAll(permissions);
- }
-
- /**
- * Get the current set of permissions this user has.
- * @return the current set of permissions.
- */
- public Set getCurrentPermissions() {
- return permissions;
- }
-
- /**
- * Get any new permissions that have yet to be inserted.
- * @return the new set of permissions.
- */
- public Set getNewPermissions() {
- return newPermissions;
- }
-
- /**
- * Get any permissions that have not yet been deleted.
- * @return the permissions that need to be deleted.
- */
- public Set getRemovedPermissions() {
- return removedPermissions;
- }
-
- /**
- * Reset the new and removed permission sets after they are
- * no longer needed.
- */
- public void resetPermissions() {
- newPermissions.clear();
- removedPermissions.clear();
- }
-
- /**
- * Returns the ID of this user in the database, if it exists.
- *
- * @return The ID of this user in the database, or null if this user
- * was not retrieved from the database.
- */
- public Integer getUserID() {
- return userID;
- }
-
- /**
- * Sets the ID of this user to the given value.
- *
- * @param userID The ID to assign to this user.
- */
- public void setUserID(Integer userID) {
- this.userID = userID;
- }
-
- @Override
- public Set getPermissions() throws GuacamoleException {
- return Collections.unmodifiableSet(permissions);
- }
-
- @Override
- public boolean hasPermission(Permission permission) throws GuacamoleException {
- return permissions.contains(permission);
- }
-
- @Override
- public void addPermission(Permission permission) throws GuacamoleException {
- permissions.add(permission);
- newPermissions.add(permission);
- removedPermissions.remove(permission);
- }
-
- @Override
- public void removePermission(Permission permission) throws GuacamoleException {
- permissions.remove(permission);
- newPermissions.remove(permission);
- removedPermissions.add(permission);
- }
-
-}
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
deleted file mode 100644
index 66a1a16df..000000000
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/UserDirectory.java
+++ /dev/null
@@ -1,708 +0,0 @@
-/*
- * Copyright (C) 2013 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 com.google.common.base.Preconditions;
-import com.google.common.collect.Sets;
-import com.google.inject.Inject;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import org.glyptodon.guacamole.GuacamoleClientException;
-import org.glyptodon.guacamole.GuacamoleException;
-import org.glyptodon.guacamole.GuacamoleSecurityException;
-import org.glyptodon.guacamole.net.auth.Directory;
-import org.glyptodon.guacamole.net.auth.User;
-import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionGroupPermissionMapper;
-import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionPermissionMapper;
-import net.sourceforge.guacamole.net.auth.mysql.dao.SystemPermissionMapper;
-import net.sourceforge.guacamole.net.auth.mysql.dao.UserPermissionMapper;
-import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupPermissionExample;
-import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupPermissionKey;
-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.model.SystemPermissionExample;
-import net.sourceforge.guacamole.net.auth.mysql.model.SystemPermissionKey;
-import net.sourceforge.guacamole.net.auth.mysql.model.UserPermissionExample;
-import net.sourceforge.guacamole.net.auth.mysql.model.UserPermissionKey;
-import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionGroupService;
-import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionService;
-import net.sourceforge.guacamole.net.auth.mysql.service.PermissionCheckService;
-import net.sourceforge.guacamole.net.auth.mysql.service.UserService;
-import org.glyptodon.guacamole.GuacamoleUnsupportedException;
-import org.glyptodon.guacamole.net.auth.permission.ConnectionGroupPermission;
-import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission;
-import org.glyptodon.guacamole.net.auth.permission.Permission;
-import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
-import org.glyptodon.guacamole.net.auth.permission.UserPermission;
-import org.mybatis.guice.transactional.Transactional;
-
-/**
- * A MySQL based implementation of the User Directory.
- * @author James Muehlner
- */
-public class UserDirectory implements Directory {
-
- /**
- * The user this user directory belongs to. Access is based on his/her
- * permission settings.
- */
- private AuthenticatedUser currentUser;
-
- /**
- * Service for accessing users.
- */
- @Inject
- private UserService userService;
-
- /**
- * Service for accessing connections.
- */
- @Inject
- private ConnectionService connectionService;
-
- /**
- * Service for accessing connection groups.
- */
- @Inject
- private ConnectionGroupService connectionGroupService;
-
- /**
- * DAO for accessing user permissions, which will be injected.
- */
- @Inject
- private UserPermissionMapper userPermissionDAO;
-
- /**
- * DAO for accessing connection permissions, which will be injected.
- */
- @Inject
- private ConnectionPermissionMapper connectionPermissionDAO;
-
- /**
- * DAO for accessing connection group permissions, which will be injected.
- */
- @Inject
- private ConnectionGroupPermissionMapper connectionGroupPermissionDAO;
-
- /**
- * DAO for accessing system permissions, which will be injected.
- */
- @Inject
- private SystemPermissionMapper systemPermissionDAO;
-
- /**
- * Service for checking various permissions, which will be injected.
- */
- @Inject
- private PermissionCheckService permissionCheckService;
-
- /**
- * Set the user for this directory.
- *
- * @param currentUser
- * The user whose permissions define the visibility of other users in
- * this directory.
- */
- public void init(AuthenticatedUser currentUser) {
- this.currentUser = currentUser;
- }
-
- @Transactional
- @Override
- public org.glyptodon.guacamole.net.auth.User get(String identifier)
- throws GuacamoleException {
-
- // Get user
- MySQLUser user = userService.retrieveUser(identifier);
-
- if(user == null)
- return null;
-
- // Verify access is granted
- permissionCheckService.verifyUserAccess(currentUser,
- user.getUserID(),
- MySQLConstants.USER_READ);
-
- // Return user
- return user;
-
- }
-
- @Transactional
- @Override
- public Set getIdentifiers() throws GuacamoleException {
- return permissionCheckService.retrieveUsernames(currentUser,
- MySQLConstants.USER_READ);
- }
-
- @Override
- @Transactional
- public void add(org.glyptodon.guacamole.net.auth.User object)
- throws GuacamoleException {
-
- String username = object.getUsername().trim();
- if(username.isEmpty())
- throw new GuacamoleClientException("The username cannot be blank.");
-
- // Verify current user has permission to create users
- permissionCheckService.verifySystemAccess(currentUser,
- MySQLConstants.SYSTEM_USER_CREATE);
- Preconditions.checkNotNull(object);
-
- // Verify that no user already exists with this username.
- MySQLUser previousUser = userService.retrieveUser(username);
- if(previousUser != null)
- throw new GuacamoleClientException("That username is already in use.");
-
- // Create new user
- MySQLUser user = userService.createUser(username, object.getPassword());
-
- // Create permissions of new user in database
- createPermissions(user.getUserID(), object.getPermissions());
-
- // Give the current user full access to the newly created user.
- UserPermissionKey newUserPermission = new UserPermissionKey();
- newUserPermission.setUser_id(currentUser.getUserID());
- newUserPermission.setAffected_user_id(user.getUserID());
-
- // READ permission on new user
- newUserPermission.setPermission(MySQLConstants.USER_READ);
- userPermissionDAO.insert(newUserPermission);
-
- // UPDATE permission on new user
- newUserPermission.setPermission(MySQLConstants.USER_UPDATE);
- userPermissionDAO.insert(newUserPermission);
-
- // DELETE permission on new user
- newUserPermission.setPermission(MySQLConstants.USER_DELETE);
- userPermissionDAO.insert(newUserPermission);
-
- // ADMINISTER permission on new user
- newUserPermission.setPermission(MySQLConstants.USER_ADMINISTER);
- userPermissionDAO.insert(newUserPermission);
-
- }
-
- /**
- * Add the given permissions to the given user.
- *
- * @param user_id The ID of the user whose permissions should be updated.
- * @param permissions The permissions to add.
- * @throws GuacamoleException If an error occurs while updating the
- * permissions of the given user.
- */
- private void createPermissions(int user_id, Set permissions) throws GuacamoleException {
-
- // Partition given permissions by permission type
- List newUserPermissions = new ArrayList();
- List newConnectionPermissions = new ArrayList();
- List newConnectionGroupPermissions = new ArrayList();
- List newSystemPermissions = new ArrayList();
-
- for (Permission permission : permissions) {
-
- if (permission instanceof UserPermission)
- newUserPermissions.add((UserPermission) permission);
-
- else if (permission instanceof ConnectionPermission)
- newConnectionPermissions.add((ConnectionPermission) permission);
-
- else if (permission instanceof ConnectionGroupPermission)
- newConnectionGroupPermissions.add((ConnectionGroupPermission) permission);
-
- else if (permission instanceof SystemPermission)
- newSystemPermissions.add((SystemPermission) permission);
- }
-
- // Create the new permissions
- createUserPermissions(user_id, newUserPermissions);
- createConnectionPermissions(user_id, newConnectionPermissions);
- createConnectionGroupPermissions(user_id, newConnectionGroupPermissions);
- createSystemPermissions(user_id, newSystemPermissions);
-
- }
-
- /**
- * Remove the given permissions from the given user.
- *
- * @param user_id The ID of the user whose permissions should be updated.
- * @param permissions The permissions to remove.
- * @throws GuacamoleException If an error occurs while updating the
- * permissions of the given user.
- */
- private void removePermissions(int user_id, Set permissions)
- throws GuacamoleException {
-
- // Partition given permissions by permission type
- List removedUserPermissions = new ArrayList();
- List removedConnectionPermissions = new ArrayList();
- List removedConnectionGroupPermissions = new ArrayList();
- List removedSystemPermissions = new ArrayList();
-
- for (Permission permission : permissions) {
-
- if (permission instanceof UserPermission)
- removedUserPermissions.add((UserPermission) permission);
-
- else if (permission instanceof ConnectionPermission)
- removedConnectionPermissions.add((ConnectionPermission) permission);
-
- else if (permission instanceof ConnectionGroupPermission)
- removedConnectionGroupPermissions.add((ConnectionGroupPermission) permission);
-
- else if (permission instanceof SystemPermission)
- removedSystemPermissions.add((SystemPermission) permission);
- }
-
- // Delete the removed permissions.
- deleteUserPermissions(user_id, removedUserPermissions);
- deleteConnectionPermissions(user_id, removedConnectionPermissions);
- deleteConnectionGroupPermissions(user_id, removedConnectionGroupPermissions);
- deleteSystemPermissions(user_id, removedSystemPermissions);
-
- }
-
- /**
- * Create the given user permissions for the given user.
- *
- * @param user_id The ID of the user to change the permissions of.
- * @param permissions The new permissions the given user should have when
- * this operation completes.
- * @throws GuacamoleException If permission to alter the access permissions
- * of affected objects is denied.
- */
- private void createUserPermissions(int user_id,
- Collection permissions)
- throws GuacamoleException {
-
- // If no permissions given, stop now
- if(permissions.isEmpty())
- return;
-
- // Get list of administerable user IDs
- List administerableUserIDs =
- permissionCheckService.retrieveUserIDs(currentUser,
- MySQLConstants.USER_ADMINISTER);
-
- // Get set of usernames corresponding to administerable users
- Map administerableUsers =
- userService.translateUsernames(administerableUserIDs);
-
- // Insert all given permissions
- for (UserPermission permission : permissions) {
-
- // Get original ID
- Integer affected_id =
- administerableUsers.get(permission.getObjectIdentifier());
-
- // Verify that the user actually has permission to administrate
- // every one of these users
- if (affected_id == null)
- throw new GuacamoleSecurityException(
- "User #" + currentUser.getUserID()
- + " does not have permission to administrate user "
- + permission.getObjectIdentifier());
-
- // Create new permission
- UserPermissionKey newPermission = new UserPermissionKey();
- newPermission.setUser_id(currentUser.getUserID());
- newPermission.setPermission(MySQLConstants.getUserConstant(permission.getType()));
- newPermission.setAffected_user_id(affected_id);
- userPermissionDAO.insert(newPermission);
-
- }
-
- }
-
- /**
- * Delete permissions having to do with users for a given user.
- *
- * @param user_id The ID of the user to change the permissions of.
- * @param permissions The permissions the given user should no longer have
- * when this operation completes.
- * @throws GuacamoleException If permission to alter the access permissions
- * of affected objects is denied.
- */
- private void deleteUserPermissions(int user_id,
- Collection permissions)
- throws GuacamoleException {
-
- // If no permissions given, stop now
- if(permissions.isEmpty())
- return;
-
- // Get list of administerable user IDs
- List administerableUserIDs =
- permissionCheckService.retrieveUserIDs(currentUser,
- MySQLConstants.USER_ADMINISTER);
-
- // Get set of usernames corresponding to administerable users
- Map administerableUsers =
- userService.translateUsernames(administerableUserIDs);
-
- // Delete requested permissions
- for (UserPermission permission : permissions) {
-
- // Get original ID
- Integer affected_id =
- administerableUsers.get(permission.getObjectIdentifier());
-
- // Verify that the user actually has permission to administrate
- // every one of these users
- if (affected_id == null)
- throw new GuacamoleSecurityException(
- "User #" + currentUser.getUserID()
- + " does not have permission to administrate user "
- + permission.getObjectIdentifier());
-
- // Delete requested permission
- UserPermissionExample userPermissionExample = new UserPermissionExample();
- userPermissionExample.createCriteria()
- .andUser_idEqualTo(user_id)
- .andPermissionEqualTo(MySQLConstants.getUserConstant(permission.getType()))
- .andAffected_user_idEqualTo(affected_id);
- userPermissionDAO.deleteByExample(userPermissionExample);
-
- }
-
- }
-
- /**
- * Create any new permissions having to do with connections for a given
- * user.
- *
- * @param user_id The ID of the user to assign or remove permissions from.
- * @param permissions The new permissions the user should have after this
- * operation completes.
- * @throws GuacamoleException If permission to alter the access permissions
- * of affected objects is deniedD
- */
- private void createConnectionPermissions(int user_id,
- Collection permissions)
- throws GuacamoleException {
-
- // If no permissions given, stop now
- if(permissions.isEmpty())
- return;
-
- // Get list of administerable connection IDs
- Set administerableConnectionIDs = Sets.newHashSet(
- permissionCheckService.retrieveConnectionIDs(currentUser,
- MySQLConstants.CONNECTION_ADMINISTER));
-
- // Insert all given permissions
- for (ConnectionPermission permission : permissions) {
-
- // Get original ID
- Integer connection_id = Integer.valueOf(permission.getObjectIdentifier());
-
- // Throw exception if permission to administer this connection
- // is not granted
- if (!administerableConnectionIDs.contains(connection_id))
- throw new GuacamoleSecurityException(
- "User #" + currentUser.getUserID()
- + " does not have permission to administrate connection "
- + permission.getObjectIdentifier());
-
- // Create new permission
- ConnectionPermissionKey newPermission = new ConnectionPermissionKey();
- newPermission.setUser_id(user_id);
- newPermission.setPermission(MySQLConstants.getConnectionConstant(permission.getType()));
- newPermission.setConnection_id(connection_id);
- connectionPermissionDAO.insert(newPermission);
-
- }
- }
-
- /**
- * Create any new permissions having to do with connection groups
- * for a given user.
- *
- * @param user_id The ID of the user to assign or remove permissions from.
- * @param permissions The new permissions the user should have after this
- * operation completes.
- * @throws GuacamoleException If permission to alter the access permissions
- * of affected objects is deniedD
- */
- private void createConnectionGroupPermissions(int user_id,
- Collection permissions)
- throws GuacamoleException {
-
- // If no permissions given, stop now
- if(permissions.isEmpty())
- return;
-
- // Get list of administerable connection group IDs
- Set administerableConnectionGroupIDs = Sets.newHashSet(
- permissionCheckService.retrieveConnectionGroupIDs(currentUser,
- MySQLConstants.CONNECTION_GROUP_ADMINISTER));
-
- // Insert all given permissions
- for (ConnectionGroupPermission permission : permissions) {
-
- // Get original ID
- Integer connection_group_id = Integer.valueOf(permission.getObjectIdentifier());
-
- // Throw exception if permission to administer this connection group
- // is not granted
- if (!administerableConnectionGroupIDs.contains(connection_group_id))
- throw new GuacamoleSecurityException(
- "User #" + currentUser.getUserID()
- + " does not have permission to administrate connection group"
- + permission.getObjectIdentifier());
-
- // Create new permission
- ConnectionGroupPermissionKey newPermission = new ConnectionGroupPermissionKey();
- newPermission.setUser_id(user_id);
- newPermission.setPermission(MySQLConstants.getConnectionGroupConstant(permission.getType()));
- newPermission.setConnection_group_id(connection_group_id);
- connectionGroupPermissionDAO.insert(newPermission);
-
- }
- }
-
- /**
- * Delete permissions having to do with connections for a given user.
- *
- * @param user_id The ID of the user to change the permissions of.
- * @param permissions The permissions the given user should no longer have
- * when this operation completes.
- * @throws GuacamoleException If permission to alter the access permissions
- * of affected objects is denied.
- */
- private void deleteConnectionPermissions(int user_id,
- Collection permissions)
- throws GuacamoleException {
-
- // If no permissions given, stop now
- if(permissions.isEmpty())
- return;
-
- // Get list of administerable connection IDs
- Set administerableConnectionIDs = Sets.newHashSet(
- permissionCheckService.retrieveConnectionIDs(currentUser,
- MySQLConstants.CONNECTION_ADMINISTER));
-
- // Delete requested permissions
- for (ConnectionPermission permission : permissions) {
-
- // Get original ID
- Integer connection_id = Integer.valueOf(permission.getObjectIdentifier());
-
- // Verify that the user actually has permission to administrate
- // every one of these connections
- if (!administerableConnectionIDs.contains(connection_id))
- throw new GuacamoleSecurityException(
- "User #" + currentUser.getUserID()
- + " does not have permission to administrate connection "
- + permission.getObjectIdentifier());
-
- ConnectionPermissionExample connectionPermissionExample = new ConnectionPermissionExample();
- connectionPermissionExample.createCriteria()
- .andUser_idEqualTo(user_id)
- .andPermissionEqualTo(MySQLConstants.getConnectionConstant(permission.getType()))
- .andConnection_idEqualTo(connection_id);
- connectionPermissionDAO.deleteByExample(connectionPermissionExample);
-
- }
-
- }
-
- /**
- * Delete permissions having to do with connection groups for a given user.
- *
- * @param user_id The ID of the user to change the permissions of.
- * @param permissions The permissions the given user should no longer have
- * when this operation completes.
- * @throws GuacamoleException If permission to alter the access permissions
- * of affected objects is denied.
- */
- private void deleteConnectionGroupPermissions(int user_id,
- Collection permissions)
- throws GuacamoleException {
-
- // If no permissions given, stop now
- if(permissions.isEmpty())
- return;
-
- // Get list of administerable connection group IDs
- Set administerableConnectionGroupIDs = Sets.newHashSet(
- permissionCheckService.retrieveConnectionGroupIDs(currentUser,
- MySQLConstants.CONNECTION_GROUP_ADMINISTER));
-
- // Delete requested permissions
- for (ConnectionGroupPermission permission : permissions) {
-
- // Get original ID
- Integer connection_group_id = Integer.valueOf(permission.getObjectIdentifier());
-
- // Verify that the user actually has permission to administrate
- // every one of these connection groups
- if (!administerableConnectionGroupIDs.contains(connection_group_id))
- throw new GuacamoleSecurityException(
- "User #" + currentUser.getUserID()
- + " does not have permission to administrate connection group"
- + permission.getObjectIdentifier());
-
- ConnectionGroupPermissionExample connectionGroupPermissionExample = new ConnectionGroupPermissionExample();
- connectionGroupPermissionExample.createCriteria()
- .andUser_idEqualTo(user_id)
- .andPermissionEqualTo(MySQLConstants.getConnectionGroupConstant(permission.getType()))
- .andConnection_group_idEqualTo(connection_group_id);
- connectionGroupPermissionDAO.deleteByExample(connectionGroupPermissionExample);
-
- }
-
- }
-
- /**
- * Create any new system permissions for a given user. All permissions in
- * the given list will be inserted.
- *
- * @param user_id The ID of the user whose permissions should be updated.
- * @param permissions The new system permissions that the given user should
- * have when this operation completes.
- * @throws GuacamoleException If permission to administer system permissions
- * is denied.
- */
- private void createSystemPermissions(int user_id,
- Collection permissions) throws GuacamoleException {
-
- // If no permissions given, stop now
- if(permissions.isEmpty())
- return;
-
- // Only a system administrator can add system permissions.
- permissionCheckService.verifySystemAccess(
- currentUser, SystemPermission.Type.ADMINISTER.name());
-
- // Insert all requested permissions
- for (SystemPermission permission : permissions) {
-
- // Insert permission
- SystemPermissionKey newSystemPermission = new SystemPermissionKey();
- newSystemPermission.setUser_id(user_id);
- newSystemPermission.setPermission(MySQLConstants.getSystemConstant(permission.getType()));
- systemPermissionDAO.insert(newSystemPermission);
-
- }
-
- }
-
- /**
- * Delete system permissions for a given user. All permissions in
- * the given list will be removed from the user.
- *
- * @param user_id The ID of the user whose permissions should be updated.
- * @param permissions The permissions the given user should no longer have
- * when this operation completes.
- * @throws GuacamoleException If the permissions specified could not be
- * removed due to system restrictions.
- */
- private void deleteSystemPermissions(int user_id,
- Collection permissions)
- throws GuacamoleException {
-
- // If no permissions given, stop now
- if (permissions.isEmpty())
- return;
-
- // Prevent self-de-adminifying
- if (user_id == currentUser.getUserID())
- throw new GuacamoleUnsupportedException("Removing your own administrative permissions is not allowed.");
-
- // Build list of requested system permissions
- List systemPermissionTypes = new ArrayList();
- for (SystemPermission permission : permissions)
- systemPermissionTypes.add(MySQLConstants.getSystemConstant(permission.getType()));
-
- // Delete the requested system permissions for this user
- SystemPermissionExample systemPermissionExample = new SystemPermissionExample();
- systemPermissionExample.createCriteria().andUser_idEqualTo(user_id)
- .andPermissionIn(systemPermissionTypes);
- systemPermissionDAO.deleteByExample(systemPermissionExample);
-
- }
-
- @Override
- @Transactional
- public void update(org.glyptodon.guacamole.net.auth.User object)
- throws GuacamoleException {
-
- // If user not actually from this auth provider, we can't handle updated
- // permissions.
- if (!(object instanceof MySQLUser))
- throw new GuacamoleUnsupportedException("User not from database.");
-
- MySQLUser mySQLUser = (MySQLUser) object;
-
- // Validate permission to update this user is granted
- permissionCheckService.verifyUserAccess(currentUser,
- mySQLUser.getUserID(),
- MySQLConstants.USER_UPDATE);
-
- // Update the user in the database
- userService.updateUser(mySQLUser);
-
- // Update permissions in database
- createPermissions(mySQLUser.getUserID(), mySQLUser.getNewPermissions());
- removePermissions(mySQLUser.getUserID(), mySQLUser.getRemovedPermissions());
-
- // The appropriate permissions have been inserted and deleted, so
- // reset the new and removed permission sets.
- mySQLUser.resetPermissions();
-
- }
-
- @Override
- @Transactional
- public void remove(String identifier) throws GuacamoleException {
-
- // Get user pending deletion
- MySQLUser user = userService.retrieveUser(identifier);
-
- // Prevent self-deletion
- if (user.getUserID() == currentUser.getUserID())
- throw new GuacamoleUnsupportedException("Deleting your own user is not allowed.");
-
- // Validate current user has permission to remove the specified user
- permissionCheckService.verifyUserAccess(currentUser,
- user.getUserID(),
- MySQLConstants.USER_DELETE);
-
- // Delete specified user
- userService.deleteUser(user.getUserID());
-
- }
-
- @Override
- public void move(String identifier, Directory groupIdentifier)
- throws GuacamoleException {
- throw new GuacamoleSecurityException("Permission denied.");
- }
-
-}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/ConnectionGroupService.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/ConnectionGroupService.java
deleted file mode 100644
index 4c21ee548..000000000
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/ConnectionGroupService.java
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright (C) 2013 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.service;
-
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import org.glyptodon.guacamole.GuacamoleException;
-import org.glyptodon.guacamole.net.GuacamoleSocket;
-import net.sourceforge.guacamole.net.auth.mysql.ActiveConnectionMap;
-import net.sourceforge.guacamole.net.auth.mysql.AuthenticatedUser;
-import net.sourceforge.guacamole.net.auth.mysql.MySQLConnection;
-import net.sourceforge.guacamole.net.auth.mysql.MySQLConnectionGroup;
-import net.sourceforge.guacamole.net.auth.mysql.MySQLConstants;
-import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionGroupMapper;
-import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroup;
-import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupExample;
-import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupExample.Criteria;
-import net.sourceforge.guacamole.net.auth.mysql.properties.MySQLGuacamoleProperties;
-import org.glyptodon.guacamole.GuacamoleClientTooManyException;
-import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
-import org.glyptodon.guacamole.GuacamoleServerBusyException;
-import org.glyptodon.guacamole.properties.GuacamoleProperties;
-import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
-
-/**
- * Service which provides convenience methods for creating, retrieving, and
- * manipulating connection groups.
- *
- * @author James Muehlner
- */
-public class ConnectionGroupService {
-
- /**
- * Service for managing connections.
- */
- @Inject
- private ConnectionService connectionService;
-
- /**
- * DAO for accessing connection groups.
- */
- @Inject
- private ConnectionGroupMapper connectionGroupDAO;
-
- /**
- * Provider which creates MySQLConnectionGroups.
- */
- @Inject
- private Provider mysqlConnectionGroupProvider;
-
- /**
- * The map of all active connections.
- */
- @Inject
- private ActiveConnectionMap activeConnectionMap;
-
-
- /**
- * Retrieves the connection group having the given
- * name from the database.
- *
- * @param name
- * The name of the connection to return.
- *
- * @param parentID
- * The ID of the parent connection group.
- *
- * @param currentUser
- * The user who queried this connection group.
- *
- * @return
- * The connection having the given name, or null if no such connection
- * group could be found.
- */
- public MySQLConnectionGroup retrieveConnectionGroup(String name, Integer parentID,
- AuthenticatedUser currentUser) {
-
- // Create criteria
- ConnectionGroupExample example = new ConnectionGroupExample();
- Criteria criteria = example.createCriteria().andConnection_group_nameEqualTo(name);
- if(parentID != null)
- criteria.andParent_idEqualTo(parentID);
- else
- criteria.andParent_idIsNull();
-
- // Query connection group by name and parentID
- List connectionGroups =
- connectionGroupDAO.selectByExample(example);
-
- // If no connection group found, return null
- if(connectionGroups.isEmpty())
- return null;
-
- // Otherwise, return found connection
- return toMySQLConnectionGroup(connectionGroups.get(0), currentUser);
-
- }
-
- /**
- * Retrieves the connection group having the given unique identifier
- * from the database.
- *
- * @param uniqueIdentifier
- * The unique identifier of the connection group to retrieve.
- *
- * @param currentUser
- * The user who queried this connection group.
- *
- * @return
- * The connection group having the given unique identifier, or null if
- * no such connection group was found.
- *
- * @throws GuacamoleException
- * If an error occurs while retrieving the connection group.
- */
- public MySQLConnectionGroup retrieveConnectionGroup(String uniqueIdentifier,
- AuthenticatedUser currentUser) throws GuacamoleException {
-
- // The unique identifier for a MySQLConnectionGroup is the database ID
- Integer connectionGroupID = null;
-
- // Try to parse the connectionID if it's not the root group
- if(!MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER.equals(uniqueIdentifier)) {
- try {
- connectionGroupID = Integer.parseInt(uniqueIdentifier);
- } catch(NumberFormatException e) {
- throw new GuacamoleResourceNotFoundException("Invalid connection group ID.");
- }
- }
-
- return retrieveConnectionGroup(connectionGroupID, currentUser);
- }
-
- /**
- * Retrieves the connection group having the given ID from the database.
- *
- * @param id
- * The ID of the connection group to retrieve.
- *
- * @param currentUser
- * The user who queried this connection.
- *
- * @return
- * The connection group having the given ID, or null if no such
- * connection was found.
- */
- public MySQLConnectionGroup retrieveConnectionGroup(Integer id, AuthenticatedUser currentUser) {
-
- // This is the root connection group, so just create it here
- if(id == null) {
- MySQLConnectionGroup connectionGroup = mysqlConnectionGroupProvider.get();
- connectionGroup.init(null, null,
- MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER,
- MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER,
- org.glyptodon.guacamole.net.auth.ConnectionGroup.Type.ORGANIZATIONAL,
- currentUser);
-
- return connectionGroup;
- }
-
- // Query connection by ID
- ConnectionGroup connectionGroup = connectionGroupDAO.selectByPrimaryKey(id);
-
- // If no connection found, return null
- if(connectionGroup == null)
- return null;
-
- // Otherwise, return found connection
- return toMySQLConnectionGroup(connectionGroup, currentUser);
- }
-
- /**
- * Connect to the connection within the given group with the lowest number
- * of currently active users.
- *
- * @param group
- * The group to load balance across.
- *
- * @param info
- * The information to use when performing the connection handshake.
- *
- * @param currentUser
- * The user who is connecting to the socket.
- *
- * @return
- * The connected socket.
- *
- * @throws GuacamoleException
- * If an error occurs while connecting the socket.
- */
- public GuacamoleSocket connect(MySQLConnectionGroup group,
- GuacamoleClientInformation info, AuthenticatedUser currentUser)
- throws GuacamoleException {
-
- // Get all connections in the group.
- List connectionIDs = connectionService.getAllConnectionIDs
- (group.getConnectionGroupID());
-
- synchronized (activeConnectionMap) {
-
- // Get the least used connection.
- Integer leastUsedConnectionID =
- activeConnectionMap.getLeastUsedConnection(connectionIDs);
-
- if(leastUsedConnectionID == null)
- throw new GuacamoleResourceNotFoundException("No connections found in group.");
-
- if(GuacamoleProperties.getProperty(
- MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS, false)
- && activeConnectionMap.isActive(leastUsedConnectionID))
- throw new GuacamoleServerBusyException
- ("Cannot connect. All connections are in use.");
-
- if(GuacamoleProperties.getProperty(
- MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS, true)
- && activeConnectionMap.isConnectionGroupUserActive(group.getConnectionGroupID(), currentUser.getUserID()))
- throw new GuacamoleClientTooManyException
- ("Cannot connect. Connection group already in use by this user.");
-
- // Get the connection
- MySQLConnection connection = connectionService
- .retrieveConnection(leastUsedConnectionID, currentUser);
-
- // Connect to the connection
- return connectionService.connect(connection, info, currentUser, group.getConnectionGroupID());
-
- }
-
- }
-
- /**
- * Returns a list of the IDs of all connection groups with a given parent ID.
- * @param parentID The ID of the parent for all the queried connection groups.
- * @return a list of the IDs of all connection groups with a given parent ID.
- */
- public List getAllConnectionGroupIDs(Integer parentID) {
-
- // Create criteria
- ConnectionGroupExample example = new ConnectionGroupExample();
- Criteria criteria = example.createCriteria();
-
- if(parentID != null)
- criteria.andParent_idEqualTo(parentID);
- else
- criteria.andParent_idIsNull();
-
- // Query the connections
- List connectionGroups = connectionGroupDAO.selectByExample(example);
-
- // List of IDs of connections with the given parent
- List connectionGroupIDs = new ArrayList();
-
- for(ConnectionGroup connectionGroup : connectionGroups) {
- connectionGroupIDs.add(connectionGroup.getConnection_group_id());
- }
-
- return connectionGroupIDs;
- }
-
- /**
- * Get the identifiers of all the connection groups defined in the system
- * with a certain parentID.
- *
- * @return A Set of identifiers of all the connection groups defined
- * in the system with the given parentID.
- */
- public Set getAllConnectionGroupIdentifiers(Integer parentID) {
-
- // Set of all present connection identifiers
- Set identifiers = new HashSet();
-
- // Set up Criteria
- ConnectionGroupExample example = new ConnectionGroupExample();
- Criteria criteria = example.createCriteria();
- if(parentID != null)
- criteria.andParent_idEqualTo(parentID);
- else
- criteria.andParent_idIsNull();
-
- // Query connection identifiers
- List connectionGroups =
- connectionGroupDAO.selectByExample(example);
- for (ConnectionGroup connectionGroup : connectionGroups)
- identifiers.add(String.valueOf(connectionGroup.getConnection_group_id()));
-
- return identifiers;
-
- }
-
- /**
- * Convert the given database-retrieved Connection into a MySQLConnection.
- * The parameters of the given connection will be read and added to the
- * MySQLConnection in the process.
- *
- * @param connection
- * The connection to convert.
- *
- * @param currentUser
- * The user who queried this connection.
- *
- * @return
- * A new MySQLConnection containing all data associated with the
- * specified connection.
- */
- private MySQLConnectionGroup toMySQLConnectionGroup(ConnectionGroup connectionGroup,
- AuthenticatedUser currentUser) {
-
- // Create new MySQLConnection from retrieved data
- MySQLConnectionGroup mySQLConnectionGroup = mysqlConnectionGroupProvider.get();
-
- String mySqlType = connectionGroup.getType();
- org.glyptodon.guacamole.net.auth.ConnectionGroup.Type authType;
-
- if(mySqlType.equals(MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL))
- authType = org.glyptodon.guacamole.net.auth.ConnectionGroup.Type.ORGANIZATIONAL;
- else
- authType = org.glyptodon.guacamole.net.auth.ConnectionGroup.Type.BALANCING;
-
- mySQLConnectionGroup.init(
- connectionGroup.getConnection_group_id(),
- connectionGroup.getParent_id(),
- connectionGroup.getConnection_group_name(),
- Integer.toString(connectionGroup.getConnection_group_id()),
- authType,
- currentUser
- );
-
- return mySQLConnectionGroup;
-
- }
-
- /**
- * Get the connection group IDs of all the connection groups defined in the system.
- *
- * @return A list of connection group IDs of all the connection groups defined in the system.
- */
- public List