diff --git a/extensions/guacamole-auth-mysql/.gitignore b/extensions/guacamole-auth-mysql/.gitignore
new file mode 100644
index 000000000..42f4a1a64
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/.gitignore
@@ -0,0 +1,2 @@
+target/
+*~
diff --git a/extensions/guacamole-auth-mysql/README b/extensions/guacamole-auth-mysql/README
new file mode 100644
index 000000000..5543c124f
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/README
@@ -0,0 +1,171 @@
+
+------------------------------------------------------------
+ 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
new file mode 100644
index 000000000..d0fb6d5bd
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/doc/example/settings.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+ guacamole-mybatis
+
+ SCHEMA
+ DATABASE
+ USER
+ PASS
+
+
+
+
+
+
+ guacamole-mybatis
+
+
+
diff --git a/extensions/guacamole-auth-mysql/pom.xml b/extensions/guacamole-auth-mysql/pom.xml
new file mode 100644
index 000000000..4938d42f4
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/pom.xml
@@ -0,0 +1,141 @@
+
+
+ 4.0.0
+ net.sourceforge.guacamole
+ guacamole-auth-mysql
+ jar
+ 0.8.0
+ 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
+
+
+
+
+
+
+
+
+
+
+
+
+ net.sourceforge.guacamole
+ guacamole-common
+ 0.8.0
+
+
+
+
+ net.sourceforge.guacamole
+ guacamole-ext
+ 0.8.0
+
+
+
+
+ org.slf4j
+ slf4j-api
+ 1.6.1
+
+
+ org.slf4j
+ slf4j-jcl
+ 1.6.1
+ runtime
+
+
+
+
+ org.mybatis
+ mybatis
+ 3.1.1
+
+
+
+
+ org.mybatis
+ mybatis-guice
+ 3.2
+
+
+
+
+ com.google.collections
+ google-collections
+ 1.0
+
+
+
+
+
+
+
+ guac-dev
+ http://guac-dev.org/repo
+
+
+
+
+
diff --git a/extensions/guacamole-auth-mysql/schema/001-create-schema.sql b/extensions/guacamole-auth-mysql/schema/001-create-schema.sql
new file mode 100644
index 000000000..6351dd6ff
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/schema/001-create-schema.sql
@@ -0,0 +1,153 @@
+
+--
+-- Table of connections. Each connection has a name, protocol, and
+-- associated set of parameters.
+--
+
+CREATE TABLE `guacamole_connection` (
+
+ `connection_id` int(11) NOT NULL AUTO_INCREMENT,
+ `connection_name` varchar(128) NOT NULL,
+ `protocol` varchar(32) NOT NULL,
+
+ PRIMARY KEY (`connection_id`),
+ UNIQUE KEY `connection_name` (`connection_name`)
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Table of users. Each user has a unique username and a hashed password
+-- with corresponding salt.
+--
+
+CREATE TABLE `guacamole_user` (
+
+ `user_id` int(11) NOT NULL AUTO_INCREMENT,
+ `username` varchar(128) NOT NULL,
+ `password_hash` binary(32) NOT NULL,
+ `password_salt` binary(32) NOT NULL,
+
+ PRIMARY KEY (`user_id`),
+ UNIQUE KEY `username` (`username`)
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Table of connection parameters. Each parameter is simply a name/value pair
+-- associated with a connection.
+--
+
+CREATE TABLE `guacamole_connection_parameter` (
+
+ `connection_id` int(11) NOT NULL,
+ `parameter_name` varchar(128) NOT NULL,
+ `parameter_value` varchar(4096) NOT NULL,
+
+ PRIMARY KEY (`connection_id`,`parameter_name`),
+
+ CONSTRAINT `guacamole_connection_parameter_ibfk_1`
+ FOREIGN KEY (`connection_id`)
+ REFERENCES `guacamole_connection` (`connection_id`) ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Table of connection permissions. Each connection permission grants a user
+-- specific access to a connection.
+--
+
+CREATE TABLE `guacamole_connection_permission` (
+
+ `user_id` int(11) NOT NULL,
+ `connection_id` int(11) NOT NULL,
+ `permission` enum('READ',
+ 'UPDATE',
+ 'DELETE',
+ 'ADMINISTER') NOT NULL,
+
+ PRIMARY KEY (`user_id`,`connection_id`,`permission`),
+
+ CONSTRAINT `guacamole_connection_permission_ibfk_1`
+ FOREIGN KEY (`connection_id`)
+ REFERENCES `guacamole_connection` (`connection_id`) ON DELETE CASCADE,
+
+ CONSTRAINT `guacamole_connection_permission_ibfk_2`
+ FOREIGN KEY (`user_id`)
+ REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Table of system permissions. Each system permission grants a user a
+-- system-level privilege of some kind.
+--
+
+CREATE TABLE `guacamole_system_permission` (
+
+ `user_id` int(11) NOT NULL,
+ `permission` enum('CREATE_CONNECTION',
+ 'CREATE_USER',
+ 'ADMINISTER') NOT NULL,
+
+ PRIMARY KEY (`user_id`,`permission`),
+
+ CONSTRAINT `guacamole_system_permission_ibfk_1`
+ FOREIGN KEY (`user_id`)
+ REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Table of user permissions. Each user permission grants a user access to
+-- another user (the "affected" user) for a specific type of operation.
+--
+
+CREATE TABLE `guacamole_user_permission` (
+
+ `user_id` int(11) NOT NULL,
+ `affected_user_id` int(11) NOT NULL,
+ `permission` enum('READ',
+ 'UPDATE',
+ 'DELETE',
+ 'ADMINISTER') NOT NULL,
+
+ PRIMARY KEY (`user_id`,`affected_user_id`,`permission`),
+
+ CONSTRAINT `guacamole_user_permission_ibfk_1`
+ FOREIGN KEY (`affected_user_id`)
+ REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE,
+
+ CONSTRAINT `guacamole_user_permission_ibfk_2`
+ FOREIGN KEY (`user_id`)
+ REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Table of connection history records. Each record defines a specific user's
+-- session, including the connection used, the start time, and the end time
+-- (if any).
+--
+
+CREATE TABLE `guacamole_connection_history` (
+
+ `history_id` int(11) NOT NULL AUTO_INCREMENT,
+ `user_id` int(11) NOT NULL,
+ `connection_id` int(11) NOT NULL,
+ `start_date` datetime NOT NULL,
+ `end_date` datetime DEFAULT NULL,
+
+ PRIMARY KEY (`history_id`),
+ KEY `user_id` (`user_id`),
+ KEY `connection_id` (`connection_id`),
+
+ CONSTRAINT `guacamole_connection_history_ibfk_1`
+ FOREIGN KEY (`user_id`)
+ REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE,
+
+ CONSTRAINT `guacamole_connection_history_ibfk_2`
+ FOREIGN KEY (`connection_id`)
+ REFERENCES `guacamole_connection` (`connection_id`) ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
diff --git a/extensions/guacamole-auth-mysql/schema/002-create-admin-user.sql b/extensions/guacamole-auth-mysql/schema/002-create-admin-user.sql
new file mode 100644
index 000000000..1efed1ccb
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/schema/002-create-admin-user.sql
@@ -0,0 +1,16 @@
+
+-- Create default user "guacadmin" with password "guacadmin"
+insert into guacamole_user values(1, 'guacadmin',
+ x'CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', -- 'guacadmin'
+ x'FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264');
+
+-- Grant this user create permissions
+insert into guacamole_system_permission values(1, 'CREATE_CONNECTION');
+insert into guacamole_system_permission values(1, 'CREATE_USER');
+insert into guacamole_system_permission values(1, 'ADMINISTER');
+
+-- Grant admin permission to read/update/administer self
+insert into guacamole_user_permission values(1, 1, 'READ');
+insert into guacamole_user_permission values(1, 1, 'UPDATE');
+insert into guacamole_user_permission values(1, 1, 'ADMINISTER');
+
diff --git a/extensions/guacamole-auth-mysql/src/main/assembly/dist.xml b/extensions/guacamole-auth-mysql/src/main/assembly/dist.xml
new file mode 100644
index 000000000..a13bce3e2
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/assembly/dist.xml
@@ -0,0 +1,54 @@
+
+
+ dist
+ ${project.artifactId}-${project.version}
+
+
+
+ tar.gz
+
+
+
+
+
+
+
+ /
+ doc
+
+
+
+
+ /schema
+ schema
+
+
+
+
+
+
+
+
+ /lib
+ runtime
+ false
+ true
+ true
+
+
+
+
+ net.sourceforge.guacamole:guacamole-common
+
+
+ net.sourceforge.guacamole:guacamole-ext
+
+
+
+
+
+
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/ActiveConnectionSet.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/ActiveConnectionSet.java
new file mode 100644
index 000000000..4e5ba4937
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/ActiveConnectionSet.java
@@ -0,0 +1,121 @@
+
+package net.sourceforge.guacamole.net.auth.mysql;
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+import com.google.inject.Inject;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import net.sourceforge.guacamole.GuacamoleException;
+import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionHistoryMapper;
+import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionHistory;
+
+/**
+ * Represents the set of currently active Connections. Whenever a socket is
+ * opened, the connection ID should be added to this set, and whenever a socket
+ * is closed, the connection ID should be removed from this set.
+ *
+ * @author James Muehlner
+ */
+public class ActiveConnectionSet {
+
+ /**
+ * DAO for accessing connection history.
+ */
+ @Inject
+ private ConnectionHistoryMapper connectionHistoryDAO;
+
+ /**
+ * Set of all the connections that are currently active.
+ */
+ private Set activeConnectionSet = new HashSet();
+
+ /**
+ * 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 activeConnectionSet.contains(connectionID);
+ }
+
+ /**
+ * 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.
+ * @return The ID of the history record created for this open connection.
+ */
+ public int openConnection(int connectionID, int userID) {
+
+ // 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);
+
+ // Mark the connection as active
+ activeConnectionSet.add(connectionID);
+
+ return connectionHistory.getHistory_id();
+ }
+
+ /**
+ * Set a connection as closed.
+ * @param connectionID The ID of the connection that is being opened.
+ * @param historyID The ID of the history record about the open connection.
+ * @throws GuacamoleException If the open connection history is not found.
+ */
+ public void closeConnection(int connectionID, int historyID)
+ throws GuacamoleException {
+
+ // Get the existing history record
+ ConnectionHistory connectionHistory =
+ connectionHistoryDAO.selectByPrimaryKey(historyID);
+
+ if(connectionHistory == null)
+ throw new GuacamoleException("History record not found.");
+
+ // Update the connection history record to mark that it is now closed
+ connectionHistory.setEnd_date(new Date());
+ connectionHistoryDAO.updateByPrimaryKey(connectionHistory);
+
+ // Remove the connection from the set of active connections.
+ activeConnectionSet.remove(connectionID);
+ }
+}
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
new file mode 100644
index 000000000..11398ba12
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/ConnectionDirectory.java
@@ -0,0 +1,254 @@
+
+package net.sourceforge.guacamole.net.auth.mysql;
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+import com.google.inject.Inject;
+import java.util.Set;
+import net.sourceforge.guacamole.GuacamoleClientException;
+import net.sourceforge.guacamole.GuacamoleException;
+import net.sourceforge.guacamole.net.auth.Connection;
+import net.sourceforge.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.ConnectionService;
+import net.sourceforge.guacamole.net.auth.mysql.service.PermissionCheckService;
+import net.sourceforge.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 ID of the user who this connection directory belongs to.
+ * Access is based on his/her permission settings.
+ */
+ private int user_id;
+
+ /**
+ * Service for checking permissions.
+ */
+ @Inject
+ private PermissionCheckService permissionCheckService;
+
+ /**
+ * Service managing connections.
+ */
+ @Inject
+ private ConnectionService connectionService;
+
+ /**
+ * 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 for this directory.
+ *
+ * @param user_id The ID of the user owning this connection directory.
+ */
+ public void init(int user_id) {
+ this.user_id = user_id;
+ }
+
+ @Transactional
+ @Override
+ public Connection get(String identifier) throws GuacamoleException {
+
+ // Get connection
+ MySQLConnection connection =
+ connectionService.retrieveConnection(identifier, user_id);
+
+ // Verify access is granted
+ permissionCheckService.verifyConnectionAccess(
+ this.user_id,
+ connection.getConnectionID(),
+ MySQLConstants.CONNECTION_READ);
+
+ // Return connection
+ return connection;
+
+ }
+
+ @Transactional
+ @Override
+ public Set getIdentifiers() throws GuacamoleException {
+ return permissionCheckService.retrieveConnectionNames(user_id,
+ MySQLConstants.CONNECTION_READ);
+ }
+
+ @Transactional
+ @Override
+ public void add(Connection object) throws GuacamoleException {
+
+ String identifier = object.getIdentifier().trim();
+ if(identifier.isEmpty())
+ throw new GuacamoleClientException("The connection identifier cannot be blank.");
+
+ // Verify permission to create
+ permissionCheckService.verifySystemAccess(this.user_id,
+ MySQLConstants.SYSTEM_CONNECTION_CREATE);
+
+ // Verify that no connection already exists with this identifier.
+ MySQLConnection previousConnection =
+ connectionService.retrieveConnection(identifier, user_id);
+ if(previousConnection != null)
+ throw new GuacamoleClientException("That connection identifier is already in use.");
+
+ // Create connection
+ MySQLConnection connection = connectionService.createConnection(
+ identifier, object.getConfiguration().getProtocol(),
+ user_id);
+
+ // 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(this.user_id);
+ 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 GuacamoleException("Connection not from database.");
+
+ MySQLConnection mySQLConnection = (MySQLConnection) object;
+
+ // Verify permission to update
+ permissionCheckService.verifyConnectionAccess(this.user_id,
+ 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, user_id);
+
+ // Verify permission to delete
+ permissionCheckService.verifyConnectionAccess(this.user_id,
+ mySQLConnection.getConnectionID(),
+ MySQLConstants.CONNECTION_DELETE);
+
+ // Delete the connection itself
+ connectionService.deleteConnection(mySQLConnection.getConnectionID());
+
+ }
+
+}
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
new file mode 100644
index 000000000..e872df0a0
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java
@@ -0,0 +1,177 @@
+
+package net.sourceforge.guacamole.net.auth.mysql;
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+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 net.sourceforge.guacamole.GuacamoleException;
+import net.sourceforge.guacamole.net.auth.AuthenticationProvider;
+import net.sourceforge.guacamole.net.auth.Credentials;
+import net.sourceforge.guacamole.net.auth.UserContext;
+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.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.SaltService;
+import net.sourceforge.guacamole.net.auth.mysql.service.SecureRandomSaltService;
+import net.sourceforge.guacamole.net.auth.mysql.service.SHA256PasswordEncryptionService;
+import net.sourceforge.guacamole.net.auth.mysql.service.UserService;
+import net.sourceforge.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 ActiveConnectionSet activeConnectionSet = new ActiveConnectionSet();
+
+ /**
+ * 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(authenticatedUser.getUserID());
+ 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();
+
+ // 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");
+
+ // Set up Guice injector.
+ injector = Guice.createInjector(
+ JdbcHelper.MySQL,
+
+ new Module() {
+ @Override
+ public void configure(Binder binder) {
+ Names.bindProperties(binder, myBatisProperties);
+ }
+ },
+
+ 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(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(UserService.class);
+ bind(ActiveConnectionSet.class).toInstance(activeConnectionSet);
+
+ }
+ } // end of mybatis module
+
+ );
+ } // end of constructor
+
+}
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
new file mode 100644
index 000000000..dc68cfcb4
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnection.java
@@ -0,0 +1,132 @@
+
+package net.sourceforge.guacamole.net.auth.mysql;
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+import com.google.inject.Inject;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import net.sourceforge.guacamole.GuacamoleException;
+import net.sourceforge.guacamole.net.GuacamoleSocket;
+import net.sourceforge.guacamole.net.auth.AbstractConnection;
+import net.sourceforge.guacamole.net.auth.ConnectionRecord;
+import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionService;
+import net.sourceforge.guacamole.protocol.GuacamoleClientInformation;
+import net.sourceforge.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 user who queried or created this connection.
+ */
+ private int userID;
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Initialize from explicit values.
+ *
+ * @param connectionID The ID of the associated database record, if any.
+ * @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 userID The IID of the user who queried this connection.
+ */
+ public void init(Integer connectionID, String identifier,
+ GuacamoleConfiguration config,
+ List extends ConnectionRecord> history, int userID) {
+
+ this.connectionID = connectionID;
+ setIdentifier(identifier);
+ setConfiguration(config);
+ this.history.addAll(history);
+ this.userID = userID;
+
+ }
+
+ @Override
+ public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
+ return connectionService.connect(this, info, userID);
+ }
+
+ @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/MySQLConnectionRecord.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnectionRecord.java
new file mode 100644
index 000000000..bee0917a0
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnectionRecord.java
@@ -0,0 +1,103 @@
+
+package net.sourceforge.guacamole.net.auth.mysql;
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+import java.util.Date;
+import net.sourceforge.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;
+
+ /**
+ * 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.
+ */
+ public MySQLConnectionRecord(Date startDate, Date endDate,
+ String username) {
+ if (startDate != null) this.startDate = new Date(startDate.getTime());
+ if (endDate != null) this.endDate = new Date(endDate.getTime());
+ this.username = username;
+ }
+
+ @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() {
+ // If the end date hasn't been stored yet, the connection is still open.
+ return endDate == null;
+ }
+
+}
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
new file mode 100644
index 000000000..9b72c3f57
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConstants.java
@@ -0,0 +1,186 @@
+
+package net.sourceforge.guacamole.net.auth.mysql;
+
+import net.sourceforge.guacamole.net.auth.permission.ObjectPermission;
+import net.sourceforge.guacamole.net.auth.permission.SystemPermission;
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * 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 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 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 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 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
new file mode 100644
index 000000000..8b2b6aade
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleSocket.java
@@ -0,0 +1,114 @@
+
+package net.sourceforge.guacamole.net.auth.mysql;
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+import com.google.inject.Inject;
+import net.sourceforge.guacamole.GuacamoleException;
+import net.sourceforge.guacamole.io.GuacamoleReader;
+import net.sourceforge.guacamole.io.GuacamoleWriter;
+import net.sourceforge.guacamole.net.GuacamoleSocket;
+
+/**
+ * A MySQL specific wrapper around a ConfiguredGuacamoleSocket.
+ * @author James Muehlner
+ */
+public class MySQLGuacamoleSocket implements GuacamoleSocket {
+
+ /**
+ * Injected ActiveConnectionSet which will contain all active connections.
+ */
+ @Inject
+ private ActiveConnectionSet activeConnectionSet;
+
+ /**
+ * The wrapped socket.
+ */
+ private GuacamoleSocket socket;
+
+ /**
+ * The ID associated with the connection associated with the wrapped
+ * socket.
+ */
+ private int connectionID;
+
+ /**
+ * The ID of the history record associated with this instance of the
+ * connection.
+ */
+ private int historyID;
+
+ /**
+ * Initialize this MySQLGuacamoleSocket with the provided GuacamoleSocket.
+ *
+ * @param socket The ConfiguredGuacamoleSocket to wrap.
+ * @param connectionID The ID of the connection associated with the given
+ * socket.
+ * @param historyID The ID of the history record associated with this
+ * instance of the connection.
+ */
+ public void init(GuacamoleSocket socket, int connectionID, int historyID) {
+ this.socket = socket;
+ this.connectionID = connectionID;
+ this.historyID = historyID;
+ }
+
+ @Override
+ public GuacamoleReader getReader() {
+ return socket.getReader();
+ }
+
+ @Override
+ public GuacamoleWriter getWriter() {
+ return socket.getWriter();
+ }
+
+ @Override
+ public void close() throws GuacamoleException {
+
+ // Close socket
+ socket.close();
+
+ // Mark this connection as inactive
+ activeConnectionSet.closeConnection(connectionID, historyID);
+ }
+
+ @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
new file mode 100644
index 000000000..e969a61b2
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUser.java
@@ -0,0 +1,193 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+package net.sourceforge.guacamole.net.auth.mysql;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import net.sourceforge.guacamole.GuacamoleException;
+import net.sourceforge.guacamole.net.auth.AbstractUser;
+import net.sourceforge.guacamole.net.auth.User;
+import net.sourceforge.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/MySQLUserContext.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUserContext.java
new file mode 100644
index 000000000..94cc3991e
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUserContext.java
@@ -0,0 +1,106 @@
+
+package net.sourceforge.guacamole.net.auth.mysql;
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+import com.google.inject.Inject;
+import net.sourceforge.guacamole.GuacamoleException;
+import net.sourceforge.guacamole.net.auth.Connection;
+import net.sourceforge.guacamole.net.auth.Directory;
+import net.sourceforge.guacamole.net.auth.User;
+import net.sourceforge.guacamole.net.auth.UserContext;
+import net.sourceforge.guacamole.net.auth.mysql.service.UserService;
+
+/**
+ * The MySQL representation of a UserContext.
+ * @author James Muehlner
+ */
+public class MySQLUserContext implements UserContext {
+
+ /**
+ * The ID of the user owning this context. The permissions of this user
+ * dictate the access given via the user and connection directories.
+ */
+ private int user_id;
+
+ /**
+ * User directory restricted by the permissions of the user associated
+ * with this context.
+ */
+ @Inject
+ private UserDirectory userDirectory;
+
+ /**
+ * Connection directory restricted by the permissions of the user associated
+ * with this context.
+ */
+ @Inject
+ private ConnectionDirectory connectionDirectory;
+
+ /**
+ * Service for accessing users.
+ */
+ @Inject
+ private UserService userService;
+
+ /**
+ * Initializes the user and directories associated with this context.
+ *
+ * @param user_id The ID of the user owning this context.
+ */
+ public void init(int user_id) {
+ this.user_id = user_id;
+ userDirectory.init(user_id);
+ connectionDirectory.init(user_id);
+ }
+
+ @Override
+ public User self() {
+ return userService.retrieveUser(user_id);
+ }
+
+ @Override
+ public Directory getUserDirectory() throws GuacamoleException {
+ return userDirectory;
+ }
+
+ @Override
+ public Directory getConnectionDirectory() throws GuacamoleException {
+ return connectionDirectory;
+ }
+
+}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/UserDirectory.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/UserDirectory.java
new file mode 100644
index 000000000..4a432cf45
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/UserDirectory.java
@@ -0,0 +1,601 @@
+
+package net.sourceforge.guacamole.net.auth.mysql;
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+import com.google.common.base.Preconditions;
+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 net.sourceforge.guacamole.GuacamoleClientException;
+import net.sourceforge.guacamole.GuacamoleException;
+import net.sourceforge.guacamole.GuacamoleSecurityException;
+import net.sourceforge.guacamole.net.auth.Directory;
+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.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.ConnectionService;
+import net.sourceforge.guacamole.net.auth.mysql.service.PermissionCheckService;
+import net.sourceforge.guacamole.net.auth.mysql.service.UserService;
+import net.sourceforge.guacamole.net.auth.permission.ConnectionPermission;
+import net.sourceforge.guacamole.net.auth.permission.Permission;
+import net.sourceforge.guacamole.net.auth.permission.SystemPermission;
+import net.sourceforge.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 ID of the user who this user directory belongs to.
+ * Access is based on his/her permission settings.
+ */
+ private int user_id;
+
+ /**
+ * Service for accessing users.
+ */
+ @Inject
+ private UserService userService;
+
+ /**
+ * Service for accessing connections.
+ */
+ @Inject
+ private ConnectionService connectionService;
+
+ /**
+ * 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 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 user_id The ID of the user whose permissions define the visibility
+ * of other users in this directory.
+ */
+ public void init(int user_id) {
+ this.user_id = user_id;
+ }
+
+ @Transactional
+ @Override
+ public net.sourceforge.guacamole.net.auth.User get(String identifier)
+ throws GuacamoleException {
+
+ // Get user
+ MySQLUser user = userService.retrieveUser(identifier);
+
+ // Verify access is granted
+ permissionCheckService.verifyUserAccess(this.user_id,
+ user.getUserID(),
+ MySQLConstants.USER_READ);
+
+ // Return user
+ return userService.retrieveUser(identifier);
+
+ }
+
+ @Transactional
+ @Override
+ public Set getIdentifiers() throws GuacamoleException {
+ return permissionCheckService.retrieveUsernames(user_id,
+ MySQLConstants.USER_READ);
+ }
+
+ @Override
+ @Transactional
+ public void add(net.sourceforge.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(this.user_id,
+ 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(this.user_id);
+ 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 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 SystemPermission)
+ newSystemPermissions.add((SystemPermission) permission);
+ }
+
+ // Create the new permissions
+ createUserPermissions(user_id, newUserPermissions);
+ createConnectionPermissions(user_id, newConnectionPermissions);
+ 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 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 SystemPermission)
+ removedSystemPermissions.add((SystemPermission) permission);
+ }
+
+ // Delete the removed permissions.
+ deleteUserPermissions(user_id, removedUserPermissions);
+ deleteConnectionPermissions(user_id, removedConnectionPermissions);
+ 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(this.user_id,
+ 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 #" + this.user_id
+ + " does not have permission to administrate user "
+ + permission.getObjectIdentifier());
+
+ // Create new permission
+ UserPermissionKey newPermission = new UserPermissionKey();
+ newPermission.setUser_id(user_id);
+ 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(this.user_id,
+ 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 #" + this.user_id
+ + " 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
+ List administerableConnectionIDs =
+ permissionCheckService.retrieveConnectionIDs(this.user_id,
+ MySQLConstants.CONNECTION_ADMINISTER);
+
+ // Get set of names corresponding to administerable connections
+ Map administerableConnections =
+ connectionService.translateNames(administerableConnectionIDs);
+
+ // Insert all given permissions
+ for (ConnectionPermission permission : permissions) {
+
+ // Get original ID
+ Integer connection_id =
+ administerableConnections.get(permission.getObjectIdentifier());
+
+ // Throw exception if permission to administer this connection
+ // is not granted
+ if (connection_id == null)
+ throw new GuacamoleSecurityException(
+ "User #" + this.user_id
+ + " 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);
+
+ }
+ }
+
+ /**
+ * 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
+ List administerableConnectionIDs =
+ permissionCheckService.retrieveConnectionIDs(this.user_id,
+ MySQLConstants.CONNECTION_ADMINISTER);
+
+ // Get set of names corresponding to administerable connections
+ Map administerableConnections =
+ connectionService.translateNames(administerableConnectionIDs);
+
+ // Delete requested permissions
+ for (ConnectionPermission permission : permissions) {
+
+ // Get original ID
+ Integer connection_id =
+ administerableConnections.get(permission.getObjectIdentifier());
+
+ // Verify that the user actually has permission to administrate
+ // every one of these connections
+ if (connection_id == null)
+ throw new GuacamoleSecurityException(
+ "User #" + this.user_id
+ + " 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);
+
+ }
+
+ }
+
+ /**
+ * 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(
+ this.user_id, 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 == this.user_id)
+ throw new GuacamoleClientException("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(net.sourceforge.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 GuacamoleException("User not from database.");
+
+ MySQLUser mySQLUser = (MySQLUser) object;
+
+ // Validate permission to update this user is granted
+ permissionCheckService.verifyUserAccess(this.user_id,
+ 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() == this.user_id)
+ throw new GuacamoleClientException("Deleting your own user is not allowed.");
+
+ // Validate current user has permission to remove the specified user
+ permissionCheckService.verifyUserAccess(this.user_id,
+ user.getUserID(),
+ MySQLConstants.USER_DELETE);
+
+ // Delete specified user
+ userService.deleteUser(user.getUserID());
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/package-info.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/package-info.java
new file mode 100644
index 000000000..81f802bbb
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/package-info.java
@@ -0,0 +1,7 @@
+
+/**
+ * Base classes which support the MySQL authentication provider, including
+ * the authentication provider itself.
+ */
+package net.sourceforge.guacamole.net.auth.mysql;
+
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/MySQLGuacamoleProperties.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/MySQLGuacamoleProperties.java
new file mode 100644
index 000000000..10ca5525f
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/MySQLGuacamoleProperties.java
@@ -0,0 +1,112 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+package net.sourceforge.guacamole.net.auth.mysql.properties;
+
+import net.sourceforge.guacamole.properties.BooleanGuacamoleProperty;
+import net.sourceforge.guacamole.properties.IntegerGuacamoleProperty;
+import net.sourceforge.guacamole.properties.StringGuacamoleProperty;
+
+/**
+ * Properties used by the MySQL Authentication plugin.
+ * @author James Muehlner
+ */
+public class MySQLGuacamoleProperties {
+
+ /**
+ * This class should not be instantiated.
+ */
+ private MySQLGuacamoleProperties() {}
+
+ /**
+ * The URL of the MySQL server hosting the guacamole authentication tables.
+ */
+ public static final StringGuacamoleProperty MYSQL_HOSTNAME = new StringGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "mysql-hostname"; }
+
+ };
+
+ /**
+ * The port of the MySQL server hosting the guacamole authentication tables.
+ */
+ public static final IntegerGuacamoleProperty MYSQL_PORT = new IntegerGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "mysql-port"; }
+
+ };
+
+ /**
+ * The name of the MySQL database containing the guacamole authentication tables.
+ */
+ public static final StringGuacamoleProperty MYSQL_DATABASE = new StringGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "mysql-database"; }
+
+ };
+
+ /**
+ * The username used to authenticate to the MySQL database containing the guacamole authentication tables.
+ */
+ public static final StringGuacamoleProperty MYSQL_USERNAME = new StringGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "mysql-username"; }
+
+ };
+
+ /**
+ * The password used to authenticate to the MySQL database containing the guacamole authentication tables.
+ */
+ public static final StringGuacamoleProperty MYSQL_PASSWORD = new StringGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "mysql-password"; }
+
+ };
+
+ /**
+ * Whether or not multiple users accessing the same connection at the same time should be disallowed.
+ */
+ public static final BooleanGuacamoleProperty MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS = new BooleanGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "mysql-disallow-simultaneous-connections"; }
+
+ };
+}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/package-info.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/package-info.java
new file mode 100644
index 000000000..d327a33bc
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/properties/package-info.java
@@ -0,0 +1,7 @@
+
+/**
+ * Properties which control the configuration of the MySQL authentication
+ * provider.
+ */
+package net.sourceforge.guacamole.net.auth.mysql.properties;
+
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/ConnectionService.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/ConnectionService.java
new file mode 100644
index 000000000..71e26944a
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/ConnectionService.java
@@ -0,0 +1,456 @@
+
+package net.sourceforge.guacamole.net.auth.mysql.service;
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import net.sourceforge.guacamole.GuacamoleClientException;
+import net.sourceforge.guacamole.GuacamoleException;
+import net.sourceforge.guacamole.net.GuacamoleSocket;
+import net.sourceforge.guacamole.net.InetGuacamoleSocket;
+import net.sourceforge.guacamole.net.auth.mysql.ActiveConnectionSet;
+import net.sourceforge.guacamole.net.auth.mysql.MySQLConnection;
+import net.sourceforge.guacamole.net.auth.mysql.MySQLConnectionRecord;
+import net.sourceforge.guacamole.net.auth.mysql.MySQLGuacamoleSocket;
+import net.sourceforge.guacamole.net.auth.mysql.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.model.Connection;
+import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionExample;
+import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionHistory;
+import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionHistoryExample;
+import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionParameter;
+import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionParameterExample;
+import net.sourceforge.guacamole.net.auth.mysql.properties.MySQLGuacamoleProperties;
+import net.sourceforge.guacamole.properties.GuacamoleProperties;
+import net.sourceforge.guacamole.protocol.ConfiguredGuacamoleSocket;
+import net.sourceforge.guacamole.protocol.GuacamoleClientInformation;
+import net.sourceforge.guacamole.protocol.GuacamoleConfiguration;
+import org.apache.ibatis.session.RowBounds;
+
+/**
+ * Service which provides convenience methods for creating, retrieving, and
+ * manipulating connections.
+ *
+ * @author Michael Jumper, James Muehlner
+ */
+public class ConnectionService {
+
+ /**
+ * DAO for accessing connections.
+ */
+ @Inject
+ private ConnectionMapper connectionDAO;
+
+ /**
+ * DAO for accessing connection parameters.
+ */
+ @Inject
+ private ConnectionParameterMapper connectionParameterDAO;
+
+ /**
+ * DAO for accessing connection history.
+ */
+ @Inject
+ private ConnectionHistoryMapper connectionHistoryDAO;
+
+ /**
+ * Provider which creates MySQLConnections.
+ */
+ @Inject
+ private Provider mySQLConnectionProvider;
+
+ /**
+ * Provider which creates MySQLGuacamoleSockets.
+ */
+ @Inject
+ private Provider mySQLGuacamoleSocketProvider;
+
+ /**
+ * Set of all currently active connections.
+ */
+ @Inject
+ private ActiveConnectionSet activeConnectionSet;
+
+ /**
+ * Service managing users.
+ */
+ @Inject
+ private UserService userService;
+
+ /**
+ * Retrieves the connection having the given name from the database.
+ *
+ * @param name The name of the connection to return.
+ * @param userID The ID of the user who queried this connection.
+ * @return The connection having the given name, or null if no such
+ * connection could be found.
+ */
+ public MySQLConnection retrieveConnection(String name, int userID) {
+
+ // Query connection by connection identifier (name)
+ ConnectionExample example = new ConnectionExample();
+ example.createCriteria().andConnection_nameEqualTo(name);
+ List connections =
+ connectionDAO.selectByExample(example);
+
+ // If no connection found, return null
+ if(connections.isEmpty())
+ return null;
+
+ // Assert only one connection found
+ assert connections.size() == 1 : "Multiple connections with same name.";
+
+ // Otherwise, return found connection
+ return toMySQLConnection(connections.get(0), userID);
+
+ }
+
+ /**
+ * Retrieves the connection having the given ID from the database.
+ *
+ * @param id The ID of the connection to retrieve.
+ * @param userID The ID of the user who queried this connection.
+ * @return The connection having the given ID, or null if no such
+ * connection was found.
+ */
+ public MySQLConnection retrieveConnection(int id, int userID) {
+
+ // Query connection by ID
+ Connection connection = connectionDAO.selectByPrimaryKey(id);
+
+ // If no connection found, return null
+ if(connection == null)
+ return null;
+
+ // Otherwise, return found connection
+ return toMySQLConnection(connection, userID);
+ }
+
+ /**
+ * Retrieves a translation map of connection names to their corresponding
+ * IDs.
+ *
+ * @param ids The IDs of the connections to retrieve the names of.
+ * @return A map containing the names of all connections and their
+ * corresponding IDs.
+ */
+ public Map translateNames(List ids) {
+
+ // If no IDs given, just return empty map
+ if (ids.isEmpty())
+ return Collections.EMPTY_MAP;
+
+ // Map of all names onto their corresponding IDs.
+ Map names = new HashMap();
+
+ // Get all connections having the given IDs
+ ConnectionExample example = new ConnectionExample();
+ example.createCriteria().andConnection_idIn(ids);
+ List connections = connectionDAO.selectByExample(example);
+
+ // Produce set of names
+ for (Connection connection : connections)
+ names.put(connection.getConnection_name(),
+ connection.getConnection_id());
+
+ return names;
+
+ }
+
+ /**
+ * Retrieves a map of all connection names for the given IDs.
+ *
+ * @param ids The IDs of the connections to retrieve the names of.
+ * @return A map containing the names of all connections and their
+ * corresponding IDs.
+ */
+ public Map retrieveNames(Collection ids) {
+
+ // If no IDs given, just return empty map
+ if (ids.isEmpty())
+ return Collections.EMPTY_MAP;
+
+ // Map of all names onto their corresponding IDs.
+ Map names = new HashMap();
+
+ // Get all connections having the given IDs
+ ConnectionExample example = new ConnectionExample();
+ example.createCriteria().andConnection_idIn(Lists.newArrayList(ids));
+ List connections = connectionDAO.selectByExample(example);
+
+ // Produce set of names
+ for (Connection connection : connections)
+ names.put(connection.getConnection_id(),
+ connection.getConnection_name());
+
+ return names;
+
+ }
+
+ /**
+ * 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 userID The user who queried this connection.
+ * @return A new MySQLConnection containing all data associated with the
+ * specified connection.
+ */
+ private MySQLConnection toMySQLConnection(Connection connection, int userID) {
+
+ // Build configuration
+ GuacamoleConfiguration config = new GuacamoleConfiguration();
+
+ // Query parameters for configuration
+ ConnectionParameterExample connectionParameterExample = new ConnectionParameterExample();
+ connectionParameterExample.createCriteria().andConnection_idEqualTo(connection.getConnection_id());
+ List connectionParameters =
+ connectionParameterDAO.selectByExample(connectionParameterExample);
+
+ // Set protocol
+ config.setProtocol(connection.getProtocol());
+
+ // Set all values for all parameters
+ for (ConnectionParameter parameter : connectionParameters)
+ config.setParameter(parameter.getParameter_name(),
+ parameter.getParameter_value());
+
+ // Create new MySQLConnection from retrieved data
+ MySQLConnection mySQLConnection = mySQLConnectionProvider.get();
+ mySQLConnection.init(
+ connection.getConnection_id(),
+ connection.getConnection_name(),
+ config,
+ retrieveHistory(connection.getConnection_id()),
+ userID
+ );
+
+ return mySQLConnection;
+
+ }
+
+ /**
+ * Retrieves the history of the connection having the given ID.
+ *
+ * @param connectionID The ID of the connection to retrieve the history of.
+ * @return A list of MySQLConnectionRecord documenting the history of this
+ * connection.
+ */
+ public List retrieveHistory(int connectionID) {
+
+ // Retrieve history records relating to given connection ID
+ ConnectionHistoryExample example = new ConnectionHistoryExample();
+ example.createCriteria().andConnection_idEqualTo(connectionID);
+
+ // We want to return the newest records first
+ example.setOrderByClause("start_date DESC");
+
+ // Set the maximum number of history records returned to 100
+ RowBounds rowBounds = new RowBounds(0, 100);
+
+ // Retrieve all connection history entries
+ List connectionHistories =
+ connectionHistoryDAO.selectByExampleWithRowbounds(example, rowBounds);
+
+ // Convert history entries to connection records
+ List connectionRecords = new ArrayList();
+ Set userIDSet = new HashSet();
+ for(ConnectionHistory history : connectionHistories) {
+ userIDSet.add(history.getUser_id());
+ }
+
+ // Get all the usernames for the users who are in the history
+ Map usernameMap = userService.retrieveUsernames(userIDSet);
+
+ // Create the new ConnectionRecords
+ for(ConnectionHistory history : connectionHistories) {
+ Date startDate = history.getStart_date();
+ Date endDate = history.getEnd_date();
+ String username = usernameMap.get(history.getUser_id());
+ MySQLConnectionRecord connectionRecord = new MySQLConnectionRecord(startDate, endDate, username);
+ connectionRecords.add(connectionRecord);
+ }
+
+ return connectionRecords;
+ }
+
+ /**
+ * Create a MySQLGuacamoleSocket using the provided connection.
+ *
+ * @param connection The connection to use when connecting the socket.
+ * @param info The information to use when performing the connection
+ * handshake.
+ * @param userID The ID of the user who is connecting to the socket.
+ * @return The connected socket.
+ * @throws GuacamoleException If an error occurs while connecting the
+ * socket.
+ */
+ public MySQLGuacamoleSocket connect(MySQLConnection connection,
+ GuacamoleClientInformation info, int userID)
+ throws GuacamoleException {
+
+ // If the given connection is active, and multiple simultaneous
+ // connections are not allowed, disallow connection
+ if(GuacamoleProperties.getProperty(
+ MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS, false)
+ && activeConnectionSet.isActive(connection.getConnectionID()))
+ throw new GuacamoleClientException("Cannot connect. This connection is in use.");
+
+ // Get guacd connection information
+ String host = GuacamoleProperties.getProperty(GuacamoleProperties.GUACD_HOSTNAME);
+ int port = GuacamoleProperties.getProperty(GuacamoleProperties.GUACD_PORT);
+
+ // Get socket
+ GuacamoleSocket socket = new ConfiguredGuacamoleSocket(
+ new InetGuacamoleSocket(host, port),
+ connection.getConfiguration(), info
+ );
+
+ // Mark this connection as active
+ int historyID = activeConnectionSet.openConnection(connection.getConnectionID(), userID);
+
+ // Return new MySQLGuacamoleSocket
+ MySQLGuacamoleSocket mySQLGuacamoleSocket = mySQLGuacamoleSocketProvider.get();
+ mySQLGuacamoleSocket.init(socket, connection.getConnectionID(), historyID);
+ return mySQLGuacamoleSocket;
+
+ }
+
+ /**
+ * Creates a new connection having the given name and protocol.
+ *
+ * @param name The name to assign to the new connection.
+ * @param protocol The protocol to assign to the new connection.
+ * @param userID The ID of the user who created this connection.
+ * @return A new MySQLConnection containing the data of the newly created
+ * connection.
+ */
+ public MySQLConnection createConnection(String name, String protocol, int userID) {
+
+ // Initialize database connection
+ Connection connection = new Connection();
+ connection.setConnection_name(name);
+ connection.setProtocol(protocol);
+
+ // Create connection
+ connectionDAO.insert(connection);
+ return toMySQLConnection(connection, userID);
+
+ }
+
+ /**
+ * Deletes the connection having the given ID from the database.
+ * @param id The ID of the connection to delete.
+ */
+ public void deleteConnection(int id) {
+ connectionDAO.deleteByPrimaryKey(id);
+ }
+
+ /**
+ * Updates the connection in the database corresponding to the given
+ * MySQLConnection.
+ *
+ * @param mySQLConnection The MySQLConnection to update (save) to the
+ * database. This connection must already exist.
+ */
+ public void updateConnection(MySQLConnection mySQLConnection) {
+
+ // Populate connection
+ Connection connection = new Connection();
+ connection.setConnection_id(mySQLConnection.getConnectionID());
+ connection.setConnection_name(mySQLConnection.getIdentifier());
+ connection.setProtocol(mySQLConnection.getConfiguration().getProtocol());
+
+ // Update the connection in the database
+ connectionDAO.updateByPrimaryKeySelective(connection);
+
+ }
+
+ /**
+ * Get the names of all the connections defined in the system.
+ *
+ * @return A Set of names of all the connections defined in the system.
+ */
+ public Set getAllConnectionNames() {
+
+ // Set of all present connection names
+ Set names = new HashSet();
+
+ // Query all connection names
+ List connections =
+ connectionDAO.selectByExample(new ConnectionExample());
+ for (Connection connection : connections)
+ names.add(connection.getConnection_name());
+
+ return names;
+
+ }
+
+ /**
+ * Get the connection IDs of all the connections defined in the system.
+ *
+ * @return A list of connection IDs of all the connections defined in the system.
+ */
+ public List getAllConnectionIDs() {
+
+ // Set of all present connection IDs
+ List connectionIDs = new ArrayList();
+
+ // Query all connection IDs
+ List connections =
+ connectionDAO.selectByExample(new ConnectionExample());
+ for (Connection connection : connections)
+ connectionIDs.add(connection.getConnection_id());
+
+ return connectionIDs;
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/PasswordEncryptionService.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/PasswordEncryptionService.java
new file mode 100644
index 000000000..0989a1bfd
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/PasswordEncryptionService.java
@@ -0,0 +1,69 @@
+
+package net.sourceforge.guacamole.net.auth.mysql.service;
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * A service to perform password encryption and checking.
+ * @author James Muehlner
+ */
+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.
+ *
+ * @param password The password to hash.
+ * @param salt The salt to use when hashing the password.
+ * @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/PermissionCheckService.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/PermissionCheckService.java
new file mode 100644
index 000000000..ae3a11387
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/PermissionCheckService.java
@@ -0,0 +1,497 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+package net.sourceforge.guacamole.net.auth.mysql.service;
+
+import com.google.inject.Inject;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import net.sourceforge.guacamole.GuacamoleSecurityException;
+import net.sourceforge.guacamole.net.auth.mysql.MySQLConstants;
+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.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.permission.ConnectionPermission;
+import net.sourceforge.guacamole.net.auth.permission.Permission;
+import net.sourceforge.guacamole.net.auth.permission.SystemPermission;
+import net.sourceforge.guacamole.net.auth.permission.UserPermission;
+
+/**
+ * A service to retrieve information about what objects a user has permission to.
+ * @author James Muehlner
+ */
+public class PermissionCheckService {
+
+ /**
+ * Service for accessing users.
+ */
+ @Inject
+ private UserService userService;
+
+ /**
+ * Service for accessing connections.
+ */
+ @Inject
+ private ConnectionService connectionService;
+
+ /**
+ * DAO for accessing permissions related to users.
+ */
+ @Inject
+ private UserPermissionMapper userPermissionDAO;
+
+ /**
+ * DAO for accessing permissions related to connections.
+ */
+ @Inject
+ private ConnectionPermissionMapper connectionPermissionDAO;
+
+ /**
+ * DAO for accessing permissions related to the system as a whole.
+ */
+ @Inject
+ private SystemPermissionMapper systemPermissionDAO;
+
+ /**
+ * Verifies that the user has the specified access to the given other
+ * user. If permission is denied, a GuacamoleSecurityException is thrown.
+ *
+ * @param userID The ID of the user to check.
+ * @param affectedUserID The user that would be affected by the operation
+ * if permission is granted.
+ * @param permissionType The type of permission to check for.
+ * @throws GuacamoleSecurityException If the specified permission is not
+ * granted.
+ */
+ public void verifyUserAccess(int userID, int affectedUserID,
+ String permissionType) throws GuacamoleSecurityException {
+
+ // If permission does not exist, throw exception
+ if(!checkUserAccess(userID, affectedUserID, permissionType))
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+ /**
+ * Verifies that the user has the specified access to the given connection.
+ * If permission is denied, a GuacamoleSecurityException is thrown.
+ *
+ * @param userID The ID of the user to check.
+ * @param affectedConnectionID The connection that would be affected by the
+ * operation if permission is granted.
+ * @param permissionType The type of permission to check for.
+ * @throws GuacamoleSecurityException If the specified permission is not
+ * granted.
+ */
+ public void verifyConnectionAccess(int userID, int affectedConnectionID, String permissionType) throws GuacamoleSecurityException {
+
+ // If permission does not exist, throw exception
+ if(!checkConnectionAccess(userID, affectedConnectionID, permissionType))
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+ /**
+ * Verifies that the user has the specified access to the system. If
+ * permission is denied, a GuacamoleSecurityException is thrown.
+ *
+ * @param userID The ID of the user to check.
+ * @param systemPermissionType The type of permission to check for.
+ * @throws GuacamoleSecurityException If the specified permission is not
+ * granted.
+ */
+ public void verifySystemAccess(int userID, String systemPermissionType)
+ throws GuacamoleSecurityException {
+
+ // If permission does not exist, throw exception
+ if(!checkSystemAccess(userID, systemPermissionType))
+ throw new GuacamoleSecurityException("Permission denied.");
+
+ }
+
+ /**
+ * Checks whether a user has the specified type of access to the affected
+ * user.
+ *
+ * @param userID The ID of the user to check.
+ * @param affectedUserID The user that would be affected by the operation
+ * if permission is granted.
+ * @param permissionType The type of permission to check for.
+ * @return true if the specified permission is granted, false otherwise.
+ */
+ public boolean checkUserAccess(int userID, Integer affectedUserID, String permissionType) {
+
+ // A system administrator has full access to everything.
+ if(checkSystemAdministratorAccess(userID))
+ return true;
+
+ // Check existence of requested permission
+ UserPermissionExample example = new UserPermissionExample();
+ example.createCriteria().andUser_idEqualTo(userID).andAffected_user_idEqualTo(affectedUserID).andPermissionEqualTo(permissionType);
+ return userPermissionDAO.countByExample(example) > 0;
+
+ }
+
+ /**
+ * Checks whether a user has the specified type of access to the affected
+ * connection.
+ *
+ * @param userID The ID of the user to check.
+ * @param affectedConnectionID The connection that would be affected by the
+ * operation if permission is granted.
+ * @param permissionType The type of permission to check for.
+ * @return true if the specified permission is granted, false otherwise.
+ */
+ public boolean checkConnectionAccess(int userID, Integer affectedConnectionID, String permissionType) {
+
+ // A system administrator has full access to everything.
+ if(checkSystemAdministratorAccess(userID))
+ return true;
+
+ // Check existence of requested permission
+ ConnectionPermissionExample example = new ConnectionPermissionExample();
+ example.createCriteria().andUser_idEqualTo(userID).andConnection_idEqualTo(affectedConnectionID).andPermissionEqualTo(permissionType);
+ return connectionPermissionDAO.countByExample(example) > 0;
+
+ }
+
+ /**
+ * Checks whether a user has the specified type of access to the system.
+ *
+ * @param userID The ID of the user to check.
+ * @param systemPermissionType The type of permission to check for.
+ * @return true if the specified permission is granted, false otherwise.
+ */
+ private boolean checkSystemAccess(int userID, String systemPermissionType) {
+
+ // A system administrator has full access to everything.
+ if(checkSystemAdministratorAccess(userID))
+ return true;
+
+ // Check existence of requested permission
+ SystemPermissionExample example = new SystemPermissionExample();
+ example.createCriteria().andUser_idEqualTo(userID).andPermissionEqualTo(systemPermissionType);
+ return systemPermissionDAO.countByExample(example) > 0;
+
+ }
+
+
+ /**
+ * Checks whether a user has system administrator access to the system.
+ *
+ * @param userID The ID of the user to check.
+ * @return true if the system administrator access exists, false otherwise.
+ */
+ private boolean checkSystemAdministratorAccess(int userID) {
+
+ // Check existence of system administrator permission
+ SystemPermissionExample example = new SystemPermissionExample();
+ example.createCriteria().andUser_idEqualTo(userID).
+ andPermissionEqualTo(MySQLConstants.SYSTEM_ADMINISTER);
+ return systemPermissionDAO.countByExample(example) > 0;
+ }
+
+ /**
+ * Find the list of the IDs of all users a user has permission to.
+ * The access type is defined by permissionType.
+ *
+ * @param userID The ID of the user to check.
+ * @param permissionType The type of permission to check for.
+ * @return A list of all user IDs this user has the specified access to.
+ */
+ public List retrieveUserIDs(int userID, String permissionType) {
+
+ // A system administrator has access to all users.
+ if(checkSystemAdministratorAccess(userID))
+ return userService.getAllUserIDs();
+
+ // Query all user permissions for the given user and permission type
+ UserPermissionExample example = new UserPermissionExample();
+ example.createCriteria().andUser_idEqualTo(userID).andPermissionEqualTo(permissionType);
+ example.setDistinct(true);
+ List userPermissions =
+ userPermissionDAO.selectByExample(example);
+
+ // Convert result into list of IDs
+ List userIDs = new ArrayList(userPermissions.size());
+ for(UserPermissionKey permission : userPermissions)
+ userIDs.add(permission.getAffected_user_id());
+
+ return userIDs;
+
+ }
+
+ /**
+ * Find the list of the IDs of all connections a user has permission to.
+ * The access type is defined by permissionType.
+ *
+ * @param userID The ID of the user to check.
+ * @param permissionType The type of permission to check for.
+ * @return A list of all connection IDs this user has the specified access
+ * to.
+ */
+ public List retrieveConnectionIDs(int userID,
+ String permissionType) {
+
+ // A system administrator has access to all connections.
+ if(checkSystemAdministratorAccess(userID))
+ return connectionService.getAllConnectionIDs();
+
+ // Query all connection permissions for the given user and permission type
+ ConnectionPermissionExample example = new ConnectionPermissionExample();
+ example.createCriteria().andUser_idEqualTo(userID).andPermissionEqualTo(permissionType);
+ example.setDistinct(true);
+ List connectionPermissions =
+ connectionPermissionDAO.selectByExample(example);
+
+ // Convert result into list of IDs
+ List connectionIDs = new ArrayList(connectionPermissions.size());
+ for(ConnectionPermissionKey permission : connectionPermissions)
+ connectionIDs.add(permission.getConnection_id());
+
+ return connectionIDs;
+
+ }
+
+ /**
+ * Retrieve all existing usernames that the given user has permission to
+ * perform the given operation upon.
+ *
+ * @param userID The user whose permissions should be checked.
+ * @param permissionType The permission to check.
+ * @return A set of all usernames for which the given user has the given
+ * permission.
+ */
+ public Set retrieveUsernames(int userID, String permissionType) {
+
+ // A system administrator has access to all users.
+ if(checkSystemAdministratorAccess(userID))
+ return userService.getAllUsernames();
+
+ // List of all user IDs for which this user has read access
+ List userIDs =
+ retrieveUserIDs(userID, MySQLConstants.USER_READ);
+
+ // Query all associated users
+ return userService.translateUsernames(userIDs).keySet();
+
+ }
+
+ /**
+ * Retrieve all existing connection names that the given user has permission
+ * to perform the given operation upon.
+ *
+ * @param userID The user whose permissions should be checked.
+ * @param permissionType The permission to check.
+ * @return A set of all connection names for which the given user has the
+ * given permission.
+ */
+ public Set retrieveConnectionNames(int userID, String permissionType) {
+
+ // A system administrator has access to all connections.
+ if(checkSystemAdministratorAccess(userID))
+ return connectionService.getAllConnectionNames();
+
+ // List of all connection IDs for which this connection has read access
+ List connectionIDs =
+ retrieveConnectionIDs(userID, MySQLConstants.CONNECTION_READ);
+
+ // Query all associated connections
+ return connectionService.translateNames(connectionIDs).keySet();
+
+ }
+
+ /**
+ * Retrieves all user permissions granted to the user having the given ID.
+ *
+ * @param userID The ID of the user to retrieve permissions of.
+ * @return A set of all user permissions granted to the user having the
+ * given ID.
+ */
+ public Set retrieveUserPermissions(int userID) {
+
+ // Set of all permissions
+ Set permissions = new HashSet();
+
+ // Query all user permissions
+ UserPermissionExample userPermissionExample = new UserPermissionExample();
+ userPermissionExample.createCriteria().andUser_idEqualTo(userID);
+ List userPermissions =
+ userPermissionDAO.selectByExample(userPermissionExample);
+
+ // Get list of affected user IDs
+ List affectedUserIDs = new ArrayList();
+ for(UserPermissionKey userPermission : userPermissions)
+ affectedUserIDs.add(userPermission.getAffected_user_id());
+
+ // Get corresponding usernames
+ Map affectedUsers =
+ userService.retrieveUsernames(affectedUserIDs);
+
+ // Add user permissions
+ for(UserPermissionKey userPermission : userPermissions) {
+
+ // Construct permission from data
+ UserPermission permission = new UserPermission(
+ UserPermission.Type.valueOf(userPermission.getPermission()),
+ affectedUsers.get(userPermission.getAffected_user_id())
+ );
+
+ // Add to set
+ permissions.add(permission);
+
+ }
+
+ return permissions;
+
+ }
+
+ /**
+ * Retrieves all connection permissions granted to the user having the
+ * given ID.
+ *
+ * @param userID The ID of the user to retrieve permissions of.
+ * @return A set of all connection permissions granted to the user having
+ * the given ID.
+ */
+ public Set retrieveConnectionPermissions(int userID) {
+
+ // Set of all permissions
+ Set permissions = new HashSet();
+
+ // Query all connection permissions
+ ConnectionPermissionExample connectionPermissionExample = new ConnectionPermissionExample();
+ connectionPermissionExample.createCriteria().andUser_idEqualTo(userID);
+ List connectionPermissions =
+ connectionPermissionDAO.selectByExample(connectionPermissionExample);
+
+ // Get list of affected connection IDs
+ List connectionIDs = new ArrayList();
+ for(ConnectionPermissionKey connectionPermission : connectionPermissions)
+ connectionIDs.add(connectionPermission.getConnection_id());
+
+ // Get corresponding names
+ Map affectedConnections =
+ connectionService.retrieveNames(connectionIDs);
+
+ // Add connection permissions
+ for(ConnectionPermissionKey connectionPermission : connectionPermissions) {
+
+ // Construct permission from data
+ ConnectionPermission permission = new ConnectionPermission(
+ ConnectionPermission.Type.valueOf(connectionPermission.getPermission()),
+ affectedConnections.get(connectionPermission.getConnection_id())
+ );
+
+ // Add to set
+ permissions.add(permission);
+
+ }
+
+ return permissions;
+
+ }
+
+ /**
+ * Retrieves all system permissions granted to the user having the
+ * given ID.
+ *
+ * @param userID The ID of the user to retrieve permissions of.
+ * @return A set of all system permissions granted to the user having the
+ * given ID.
+ */
+ public Set retrieveSystemPermissions(int userID) {
+
+ // Set of all permissions
+ Set permissions = new HashSet();
+
+ // And finally, system permissions
+ SystemPermissionExample systemPermissionExample = new SystemPermissionExample();
+ systemPermissionExample.createCriteria().andUser_idEqualTo(userID);
+ List systemPermissions =
+ systemPermissionDAO.selectByExample(systemPermissionExample);
+ for(SystemPermissionKey systemPermission : systemPermissions) {
+
+ // User creation permission
+ if(systemPermission.getPermission().equals(MySQLConstants.SYSTEM_USER_CREATE))
+ permissions.add(new SystemPermission(SystemPermission.Type.CREATE_USER));
+
+ // System creation permission
+ else if(systemPermission.getPermission().equals(MySQLConstants.SYSTEM_CONNECTION_CREATE))
+ permissions.add(new SystemPermission(SystemPermission.Type.CREATE_CONNECTION));
+
+ // System administration permission
+ else if(systemPermission.getPermission().equals(MySQLConstants.SYSTEM_ADMINISTER))
+ permissions.add(new SystemPermission(SystemPermission.Type.ADMINISTER));
+
+ }
+
+ return permissions;
+
+ }
+
+ /**
+ * Retrieves all permissions granted to the user having the given ID.
+ *
+ * @param userID The ID of the user to retrieve permissions of.
+ * @return A set of all permissions granted to the user having the given
+ * ID.
+ */
+ public Set retrieveAllPermissions(int userID) {
+
+ // Set which will contain all permissions
+ Set allPermissions = new HashSet();
+
+ // Add user permissions
+ allPermissions.addAll(retrieveUserPermissions(userID));
+
+ // Add connection permissions
+ allPermissions.addAll(retrieveConnectionPermissions(userID));
+
+ // Add system permissions
+ allPermissions.addAll(retrieveSystemPermissions(userID));
+
+ return allPermissions;
+ }
+
+}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SHA256PasswordEncryptionService.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SHA256PasswordEncryptionService.java
new file mode 100644
index 000000000..04fea1ae7
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SHA256PasswordEncryptionService.java
@@ -0,0 +1,90 @@
+
+package net.sourceforge.guacamole.net.auth.mysql.service;
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import javax.xml.bind.DatatypeConverter;
+
+/**
+ * Provides a SHA-256 based implementation of the password encryption functionality.
+ * @author James Muehlner
+ */
+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) {
+
+ try {
+
+ // Build salted password
+ StringBuilder builder = new StringBuilder();
+ builder.append(password);
+ builder.append(DatatypeConverter.printHexBinary(salt));
+
+ // Hash UTF-8 bytes of salted password
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ md.update(builder.toString().getBytes("UTF-8"));
+ return md.digest();
+
+ }
+
+ // Should not happen
+ catch (UnsupportedEncodingException ex) {
+ throw new RuntimeException(ex);
+ }
+
+ // Should not happen
+ catch (NoSuchAlgorithmException ex) {
+ throw new RuntimeException(ex);
+ }
+
+ }
+}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SaltService.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SaltService.java
new file mode 100644
index 000000000..0d194c9a0
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SaltService.java
@@ -0,0 +1,48 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+package net.sourceforge.guacamole.net.auth.mysql.service;
+
+/**
+ * A service to generate password salts.
+ * @author James Muehlner
+ */
+public interface SaltService {
+ /**
+ * Generates a new String that can be used as a password salt.
+ * @return a new salt for password encryption.
+ */
+ public byte[] generateSalt();
+}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SecureRandomSaltService.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SecureRandomSaltService.java
new file mode 100644
index 000000000..35caba240
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/SecureRandomSaltService.java
@@ -0,0 +1,60 @@
+
+package net.sourceforge.guacamole.net.auth.mysql.service;
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+import java.security.SecureRandom;
+
+/**
+ * Generates password salts via SecureRandom.
+ * @author James Muehlner
+ */
+public class SecureRandomSaltService implements SaltService {
+
+ /**
+ * Instance of SecureRandom for generating the salt.
+ */
+ private SecureRandom secureRandom = new SecureRandom();
+
+ @Override
+ public byte[] generateSalt() {
+ byte[] salt = new byte[32];
+ secureRandom.nextBytes(salt);
+ return salt;
+ }
+
+}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/UserService.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/UserService.java
new file mode 100644
index 000000000..fe3fa8b34
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/UserService.java
@@ -0,0 +1,381 @@
+
+package net.sourceforge.guacamole.net.auth.mysql.service;
+
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is guacamole-auth-mysql.
+ *
+ * The Initial Developer of the Original Code is
+ * James Muehlner.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import net.sourceforge.guacamole.GuacamoleException;
+import net.sourceforge.guacamole.net.auth.Credentials;
+import net.sourceforge.guacamole.net.auth.mysql.MySQLUser;
+import net.sourceforge.guacamole.net.auth.mysql.dao.UserMapper;
+import net.sourceforge.guacamole.net.auth.mysql.model.User;
+import net.sourceforge.guacamole.net.auth.mysql.model.UserExample;
+import net.sourceforge.guacamole.net.auth.mysql.model.UserWithBLOBs;
+
+/**
+ * Service which provides convenience methods for creating, retrieving, and
+ * manipulating users.
+ *
+ * @author Michael Jumper, James Muehlner
+ */
+public class UserService {
+
+ /**
+ * DAO for accessing users.
+ */
+ @Inject
+ private UserMapper userDAO;
+
+ /**
+ * Provider for creating users.
+ */
+ @Inject
+ private Provider mySQLUserProvider;
+
+ /**
+ * Service for checking permissions.
+ */
+ @Inject
+ private PermissionCheckService permissionCheckService;
+
+ /**
+ * Service for encrypting passwords.
+ */
+ @Inject
+ private PasswordEncryptionService passwordService;
+
+ /**
+ * Service for generating random salts.
+ */
+ @Inject
+ private SaltService saltService;
+
+ /**
+ * Create a new MySQLUser based on the provided User.
+ *
+ * @param user The User to use when populating the data of the given
+ * MySQLUser.
+ * @return A new MySQLUser object, populated with the data of the given
+ * user.
+ *
+ * @throws GuacamoleException If an error occurs while reading the data
+ * of the provided User.
+ */
+ public MySQLUser toMySQLUser(net.sourceforge.guacamole.net.auth.User user) throws GuacamoleException {
+ MySQLUser mySQLUser = mySQLUserProvider.get();
+ mySQLUser.init(user);
+ return mySQLUser;
+ }
+
+ /**
+ * Create a new MySQLUser based on the provided database record.
+ *
+ * @param user The database record describing the user.
+ * @return A new MySQLUser object, populated with the data of the given
+ * database record.
+ */
+ private MySQLUser toMySQLUser(UserWithBLOBs user) {
+
+ // Retrieve user from provider
+ MySQLUser mySQLUser = mySQLUserProvider.get();
+
+ // Init with data from given database user
+ mySQLUser.init(
+ user.getUser_id(),
+ user.getUsername(),
+ null,
+ permissionCheckService.retrieveAllPermissions(user.getUser_id())
+ );
+
+ // Return new user
+ return mySQLUser;
+
+ }
+
+ /**
+ * Retrieves the user having the given ID from the database.
+ *
+ * @param id The ID of the user to retrieve.
+ * @return The existing MySQLUser object if found, null otherwise.
+ */
+ public MySQLUser retrieveUser(int id) {
+
+ // Query user by ID
+ UserWithBLOBs user = userDAO.selectByPrimaryKey(id);
+
+ // If no user found, return null
+ if(user == null)
+ return null;
+
+ // Otherwise, return found user
+ return toMySQLUser(user);
+
+ }
+
+ /**
+ * Retrieves the user having the given username from the database.
+ *
+ * @param name The username of the user to retrieve.
+ * @return The existing MySQLUser object if found, null otherwise.
+ */
+ public MySQLUser retrieveUser(String name) {
+
+ // Query user by ID
+ UserExample example = new UserExample();
+ example.createCriteria().andUsernameEqualTo(name);
+ List users = userDAO.selectByExampleWithBLOBs(example);
+
+ // If no user found, return null
+ if(users.isEmpty())
+ return null;
+
+ // Otherwise, return found user
+ return toMySQLUser(users.get(0));
+
+ }
+
+ /**
+ * Retrieves the user corresponding to the given credentials from the
+ * database.
+ *
+ * @param credentials The credentials to use when locating the user.
+ * @return The existing MySQLUser object if the credentials given are
+ * valid, null otherwise.
+ */
+ public MySQLUser retrieveUser(Credentials credentials) {
+
+ // No null users in database
+ if (credentials.getUsername() == null)
+ return null;
+
+ // Query user
+ UserExample userExample = new UserExample();
+ userExample.createCriteria().andUsernameEqualTo(credentials.getUsername());
+ List users = userDAO.selectByExampleWithBLOBs(userExample);
+
+ // Check that a user was found
+ if (users.isEmpty())
+ return null;
+
+ // Assert only one user found
+ assert users.size() == 1 : "Multiple users with same username.";
+
+ // Get first (and only) user
+ UserWithBLOBs user = users.get(0);
+
+ // Check password, if invalid return null
+ if (!passwordService.checkPassword(credentials.getPassword(),
+ user.getPassword_hash(), user.getPassword_salt()))
+ return null;
+
+ // Return found user
+ return toMySQLUser(user);
+
+ }
+
+ /**
+ * Retrieves a translation map of usernames to their corresponding IDs.
+ *
+ * @param ids The IDs of the users to retrieve the usernames of.
+ * @return A map containing the names of all users and their corresponding
+ * IDs.
+ */
+ public Map translateUsernames(List ids) {
+
+ // If no IDs given, just return empty map
+ if (ids.isEmpty())
+ return Collections.EMPTY_MAP;
+
+ // Map of all names onto their corresponding IDs
+ Map names = new HashMap();
+
+ // Get all users having the given IDs
+ UserExample example = new UserExample();
+ example.createCriteria().andUser_idIn(ids);
+ List users =
+ userDAO.selectByExample(example);
+
+ // Produce set of names
+ for (User user : users)
+ names.put(user.getUsername(), user.getUser_id());
+
+ return names;
+
+ }
+
+ /**
+ * Retrieves a map of all usernames for the given IDs.
+ *
+ * @param ids The IDs of the users to retrieve the usernames of.
+ * @return A map containing the names of all users and their corresponding
+ * IDs.
+ */
+ public Map retrieveUsernames(Collection ids) {
+
+ // If no IDs given, just return empty map
+ if (ids.isEmpty())
+ return Collections.EMPTY_MAP;
+
+ // Map of all names onto their corresponding IDs
+ Map names = new HashMap();
+
+ // Get all users having the given IDs
+ UserExample example = new UserExample();
+ example.createCriteria().andUser_idIn(Lists.newArrayList(ids));
+ List users =
+ userDAO.selectByExample(example);
+
+ // Produce set of names
+ for (User user : users)
+ names.put(user.getUser_id(), user.getUsername());
+
+ return names;
+
+ }
+
+ /**
+ * Creates a new user having the given username and password.
+ *
+ * @param username The username to assign to the new user.
+ * @param password The password to assign to the new user.
+ * @return A new MySQLUser containing the data of the newly created
+ * user.
+ */
+ public MySQLUser createUser(String username, String password) {
+
+ // Initialize database user
+ UserWithBLOBs user = new UserWithBLOBs();
+ user.setUsername(username);
+
+ // Set password if specified
+ if (password != null) {
+ byte[] salt = saltService.generateSalt();
+ user.setPassword_salt(salt);
+ user.setPassword_hash(
+ passwordService.createPasswordHash(password, salt));
+ }
+
+ // Create user
+ userDAO.insert(user);
+ return toMySQLUser(user);
+
+ }
+
+ /**
+ * Deletes the user having the given ID from the database.
+ * @param user_id The ID of the user to delete.
+ */
+ public void deleteUser(int user_id) {
+ userDAO.deleteByPrimaryKey(user_id);
+ }
+
+ /**
+ * Updates the user in the database corresponding to the given MySQLUser.
+ *
+ * @param mySQLUser The MySQLUser to update (save) to the database. This
+ * user must already exist.
+ */
+ public void updateUser(MySQLUser mySQLUser) {
+
+ UserWithBLOBs user = new UserWithBLOBs();
+ user.setUser_id(mySQLUser.getUserID());
+ user.setUsername(mySQLUser.getUsername());
+
+ // Set password if specified
+ if (mySQLUser.getPassword() != null) {
+ byte[] salt = saltService.generateSalt();
+ user.setPassword_salt(salt);
+ user.setPassword_hash(
+ passwordService.createPasswordHash(mySQLUser.getPassword(), salt));
+ }
+
+ // Update the user in the database
+ userDAO.updateByPrimaryKeySelective(user);
+
+ }
+
+ /**
+ * Get the usernames of all the users defined in the system.
+ *
+ * @return A Set of usernames of all the users defined in the system.
+ */
+ public Set getAllUsernames() {
+
+ // Set of all present usernames
+ Set usernames = new HashSet();
+
+ // Query all usernames
+ List users =
+ userDAO.selectByExample(new UserExample());
+ for (User user : users)
+ usernames.add(user.getUsername());
+
+ return usernames;
+
+ }
+
+ /**
+ * Get the user IDs of all the users defined in the system.
+ *
+ * @return A list of user IDs of all the users defined in the system.
+ */
+ public List getAllUserIDs() {
+
+ // Set of all present user IDs
+ List userIDs = new ArrayList();
+
+ // Query all user IDs
+ List users =
+ userDAO.selectByExample(new UserExample());
+ for (User user : users)
+ userIDs.add(user.getUser_id());
+
+ return userIDs;
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/package-info.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/package-info.java
new file mode 100644
index 000000000..4cc071f2d
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/package-info.java
@@ -0,0 +1,7 @@
+
+/**
+ * Service classes which help fill the needs of the MySQL authentication
+ * provider.
+ */
+package net.sourceforge.guacamole.net.auth.mysql.service;
+
diff --git a/extensions/guacamole-auth-mysql/src/main/resources/generatorConfig.xml b/extensions/guacamole-auth-mysql/src/main/resources/generatorConfig.xml
new file mode 100644
index 000000000..879ed22c5
--- /dev/null
+++ b/extensions/guacamole-auth-mysql/src/main/resources/generatorConfig.xml
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+