Merge guacamole-auth-mysql as extension.

This commit is contained in:
Michael Jumper
2013-06-05 16:35:04 -07:00
29 changed files with 4375 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
target/
*~

View File

@@ -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:
<settings>
<profiles>
...profiles...
</profiles>
</settings>
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:
<profile>
<id>guacamole-mybatis</id>
<properties>
<guacamole.database.catalog>DATABASE</guacamole.database.catalog>
<guacamole.database.user>USERNAME</guacamole.database.user>
<guacamole.database.password>PASSWORD</guacamole.database.password>
</properties>
</profile>
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:
<activeProfiles>
<activeProfile>guacamole-mybatis</activeProfile>
</activeProfiles>
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/

View File

@@ -0,0 +1,21 @@
<settings>
<!-- Profile defining the properties required for a MyBatis build -->
<profiles>
<profile>
<id>guacamole-mybatis</id>
<properties>
<guacamole.database.catalog>SCHEMA</guacamole.database.catalog>
<guacamole.database.schema>DATABASE</guacamole.database.schema>
<guacamole.database.user>USER</guacamole.database.user>
<guacamole.database.password>PASS</guacamole.database.password>
</properties>
</profile>
</profiles>
<!-- Activate by default -->
<activeProfiles>
<activeProfile>guacamole-mybatis</activeProfile>
</activeProfiles>
</settings>

View File

@@ -0,0 +1,141 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.sourceforge.guacamole</groupId>
<artifactId>guacamole-auth-mysql</artifactId>
<packaging>jar</packaging>
<version>0.8.0</version>
<name>guacamole-auth-mysql</name>
<url>http://guac-dev.org/</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<!-- Written for 1.6 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<!-- Assembly plugin - for easy distribution -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<configuration>
<finalName>${project.artifactId}-${project.version}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/assembly/dist.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-dist-archive</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- MyBatis Generator plugin -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<executions>
<execution>
<id>Generate MyBatis Artifacts</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<!-- MySQL Connector -->
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.23</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Guacamole Java API -->
<dependency>
<groupId>net.sourceforge.guacamole</groupId>
<artifactId>guacamole-common</artifactId>
<version>0.8.0</version>
</dependency>
<!-- Guacamole Extension API -->
<dependency>
<groupId>net.sourceforge.guacamole</groupId>
<artifactId>guacamole-ext</artifactId>
<version>0.8.0</version>
</dependency>
<!-- SLF4J - logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jcl</artifactId>
<version>1.6.1</version>
<scope>runtime</scope>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.1.1</version>
</dependency>
<!-- MyBatis Guice -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-guice</artifactId>
<version>3.2</version>
</dependency>
<!-- Google Collections -->
<dependency>
<groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<repositories>
<!-- Central Guacamole repository -->
<repository>
<id>guac-dev</id>
<url>http://guac-dev.org/repo</url>
</repository>
</repositories>
</project>

View File

@@ -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;

View File

@@ -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');

View File

@@ -0,0 +1,54 @@
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>dist</id>
<baseDirectory>${project.artifactId}-${project.version}</baseDirectory>
<!-- Output tar.gz -->
<formats>
<format>tar.gz</format>
</formats>
<!-- Include docs and schema -->
<fileSets>
<!-- Include docs -->
<fileSet>
<outputDirectory>/</outputDirectory>
<directory>doc</directory>
</fileSet>
<!-- Include schema -->
<fileSet>
<outputDirectory>/schema</outputDirectory>
<directory>schema</directory>
</fileSet>
</fileSets>
<!-- Include self and all dependencies except guacamole-common
and guacamole-ext -->
<dependencySets>
<dependencySet>
<outputDirectory>/lib</outputDirectory>
<scope>runtime</scope>
<unpack>false</unpack>
<useProjectArtifact>true</useProjectArtifact>
<useTransitiveFiltering>true</useTransitiveFiltering>
<excludes>
<!-- Do not include guacamole-common -->
<exclude>net.sourceforge.guacamole:guacamole-common</exclude>
<!-- Do not include guacamole-ext -->
<exclude>net.sourceforge.guacamole:guacamole-ext</exclude>
</excludes>
</dependencySet>
</dependencySets>
</assembly>

View File

@@ -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<Integer> activeConnectionSet = new HashSet<Integer>();
/**
* 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);
}
}

View File

@@ -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<String, Connection>{
/**
* 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<String> 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());
}
}

View File

@@ -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
}

View File

@@ -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<ConnectionRecord> history = new ArrayList<ConnectionRecord>();
/**
* 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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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<Permission> permissions = new HashSet<Permission>();
/**
* Any newly added permissions that have yet to be committed.
*/
private Set<Permission> newPermissions = new HashSet<Permission>();
/**
* Any newly deleted permissions that have yet to be deleted.
*/
private Set<Permission> removedPermissions = new HashSet<Permission>();
/**
* 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<Permission> 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<Permission> getCurrentPermissions() {
return permissions;
}
/**
* Get any new permissions that have yet to be inserted.
* @return the new set of permissions.
*/
public Set<Permission> getNewPermissions() {
return newPermissions;
}
/**
* Get any permissions that have not yet been deleted.
* @return the permissions that need to be deleted.
*/
public Set<Permission> 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<Permission> 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);
}
}

View File

@@ -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<String, User> getUserDirectory() throws GuacamoleException {
return userDirectory;
}
@Override
public Directory<String, Connection> getConnectionDirectory() throws GuacamoleException {
return connectionDirectory;
}
}

View File

@@ -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<String, net.sourceforge.guacamole.net.auth.User> {
/**
* 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<String> 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<Permission> permissions) throws GuacamoleException {
// Partition given permissions by permission type
List<UserPermission> newUserPermissions = new ArrayList<UserPermission>();
List<ConnectionPermission> newConnectionPermissions = new ArrayList<ConnectionPermission>();
List<SystemPermission> newSystemPermissions = new ArrayList<SystemPermission>();
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<Permission> permissions)
throws GuacamoleException {
// Partition given permissions by permission type
List<UserPermission> removedUserPermissions = new ArrayList<UserPermission>();
List<ConnectionPermission> removedConnectionPermissions = new ArrayList<ConnectionPermission>();
List<SystemPermission> removedSystemPermissions = new ArrayList<SystemPermission>();
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<UserPermission> permissions)
throws GuacamoleException {
// If no permissions given, stop now
if(permissions.isEmpty())
return;
// Get list of administerable user IDs
List<Integer> administerableUserIDs =
permissionCheckService.retrieveUserIDs(this.user_id,
MySQLConstants.USER_ADMINISTER);
// Get set of usernames corresponding to administerable users
Map<String, Integer> 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<UserPermission> permissions)
throws GuacamoleException {
// If no permissions given, stop now
if(permissions.isEmpty())
return;
// Get list of administerable user IDs
List<Integer> administerableUserIDs =
permissionCheckService.retrieveUserIDs(this.user_id,
MySQLConstants.USER_ADMINISTER);
// Get set of usernames corresponding to administerable users
Map<String, Integer> 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<ConnectionPermission> permissions)
throws GuacamoleException {
// If no permissions given, stop now
if(permissions.isEmpty())
return;
// Get list of administerable connection IDs
List<Integer> administerableConnectionIDs =
permissionCheckService.retrieveConnectionIDs(this.user_id,
MySQLConstants.CONNECTION_ADMINISTER);
// Get set of names corresponding to administerable connections
Map<String, Integer> 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<ConnectionPermission> permissions)
throws GuacamoleException {
// If no permissions given, stop now
if(permissions.isEmpty())
return;
// Get list of administerable connection IDs
List<Integer> administerableConnectionIDs =
permissionCheckService.retrieveConnectionIDs(this.user_id,
MySQLConstants.CONNECTION_ADMINISTER);
// Get set of names corresponding to administerable connections
Map<String, Integer> 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<SystemPermission> 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<SystemPermission> 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<String> systemPermissionTypes = new ArrayList<String>();
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());
}
}

View File

@@ -0,0 +1,7 @@
/**
* Base classes which support the MySQL authentication provider, including
* the authentication provider itself.
*/
package net.sourceforge.guacamole.net.auth.mysql;

View File

@@ -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"; }
};
}

View File

@@ -0,0 +1,7 @@
/**
* Properties which control the configuration of the MySQL authentication
* provider.
*/
package net.sourceforge.guacamole.net.auth.mysql.properties;

View File

@@ -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<MySQLConnection> mySQLConnectionProvider;
/**
* Provider which creates MySQLGuacamoleSockets.
*/
@Inject
private Provider<MySQLGuacamoleSocket> 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<Connection> 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<String, Integer> translateNames(List<Integer> 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<String, Integer> names = new HashMap<String, Integer>();
// Get all connections having the given IDs
ConnectionExample example = new ConnectionExample();
example.createCriteria().andConnection_idIn(ids);
List<Connection> 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<Integer, String> retrieveNames(Collection<Integer> 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<Integer, String> names = new HashMap<Integer, String>();
// Get all connections having the given IDs
ConnectionExample example = new ConnectionExample();
example.createCriteria().andConnection_idIn(Lists.newArrayList(ids));
List<Connection> 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<ConnectionParameter> 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<MySQLConnectionRecord> 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<ConnectionHistory> connectionHistories =
connectionHistoryDAO.selectByExampleWithRowbounds(example, rowBounds);
// Convert history entries to connection records
List<MySQLConnectionRecord> connectionRecords = new ArrayList<MySQLConnectionRecord>();
Set<Integer> userIDSet = new HashSet<Integer>();
for(ConnectionHistory history : connectionHistories) {
userIDSet.add(history.getUser_id());
}
// Get all the usernames for the users who are in the history
Map<Integer, String> 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<String> getAllConnectionNames() {
// Set of all present connection names
Set<String> names = new HashSet<String>();
// Query all connection names
List<Connection> 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<Integer> getAllConnectionIDs() {
// Set of all present connection IDs
List<Integer> connectionIDs = new ArrayList<Integer>();
// Query all connection IDs
List<Connection> connections =
connectionDAO.selectByExample(new ConnectionExample());
for (Connection connection : connections)
connectionIDs.add(connection.getConnection_id());
return connectionIDs;
}
}

View File

@@ -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);
}

View File

@@ -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<Integer> 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<UserPermissionKey> userPermissions =
userPermissionDAO.selectByExample(example);
// Convert result into list of IDs
List<Integer> userIDs = new ArrayList<Integer>(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<Integer> 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<ConnectionPermissionKey> connectionPermissions =
connectionPermissionDAO.selectByExample(example);
// Convert result into list of IDs
List<Integer> connectionIDs = new ArrayList<Integer>(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<String> 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<Integer> 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<String> 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<Integer> 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<UserPermission> retrieveUserPermissions(int userID) {
// Set of all permissions
Set<UserPermission> permissions = new HashSet<UserPermission>();
// Query all user permissions
UserPermissionExample userPermissionExample = new UserPermissionExample();
userPermissionExample.createCriteria().andUser_idEqualTo(userID);
List<UserPermissionKey> userPermissions =
userPermissionDAO.selectByExample(userPermissionExample);
// Get list of affected user IDs
List<Integer> affectedUserIDs = new ArrayList<Integer>();
for(UserPermissionKey userPermission : userPermissions)
affectedUserIDs.add(userPermission.getAffected_user_id());
// Get corresponding usernames
Map<Integer, String> 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<ConnectionPermission> retrieveConnectionPermissions(int userID) {
// Set of all permissions
Set<ConnectionPermission> permissions = new HashSet<ConnectionPermission>();
// Query all connection permissions
ConnectionPermissionExample connectionPermissionExample = new ConnectionPermissionExample();
connectionPermissionExample.createCriteria().andUser_idEqualTo(userID);
List<ConnectionPermissionKey> connectionPermissions =
connectionPermissionDAO.selectByExample(connectionPermissionExample);
// Get list of affected connection IDs
List<Integer> connectionIDs = new ArrayList<Integer>();
for(ConnectionPermissionKey connectionPermission : connectionPermissions)
connectionIDs.add(connectionPermission.getConnection_id());
// Get corresponding names
Map<Integer, String> 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<SystemPermission> retrieveSystemPermissions(int userID) {
// Set of all permissions
Set<SystemPermission> permissions = new HashSet<SystemPermission>();
// And finally, system permissions
SystemPermissionExample systemPermissionExample = new SystemPermissionExample();
systemPermissionExample.createCriteria().andUser_idEqualTo(userID);
List<SystemPermissionKey> 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<Permission> retrieveAllPermissions(int userID) {
// Set which will contain all permissions
Set<Permission> allPermissions = new HashSet<Permission>();
// Add user permissions
allPermissions.addAll(retrieveUserPermissions(userID));
// Add connection permissions
allPermissions.addAll(retrieveConnectionPermissions(userID));
// Add system permissions
allPermissions.addAll(retrieveSystemPermissions(userID));
return allPermissions;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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<MySQLUser> 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<UserWithBLOBs> 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<UserWithBLOBs> 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<String, Integer> translateUsernames(List<Integer> 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<String, Integer> names = new HashMap<String, Integer>();
// Get all users having the given IDs
UserExample example = new UserExample();
example.createCriteria().andUser_idIn(ids);
List<User> 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<Integer, String> retrieveUsernames(Collection<Integer> 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<Integer, String> names = new HashMap<Integer, String>();
// Get all users having the given IDs
UserExample example = new UserExample();
example.createCriteria().andUser_idIn(Lists.newArrayList(ids));
List<User> 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<String> getAllUsernames() {
// Set of all present usernames
Set<String> usernames = new HashSet<String>();
// Query all usernames
List<User> 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<Integer> getAllUserIDs() {
// Set of all present user IDs
List<Integer> userIDs = new ArrayList<Integer>();
// Query all user IDs
List<User> users =
userDAO.selectByExample(new UserExample());
for (User user : users)
userIDs.add(user.getUser_id());
return userIDs;
}
}

View File

@@ -0,0 +1,7 @@
/**
* Service classes which help fill the needs of the MySQL authentication
* provider.
*/
package net.sourceforge.guacamole.net.auth.mysql.service;

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="guacamoleTables" targetRuntime="MyBatis3">
<!-- Allow selectByExample with RowBounds -->
<plugin type="org.mybatis.generator.plugins.RowBoundsPlugin"/>
<!-- MySQL JDBC driver class. -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306"
userId="${guacamole.database.user}"
password="${guacamole.database.password}"/>
<javaModelGenerator
targetPackage="net.sourceforge.guacamole.net.auth.mysql.model"
targetProject="MAVEN"/>
<sqlMapGenerator
targetPackage="net.sourceforge.guacamole.net.auth.mysql.dao"
targetProject="MAVEN"/>
<javaClientGenerator type="XMLMAPPER"
targetPackage="net.sourceforge.guacamole.net.auth.mysql.dao"
targetProject="MAVEN"/>
<!-- TABLES -->
<table tableName="guacamole_connection"
catalog="${guacamole.database.catalog}"
schema="${guacamole.database.schema}"
domainObjectName="Connection" >
<property name="useActualColumnNames" value="true"/>
<property name="ignoreQualifiersAtRuntime" value="true"/>
<generatedKey column="connection_id" identity="true"
sqlStatement="SELECT LAST_INSERT_ID()"/>
</table>
<table tableName="guacamole_connection_parameter"
catalog="${guacamole.database.catalog}"
schema="${guacamole.database.schema}"
domainObjectName="ConnectionParameter" >
<property name="useActualColumnNames" value="true"/>
<property name="ignoreQualifiersAtRuntime" value="true"/>
</table>
<table tableName="guacamole_connection_permission"
catalog="${guacamole.database.catalog}"
schema="${guacamole.database.schema}"
domainObjectName="ConnectionPermission" >
<property name="useActualColumnNames" value="true"/>
<property name="ignoreQualifiersAtRuntime" value="true"/>
</table>
<table tableName="guacamole_system_permission"
catalog="${guacamole.database.catalog}"
schema="${guacamole.database.schema}"
domainObjectName="SystemPermission" >
<property name="useActualColumnNames" value="true"/>
<property name="ignoreQualifiersAtRuntime" value="true"/>
</table>
<table tableName="guacamole_user"
catalog="${guacamole.database.catalog}"
schema="${guacamole.database.schema}"
domainObjectName="User" >
<property name="useActualColumnNames" value="true"/>
<property name="ignoreQualifiersAtRuntime" value="true"/>
<generatedKey column="user_id" identity="true"
sqlStatement="SELECT LAST_INSERT_ID()"/>
</table>
<table tableName="guacamole_user_permission"
catalog="${guacamole.database.catalog}"
schema="${guacamole.database.schema}"
domainObjectName="UserPermission" >
<property name="useActualColumnNames" value="true"/>
<property name="ignoreQualifiersAtRuntime" value="true"/>
</table>
<table tableName="guacamole_connection_history"
catalog="${guacamole.database.catalog}"
schema="${guacamole.database.schema}"
domainObjectName="ConnectionHistory" >
<property name="useActualColumnNames" value="true"/>
<property name="ignoreQualifiersAtRuntime" value="true"/>
<generatedKey column="history_id" identity="true"
sqlStatement="SELECT LAST_INSERT_ID()"/>
</table>
</context>
</generatorConfiguration>