GUAC-1101: Remove use of mybatis-generator. Temporarily remove all but users. Add common interfaces and simple queries.

This commit is contained in:
Michael Jumper
2015-02-12 19:53:52 -08:00
parent 03f94c15cd
commit d3d5fef1e7
24 changed files with 841 additions and 4806 deletions

View File

@@ -48,32 +48,6 @@
</executions> </executions>
</plugin> </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> </plugins>
</build> </build>
@@ -104,22 +78,31 @@
<dependency> <dependency>
<groupId>org.mybatis</groupId> <groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId> <artifactId>mybatis</artifactId>
<version>3.1.1</version> <version>3.2.8</version>
</dependency> </dependency>
<!-- MyBatis Guice --> <!-- MyBatis Guice -->
<dependency> <dependency>
<groupId>org.mybatis</groupId> <groupId>org.mybatis</groupId>
<artifactId>mybatis-guice</artifactId> <artifactId>mybatis-guice</artifactId>
<version>3.2</version> <version>3.6</version>
</dependency> </dependency>
<!-- Guice -->
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
</dependency>
<!-- Google Collections --> <!-- Google Collections -->
<dependency> <dependency>
<groupId>com.google.collections</groupId> <groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId> <artifactId>google-collections</artifactId>
<version>1.0</version> <version>1.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -1,502 +0,0 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.sourceforge.guacamole.net.auth.mysql;
import com.google.inject.Inject;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.glyptodon.guacamole.GuacamoleException;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionHistoryMapper;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionHistory;
import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
/**
* Represents the map of currently active Connections to the count of the number
* of current users. Whenever a socket is opened, the connection count should be
* incremented, and whenever a socket is closed, the connection count should be
* decremented.
*
* @author James Muehlner
*/
public class ActiveConnectionMap {
/**
* Represents the count of users currently using a MySQL connection.
*/
public class Connection {
/**
* The ID of the MySQL connection that this Connection represents.
*/
private int connectionID;
/**
* The number of users currently using this connection.
*/
private int currentUserCount;
/**
* Returns the ID of the MySQL connection that this Connection
* represents.
*
* @return the ID of the MySQL connection that this Connection
* represents.
*/
public int getConnectionID() {
return connectionID;
}
/**
* Returns the number of users currently using this connection.
*
* @return the number of users currently using this connection.
*/
public int getCurrentUserCount() {
return currentUserCount;
}
/**
* Set the current user count for this connection.
*
* @param currentUserCount The new user count for this Connection.
*/
public void setCurrentUserCount(int currentUserCount) {
this.currentUserCount = currentUserCount;
}
/**
* Create a new Connection for the given connectionID with a zero
* current user count.
*
* @param connectionID The ID of the MySQL connection that this
* Connection represents.
*/
public Connection(int connectionID) {
this.connectionID = connectionID;
this.currentUserCount = 0;
}
}
/*
* Represents a user connected to a connection or BALANCING connection group.
*/
public class ConnectionUser {
/**
* The ID of the connection or connection group that this ConnectionUser refers to.
*/
private int identifier;
/**
* The user that this ConnectionUser refers to.
*/
private int userID;
/**
* Returns ID of the connection or connection group that this ConnectionUser refers to.
* @return ID of the connection or connection group that this ConnectionUser refers to.
*/
public int getIdentifier() {
return identifier;
}
/**
* Returns the user ID that this ConnectionUser refers to.
* @return the user ID that this ConnectionUser refers to.
*/
public int getUserID() {
return userID;
}
/**
* Create a ConnectionUser with the given connection or connection group
* ID and user ID.
*
* @param identifier The connection or connection group ID that this
* ConnectionUser refers to.
* @param userID The user ID that this ConnectionUser refers to.
*/
public ConnectionUser(int identifier, int userID) {
this.identifier = identifier;
this.userID = userID;
}
@Override
public boolean equals(Object other) {
// Only another ConnectionUser can equal this ConnectionUser
if(!(other instanceof ConnectionUser))
return false;
ConnectionUser otherConnectionGroupUser =
(ConnectionUser)other;
/*
* Two ConnectionGroupUsers are equal iff they represent the exact
* same pairing of connection or connection group and user.
*/
return this.identifier == otherConnectionGroupUser.identifier
&& this.userID == otherConnectionGroupUser.userID;
}
@Override
public int hashCode() {
int hash = 3;
hash = 23 * hash + this.identifier;
hash = 23 * hash + this.userID;
return hash;
}
}
/**
* DAO for accessing connection history.
*/
@Inject
private ConnectionHistoryMapper connectionHistoryDAO;
/**
* Map of all the connections that are currently active to the
* count of current users.
*/
private Map<Integer, Connection> activeConnectionMap =
new HashMap<Integer, Connection>();
/**
* Map of all the connection group users to the count of current usages.
*/
private Map<ConnectionUser, Integer> activeConnectionGroupUserMap =
new HashMap<ConnectionUser, Integer>();
/**
* Map of all the connection users to the count of current usages.
*/
private Map<ConnectionUser, Integer> activeConnectionUserMap =
new HashMap<ConnectionUser, Integer>();
/**
* Returns the number of connections opened by the given user using
* the given ConnectionGroup.
*
* @param connectionGroupID The connection group ID that this
* ConnectionUser refers to.
* @param userID The user ID that this ConnectionUser refers to.
*
* @return The number of connections opened by the given user to the given
* ConnectionGroup.
*/
public int getConnectionGroupUserCount(int connectionGroupID, int userID) {
Integer count = activeConnectionGroupUserMap.get
(new ConnectionUser(connectionGroupID, userID));
// No ConnectionUser found means this combination was never used
if(count == null)
return 0;
return count;
}
/**
* Checks if the given user is currently connected to the given BALANCING
* connection group.
*
* @param connectionGroupID The connection group ID that this
* ConnectionUser refers to.
* @param userID The user ID that this ConnectionUser refers to.
*
* @return True if the given user is currently connected to the given
* BALANCING connection group, false otherwise.
*/
public boolean isConnectionGroupUserActive(int connectionGroupID, int userID) {
Integer count = activeConnectionGroupUserMap.get
(new ConnectionUser(connectionGroupID, userID));
// The connection group is in use if the ConnectionUser count > 0
return count != null && count > 0;
}
/**
* Increment the count of the number of connections opened by the given user
* to the given ConnectionGroup.
*
* @param connectionGroupID The connection group ID that this
* ConnectionUser refers to.
* @param userID The user ID that this ConnectionUser refers to.
*/
private void incrementConnectionGroupUserCount(int connectionGroupID, int userID) {
int currentCount = getConnectionGroupUserCount(connectionGroupID, userID);
activeConnectionGroupUserMap.put
(new ConnectionUser(connectionGroupID, userID), currentCount + 1);
}
/**
* Decrement the count of the number of connections opened by the given user
* to the given ConnectionGroup.
*
* @param connectionGroupID The connection group ID that this
* ConnectionUser refers to.
* @param userID The user ID that this ConnectionUser refers to.
*/
private void decrementConnectionGroupUserCount(int connectionGroupID, int userID) {
int currentCount = getConnectionGroupUserCount(connectionGroupID, userID);
activeConnectionGroupUserMap.put
(new ConnectionUser(connectionGroupID, userID), currentCount - 1);
}
/**
* Returns the number of connections opened by the given user using
* the given Connection.
*
* @param connectionID The connection ID that this ConnectionUser refers to.
* @param userID The user ID that this ConnectionUser refers to.
*
* @return The number of connections opened by the given user to the given
* connection.
*/
public int getConnectionUserCount(int connectionID, int userID) {
Integer count = activeConnectionUserMap.get
(new ConnectionUser(connectionID, userID));
// No ConnectionUser found means this combination was never used
if(count == null)
return 0;
return count;
}
/**
* Checks if the given user is currently connected to the given connection.
*
* @param connectionID The connection ID that this ConnectionUser refers to.
* @param userID The user ID that this ConnectionUser refers to.
*
* @return True if the given user is currently connected to the given
* connection, false otherwise.
*/
public boolean isConnectionUserActive(int connectionID, int userID) {
Integer count = activeConnectionUserMap.get
(new ConnectionUser(connectionID, userID));
// The connection is in use if the ConnectionUser count > 0
return count != null && count > 0;
}
/**
* Increment the count of the number of connections opened by the given user
* to the given Connection.
*
* @param connectionID The connection ID that this ConnectionUser refers to.
* @param userID The user ID that this ConnectionUser refers to.
*/
private void incrementConnectionUserCount(int connectionID, int userID) {
int currentCount = getConnectionUserCount(connectionID, userID);
activeConnectionUserMap.put
(new ConnectionUser(connectionID, userID), currentCount + 1);
}
/**
* Decrement the count of the number of connections opened by the given user
* to the given Connection.
*
* @param connectionID The connection ID that this ConnectionUser refers to.
* @param userID The user ID that this ConnectionUser refers to.
*/
private void decrementConnectionUserCount(int connectionID, int userID) {
int currentCount = getConnectionUserCount(connectionID, userID);
activeConnectionUserMap.put
(new ConnectionUser(connectionID, userID), currentCount - 1);
}
/**
* Returns the ID of the connection with the lowest number of current
* active users, if found.
*
* @param connectionIDs The subset of connection IDs to find the least
* used connection within.
*
* @return The ID of the connection with the lowest number of current
* active users, if found.
*/
public Integer getLeastUsedConnection(Collection<Integer> connectionIDs) {
if(connectionIDs.isEmpty())
return null;
int minUserCount = Integer.MAX_VALUE;
Integer minConnectionID = null;
for(Integer connectionID : connectionIDs) {
Connection connection = activeConnectionMap.get(connectionID);
/*
* If the connection is not found in the map, it has not been used,
* and therefore will be count 0.
*/
if(connection == null) {
minUserCount = 0;
minConnectionID = connectionID;
}
// If this is the least active connection
else if(connection.getCurrentUserCount() < minUserCount) {
minUserCount = connection.getCurrentUserCount();
minConnectionID = connection.getConnectionID();
}
}
return minConnectionID;
}
/**
* Returns the count of currently active users for the given connectionID.
* @return the count of currently active users for the given connectionID.
*/
public int getCurrentUserCount(int connectionID) {
Connection connection = activeConnectionMap.get(connectionID);
if(connection == null)
return 0;
return connection.getCurrentUserCount();
}
/**
* Decrement the current user count for this Connection.
*
* @param connectionID The ID of the MySQL connection that this
* Connection represents.
*
* @throws GuacamoleException If the connection is not found.
*/
private void decrementUserCount(int connectionID)
throws GuacamoleException {
Connection connection = activeConnectionMap.get(connectionID);
if(connection == null)
throw new GuacamoleResourceNotFoundException
("Connection to decrement does not exist.");
// Decrement the current user count
connection.setCurrentUserCount(connection.getCurrentUserCount() - 1);
}
/**
* Increment the current user count for this Connection.
*
* @param connectionID The ID of the MySQL connection that this
* Connection represents.
*
* @throws GuacamoleException If the connection is not found.
*/
private void incrementUserCount(int connectionID) {
Connection connection = activeConnectionMap.get(connectionID);
// If the Connection does not exist, it should be created
if(connection == null) {
connection = new Connection(connectionID);
activeConnectionMap.put(connectionID, connection);
}
// Increment the current user count
connection.setCurrentUserCount(connection.getCurrentUserCount() + 1);
}
/**
* Check if a connection is currently in use.
* @param connectionID The connection to check the status of.
* @return true if the connection is currently in use.
*/
public boolean isActive(int connectionID) {
return getCurrentUserCount(connectionID) > 0;
}
/**
* Set a connection as open.
* @param connectionID The ID of the connection that is being opened.
* @param userID The ID of the user who is opening the connection.
* @param connectionGroupID The ID of the BALANCING connection group that is
* being connected to; null if not used.
* @return The ID of the history record created for this open connection.
*/
public int openConnection(int connectionID, int userID, Integer connectionGroupID) {
// Create the connection history record
ConnectionHistory connectionHistory = new ConnectionHistory();
connectionHistory.setConnection_id(connectionID);
connectionHistory.setUser_id(userID);
connectionHistory.setStart_date(new Date());
connectionHistoryDAO.insert(connectionHistory);
// Increment the user count
incrementUserCount(connectionID);
// Increment the connection user count
incrementConnectionUserCount(connectionID, userID);
// If this is a connection to a BALANCING ConnectionGroup, increment the count
if(connectionGroupID != null)
incrementConnectionGroupUserCount(connectionGroupID, userID);
return connectionHistory.getHistory_id();
}
/**
* Set a connection as closed.
* @param historyID The ID of the history record about the open connection.
* @param connectionGroupID The ID of the BALANCING connection group that is
* being connected to; null if not used.
* @throws GuacamoleException If the open connection history is not found.
*/
public void closeConnection(int historyID, Integer connectionGroupID)
throws GuacamoleException {
// Get the existing history record
ConnectionHistory connectionHistory =
connectionHistoryDAO.selectByPrimaryKey(historyID);
if(connectionHistory == null)
throw new GuacamoleResourceNotFoundException("History record not found.");
// Get the connection and user IDs
int connectionID = connectionHistory.getConnection_id();
int userID = connectionHistory.getUser_id();
// Update the connection history record to mark that it is now closed
connectionHistory.setEnd_date(new Date());
connectionHistoryDAO.updateByPrimaryKey(connectionHistory);
// Decrement the user count.
decrementUserCount(connectionID);
// Decrement the connection user count
decrementConnectionUserCount(connectionID, userID);
// If this is a connection to a BALANCING ConnectionGroup, decrement the count
if(connectionGroupID != null)
decrementConnectionGroupUserCount(connectionGroupID, userID);
}
}

View File

@@ -1,336 +0,0 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.sourceforge.guacamole.net.auth.mysql;
import com.google.inject.Inject;
import java.util.Set;
import org.glyptodon.guacamole.GuacamoleClientException;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.Connection;
import org.glyptodon.guacamole.net.auth.Directory;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionParameterMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionParameter;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionParameterExample;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionKey;
import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionGroupService;
import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionService;
import net.sourceforge.guacamole.net.auth.mysql.service.PermissionCheckService;
import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
import org.glyptodon.guacamole.GuacamoleUnsupportedException;
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
import org.mybatis.guice.transactional.Transactional;
/**
* A MySQL-based implementation of the connection directory.
*
* @author James Muehlner
*/
public class ConnectionDirectory implements Directory<String, Connection>{
/**
* The user who this connection directory belongs to. Access is based on
* his/her permission settings.
*/
private AuthenticatedUser currentUser;
/**
* The ID of the parent connection group.
*/
private Integer parentID;
/**
* Service for checking permissions.
*/
@Inject
private PermissionCheckService permissionCheckService;
/**
* Service managing connections.
*/
@Inject
private ConnectionService connectionService;
/**
* Service managing connection groups.
*/
@Inject
private ConnectionGroupService connectionGroupService;
/**
* Service for manipulating connection permissions in the database.
*/
@Inject
private ConnectionPermissionMapper connectionPermissionDAO;
/**
* Service for manipulating connection parameters in the database.
*/
@Inject
private ConnectionParameterMapper connectionParameterDAO;
/**
* Set the user and parentID for this directory.
*
* @param currentUser
* The user owning this connection directory.
*
* @param parentID
* The ID of the parent connection group.
*/
public void init(AuthenticatedUser currentUser, Integer parentID) {
this.currentUser = currentUser;
this.parentID = parentID;
}
@Transactional
@Override
public Connection get(String identifier) throws GuacamoleException {
// Get connection
MySQLConnection connection =
connectionService.retrieveConnection(identifier, currentUser);
if(connection == null)
return null;
// Verify permission to use the parent connection group for organizational purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(connection.getParentID(), currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
// Verify access is granted
permissionCheckService.verifyConnectionAccess(
currentUser,
connection.getConnectionID(),
MySQLConstants.CONNECTION_READ);
// Return connection
return connection;
}
@Transactional
@Override
public Set<String> getIdentifiers() throws GuacamoleException {
// Verify permission to use the connection group for organizational purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(parentID, currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
return permissionCheckService.retrieveConnectionIdentifiers(currentUser,
parentID, MySQLConstants.CONNECTION_READ);
}
@Transactional
@Override
public void add(Connection object) throws GuacamoleException {
String name = object.getName().trim();
if(name.isEmpty())
throw new GuacamoleClientException("The connection name cannot be blank.");
// Verify permission to create
permissionCheckService.verifySystemAccess(currentUser,
MySQLConstants.SYSTEM_CONNECTION_CREATE);
// Verify permission to edit the connection group
permissionCheckService.verifyConnectionGroupAccess(currentUser,
this.parentID, MySQLConstants.CONNECTION_GROUP_UPDATE);
// Verify permission to use the connection group for organizational purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(parentID, currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
// Verify that no connection already exists with this name.
MySQLConnection previousConnection =
connectionService.retrieveConnection(name, parentID, currentUser);
if(previousConnection != null)
throw new GuacamoleClientException("That connection name is already in use.");
// Create connection
MySQLConnection connection = connectionService.createConnection(
name, object.getConfiguration().getProtocol(), currentUser, parentID);
// Set the connection ID
object.setIdentifier(connection.getIdentifier());
// Add connection parameters
createConfigurationValues(connection.getConnectionID(),
object.getConfiguration());
// Finally, give the current user full access to the newly created
// connection.
ConnectionPermissionKey newConnectionPermission = new ConnectionPermissionKey();
newConnectionPermission.setUser_id(currentUser.getUserID());
newConnectionPermission.setConnection_id(connection.getConnectionID());
// Read permission
newConnectionPermission.setPermission(MySQLConstants.CONNECTION_READ);
connectionPermissionDAO.insert(newConnectionPermission);
// Update permission
newConnectionPermission.setPermission(MySQLConstants.CONNECTION_UPDATE);
connectionPermissionDAO.insert(newConnectionPermission);
// Delete permission
newConnectionPermission.setPermission(MySQLConstants.CONNECTION_DELETE);
connectionPermissionDAO.insert(newConnectionPermission);
// Administer permission
newConnectionPermission.setPermission(MySQLConstants.CONNECTION_ADMINISTER);
connectionPermissionDAO.insert(newConnectionPermission);
}
/**
* Inserts all parameter values from the given configuration into the
* database, associating them with the connection having the givenID.
*
* @param connection_id The ID of the connection to associate all
* parameters with.
* @param config The GuacamoleConfiguration to read parameters from.
*/
private void createConfigurationValues(int connection_id,
GuacamoleConfiguration config) {
// Insert new parameters for each parameter in the config
for (String name : config.getParameterNames()) {
// Create a ConnectionParameter based on the current parameter
ConnectionParameter parameter = new ConnectionParameter();
parameter.setConnection_id(connection_id);
parameter.setParameter_name(name);
parameter.setParameter_value(config.getParameter(name));
// Insert connection parameter
connectionParameterDAO.insert(parameter);
}
}
@Transactional
@Override
public void update(Connection object) throws GuacamoleException {
// If connection not actually from this auth provider, we can't handle
// the update
if (!(object instanceof MySQLConnection))
throw new GuacamoleUnsupportedException("Connection not from database.");
MySQLConnection mySQLConnection = (MySQLConnection) object;
// Verify permission to update
permissionCheckService.verifyConnectionAccess(currentUser,
mySQLConnection.getConnectionID(),
MySQLConstants.CONNECTION_UPDATE);
// Perform update
connectionService.updateConnection(mySQLConnection);
// Delete old connection parameters
ConnectionParameterExample parameterExample = new ConnectionParameterExample();
parameterExample.createCriteria().andConnection_idEqualTo(mySQLConnection.getConnectionID());
connectionParameterDAO.deleteByExample(parameterExample);
// Add connection parameters
createConfigurationValues(mySQLConnection.getConnectionID(),
object.getConfiguration());
}
@Transactional
@Override
public void remove(String identifier) throws GuacamoleException {
// Get connection
MySQLConnection mySQLConnection =
connectionService.retrieveConnection(identifier, currentUser);
if(mySQLConnection == null)
throw new GuacamoleResourceNotFoundException("Connection not found.");
// Verify permission to use the parent connection group for organizational purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(mySQLConnection.getParentID(), currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
// Verify permission to delete
permissionCheckService.verifyConnectionAccess(currentUser,
mySQLConnection.getConnectionID(),
MySQLConstants.CONNECTION_DELETE);
// Delete the connection itself
connectionService.deleteConnection(mySQLConnection.getConnectionID());
}
@Override
public void move(String identifier, Directory<String, Connection> directory)
throws GuacamoleException {
if(!(directory instanceof ConnectionDirectory))
throw new GuacamoleUnsupportedException("Directory not from database");
Integer toConnectionGroupID = ((ConnectionDirectory)directory).parentID;
// Get connection
MySQLConnection mySQLConnection =
connectionService.retrieveConnection(identifier, currentUser);
if(mySQLConnection == null)
throw new GuacamoleResourceNotFoundException("Connection not found.");
// Verify permission to update the connection
permissionCheckService.verifyConnectionAccess(currentUser,
mySQLConnection.getConnectionID(),
MySQLConstants.CONNECTION_UPDATE);
// Verify permission to use the from connection group for organizational purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(mySQLConnection.getParentID(), currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
// Verify permission to update the from connection group
permissionCheckService.verifyConnectionGroupAccess(currentUser,
mySQLConnection.getParentID(), MySQLConstants.CONNECTION_GROUP_UPDATE);
// Verify permission to use the to connection group for organizational purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(toConnectionGroupID, currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
// Verify permission to update the to connection group
permissionCheckService.verifyConnectionGroupAccess(currentUser,
toConnectionGroupID, MySQLConstants.CONNECTION_GROUP_UPDATE);
// Verify that no connection already exists with this name.
MySQLConnection previousConnection =
connectionService.retrieveConnection(mySQLConnection.getName(),
toConnectionGroupID, currentUser);
if(previousConnection != null)
throw new GuacamoleClientException("That connection name is already in use.");
// Update the connection
mySQLConnection.setParentID(toConnectionGroupID);
connectionService.updateConnection(mySQLConnection);
}
}

View File

@@ -1,300 +0,0 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.sourceforge.guacamole.net.auth.mysql;
import com.google.inject.Inject;
import java.util.Set;
import org.glyptodon.guacamole.GuacamoleClientException;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.net.auth.ConnectionGroup.Type;
import org.glyptodon.guacamole.net.auth.Directory;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionGroupPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupPermissionKey;
import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionGroupService;
import net.sourceforge.guacamole.net.auth.mysql.service.PermissionCheckService;
import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
import org.glyptodon.guacamole.GuacamoleUnsupportedException;
import org.mybatis.guice.transactional.Transactional;
/**
* A MySQL-based implementation of the connection group directory.
*
* @author James Muehlner
*/
public class ConnectionGroupDirectory implements Directory<String, ConnectionGroup>{
/**
* The user who this connection directory belongs to. Access is based on
* his/her permission settings.
*/
private AuthenticatedUser currentUser;
/**
* The ID of the parent connection group.
*/
private Integer parentID;
/**
* Service for checking permissions.
*/
@Inject
private PermissionCheckService permissionCheckService;
/**
* Service managing connection groups.
*/
@Inject
private ConnectionGroupService connectionGroupService;
/**
* Service for manipulating connection group permissions in the database.
*/
@Inject
private ConnectionGroupPermissionMapper connectionGroupPermissionDAO;
/**
* Set the user and parentID for this directory.
*
* @param currentUser
* The user owning this connection group directory.
*
* @param parentID
* The ID of the parent connection group.
*/
public void init(AuthenticatedUser currentUser, Integer parentID) {
this.parentID = parentID;
this.currentUser = currentUser;
}
@Transactional
@Override
public ConnectionGroup get(String identifier) throws GuacamoleException {
// Get connection
MySQLConnectionGroup connectionGroup =
connectionGroupService.retrieveConnectionGroup(identifier, currentUser);
if(connectionGroup == null)
return null;
// Verify permission to use the parent connection group for organizational purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(connectionGroup.getParentID(), currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
// Verify access is granted
permissionCheckService.verifyConnectionGroupAccess(
currentUser,
connectionGroup.getConnectionGroupID(),
MySQLConstants.CONNECTION_GROUP_READ);
// Return connection group
return connectionGroup;
}
@Transactional
@Override
public Set<String> getIdentifiers() throws GuacamoleException {
// Verify permission to use the connection group for organizational purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(parentID, currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
return permissionCheckService.retrieveConnectionGroupIdentifiers(currentUser,
parentID, MySQLConstants.CONNECTION_GROUP_READ);
}
@Transactional
@Override
public void add(ConnectionGroup object) throws GuacamoleException {
String name = object.getName().trim();
if(name.isEmpty())
throw new GuacamoleClientException("The connection group name cannot be blank.");
Type type = object.getType();
String mySQLType = MySQLConstants.getConnectionGroupTypeConstant(type);
// Verify permission to create
permissionCheckService.verifySystemAccess(currentUser,
MySQLConstants.SYSTEM_CONNECTION_GROUP_CREATE);
// Verify permission to edit the parent connection group
permissionCheckService.verifyConnectionGroupAccess(currentUser,
this.parentID, MySQLConstants.CONNECTION_GROUP_UPDATE);
// Verify permission to use the parent connection group for organizational purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(parentID, currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
// Verify that no connection already exists with this name.
MySQLConnectionGroup previousConnectionGroup =
connectionGroupService.retrieveConnectionGroup(name, parentID, currentUser);
if(previousConnectionGroup != null)
throw new GuacamoleClientException("That connection group name is already in use.");
// Create connection group
MySQLConnectionGroup connectionGroup = connectionGroupService
.createConnectionGroup(name, currentUser, parentID, mySQLType);
// Set the connection group ID
object.setIdentifier(connectionGroup.getIdentifier());
// Finally, give the current user full access to the newly created
// connection group.
ConnectionGroupPermissionKey newConnectionGroupPermission = new ConnectionGroupPermissionKey();
newConnectionGroupPermission.setUser_id(currentUser.getUserID());
newConnectionGroupPermission.setConnection_group_id(connectionGroup.getConnectionGroupID());
// Read permission
newConnectionGroupPermission.setPermission(MySQLConstants.CONNECTION_GROUP_READ);
connectionGroupPermissionDAO.insert(newConnectionGroupPermission);
// Update permission
newConnectionGroupPermission.setPermission(MySQLConstants.CONNECTION_GROUP_UPDATE);
connectionGroupPermissionDAO.insert(newConnectionGroupPermission);
// Delete permission
newConnectionGroupPermission.setPermission(MySQLConstants.CONNECTION_GROUP_DELETE);
connectionGroupPermissionDAO.insert(newConnectionGroupPermission);
// Administer permission
newConnectionGroupPermission.setPermission(MySQLConstants.CONNECTION_GROUP_ADMINISTER);
connectionGroupPermissionDAO.insert(newConnectionGroupPermission);
}
@Transactional
@Override
public void update(ConnectionGroup object) throws GuacamoleException {
// If connection not actually from this auth provider, we can't handle
// the update
if (!(object instanceof MySQLConnectionGroup))
throw new GuacamoleUnsupportedException("Connection not from database.");
MySQLConnectionGroup mySQLConnectionGroup = (MySQLConnectionGroup) object;
// Verify permission to update
permissionCheckService.verifyConnectionGroupAccess(currentUser,
mySQLConnectionGroup.getConnectionGroupID(),
MySQLConstants.CONNECTION_GROUP_UPDATE);
// Perform update
connectionGroupService.updateConnectionGroup(mySQLConnectionGroup);
}
@Transactional
@Override
public void remove(String identifier) throws GuacamoleException {
// Get connection
MySQLConnectionGroup mySQLConnectionGroup =
connectionGroupService.retrieveConnectionGroup(identifier, currentUser);
if(mySQLConnectionGroup == null)
throw new GuacamoleResourceNotFoundException("Connection group not found.");
// Verify permission to use the parent connection group for organizational purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(mySQLConnectionGroup.getParentID(), currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
// Verify permission to delete
permissionCheckService.verifyConnectionGroupAccess(currentUser,
mySQLConnectionGroup.getConnectionGroupID(),
MySQLConstants.CONNECTION_GROUP_DELETE);
// Delete the connection group itself
connectionGroupService.deleteConnectionGroup
(mySQLConnectionGroup.getConnectionGroupID());
}
@Override
public void move(String identifier, Directory<String, ConnectionGroup> directory)
throws GuacamoleException {
if(MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER.equals(identifier))
throw new GuacamoleUnsupportedException("The root connection group cannot be moved.");
if(!(directory instanceof ConnectionGroupDirectory))
throw new GuacamoleUnsupportedException("Directory not from database");
Integer toConnectionGroupID = ((ConnectionGroupDirectory)directory).parentID;
// Get connection group
MySQLConnectionGroup mySQLConnectionGroup =
connectionGroupService.retrieveConnectionGroup(identifier, currentUser);
if(mySQLConnectionGroup == null)
throw new GuacamoleResourceNotFoundException("Connection group not found.");
// Verify permission to update the connection group
permissionCheckService.verifyConnectionGroupAccess(currentUser,
mySQLConnectionGroup.getConnectionGroupID(),
MySQLConstants.CONNECTION_GROUP_UPDATE);
// Verify permission to use the from connection group for organizational purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(mySQLConnectionGroup.getParentID(), currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
// Verify permission to update the from connection group
permissionCheckService.verifyConnectionGroupAccess(currentUser,
mySQLConnectionGroup.getParentID(), MySQLConstants.CONNECTION_GROUP_UPDATE);
// Verify permission to use the to connection group for organizational purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(toConnectionGroupID, currentUser, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
// Verify permission to update the to connection group
permissionCheckService.verifyConnectionGroupAccess(currentUser,
toConnectionGroupID, MySQLConstants.CONNECTION_GROUP_UPDATE);
// Verify that no connection already exists with this name.
MySQLConnectionGroup previousConnectionGroup =
connectionGroupService.retrieveConnectionGroup(mySQLConnectionGroup.getName(),
toConnectionGroupID, currentUser);
if(previousConnectionGroup != null)
throw new GuacamoleClientException("That connection group name is already in use.");
// Verify that moving this connectionGroup would not cause a cycle
Integer relativeParentID = toConnectionGroupID;
while(relativeParentID != null) {
if(relativeParentID == mySQLConnectionGroup.getConnectionGroupID())
throw new GuacamoleUnsupportedException("Connection group cycle detected.");
MySQLConnectionGroup relativeParentGroup = connectionGroupService.
retrieveConnectionGroup(relativeParentID, currentUser);
relativeParentID = relativeParentGroup.getParentID();
}
// Update the connection
mySQLConnectionGroup.setParentID(toConnectionGroupID);
connectionGroupService.updateConnectionGroup(mySQLConnectionGroup);
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.sourceforge.guacamole.net.auth.mysql;
/**
* Common interface for objects that will ultimately be made available through
* the Directory class. All such objects will need the same base set of queries
* to fulfill the needs of the Directory class.
*
* @author Michael Jumper
* @param <ModelType>
* The type of object contained within the directory whose objects are
* mapped by this mapper.
*/
public interface DirectoryObject<ModelType> {
/**
* Returns the backing model object. Changes to the model object will
* affect this object, and changes to this object will affect the model
* object.
*
* @return
* The user model object backing this MySQLUser.
*/
public ModelType getModel();
/**
* Sets the backing model object. This will effectively replace all data
* contained within this object.
*
* @param model
* The backing model object.
*/
public void setModel(ModelType model);
}

View File

@@ -33,20 +33,9 @@ import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.AuthenticationProvider; import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
import org.glyptodon.guacamole.net.auth.Credentials; import org.glyptodon.guacamole.net.auth.Credentials;
import org.glyptodon.guacamole.net.auth.UserContext; import org.glyptodon.guacamole.net.auth.UserContext;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionGroupMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionGroupPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionHistoryMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionParameterMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.SystemPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.UserMapper; import net.sourceforge.guacamole.net.auth.mysql.dao.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.properties.MySQLGuacamoleProperties;
import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionGroupService;
import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionService;
import net.sourceforge.guacamole.net.auth.mysql.service.PasswordEncryptionService; import net.sourceforge.guacamole.net.auth.mysql.service.PasswordEncryptionService;
import net.sourceforge.guacamole.net.auth.mysql.service.PermissionCheckService;
import net.sourceforge.guacamole.net.auth.mysql.service.SHA256PasswordEncryptionService; import net.sourceforge.guacamole.net.auth.mysql.service.SHA256PasswordEncryptionService;
import net.sourceforge.guacamole.net.auth.mysql.service.SaltService; 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.SecureRandomSaltService;
@@ -65,16 +54,11 @@ import org.mybatis.guice.datasource.helper.JdbcHelper;
*/ */
public class MySQLAuthenticationProvider implements AuthenticationProvider { public class MySQLAuthenticationProvider implements AuthenticationProvider {
/**
* Set of all active connections.
*/
private ActiveConnectionMap activeConnectionMap = new ActiveConnectionMap();
/** /**
* Injector which will manage the object graph of this authentication * Injector which will manage the object graph of this authentication
* provider. * provider.
*/ */
private Injector injector; private final Injector injector;
@Override @Override
public UserContext getUserContext(Credentials credentials) throws GuacamoleException { public UserContext getUserContext(Credentials credentials) throws GuacamoleException {
@@ -83,10 +67,10 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider {
UserService userService = injector.getInstance(UserService.class); UserService userService = injector.getInstance(UserService.class);
// Get user // Get user
MySQLUser authenticatedUser = userService.retrieveUser(credentials); MySQLUser user = userService.retrieveUser(credentials);
if (authenticatedUser != null) { if (user != null) {
MySQLUserContext context = injector.getInstance(MySQLUserContext.class); MySQLUserContext context = injector.getInstance(MySQLUserContext.class);
context.init(new AuthenticatedUser(authenticatedUser.getUserID(), credentials)); context.init(user);
return context; return context;
} }
@@ -145,27 +129,15 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider {
bindTransactionFactoryType(JdbcTransactionFactory.class); bindTransactionFactoryType(JdbcTransactionFactory.class);
// Add MyBatis mappers // Add MyBatis mappers
addMapperClass(ConnectionHistoryMapper.class);
addMapperClass(ConnectionMapper.class);
addMapperClass(ConnectionGroupMapper.class);
addMapperClass(ConnectionGroupPermissionMapper.class);
addMapperClass(ConnectionParameterMapper.class);
addMapperClass(ConnectionPermissionMapper.class);
addMapperClass(SystemPermissionMapper.class);
addMapperClass(UserMapper.class); addMapperClass(UserMapper.class);
addMapperClass(UserPermissionMapper.class);
// Bind interfaces // Bind interfaces
bind(MySQLUserContext.class);
bind(UserDirectory.class);
bind(MySQLUser.class); bind(MySQLUser.class);
bind(SaltService.class).to(SecureRandomSaltService.class); bind(MySQLUserContext.class);
bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class); bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class);
bind(PermissionCheckService.class); bind(SaltService.class).to(SecureRandomSaltService.class);
bind(ConnectionService.class); bind(UserDirectory.class);
bind(ConnectionGroupService.class);
bind(UserService.class); bind(UserService.class);
bind(ActiveConnectionMap.class).toInstance(activeConnectionMap);
} }
} // end of mybatis module } // end of mybatis module

View File

@@ -1,164 +0,0 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.sourceforge.guacamole.net.auth.mysql;
import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.GuacamoleSocket;
import org.glyptodon.guacamole.net.auth.AbstractConnection;
import org.glyptodon.guacamole.net.auth.ConnectionRecord;
import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionService;
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
/**
* A MySQL based implementation of the Connection object.
* @author James Muehlner
*/
public class MySQLConnection extends AbstractConnection {
/**
* The ID associated with this connection in the database.
*/
private Integer connectionID;
/**
* The ID of the parent connection group for this connection.
*/
private Integer parentID;
/**
* The user who queried or created this connection.
*/
private AuthenticatedUser currentUser;
/**
* History of this connection.
*/
private List<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;
}
/**
* Get the ID of the parent connection group for this connection, if any.
* @return The ID of the parent connection group for this connection, if any.
*/
public Integer getParentID() {
return parentID;
}
/**
* Sets the ID of the parent connection group for this connection.
* @param parentID The ID of the parent connection group for this connection.
*/
public void setParentID(Integer parentID) {
this.parentID = parentID;
// Translate to string identifier
if (parentID != null)
this.setParentIdentifier(String.valueOf(parentID));
else
this.setParentIdentifier(MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER);
}
/**
* Initialize from explicit values.
*
* @param connectionID
* The ID of the associated database record, if any.
*
* @param parentID
* The ID of the parent connection group for this connection, if any.
*
* @param name
* The human-readable name associated with this connection.
*
* @param identifier
* The unique identifier associated with this connection.
*
* @param config
* The GuacamoleConfiguration associated with this connection.
*
* @param history
* All ConnectionRecords associated with this connection.
*
* @param currentUser
* The user who queried this connection.
*/
public void init(Integer connectionID, Integer parentID, String name,
String identifier, GuacamoleConfiguration config,
List<? extends ConnectionRecord> history,
AuthenticatedUser currentUser) {
this.connectionID = connectionID;
this.setParentID(parentID);
setName(name);
setIdentifier(identifier);
setConfiguration(config);
this.history.addAll(history);
this.currentUser = currentUser;
}
@Override
public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
return connectionService.connect(this, info, currentUser, null);
}
@Override
public List<? extends ConnectionRecord> getHistory() throws GuacamoleException {
return Collections.unmodifiableList(history);
}
}

View File

@@ -1,199 +0,0 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.sourceforge.guacamole.net.auth.mysql;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.GuacamoleSocket;
import org.glyptodon.guacamole.net.auth.AbstractConnectionGroup;
import org.glyptodon.guacamole.net.auth.Connection;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.net.auth.Directory;
import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionGroupService;
import net.sourceforge.guacamole.net.auth.mysql.service.PermissionCheckService;
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
/**
* A MySQL based implementation of the ConnectionGroup object.
* @author James Muehlner
*/
public class MySQLConnectionGroup extends AbstractConnectionGroup {
/**
* The ID associated with this connection group in the database.
*/
private Integer connectionGroupID;
/**
* The ID of the parent connection group for this connection group.
*/
private Integer parentID;
/**
* The user who queried or created this connection group.
*/
private AuthenticatedUser currentUser;
/**
* A Directory of connections that have this connection group as a parent.
*/
private ConnectionDirectory connectionDirectory = null;
/**
* A Directory of connection groups that have this connection group as a parent.
*/
private ConnectionGroupDirectory connectionGroupDirectory = null;
/**
* Service managing connection groups.
*/
@Inject
private ConnectionGroupService connectionGroupService;
/**
* Service for checking permissions.
*/
@Inject
private PermissionCheckService permissionCheckService;
/**
* Service for creating new ConnectionDirectory objects.
*/
@Inject Provider<ConnectionDirectory> connectionDirectoryProvider;
/**
* Service for creating new ConnectionGroupDirectory objects.
*/
@Inject Provider<ConnectionGroupDirectory> connectionGroupDirectoryProvider;
/**
* Create a default, empty connection group.
*/
public MySQLConnectionGroup() {
}
/**
* Get the ID of the corresponding connection group record.
* @return The ID of the corresponding connection group, if any.
*/
public Integer getConnectionGroupID() {
return connectionGroupID;
}
/**
* Sets the ID of the corresponding connection group record.
* @param connectionGroupID The ID to assign to this connection group.
*/
public void setConnectionID(Integer connectionGroupID) {
this.connectionGroupID = connectionGroupID;
}
/**
* Get the ID of the parent connection group for this connection group, if any.
* @return The ID of the parent connection group for this connection group, if any.
*/
public Integer getParentID() {
return parentID;
}
/**
* Sets the ID of the parent connection group for this connection group.
* @param parentID The ID of the parent connection group for this connection group.
*/
public void setParentID(Integer parentID) {
this.parentID = parentID;
// Translate to string identifier
if (parentID != null)
this.setParentIdentifier(String.valueOf(parentID));
else
this.setParentIdentifier(MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER);
}
/**
* Initialize from explicit values.
*
* @param connectionGroupID
* The ID of the associated database record, if any.
*
* @param parentID
* The ID of the parent connection group for this connection group, if
* any.
*
* @param name
* The name of this connection group.
*
* @param identifier
* The unique identifier associated with this connection group.
*
* @param type
* The type of this connection group.
*
* @param currentUser
* The user who queried this connection.
*/
public void init(Integer connectionGroupID, Integer parentID, String name,
String identifier, ConnectionGroup.Type type, AuthenticatedUser currentUser) {
this.connectionGroupID = connectionGroupID;
this.setParentID(parentID);
setName(name);
setIdentifier(identifier);
setType(type);
this.currentUser = currentUser;
connectionDirectory = connectionDirectoryProvider.get();
connectionDirectory.init(currentUser, connectionGroupID);
connectionGroupDirectory = connectionGroupDirectoryProvider.get();
connectionGroupDirectory.init(currentUser, connectionGroupID);
}
@Override
public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
// Verify permission to use the connection group for balancing purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(this.connectionGroupID, currentUser, MySQLConstants.CONNECTION_GROUP_BALANCING);
// Verify permission to delete
permissionCheckService.verifyConnectionGroupAccess(currentUser,
this.connectionGroupID,
MySQLConstants.CONNECTION_GROUP_READ);
return connectionGroupService.connect(this, info, currentUser);
}
@Override
public Directory<String, Connection> getConnectionDirectory() throws GuacamoleException {
return connectionDirectory;
}
@Override
public Directory<String, ConnectionGroup> getConnectionGroupDirectory() throws GuacamoleException {
return connectionGroupDirectory;
}
}

View File

@@ -23,7 +23,6 @@
package net.sourceforge.guacamole.net.auth.mysql; package net.sourceforge.guacamole.net.auth.mysql;
import com.google.inject.Inject;
import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.io.GuacamoleReader; import org.glyptodon.guacamole.io.GuacamoleReader;
import org.glyptodon.guacamole.io.GuacamoleWriter; import org.glyptodon.guacamole.io.GuacamoleWriter;
@@ -35,12 +34,6 @@ import org.glyptodon.guacamole.net.GuacamoleSocket;
*/ */
public class MySQLGuacamoleSocket implements GuacamoleSocket { public class MySQLGuacamoleSocket implements GuacamoleSocket {
/**
* Injected ActiveConnectionMap which will contain all active connections.
*/
@Inject
private ActiveConnectionMap activeConnectionMap;
/** /**
* The wrapped socket. * The wrapped socket.
*/ */
@@ -86,18 +79,7 @@ public class MySQLGuacamoleSocket implements GuacamoleSocket {
@Override @Override
public void close() throws GuacamoleException { public void close() throws GuacamoleException {
socket.close();
// Mark this connection as inactive
synchronized (activeConnectionMap) {
if (isOpen())
activeConnectionMap.closeConnection(historyID, connectionGroupID);
// Close socket
socket.close();
}
} }
@Override @Override

View File

@@ -22,40 +22,50 @@
package net.sourceforge.guacamole.net.auth.mysql; package net.sourceforge.guacamole.net.auth.mysql;
import java.util.Collections; import com.google.inject.Inject;
import java.util.HashSet; import net.sourceforge.guacamole.net.auth.mysql.model.UserModel;
import java.util.Set; import net.sourceforge.guacamole.net.auth.mysql.service.PasswordEncryptionService;
import net.sourceforge.guacamole.net.auth.mysql.service.SaltService;
import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.AbstractUser;
import org.glyptodon.guacamole.net.auth.User; import org.glyptodon.guacamole.net.auth.User;
import org.glyptodon.guacamole.net.auth.permission.Permission; import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
import org.glyptodon.guacamole.net.auth.simple.SimpleObjectPermissionSet;
import org.glyptodon.guacamole.net.auth.simple.SimpleSystemPermissionSet;
/** /**
* A MySQL based implementation of the User object. * A MySQL based implementation of the User object.
* @author James Muehlner * @author James Muehlner
*/ */
public class MySQLUser extends AbstractUser { public class MySQLUser implements User, DirectoryObject<UserModel> {
/** /**
* The ID of this user in the database, if any. * Service for hashing passwords.
*/ */
private Integer userID; @Inject
private PasswordEncryptionService encryptionService;
/** /**
* The set of current permissions a user has. * Service for providing secure, random salts.
*/ */
private Set<Permission> permissions = new HashSet<Permission>(); @Inject
private SaltService saltService;
/**
* The internal model object containing the values which represent this
* user in the database.
*/
private UserModel userModel;
/** /**
* Any newly added permissions that have yet to be committed. * The plaintext password previously set by a call to setPassword(), if
* any. The password of a user cannot be retrieved once saved into the
* database, so this serves to ensure getPassword() returns a reasonable
* value if setPassword() is called. If no password has been set, or the
* user was retrieved from the database, this will be null.
*/ */
private Set<Permission> newPermissions = new HashSet<Permission>(); private String password = null;
/**
* Any newly deleted permissions that have yet to be deleted.
*/
private Set<Permission> removedPermissions = new HashSet<Permission>();
/** /**
* Creates a new, empty MySQLUser. * Creates a new, empty MySQLUser.
*/ */
@@ -63,118 +73,85 @@ public class MySQLUser extends AbstractUser {
} }
/** /**
* Initializes a new MySQLUser having the given username. * Creates a new MySQLUser backed by the given user model object. Changes
* * to this model object will affect the new MySQLUser even after creation,
* @param name The name to assign to this MySQLUser. * and changes to the new MySQLUser will affect this model object.
*
* @param userModel
* The user model object to use to back this MySQLUser.
*/ */
public void init(String name) { public MySQLUser(UserModel userModel) {
init(null, name, null, Collections.EMPTY_SET); this.userModel = userModel;
}
/**
* 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 @Override
public Set<Permission> getPermissions() throws GuacamoleException { public UserModel getModel() {
return Collections.unmodifiableSet(permissions); return userModel;
} }
@Override @Override
public boolean hasPermission(Permission permission) throws GuacamoleException { public void setModel(UserModel userModel) {
return permissions.contains(permission); this.userModel = userModel;
this.password = null;
} }
@Override @Override
public void addPermission(Permission permission) throws GuacamoleException { public String getUsername() {
permissions.add(permission); return userModel.getUsername();
newPermissions.add(permission);
removedPermissions.remove(permission);
} }
@Override @Override
public void removePermission(Permission permission) throws GuacamoleException { public void setUsername(String username) {
permissions.remove(permission); userModel.setUsername(username);
newPermissions.remove(permission); }
removedPermissions.add(permission);
@Override
public String getPassword() {
return password;
}
@Override
public void setPassword(String password) {
// Store plaintext password internally
this.password = password;
// Generate new salt and hash given password using newly-generated salt
byte[] salt = saltService.generateSalt();
byte[] hash = encryptionService.createPasswordHash(password, salt);
// Set stored salt and hash
userModel.setPasswordSalt(salt);
userModel.setPasswordHash(hash);
}
@Override
public SystemPermissionSet getSystemPermissions()
throws GuacamoleException {
// STUB
return new SimpleSystemPermissionSet();
}
@Override
public ObjectPermissionSet<String> getConnectionPermissions()
throws GuacamoleException {
// STUB
return new SimpleObjectPermissionSet<String>();
}
@Override
public ObjectPermissionSet<String> getConnectionGroupPermissions()
throws GuacamoleException {
// STUB
return new SimpleObjectPermissionSet<String>();
}
@Override
public ObjectPermissionSet<String> getUserPermissions()
throws GuacamoleException {
// STUB
return new SimpleObjectPermissionSet<String>();
} }
} }

View File

@@ -24,13 +24,15 @@ package net.sourceforge.guacamole.net.auth.mysql;
import com.google.inject.Inject; import com.google.inject.Inject;
import java.util.Collections;
import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.ConnectionGroup; import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.net.auth.Directory; import org.glyptodon.guacamole.net.auth.Directory;
import org.glyptodon.guacamole.net.auth.User; import org.glyptodon.guacamole.net.auth.User;
import org.glyptodon.guacamole.net.auth.UserContext; import org.glyptodon.guacamole.net.auth.UserContext;
import net.sourceforge.guacamole.net.auth.mysql.service.UserService; import org.glyptodon.guacamole.net.auth.simple.SimpleConnectionDirectory;
import org.glyptodon.guacamole.net.auth.Credentials; import org.glyptodon.guacamole.net.auth.simple.SimpleConnectionGroup;
import org.glyptodon.guacamole.net.auth.simple.SimpleConnectionGroupDirectory;
/** /**
* The MySQL representation of a UserContext. * The MySQL representation of a UserContext.
@@ -39,10 +41,9 @@ import org.glyptodon.guacamole.net.auth.Credentials;
public class MySQLUserContext implements UserContext { public class MySQLUserContext implements UserContext {
/** /**
* The the user owning this context. The permissions of this user dictate * The the user owning this context.
* the access given via the user and connection directories.
*/ */
private AuthenticatedUser currentUser; private MySQLUser currentUser;
/** /**
* User directory restricted by the permissions of the user associated * User directory restricted by the permissions of the user associated
@@ -51,36 +52,19 @@ public class MySQLUserContext implements UserContext {
@Inject @Inject
private UserDirectory userDirectory; private UserDirectory userDirectory;
/**
* The root connection group.
*/
@Inject
private MySQLConnectionGroup rootConnectionGroup;
/**
* Service for accessing users.
*/
@Inject
private UserService userService;
/** /**
* Initializes the user and directories associated with this context. * Initializes the user and directories associated with this context.
* *
* @param currentUser * @param currentUser
* The user owning this context. * The user owning this context.
*/ */
public void init(AuthenticatedUser currentUser) { public void init(MySQLUser currentUser) {
this.currentUser = currentUser; this.currentUser = currentUser;
userDirectory.init(currentUser);
rootConnectionGroup.init(null, null,
MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER,
MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER,
ConnectionGroup.Type.ORGANIZATIONAL, currentUser);
} }
@Override @Override
public User self() { public User self() {
return userService.retrieveUser(currentUser.getUserID()); return currentUser;
} }
@Override @Override
@@ -90,7 +74,11 @@ public class MySQLUserContext implements UserContext {
@Override @Override
public ConnectionGroup getRootConnectionGroup() throws GuacamoleException { public ConnectionGroup getRootConnectionGroup() throws GuacamoleException {
return rootConnectionGroup; /* STUB */
return new SimpleConnectionGroup("ROOT", "ROOT",
new SimpleConnectionDirectory(Collections.EMPTY_MAP),
new SimpleConnectionGroupDirectory(Collections.EMPTY_LIST)
);
} }
} }

View File

@@ -23,686 +23,76 @@
package net.sourceforge.guacamole.net.auth.mysql; package net.sourceforge.guacamole.net.auth.mysql;
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import com.google.inject.Inject; import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.Collections;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.glyptodon.guacamole.GuacamoleClientException; import net.sourceforge.guacamole.net.auth.mysql.service.UserService;
import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.GuacamoleSecurityException; import org.glyptodon.guacamole.GuacamoleSecurityException;
import org.glyptodon.guacamole.net.auth.Directory; import org.glyptodon.guacamole.net.auth.Directory;
import org.glyptodon.guacamole.net.auth.User; import org.glyptodon.guacamole.net.auth.User;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionGroupPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.SystemPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.UserPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupPermissionExample;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupPermissionKey;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionExample;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionKey;
import net.sourceforge.guacamole.net.auth.mysql.model.SystemPermissionExample;
import net.sourceforge.guacamole.net.auth.mysql.model.SystemPermissionKey;
import net.sourceforge.guacamole.net.auth.mysql.model.UserPermissionExample;
import net.sourceforge.guacamole.net.auth.mysql.model.UserPermissionKey;
import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionGroupService;
import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionService;
import net.sourceforge.guacamole.net.auth.mysql.service.PermissionCheckService;
import net.sourceforge.guacamole.net.auth.mysql.service.UserService;
import org.glyptodon.guacamole.GuacamoleUnsupportedException;
import org.glyptodon.guacamole.net.auth.permission.ConnectionGroupPermission;
import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission;
import org.glyptodon.guacamole.net.auth.permission.Permission;
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
import org.glyptodon.guacamole.net.auth.permission.UserPermission;
import org.mybatis.guice.transactional.Transactional; import org.mybatis.guice.transactional.Transactional;
/** /**
* A MySQL based implementation of the User Directory. * A MySQL based implementation of the User Directory.
*
* @author James Muehlner * @author James Muehlner
* @author Michael Jumper
*/ */
public class UserDirectory implements Directory<String, User> { public class UserDirectory implements Directory<String, User> {
/** /**
* The user this user directory belongs to. Access is based on his/her * Service for managing user objects.
* permission settings.
*/
private AuthenticatedUser currentUser;
/**
* Service for accessing users.
*/ */
@Inject @Inject
private UserService userService; private UserService userService;
/**
* Service for accessing connections.
*/
@Inject
private ConnectionService connectionService;
/**
* Service for accessing connection groups.
*/
@Inject
private ConnectionGroupService connectionGroupService;
/**
* DAO for accessing user permissions, which will be injected.
*/
@Inject
private UserPermissionMapper userPermissionDAO;
/**
* DAO for accessing connection permissions, which will be injected.
*/
@Inject
private ConnectionPermissionMapper connectionPermissionDAO;
/**
* DAO for accessing connection group permissions, which will be injected.
*/
@Inject
private ConnectionGroupPermissionMapper connectionGroupPermissionDAO;
/**
* DAO for accessing system permissions, which will be injected.
*/
@Inject
private SystemPermissionMapper systemPermissionDAO;
/**
* Service for checking various permissions, which will be injected.
*/
@Inject
private PermissionCheckService permissionCheckService;
/**
* Set the user for this directory.
*
* @param currentUser
* The user whose permissions define the visibility of other users in
* this directory.
*/
public void init(AuthenticatedUser currentUser) {
this.currentUser = currentUser;
}
@Transactional
@Override
public org.glyptodon.guacamole.net.auth.User get(String identifier)
throws GuacamoleException {
// Get user
MySQLUser user = userService.retrieveUser(identifier);
if(user == null)
return null;
// Verify access is granted
permissionCheckService.verifyUserAccess(currentUser,
user.getUserID(),
MySQLConstants.USER_READ);
// Return user
return user;
}
@Transactional
@Override
public Set<String> getIdentifiers() throws GuacamoleException {
return permissionCheckService.retrieveUsernames(currentUser,
MySQLConstants.USER_READ);
}
@Override
@Transactional
public void add(org.glyptodon.guacamole.net.auth.User object)
throws GuacamoleException {
String username = object.getUsername().trim();
if(username.isEmpty())
throw new GuacamoleClientException("The username cannot be blank.");
// Verify current user has permission to create users
permissionCheckService.verifySystemAccess(currentUser,
MySQLConstants.SYSTEM_USER_CREATE);
Preconditions.checkNotNull(object);
// Verify that no user already exists with this username.
MySQLUser previousUser = userService.retrieveUser(username);
if(previousUser != null)
throw new GuacamoleClientException("That username is already in use.");
// Create new user
MySQLUser user = userService.createUser(username, object.getPassword());
// Create permissions of new user in database
createPermissions(user.getUserID(), object.getPermissions());
// Give the current user full access to the newly created user.
UserPermissionKey newUserPermission = new UserPermissionKey();
newUserPermission.setUser_id(currentUser.getUserID());
newUserPermission.setAffected_user_id(user.getUserID());
// READ permission on new user
newUserPermission.setPermission(MySQLConstants.USER_READ);
userPermissionDAO.insert(newUserPermission);
// UPDATE permission on new user
newUserPermission.setPermission(MySQLConstants.USER_UPDATE);
userPermissionDAO.insert(newUserPermission);
// DELETE permission on new user
newUserPermission.setPermission(MySQLConstants.USER_DELETE);
userPermissionDAO.insert(newUserPermission);
// ADMINISTER permission on new user
newUserPermission.setPermission(MySQLConstants.USER_ADMINISTER);
userPermissionDAO.insert(newUserPermission);
}
/**
* Add the given permissions to the given user.
*
* @param user_id The ID of the user whose permissions should be updated.
* @param permissions The permissions to add.
* @throws GuacamoleException If an error occurs while updating the
* permissions of the given user.
*/
private void createPermissions(int user_id, Set<Permission> permissions) throws GuacamoleException {
// Partition given permissions by permission type
List<UserPermission> newUserPermissions = new ArrayList<UserPermission>();
List<ConnectionPermission> newConnectionPermissions = new ArrayList<ConnectionPermission>();
List<ConnectionGroupPermission> newConnectionGroupPermissions = new ArrayList<ConnectionGroupPermission>();
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 ConnectionGroupPermission)
newConnectionGroupPermissions.add((ConnectionGroupPermission) permission);
else if (permission instanceof SystemPermission)
newSystemPermissions.add((SystemPermission) permission);
}
// Create the new permissions
createUserPermissions(user_id, newUserPermissions);
createConnectionPermissions(user_id, newConnectionPermissions);
createConnectionGroupPermissions(user_id, newConnectionGroupPermissions);
createSystemPermissions(user_id, newSystemPermissions);
}
/**
* Remove the given permissions from the given user.
*
* @param user_id The ID of the user whose permissions should be updated.
* @param permissions The permissions to remove.
* @throws GuacamoleException If an error occurs while updating the
* permissions of the given user.
*/
private void removePermissions(int user_id, Set<Permission> permissions)
throws GuacamoleException {
// Partition given permissions by permission type
List<UserPermission> removedUserPermissions = new ArrayList<UserPermission>();
List<ConnectionPermission> removedConnectionPermissions = new ArrayList<ConnectionPermission>();
List<ConnectionGroupPermission> removedConnectionGroupPermissions = new ArrayList<ConnectionGroupPermission>();
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 ConnectionGroupPermission)
removedConnectionGroupPermissions.add((ConnectionGroupPermission) permission);
else if (permission instanceof SystemPermission)
removedSystemPermissions.add((SystemPermission) permission);
}
// Delete the removed permissions.
deleteUserPermissions(user_id, removedUserPermissions);
deleteConnectionPermissions(user_id, removedConnectionPermissions);
deleteConnectionGroupPermissions(user_id, removedConnectionGroupPermissions);
deleteSystemPermissions(user_id, removedSystemPermissions);
}
/**
* Create the given user permissions for the given user.
*
* @param user_id The ID of the user to change the permissions of.
* @param permissions The new permissions the given user should have when
* this operation completes.
* @throws GuacamoleException If permission to alter the access permissions
* of affected objects is denied.
*/
private void createUserPermissions(int user_id,
Collection<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(currentUser,
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 #" + currentUser.getUserID()
+ " does not have permission to administrate user "
+ permission.getObjectIdentifier());
// Create new permission
UserPermissionKey newPermission = new UserPermissionKey();
newPermission.setUser_id(currentUser.getUserID());
newPermission.setPermission(MySQLConstants.getUserConstant(permission.getType()));
newPermission.setAffected_user_id(affected_id);
userPermissionDAO.insert(newPermission);
}
}
/**
* Delete permissions having to do with users for a given user.
*
* @param user_id The ID of the user to change the permissions of.
* @param permissions The permissions the given user should no longer have
* when this operation completes.
* @throws GuacamoleException If permission to alter the access permissions
* of affected objects is denied.
*/
private void deleteUserPermissions(int user_id,
Collection<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(currentUser,
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 #" + currentUser.getUserID()
+ " does not have permission to administrate user "
+ permission.getObjectIdentifier());
// Delete requested permission
UserPermissionExample userPermissionExample = new UserPermissionExample();
userPermissionExample.createCriteria()
.andUser_idEqualTo(user_id)
.andPermissionEqualTo(MySQLConstants.getUserConstant(permission.getType()))
.andAffected_user_idEqualTo(affected_id);
userPermissionDAO.deleteByExample(userPermissionExample);
}
}
/**
* Create any new permissions having to do with connections for a given
* user.
*
* @param user_id The ID of the user to assign or remove permissions from.
* @param permissions The new permissions the user should have after this
* operation completes.
* @throws GuacamoleException If permission to alter the access permissions
* of affected objects is deniedD
*/
private void createConnectionPermissions(int user_id,
Collection<ConnectionPermission> permissions)
throws GuacamoleException {
// If no permissions given, stop now
if(permissions.isEmpty())
return;
// Get list of administerable connection IDs
Set<Integer> administerableConnectionIDs = Sets.<Integer>newHashSet(
permissionCheckService.retrieveConnectionIDs(currentUser,
MySQLConstants.CONNECTION_ADMINISTER));
// Insert all given permissions
for (ConnectionPermission permission : permissions) {
// Get original ID
Integer connection_id = Integer.valueOf(permission.getObjectIdentifier());
// Throw exception if permission to administer this connection
// is not granted
if (!administerableConnectionIDs.contains(connection_id))
throw new GuacamoleSecurityException(
"User #" + currentUser.getUserID()
+ " does not have permission to administrate connection "
+ permission.getObjectIdentifier());
// Create new permission
ConnectionPermissionKey newPermission = new ConnectionPermissionKey();
newPermission.setUser_id(user_id);
newPermission.setPermission(MySQLConstants.getConnectionConstant(permission.getType()));
newPermission.setConnection_id(connection_id);
connectionPermissionDAO.insert(newPermission);
}
}
/**
* Create any new permissions having to do with connection groups
* for a given user.
*
* @param user_id The ID of the user to assign or remove permissions from.
* @param permissions The new permissions the user should have after this
* operation completes.
* @throws GuacamoleException If permission to alter the access permissions
* of affected objects is deniedD
*/
private void createConnectionGroupPermissions(int user_id,
Collection<ConnectionGroupPermission> permissions)
throws GuacamoleException {
// If no permissions given, stop now
if(permissions.isEmpty())
return;
// Get list of administerable connection group IDs
Set<Integer> administerableConnectionGroupIDs = Sets.<Integer>newHashSet(
permissionCheckService.retrieveConnectionGroupIDs(currentUser,
MySQLConstants.CONNECTION_GROUP_ADMINISTER));
// Insert all given permissions
for (ConnectionGroupPermission permission : permissions) {
// Get original ID
Integer connection_group_id = Integer.valueOf(permission.getObjectIdentifier());
// Throw exception if permission to administer this connection group
// is not granted
if (!administerableConnectionGroupIDs.contains(connection_group_id))
throw new GuacamoleSecurityException(
"User #" + currentUser.getUserID()
+ " does not have permission to administrate connection group"
+ permission.getObjectIdentifier());
// Create new permission
ConnectionGroupPermissionKey newPermission = new ConnectionGroupPermissionKey();
newPermission.setUser_id(user_id);
newPermission.setPermission(MySQLConstants.getConnectionGroupConstant(permission.getType()));
newPermission.setConnection_group_id(connection_group_id);
connectionGroupPermissionDAO.insert(newPermission);
}
}
/**
* Delete permissions having to do with connections for a given user.
*
* @param user_id The ID of the user to change the permissions of.
* @param permissions The permissions the given user should no longer have
* when this operation completes.
* @throws GuacamoleException If permission to alter the access permissions
* of affected objects is denied.
*/
private void deleteConnectionPermissions(int user_id,
Collection<ConnectionPermission> permissions)
throws GuacamoleException {
// If no permissions given, stop now
if(permissions.isEmpty())
return;
// Get list of administerable connection IDs
Set<Integer> administerableConnectionIDs = Sets.<Integer>newHashSet(
permissionCheckService.retrieveConnectionIDs(currentUser,
MySQLConstants.CONNECTION_ADMINISTER));
// Delete requested permissions
for (ConnectionPermission permission : permissions) {
// Get original ID
Integer connection_id = Integer.valueOf(permission.getObjectIdentifier());
// Verify that the user actually has permission to administrate
// every one of these connections
if (!administerableConnectionIDs.contains(connection_id))
throw new GuacamoleSecurityException(
"User #" + currentUser.getUserID()
+ " does not have permission to administrate connection "
+ permission.getObjectIdentifier());
ConnectionPermissionExample connectionPermissionExample = new ConnectionPermissionExample();
connectionPermissionExample.createCriteria()
.andUser_idEqualTo(user_id)
.andPermissionEqualTo(MySQLConstants.getConnectionConstant(permission.getType()))
.andConnection_idEqualTo(connection_id);
connectionPermissionDAO.deleteByExample(connectionPermissionExample);
}
}
/**
* Delete permissions having to do with connection groups for a given user.
*
* @param user_id The ID of the user to change the permissions of.
* @param permissions The permissions the given user should no longer have
* when this operation completes.
* @throws GuacamoleException If permission to alter the access permissions
* of affected objects is denied.
*/
private void deleteConnectionGroupPermissions(int user_id,
Collection<ConnectionGroupPermission> permissions)
throws GuacamoleException {
// If no permissions given, stop now
if(permissions.isEmpty())
return;
// Get list of administerable connection group IDs
Set<Integer> administerableConnectionGroupIDs = Sets.<Integer>newHashSet(
permissionCheckService.retrieveConnectionGroupIDs(currentUser,
MySQLConstants.CONNECTION_GROUP_ADMINISTER));
// Delete requested permissions
for (ConnectionGroupPermission permission : permissions) {
// Get original ID
Integer connection_group_id = Integer.valueOf(permission.getObjectIdentifier());
// Verify that the user actually has permission to administrate
// every one of these connection groups
if (!administerableConnectionGroupIDs.contains(connection_group_id))
throw new GuacamoleSecurityException(
"User #" + currentUser.getUserID()
+ " does not have permission to administrate connection group"
+ permission.getObjectIdentifier());
ConnectionGroupPermissionExample connectionGroupPermissionExample = new ConnectionGroupPermissionExample();
connectionGroupPermissionExample.createCriteria()
.andUser_idEqualTo(user_id)
.andPermissionEqualTo(MySQLConstants.getConnectionGroupConstant(permission.getType()))
.andConnection_group_idEqualTo(connection_group_id);
connectionGroupPermissionDAO.deleteByExample(connectionGroupPermissionExample);
}
}
/**
* Create any new system permissions for a given user. All permissions in
* the given list will be inserted.
*
* @param user_id The ID of the user whose permissions should be updated.
* @param permissions The new system permissions that the given user should
* have when this operation completes.
* @throws GuacamoleException If permission to administer system permissions
* is denied.
*/
private void createSystemPermissions(int user_id,
Collection<SystemPermission> permissions) throws GuacamoleException {
// If no permissions given, stop now
if(permissions.isEmpty())
return;
// Only a system administrator can add system permissions.
permissionCheckService.verifySystemAccess(
currentUser, SystemPermission.Type.ADMINISTER.name());
// Insert all requested permissions
for (SystemPermission permission : permissions) {
// Insert permission
SystemPermissionKey newSystemPermission = new SystemPermissionKey();
newSystemPermission.setUser_id(user_id);
newSystemPermission.setPermission(MySQLConstants.getSystemConstant(permission.getType()));
systemPermissionDAO.insert(newSystemPermission);
}
}
/**
* Delete system permissions for a given user. All permissions in
* the given list will be removed from the user.
*
* @param user_id The ID of the user whose permissions should be updated.
* @param permissions The permissions the given user should no longer have
* when this operation completes.
* @throws GuacamoleException If the permissions specified could not be
* removed due to system restrictions.
*/
private void deleteSystemPermissions(int user_id,
Collection<SystemPermission> permissions)
throws GuacamoleException {
// If no permissions given, stop now
if (permissions.isEmpty())
return;
// Prevent self-de-adminifying
if (user_id == currentUser.getUserID())
throw new GuacamoleUnsupportedException("Removing your own administrative permissions is not allowed.");
// Build list of requested system permissions
List<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(org.glyptodon.guacamole.net.auth.User object)
throws GuacamoleException {
// If user not actually from this auth provider, we can't handle updated
// permissions.
if (!(object instanceof MySQLUser))
throw new GuacamoleUnsupportedException("User not from database.");
MySQLUser mySQLUser = (MySQLUser) object;
// Validate permission to update this user is granted
permissionCheckService.verifyUserAccess(currentUser,
mySQLUser.getUserID(),
MySQLConstants.USER_UPDATE);
// Update the user in the database
userService.updateUser(mySQLUser);
// Update permissions in database
createPermissions(mySQLUser.getUserID(), mySQLUser.getNewPermissions());
removePermissions(mySQLUser.getUserID(), mySQLUser.getRemovedPermissions());
// The appropriate permissions have been inserted and deleted, so
// reset the new and removed permission sets.
mySQLUser.resetPermissions();
}
@Override
@Transactional
public void remove(String identifier) throws GuacamoleException {
// Get user pending deletion
MySQLUser user = userService.retrieveUser(identifier);
// Prevent self-deletion
if (user.getUserID() == currentUser.getUserID())
throw new GuacamoleUnsupportedException("Deleting your own user is not allowed.");
// Validate current user has permission to remove the specified user
permissionCheckService.verifyUserAccess(currentUser,
user.getUserID(),
MySQLConstants.USER_DELETE);
// Delete specified user
userService.deleteUser(user.getUserID());
}
@Override @Override
public void move(String identifier, Directory<String, User> groupIdentifier) public void move(String identifier, Directory<String, User> groupIdentifier)
throws GuacamoleException { throws GuacamoleException {
throw new GuacamoleSecurityException("Permission denied."); throw new GuacamoleSecurityException("Permission denied.");
} }
@Override
public User get(String identifier) throws GuacamoleException {
return userService.retrieveObject(identifier);
}
@Override
@Transactional
public Collection<User> getAll(Collection<String> identifiers) throws GuacamoleException {
return Collections.<User>unmodifiableCollection(userService.retrieveObjects(identifiers));
}
@Override
@Transactional
public Set<String> getIdentifiers() throws GuacamoleException {
// STUB
return userService.getIdentifiers();
}
@Override
@Transactional
public void add(User object) throws GuacamoleException {
// STUB
MySQLUser user = (MySQLUser) object;
userService.createObject(user);
}
@Override
@Transactional
public void update(User object) throws GuacamoleException {
// STUB
MySQLUser user = (MySQLUser) object;
userService.updateObject(user);
}
@Override
@Transactional
public void remove(String identifier) throws GuacamoleException {
// STUB
userService.deleteObject(identifier);
}
} }

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.sourceforge.guacamole.net.auth.mysql.dao;
import java.util.Collection;
import java.util.Set;
import org.apache.ibatis.annotations.Param;
/**
* Common interface for objects that will ultimately be made available through
* the Directory class. All such objects will need the same base set of queries
* to fulfill the needs of the Directory class.
*
* @author Michael Jumper
* @param <T>
* The type of object contained within the directory whose objects are
* mapped by this mapper.
*/
public interface DirectoryObjectMapper<T> {
/**
* Selects the identifiers of all objects.
*
* @return
* A Set containing all identifiers of all objects.
*/
Set<String> selectIdentifiers();
/**
* Selects all objects which have the given identifiers. If an identifier
* has no corresponding object, it will be ignored.
*
* @param identifiers
* The identifiers of the objects to return.
*
* @return
* A Collection of all objects having the given identifiers.
*/
Collection<T> select(@Param("identifiers") Collection<String> identifiers);
/**
* Inserts the given object into the database. If the object already
* exists, this will result in an error.
*
* @param object
* The object to insert.
*
* @return
* The number of rows inserted.
*/
int insert(@Param("object") T object);
/**
* Deletes the given object into the database. If the object does not
* exist, this operation has no effect.
*
* @param identifier
* The identifier of the object to delete.
*
* @return
* The number of rows deleted.
*/
int delete(@Param("identifier") String identifier);
/**
* Updates the given existing object in the database. If the object does
* not actually exist, this operation has no effect.
*
* @param object
* The object to update.
*
* @return
* The number of rows updated.
*/
int update(@Param("object") T object);
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.sourceforge.guacamole.net.auth.mysql.dao;
import net.sourceforge.guacamole.net.auth.mysql.model.UserModel;
import org.apache.ibatis.annotations.Param;
/**
* Mapper for user objects.
*
* @author Michael Jumper
*/
public interface UserMapper extends DirectoryObjectMapper<UserModel> {
/**
* Returns the user having the given username and password, if any. If no
* such user exists, null is returned.
*
* @param username
* The username of the user to return.
*
* @param password
* The password of the user to return.
*
* @return
* The user having the given username and password, or null if no such
* user exists.
*/
UserModel selectByCredentials(@Param("username") String username,
@Param("password") String password);
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.sourceforge.guacamole.net.auth.mysql.model;
/**
* Object representation of a Guacamole user, as represented in the database.
*
* @author Michael Jumper
*/
public class UserModel {
/**
* The ID of this user in the database, if any.
*/
private Integer userID;
/**
* The unique username which identifies this user.
*/
private String username;
/**
* The SHA-256 hash of the password and salt.
*/
private byte[] passwordHash;
/**
* The 32-byte random binary password salt that was appended to the
* password prior to hashing.
*/
private byte[] passwordSalt;
/**
* Creates a new, empty user.
*/
public UserModel() {
}
/**
* Returns the username that uniquely identifies this user.
*
* @return
* The username that uniquely identifies this user.
*/
public String getUsername() {
return username;
}
/**
* Sets the username that uniquely identifies this user.
*
* @param username
* The username that uniquely identifies this user.
*/
public void setUsername(String username) {
this.username = username;
}
/**
* 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;
}
/**
* Returns the hash of this user's password and password salt. This may be
* null if the user was not retrieved from the database, and setPassword()
* has not yet been called.
*
* @return
* The hash of this user's password and password salt.
*/
public byte[] getPasswordHash() {
return passwordHash;
}
/**
* Sets the hash of this user's password and password salt. This is
* normally only set upon retrieval from the database, or through a call
* to the higher-level setPassword() function.
*
* @param passwordHash
* The hash of this user's password and password salt.
*/
public void setPasswordHash(byte[] passwordHash) {
this.passwordHash = passwordHash;
}
/**
* Returns the random salt that was used when generating this user's
* password hash. This may be null if the user was not retrieved from the
* database, and setPassword() has not yet been called.
*
* @return
* The random salt that was used when generating this user's password
* hash.
*/
public byte[] getPasswordSalt() {
return passwordSalt;
}
/**
* Sets the random salt that was used when generating this user's password
* hash. This is normally only set upon retrieval from the database, or
* through a call to the higher-level setPassword() function.
*
* @param passwordSalt
* The random salt used when generating this user's password hash.
*/
public void setPasswordSalt(byte[] passwordSalt) {
this.passwordSalt = passwordSalt;
}
}

View File

@@ -1,446 +0,0 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.sourceforge.guacamole.net.auth.mysql.service;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.GuacamoleSocket;
import net.sourceforge.guacamole.net.auth.mysql.ActiveConnectionMap;
import net.sourceforge.guacamole.net.auth.mysql.AuthenticatedUser;
import net.sourceforge.guacamole.net.auth.mysql.MySQLConnection;
import net.sourceforge.guacamole.net.auth.mysql.MySQLConnectionGroup;
import net.sourceforge.guacamole.net.auth.mysql.MySQLConstants;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionGroupMapper;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroup;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupExample;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupExample.Criteria;
import net.sourceforge.guacamole.net.auth.mysql.properties.MySQLGuacamoleProperties;
import org.glyptodon.guacamole.GuacamoleClientTooManyException;
import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
import org.glyptodon.guacamole.GuacamoleServerBusyException;
import org.glyptodon.guacamole.properties.GuacamoleProperties;
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
/**
* Service which provides convenience methods for creating, retrieving, and
* manipulating connection groups.
*
* @author James Muehlner
*/
public class ConnectionGroupService {
/**
* Service for managing connections.
*/
@Inject
private ConnectionService connectionService;
/**
* DAO for accessing connection groups.
*/
@Inject
private ConnectionGroupMapper connectionGroupDAO;
/**
* Provider which creates MySQLConnectionGroups.
*/
@Inject
private Provider<MySQLConnectionGroup> mysqlConnectionGroupProvider;
/**
* The map of all active connections.
*/
@Inject
private ActiveConnectionMap activeConnectionMap;
/**
* Retrieves the connection group having the given
* name from the database.
*
* @param name
* The name of the connection to return.
*
* @param parentID
* The ID of the parent connection group.
*
* @param currentUser
* The user who queried this connection group.
*
* @return
* The connection having the given name, or null if no such connection
* group could be found.
*/
public MySQLConnectionGroup retrieveConnectionGroup(String name, Integer parentID,
AuthenticatedUser currentUser) {
// Create criteria
ConnectionGroupExample example = new ConnectionGroupExample();
Criteria criteria = example.createCriteria().andConnection_group_nameEqualTo(name);
if(parentID != null)
criteria.andParent_idEqualTo(parentID);
else
criteria.andParent_idIsNull();
// Query connection group by name and parentID
List<ConnectionGroup> connectionGroups =
connectionGroupDAO.selectByExample(example);
// If no connection group found, return null
if(connectionGroups.isEmpty())
return null;
// Otherwise, return found connection
return toMySQLConnectionGroup(connectionGroups.get(0), currentUser);
}
/**
* Retrieves the connection group having the given unique identifier
* from the database.
*
* @param uniqueIdentifier
* The unique identifier of the connection group to retrieve.
*
* @param currentUser
* The user who queried this connection group.
*
* @return
* The connection group having the given unique identifier, or null if
* no such connection group was found.
*
* @throws GuacamoleException
* If an error occurs while retrieving the connection group.
*/
public MySQLConnectionGroup retrieveConnectionGroup(String uniqueIdentifier,
AuthenticatedUser currentUser) throws GuacamoleException {
// The unique identifier for a MySQLConnectionGroup is the database ID
Integer connectionGroupID = null;
// Try to parse the connectionID if it's not the root group
if(!MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER.equals(uniqueIdentifier)) {
try {
connectionGroupID = Integer.parseInt(uniqueIdentifier);
} catch(NumberFormatException e) {
throw new GuacamoleResourceNotFoundException("Invalid connection group ID.");
}
}
return retrieveConnectionGroup(connectionGroupID, currentUser);
}
/**
* Retrieves the connection group having the given ID from the database.
*
* @param id
* The ID of the connection group to retrieve.
*
* @param currentUser
* The user who queried this connection.
*
* @return
* The connection group having the given ID, or null if no such
* connection was found.
*/
public MySQLConnectionGroup retrieveConnectionGroup(Integer id, AuthenticatedUser currentUser) {
// This is the root connection group, so just create it here
if(id == null) {
MySQLConnectionGroup connectionGroup = mysqlConnectionGroupProvider.get();
connectionGroup.init(null, null,
MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER,
MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER,
org.glyptodon.guacamole.net.auth.ConnectionGroup.Type.ORGANIZATIONAL,
currentUser);
return connectionGroup;
}
// Query connection by ID
ConnectionGroup connectionGroup = connectionGroupDAO.selectByPrimaryKey(id);
// If no connection found, return null
if(connectionGroup == null)
return null;
// Otherwise, return found connection
return toMySQLConnectionGroup(connectionGroup, currentUser);
}
/**
* Connect to the connection within the given group with the lowest number
* of currently active users.
*
* @param group
* The group to load balance across.
*
* @param info
* The information to use when performing the connection handshake.
*
* @param currentUser
* The user who is connecting to the socket.
*
* @return
* The connected socket.
*
* @throws GuacamoleException
* If an error occurs while connecting the socket.
*/
public GuacamoleSocket connect(MySQLConnectionGroup group,
GuacamoleClientInformation info, AuthenticatedUser currentUser)
throws GuacamoleException {
// Get all connections in the group.
List<Integer> connectionIDs = connectionService.getAllConnectionIDs
(group.getConnectionGroupID());
synchronized (activeConnectionMap) {
// Get the least used connection.
Integer leastUsedConnectionID =
activeConnectionMap.getLeastUsedConnection(connectionIDs);
if(leastUsedConnectionID == null)
throw new GuacamoleResourceNotFoundException("No connections found in group.");
if(GuacamoleProperties.getProperty(
MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS, false)
&& activeConnectionMap.isActive(leastUsedConnectionID))
throw new GuacamoleServerBusyException
("Cannot connect. All connections are in use.");
if(GuacamoleProperties.getProperty(
MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS, true)
&& activeConnectionMap.isConnectionGroupUserActive(group.getConnectionGroupID(), currentUser.getUserID()))
throw new GuacamoleClientTooManyException
("Cannot connect. Connection group already in use by this user.");
// Get the connection
MySQLConnection connection = connectionService
.retrieveConnection(leastUsedConnectionID, currentUser);
// Connect to the connection
return connectionService.connect(connection, info, currentUser, group.getConnectionGroupID());
}
}
/**
* Returns a list of the IDs of all connection groups with a given parent ID.
* @param parentID The ID of the parent for all the queried connection groups.
* @return a list of the IDs of all connection groups with a given parent ID.
*/
public List<Integer> getAllConnectionGroupIDs(Integer parentID) {
// Create criteria
ConnectionGroupExample example = new ConnectionGroupExample();
Criteria criteria = example.createCriteria();
if(parentID != null)
criteria.andParent_idEqualTo(parentID);
else
criteria.andParent_idIsNull();
// Query the connections
List<ConnectionGroup> connectionGroups = connectionGroupDAO.selectByExample(example);
// List of IDs of connections with the given parent
List<Integer> connectionGroupIDs = new ArrayList<Integer>();
for(ConnectionGroup connectionGroup : connectionGroups) {
connectionGroupIDs.add(connectionGroup.getConnection_group_id());
}
return connectionGroupIDs;
}
/**
* Get the identifiers of all the connection groups defined in the system
* with a certain parentID.
*
* @return A Set of identifiers of all the connection groups defined
* in the system with the given parentID.
*/
public Set<String> getAllConnectionGroupIdentifiers(Integer parentID) {
// Set of all present connection identifiers
Set<String> identifiers = new HashSet<String>();
// Set up Criteria
ConnectionGroupExample example = new ConnectionGroupExample();
Criteria criteria = example.createCriteria();
if(parentID != null)
criteria.andParent_idEqualTo(parentID);
else
criteria.andParent_idIsNull();
// Query connection identifiers
List<ConnectionGroup> connectionGroups =
connectionGroupDAO.selectByExample(example);
for (ConnectionGroup connectionGroup : connectionGroups)
identifiers.add(String.valueOf(connectionGroup.getConnection_group_id()));
return identifiers;
}
/**
* Convert the given database-retrieved Connection into a MySQLConnection.
* The parameters of the given connection will be read and added to the
* MySQLConnection in the process.
*
* @param connection
* The connection to convert.
*
* @param currentUser
* The user who queried this connection.
*
* @return
* A new MySQLConnection containing all data associated with the
* specified connection.
*/
private MySQLConnectionGroup toMySQLConnectionGroup(ConnectionGroup connectionGroup,
AuthenticatedUser currentUser) {
// Create new MySQLConnection from retrieved data
MySQLConnectionGroup mySQLConnectionGroup = mysqlConnectionGroupProvider.get();
String mySqlType = connectionGroup.getType();
org.glyptodon.guacamole.net.auth.ConnectionGroup.Type authType;
if(mySqlType.equals(MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL))
authType = org.glyptodon.guacamole.net.auth.ConnectionGroup.Type.ORGANIZATIONAL;
else
authType = org.glyptodon.guacamole.net.auth.ConnectionGroup.Type.BALANCING;
mySQLConnectionGroup.init(
connectionGroup.getConnection_group_id(),
connectionGroup.getParent_id(),
connectionGroup.getConnection_group_name(),
Integer.toString(connectionGroup.getConnection_group_id()),
authType,
currentUser
);
return mySQLConnectionGroup;
}
/**
* Get the connection group IDs of all the connection groups defined in the system.
*
* @return A list of connection group IDs of all the connection groups defined in the system.
*/
public List<Integer> getAllConnectionGroupIDs() {
// Set of all present connection group IDs
List<Integer> connectionGroupIDs = new ArrayList<Integer>();
// Query all connection IDs
List<ConnectionGroup> connections =
connectionGroupDAO.selectByExample(new ConnectionGroupExample());
for (ConnectionGroup connection : connections)
connectionGroupIDs.add(connection.getConnection_group_id());
return connectionGroupIDs;
}
/**
* Creates a new connection group having the given name and type.
*
* @param name
* The name to assign to the new connection group.
*
* @param currentUser
* The user who created this connection group.
*
* @param parentID
* The ID of the parent of the new connection group, if any.
*
* @param type
* The type of the new connection group.
*
* @return A new MySQLConnectionGroup containing the data of the newly created
* connection group.
*/
public MySQLConnectionGroup createConnectionGroup(String name, AuthenticatedUser currentUser,
Integer parentID, String type) {
// Initialize database connection
ConnectionGroup connectionGroup = new ConnectionGroup();
connectionGroup.setConnection_group_name(name);
connectionGroup.setParent_id(parentID);
connectionGroup.setType(type);
// Create connection
connectionGroupDAO.insert(connectionGroup);
return toMySQLConnectionGroup(connectionGroup, currentUser);
}
/**
* Updates the connection group in the database corresponding to the given
* MySQLConnectionGroup.
*
* @param mySQLConnectionGroup The MySQLConnectionGroup to update (save)
* to the database.
* This connection must already exist.
*/
public void updateConnectionGroup(MySQLConnectionGroup mySQLConnectionGroup) {
// Populate connection
ConnectionGroup connectionGroup = new ConnectionGroup();
connectionGroup.setConnection_group_id(mySQLConnectionGroup.getConnectionGroupID());
connectionGroup.setParent_id(mySQLConnectionGroup.getParentID());
connectionGroup.setConnection_group_name(mySQLConnectionGroup.getName());
switch(mySQLConnectionGroup.getType()) {
case BALANCING :
connectionGroup.setType(MySQLConstants.CONNECTION_GROUP_BALANCING);
break;
case ORGANIZATIONAL:
connectionGroup.setType(MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
break;
}
// Update the connection group in the database
connectionGroupDAO.updateByPrimaryKey(connectionGroup);
}
/**
* Deletes the connection group having the given ID from the database.
* @param id The ID of the connection group to delete.
*/
public void deleteConnectionGroup(int id) {
connectionGroupDAO.deleteByPrimaryKey(id);
}
}

View File

@@ -1,548 +0,0 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.sourceforge.guacamole.net.auth.mysql.service;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.GuacamoleSocket;
import org.glyptodon.guacamole.net.InetGuacamoleSocket;
import org.glyptodon.guacamole.net.SSLGuacamoleSocket;
import net.sourceforge.guacamole.net.auth.mysql.ActiveConnectionMap;
import net.sourceforge.guacamole.net.auth.mysql.AuthenticatedUser;
import net.sourceforge.guacamole.net.auth.mysql.MySQLConnection;
import net.sourceforge.guacamole.net.auth.mysql.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.ConnectionExample.Criteria;
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 org.glyptodon.guacamole.properties.GuacamoleProperties;
import org.glyptodon.guacamole.protocol.ConfiguredGuacamoleSocket;
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
import org.apache.ibatis.session.RowBounds;
import org.glyptodon.guacamole.GuacamoleClientTooManyException;
import org.glyptodon.guacamole.GuacamoleResourceConflictException;
import org.glyptodon.guacamole.token.StandardTokens;
import org.glyptodon.guacamole.token.TokenFilter;
/**
* 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;
/**
* Map of all currently active connections.
*/
@Inject
private ActiveConnectionMap activeConnectionMap;
/**
* 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 parentID
* The ID of the parent connection group.
*
* @param currentUser
* 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, Integer parentID,
AuthenticatedUser currentUser) {
// Create criteria
ConnectionExample example = new ConnectionExample();
Criteria criteria = example.createCriteria().andConnection_nameEqualTo(name);
if(parentID != null)
criteria.andParent_idEqualTo(parentID);
else
criteria.andParent_idIsNull();
// Query connection by name and parentID
List<Connection> connections =
connectionDAO.selectByExample(example);
// If no connection found, return null
if(connections.isEmpty())
return null;
// Otherwise, return found connection
return toMySQLConnection(connections.get(0), currentUser);
}
/**
* Retrieves the connection having the given unique identifier
* from the database.
*
* @param uniqueIdentifier
* The unique identifier of the connection to retrieve.
*
* @param currentUser
* The user who queried this connection.
*
* @return
* The connection having the given unique identifier, or null if no
* such connection was found.
*/
public MySQLConnection retrieveConnection(String uniqueIdentifier, AuthenticatedUser currentUser) {
// The unique identifier for a MySQLConnection is the database ID
int connectionID;
try {
connectionID = Integer.parseInt(uniqueIdentifier);
} catch(NumberFormatException e) {
// Invalid number means it can't be a DB record; not found
return null;
}
return retrieveConnection(connectionID, currentUser);
}
/**
* Retrieves the connection having the given ID from the database.
*
* @param id
* The ID of the connection to retrieve.
*
* @param currentUser
* 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, AuthenticatedUser currentUser) {
// 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, currentUser);
}
/**
* Returns a list of the IDs of all connections with a given parent ID.
* @param parentID The ID of the parent for all the queried connections.
* @return a list of the IDs of all connections with a given parent ID.
*/
public List<Integer> getAllConnectionIDs(Integer parentID) {
// Create criteria
ConnectionExample example = new ConnectionExample();
Criteria criteria = example.createCriteria();
if(parentID != null)
criteria.andParent_idEqualTo(parentID);
else
criteria.andParent_idIsNull();
// Query the connections
List<Connection> connections = connectionDAO.selectByExample(example);
// List of IDs of connections with the given parent
List<Integer> connectionIDs = new ArrayList<Integer>();
for(Connection connection : connections) {
connectionIDs.add(connection.getConnection_id());
}
return connectionIDs;
}
/**
* Convert the given database-retrieved Connection into a MySQLConnection.
* The parameters of the given connection will be read and added to the
* MySQLConnection in the process.
*
* @param connection
* The connection to convert.
*
* @param currentUser
* The user who queried this connection.
*
* @return A new MySQLConnection containing all data associated with the
* specified connection.
*/
private MySQLConnection toMySQLConnection(Connection connection, AuthenticatedUser currentUser) {
// 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.getParent_id(),
connection.getConnection_name(),
Integer.toString(connection.getConnection_id()),
config,
retrieveHistory(connection.getConnection_id()),
currentUser
);
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());
}
// Determine whether connection is currently active
int user_count = activeConnectionMap.getCurrentUserCount(connectionID);
// 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());
// If there are active users, list the top N not-ended connections
// as active (best guess)
MySQLConnectionRecord connectionRecord;
if (user_count > 0 && endDate == null) {
connectionRecord = new MySQLConnectionRecord(startDate, endDate, username, true);
user_count--;
}
// If no active users, or end date is recorded, connection is not
// active.
else
connectionRecord = new MySQLConnectionRecord(startDate, endDate, username, false);
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 currentUser
* The user who is connecting to the socket.
*
* @param connectionGroupID
* The ID of the balancing connection group that is being connected to;
* null if not used.
*
* @return
* The connected socket.
*
* @throws GuacamoleException
* If an error occurs while connecting the socket.
*/
public MySQLGuacamoleSocket connect(MySQLConnection connection,
GuacamoleClientInformation info, AuthenticatedUser currentUser,
Integer connectionGroupID)
throws GuacamoleException {
synchronized (activeConnectionMap) {
// If the given connection is active, and multiple simultaneous
// connections are not allowed, disallow connection
if(GuacamoleProperties.getProperty(
MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS, false)
&& activeConnectionMap.isActive(connection.getConnectionID()))
throw new GuacamoleResourceConflictException("Cannot connect. This connection is in use.");
if(GuacamoleProperties.getProperty(
MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS, true)
&& activeConnectionMap.isConnectionUserActive(connection.getConnectionID(), currentUser.getUserID()))
throw new GuacamoleClientTooManyException
("Cannot connect. Connection already in use by this user.");
// Get guacd connection information
String host = GuacamoleProperties.getRequiredProperty(GuacamoleProperties.GUACD_HOSTNAME);
int port = GuacamoleProperties.getRequiredProperty(GuacamoleProperties.GUACD_PORT);
// Build token filter containing credential tokens
TokenFilter tokenFilter = new TokenFilter();
StandardTokens.addStandardTokens(tokenFilter, currentUser.getCredentials());
// Filter the configuration
GuacamoleConfiguration config = new GuacamoleConfiguration(connection.getConfiguration());
tokenFilter.filterValues(config.getParameters());
// Get socket
GuacamoleSocket socket;
if (GuacamoleProperties.getProperty(GuacamoleProperties.GUACD_SSL, false))
socket = new ConfiguredGuacamoleSocket(
new SSLGuacamoleSocket(host, port),
config, info
);
else
socket = new ConfiguredGuacamoleSocket(
new InetGuacamoleSocket(host, port),
config, info
);
// Mark this connection as active
int historyID = activeConnectionMap.openConnection(connection.getConnectionID(),
currentUser.getUserID(), connectionGroupID);
// Return new MySQLGuacamoleSocket
MySQLGuacamoleSocket mySQLGuacamoleSocket = mySQLGuacamoleSocketProvider.get();
mySQLGuacamoleSocket.init(socket, historyID, connectionGroupID);
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 currentUser
* The user who created this connection.
*
* @param parentID
* The ID of the parent connection group.
*
* @return
* A new MySQLConnection containing the data of the newly created
* connection.
*/
public MySQLConnection createConnection(String name, String protocol,
AuthenticatedUser currentUser, Integer parentID) {
// Initialize database connection
Connection connection = new Connection();
connection.setConnection_name(name);
connection.setProtocol(protocol);
connection.setParent_id(parentID);
// Create connection
connectionDAO.insert(connection);
return toMySQLConnection(connection, currentUser);
}
/**
* 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.setParent_id(mySQLConnection.getParentID());
connection.setConnection_name(mySQLConnection.getName());
connection.setProtocol(mySQLConnection.getConfiguration().getProtocol());
// Update the connection in the database
connectionDAO.updateByPrimaryKey(connection);
}
/**
* Get the identifiers of all the connections defined in the system
* with a certain parentID.
*
* @return A Set of identifiers of all the connections defined in the system
* with the given parentID.
*/
public Set<String> getAllConnectionIdentifiers(Integer parentID) {
// Set of all present connection identifiers
Set<String> identifiers = new HashSet<String>();
// Set up Criteria
ConnectionExample example = new ConnectionExample();
Criteria criteria = example.createCriteria();
if(parentID != null)
criteria.andParent_idEqualTo(parentID);
else
criteria.andParent_idIsNull();
// Query connection identifiers
List<Connection> connections =
connectionDAO.selectByExample(example);
for (Connection connection : connections)
identifiers.add(String.valueOf(connection.getConnection_id()));
return identifiers;
}
/**
* Get the connection IDs of all the connections defined in the system
* with a certain parent connection group.
*
* @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>();
// Create the criteria
ConnectionExample example = new ConnectionExample();
// Query the connections
List<Connection> connections =
connectionDAO.selectByExample(example);
for (Connection connection : connections)
connectionIDs.add(connection.getConnection_id());
return connectionIDs;
}
}

View File

@@ -0,0 +1,183 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.sourceforge.guacamole.net.auth.mysql.service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import net.sourceforge.guacamole.net.auth.mysql.DirectoryObject;
import net.sourceforge.guacamole.net.auth.mysql.dao.DirectoryObjectMapper;
/**
* Service which provides convenience methods for creating, retrieving, and
* manipulating users.
*
* @author Michael Jumper
* @param <ObjectType>
* The type of object this service provides access to.
*
* @param <ModelType>
* The underlying model object used to represent ObjectType in the
* database.
*/
public abstract class DirectoryObjectService<ObjectType extends DirectoryObject<ModelType>, ModelType> {
/**
* Returns an instance of a mapper for the type of object used by this
* service.
*
* @return
* A mapper which provides access to the model objects associated with
* the objects used by this service.
*/
protected abstract DirectoryObjectMapper<ModelType> getObjectMapper();
/**
* Returns an instance of an object which is backed by the given model
* object.
*
* @param model
* The model object to use to back the returned object.
*
* @return
* An object which is backed by the given model object.
*/
protected abstract ObjectType getObjectInstance(ModelType model);
/**
* Returns a collection of objects which are backed by the models in the
* given collection.
*
* @param models
* The model objects to use to back the objects within the returned
* collection.
*
* @return
* A collection of objects which are backed by the models in the given
* collection.
*/
protected Collection<ObjectType> getObjectInstances(Collection<ModelType> models) {
// Create new collection of objects by manually converting each model
Collection<ObjectType> objects = new ArrayList<ObjectType>(models.size());
for (ModelType model : models)
objects.add(getObjectInstance(model));
return objects;
}
/**
* Retrieves the single object that has the given identifier, if it exists.
*
* @param identifier
* The identifier of the object to retrieve.
*
* @return
* The object having the given identifier, or null if no such object
* exists.
*/
public ObjectType retrieveObject(String identifier) {
// Pull objects having given identifier
Collection<ObjectType> objects = retrieveObjects(Collections.singleton(identifier));
// If no such object, return null
if (objects.isEmpty())
return null;
// The object collection will have exactly one element unless the
// database has seriously lost integrity
assert(objects.size() == 1);
// Return first and only object
return objects.iterator().next();
}
/**
* Retrieves all objects that have the identifiers in the given collection.
*
* @param identifiers
* The identifiers of the objects to retrieve.
*
* @return
* The objects having the given identifiers.
*/
public Collection<ObjectType> retrieveObjects(Collection<String> identifiers) {
// Do not query if no identifiers given
if (identifiers.isEmpty())
return Collections.EMPTY_LIST;
// Return collection of requested objects
return getObjectInstances(getObjectMapper().select(identifiers));
}
/**
* Creates the given object within the database. If the object already
* exists, an error will be thrown. The internal model object will be
* updated appropriately to contain the new database ID.
*
* @param object
* The object to create.
*/
public void createObject(ObjectType object) {
getObjectMapper().insert(object.getModel());
}
/**
* Deletes the object having the given identifier. If no such object
* exists, this function has no effect.
*
* @param identifier
* The identifier of the object to delete.
*/
public void deleteObject(String identifier) {
getObjectMapper().delete(identifier);
}
/**
* Updates the given object in the database, applying any changes that have
* been made. If no such object exists, this function has no effect.
*
* @param object
* The object to update.
*/
public void updateObject(ObjectType object) {
getObjectMapper().update(object.getModel());
}
/**
* Returns the set of all identifiers for all objects in the database.
*
* @return
* The set of all identifiers for all objects in the database.
*/
public Set<String> getIdentifiers() {
return getObjectMapper().selectIdentifiers();
}
}

View File

@@ -22,27 +22,12 @@
package net.sourceforge.guacamole.net.auth.mysql.service; package net.sourceforge.guacamole.net.auth.mysql.service;
/** /**
* A service to perform password encryption and checking. * A service to perform password encryption and checking.
* @author James Muehlner * @author James Muehlner
*/ */
public interface PasswordEncryptionService { 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 * Creates a password hash based on the provided username, password, and
* salt. * salt.
@@ -52,4 +37,5 @@ public interface PasswordEncryptionService {
* @return The generated password hash. * @return The generated password hash.
*/ */
public byte[] createPasswordHash(String password, byte[] salt); public byte[] createPasswordHash(String password, byte[] salt);
} }

View File

@@ -1,968 +0,0 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package net.sourceforge.guacamole.net.auth.mysql.service;
import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sourceforge.guacamole.net.auth.mysql.AuthenticatedUser;
import org.glyptodon.guacamole.GuacamoleSecurityException;
import net.sourceforge.guacamole.net.auth.mysql.MySQLConnectionGroup;
import net.sourceforge.guacamole.net.auth.mysql.MySQLConstants;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionGroupPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.SystemPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.UserPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupPermissionExample;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupPermissionKey;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionExample;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionExample.Criteria;
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 org.glyptodon.guacamole.net.auth.permission.ConnectionGroupPermission;
import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission;
import org.glyptodon.guacamole.net.auth.permission.Permission;
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
import org.glyptodon.guacamole.net.auth.permission.UserPermission;
/**
* 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;
/**
* Service for accessing connection groups.
*/
@Inject
private ConnectionGroupService connectionGroupService;
/**
* 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 connection groups.
*/
@Inject
private ConnectionGroupPermissionMapper connectionGroupPermissionDAO;
/**
* 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 currentUser
* 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(AuthenticatedUser currentUser, int affectedUserID,
String permissionType) throws GuacamoleSecurityException {
// If permission does not exist, throw exception
if(!checkUserAccess(currentUser, 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 currentUser
* 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(AuthenticatedUser currentUser,
int affectedConnectionID, String permissionType) throws GuacamoleSecurityException {
// If permission does not exist, throw exception
if(!checkConnectionAccess(currentUser, affectedConnectionID, permissionType))
throw new GuacamoleSecurityException("Permission denied.");
}
/**
* Verifies that the user has the specified access to the given connection group.
* If permission is denied, a GuacamoleSecurityException is thrown.
*
* @param currentUser
* The user to check.
*
* @param affectedConnectionGroupID
* The connection group 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 verifyConnectionGroupAccess(AuthenticatedUser currentUser,
Integer affectedConnectionGroupID, String permissionType) throws GuacamoleSecurityException {
// If permission does not exist, throw exception
if(!checkConnectionGroupAccess(currentUser, affectedConnectionGroupID, 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 currentUser
* 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(AuthenticatedUser currentUser, String systemPermissionType)
throws GuacamoleSecurityException {
// If permission does not exist, throw exception
if(!checkSystemAccess(currentUser, systemPermissionType))
throw new GuacamoleSecurityException("Permission denied.");
}
/**
* Checks whether a user has the specified type of access to the affected
* user.
*
* @param currentUser
* 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(AuthenticatedUser currentUser,
Integer affectedUserID, String permissionType) {
// A system administrator has full access to everything.
if(checkSystemAdministratorAccess(currentUser))
return true;
// Check existence of requested permission
UserPermissionExample example = new UserPermissionExample();
example.createCriteria().andUser_idEqualTo(currentUser.getUserID()).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 currentUser
* 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(AuthenticatedUser currentUser,
Integer affectedConnectionID, String permissionType) {
// A system administrator has full access to everything.
if(checkSystemAdministratorAccess(currentUser))
return true;
// Check existence of requested permission
ConnectionPermissionExample example = new ConnectionPermissionExample();
example.createCriteria().andUser_idEqualTo(currentUser.getUserID()).andConnection_idEqualTo(affectedConnectionID).andPermissionEqualTo(permissionType);
return connectionPermissionDAO.countByExample(example) > 0;
}
/**
* Checks whether a user has the specified type of access to the affected
* connection group.
*
* @param currentUser
* The user to check.
*
* @param affectedConnectionGroupID
* The connection group 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 checkConnectionGroupAccess(AuthenticatedUser currentUser,
Integer affectedConnectionGroupID, String permissionType) {
// All users have implicit permission to read and update the root connection group
if(affectedConnectionGroupID == null &&
MySQLConstants.CONNECTION_GROUP_READ.equals(permissionType) ||
MySQLConstants.CONNECTION_GROUP_UPDATE.equals(permissionType))
return true;
// A system administrator has full access to everything.
if(checkSystemAdministratorAccess(currentUser))
return true;
// Check existence of requested permission
ConnectionGroupPermissionExample example = new ConnectionGroupPermissionExample();
example.createCriteria().andUser_idEqualTo(currentUser.getUserID()).andConnection_group_idEqualTo(affectedConnectionGroupID).andPermissionEqualTo(permissionType);
return connectionGroupPermissionDAO.countByExample(example) > 0;
}
/**
* Checks whether a user has the specified type of access to the system.
*
* @param currentUser
* 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(AuthenticatedUser currentUser, String systemPermissionType) {
// A system administrator has full access to everything.
if(checkSystemAdministratorAccess(currentUser))
return true;
// Check existence of requested permission
SystemPermissionExample example = new SystemPermissionExample();
example.createCriteria().andUser_idEqualTo(currentUser.getUserID()).andPermissionEqualTo(systemPermissionType);
return systemPermissionDAO.countByExample(example) > 0;
}
/**
* Checks whether a user has system administrator access to the system.
*
* @param currentUser
* The user to check.
*
* @return
* true if the system administrator access exists, false otherwise.
*/
private boolean checkSystemAdministratorAccess(AuthenticatedUser currentUser) {
// Check existence of system administrator permission
SystemPermissionExample example = new SystemPermissionExample();
example.createCriteria().andUser_idEqualTo(currentUser.getUserID())
.andPermissionEqualTo(MySQLConstants.SYSTEM_ADMINISTER);
return systemPermissionDAO.countByExample(example) > 0;
}
/**
* Verifies that the specified group can be used for organization
* by the given user.
*
* @param connectionGroupID
* The ID of the affected ConnectionGroup.
*
* @param currentUser
* The user to check.
*
* @param type
* The desired usage.
*
* @throws GuacamoleSecurityException
* If the connection group cannot be used for organization.
*/
public void verifyConnectionGroupUsageAccess(Integer connectionGroupID,
AuthenticatedUser currentUser, String type) throws GuacamoleSecurityException {
// If permission does not exist, throw exception
if(!checkConnectionGroupUsageAccess(connectionGroupID, currentUser, type))
throw new GuacamoleSecurityException("Permission denied.");
}
/**
* Check whether a user can use connectionGroup for the given usage.
*
* @param connectionGroupID
* The ID of the affected connection group.
*
* @param currentUser
* The user to check.
*
* @param usage
* The desired usage.
*
* @return
* true if the user can use the connection group for the given usage.
*/
private boolean checkConnectionGroupUsageAccess(
Integer connectionGroupID, AuthenticatedUser currentUser, String usage) {
// The root level connection group can only be used for organization
if(connectionGroupID == null)
return MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL.equals(usage);
// A system administrator has full access to everything.
if(checkSystemAdministratorAccess(currentUser))
return true;
// A connection group administrator can use the group either way.
if(checkConnectionGroupAccess(currentUser, connectionGroupID,
MySQLConstants.CONNECTION_GROUP_ADMINISTER))
return true;
// Query the connection group
MySQLConnectionGroup connectionGroup = connectionGroupService.
retrieveConnectionGroup(connectionGroupID, currentUser);
// If the connection group is not found, it cannot be used.
if(connectionGroup == null)
return false;
// Verify that the desired usage matches the type.
return MySQLConstants.getConnectionGroupTypeConstant(
connectionGroup.getType()).equals(usage);
}
/**
* Find the list of the IDs of all users a user has permission to.
* The access type is defined by permissionType.
*
* @param currentUser
* 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(AuthenticatedUser currentUser, String permissionType) {
// A system administrator has access to all users.
if(checkSystemAdministratorAccess(currentUser))
return userService.getAllUserIDs();
// Query all user permissions for the given user and permission type
UserPermissionExample example = new UserPermissionExample();
example.createCriteria().andUser_idEqualTo(currentUser.getUserID()).andPermissionEqualTo(permissionType);
example.setDistinct(true);
List<UserPermissionKey> userPermissions =
userPermissionDAO.selectByExample(example);
// Convert result into list of IDs
List<Integer> currentUsers = new ArrayList<Integer>(userPermissions.size());
for(UserPermissionKey permission : userPermissions)
currentUsers.add(permission.getAffected_user_id());
return currentUsers;
}
/**
* Find the list of the IDs of all connections a user has permission to.
* The access type is defined by permissionType.
*
* @param currentUser
* 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(AuthenticatedUser currentUser,
String permissionType) {
return retrieveConnectionIDs(currentUser, null, permissionType, false);
}
/**
* Find the list of the IDs of all connections a user has permission to.
* The access type is defined by permissionType.
*
* @param currentUser
* The user to check.
*
* @param parentID
* The parent connection group.
*
* @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(AuthenticatedUser currentUser, Integer parentID,
String permissionType) {
return retrieveConnectionIDs(currentUser, parentID, permissionType, true);
}
/**
* Find the list of the IDs of all connections a user has permission to.
* The access type is defined by permissionType.
*
* @param currentUser
* The user to check.
*
* @param parentID
* The parent connection group.
*
* @param permissionType
* The type of permission to check for.
*
* @param checkParentID
* Whether the parentID should be checked or not.
*
* @return
* A list of all connection IDs this user has the specified access to.
*/
private List<Integer> retrieveConnectionIDs(AuthenticatedUser currentUser, Integer parentID,
String permissionType, boolean checkParentID) {
// A system administrator has access to all connections.
if(checkSystemAdministratorAccess(currentUser)) {
if(checkParentID)
return connectionService.getAllConnectionIDs(parentID);
else
return connectionService.getAllConnectionIDs();
}
// Query all connection permissions for the given user and permission type
ConnectionPermissionExample example = new ConnectionPermissionExample();
Criteria criteria = example.createCriteria().andUser_idEqualTo(currentUser.getUserID())
.andPermissionEqualTo(permissionType);
// Ensure that the connections are all under the parent ID, if needed
if(checkParentID) {
// Get the IDs of all connections in the connection group
List<Integer> allConnectionIDs = connectionService.getAllConnectionIDs(parentID);
if(allConnectionIDs.isEmpty())
return Collections.EMPTY_LIST;
criteria.andConnection_idIn(allConnectionIDs);
}
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;
}
/**
* Find the list of the IDs of all connection groups a user has permission to.
* The access type is defined by permissionType.
*
* @param currentUser
* The user to check.
*
* @param permissionType
* The type of permission to check for.
*
* @return
* A list of all connection group IDs this user has the specified
* access to.
*/
public List<Integer> retrieveConnectionGroupIDs(AuthenticatedUser currentUser,
String permissionType) {
return retrieveConnectionGroupIDs(currentUser, null, permissionType, false);
}
/**
* Find the list of the IDs of all connection groups a user has permission to.
* The access type is defined by permissionType.
*
* @param currentUser
* The user to check.
*
* @param parentID
* The parent connection group.
*
* @param permissionType
* The type of permission to check for.
*
* @return
* A list of all connection group IDs this user has the specified
* access to.
*/
public List<Integer> retrieveConnectionGroupIDs(AuthenticatedUser currentUser, Integer parentID,
String permissionType) {
return retrieveConnectionGroupIDs(currentUser, parentID, permissionType, true);
}
/**
* Find the list of the IDs of all connection groups a user has permission to.
* The access type is defined by permissionType.
*
* @param currentUser
* The user to check.
*
* @param parentID
* The parent connection group.
*
* @param permissionType
* The type of permission to check for.
*
* @param checkParentID
* Whether the parentID should be checked or not.
*
* @return
* A list of all connection group IDs this user has the specified
* access to.
*/
private List<Integer> retrieveConnectionGroupIDs(AuthenticatedUser currentUser, Integer parentID,
String permissionType, boolean checkParentID) {
// A system administrator has access to all connectionGroups .
if(checkSystemAdministratorAccess(currentUser)) {
if(checkParentID)
return connectionGroupService.getAllConnectionGroupIDs(parentID);
else
return connectionGroupService.getAllConnectionGroupIDs();
}
// Query all connection permissions for the given user and permission type
ConnectionGroupPermissionExample example = new ConnectionGroupPermissionExample();
ConnectionGroupPermissionExample.Criteria criteria =
example.createCriteria().andUser_idEqualTo(currentUser.getUserID())
.andPermissionEqualTo(permissionType);
// Ensure that the connection groups are all under the parent ID, if needed
if(checkParentID) {
// Get the IDs of all connection groups in the connection group
List<Integer> allConnectionGroupIDs = connectionGroupService
.getAllConnectionGroupIDs(parentID);
if(allConnectionGroupIDs.isEmpty())
return Collections.EMPTY_LIST;
criteria.andConnection_group_idIn(allConnectionGroupIDs);
}
example.setDistinct(true);
List<ConnectionGroupPermissionKey> connectionGroupPermissions =
connectionGroupPermissionDAO.selectByExample(example);
// Convert result into list of IDs
List<Integer> connectionGroupIDs = new ArrayList<Integer>(connectionGroupPermissions.size());
for(ConnectionGroupPermissionKey permission : connectionGroupPermissions)
connectionGroupIDs.add(permission.getConnection_group_id());
// All users have implicit access to read and update the root group
if(MySQLConstants.CONNECTION_GROUP_READ.equals(permissionType)
&& MySQLConstants.CONNECTION_GROUP_UPDATE.equals(permissionType)
&& !checkParentID)
connectionGroupIDs.add(null);
return connectionGroupIDs;
}
/**
* Retrieve all existing usernames that the given user has permission to
* perform the given operation upon.
*
* @param currentUser
* 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(AuthenticatedUser currentUser, String permissionType) {
// A system administrator has access to all users.
if(checkSystemAdministratorAccess(currentUser))
return userService.getAllUsernames();
// List of all user IDs for which this user has read access
List<Integer> currentUsers =
retrieveUserIDs(currentUser, MySQLConstants.USER_READ);
// Query all associated users
return userService.translateUsernames(currentUsers).keySet();
}
/**
* Retrieve all existing connection identifiers that the given user has
* permission to perform the given operation upon.
*
* @param currentUser
* The user whose permissions should be checked.
*
* @param permissionType
* The permission to check.
*
* @param parentID
* The parent connection group.
*
* @return
* A set of all connection identifiers for which the given user has the
* given permission.
*/
public Set<String> retrieveConnectionIdentifiers(AuthenticatedUser currentUser, Integer parentID,
String permissionType) {
// A system administrator has access to all connections.
if(checkSystemAdministratorAccess(currentUser))
return connectionService.getAllConnectionIdentifiers(parentID);
// List of all connection IDs for which this user has access
List<Integer> connectionIDs =
retrieveConnectionIDs(currentUser, parentID, permissionType);
// Unique Identifiers for MySQLConnections are the database IDs
Set<String> connectionIdentifiers = new HashSet<String>();
for(Integer connectionID : connectionIDs)
connectionIdentifiers.add(Integer.toString(connectionID));
return connectionIdentifiers;
}
/**
* Retrieve all existing connection group identifiers that the given user
* has permission to perform the given operation upon.
*
* @param currentUser
* The user whose permissions should be checked.
*
* @param permissionType
* The permission to check.
*
* @param parentID
* The parent connection group.
*
* @return
* A set of all connection group identifiers for which the given user
* has the given permission.
*/
public Set<String> retrieveConnectionGroupIdentifiers(AuthenticatedUser currentUser, Integer parentID,
String permissionType) {
// A system administrator has access to all connections.
if(checkSystemAdministratorAccess(currentUser))
return connectionGroupService.getAllConnectionGroupIdentifiers(parentID);
// List of all connection group IDs for which this user has access
List<Integer> connectionGroupIDs =
retrieveConnectionGroupIDs(currentUser, parentID, permissionType);
// Unique Identifiers for MySQLConnectionGroups are the database IDs
Set<String> connectionGroupIdentifiers = new HashSet<String>();
for(Integer connectionGroupID : connectionGroupIDs)
connectionGroupIdentifiers.add(Integer.toString(connectionGroupID));
return connectionGroupIdentifiers;
}
/**
* 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);
// Add connection permissions
for(ConnectionPermissionKey connectionPermission : connectionPermissions) {
// Construct permission from data
ConnectionPermission permission = new ConnectionPermission(
ConnectionPermission.Type.valueOf(connectionPermission.getPermission()),
String.valueOf(connectionPermission.getConnection_id())
);
// Add to set
permissions.add(permission);
}
return permissions;
}
/**
* Retrieves all connection group 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 group permissions granted to the user having
* the given ID.
*/
public Set<ConnectionGroupPermission> retrieveConnectionGroupPermissions(int userID) {
// Set of all permissions
Set<ConnectionGroupPermission> permissions = new HashSet<ConnectionGroupPermission>();
// Query all connection permissions
ConnectionGroupPermissionExample connectionGroupPermissionExample = new ConnectionGroupPermissionExample();
connectionGroupPermissionExample.createCriteria().andUser_idEqualTo(userID);
List<ConnectionGroupPermissionKey> connectionGroupPermissions =
connectionGroupPermissionDAO.selectByExample(connectionGroupPermissionExample);
// Add connection permissions
for(ConnectionGroupPermissionKey connectionGroupPermission : connectionGroupPermissions) {
// Construct permission from data
ConnectionGroupPermission permission = new ConnectionGroupPermission(
ConnectionGroupPermission.Type.valueOf(connectionGroupPermission.getPermission()),
String.valueOf(connectionGroupPermission.getConnection_group_id())
);
// Add to set
permissions.add(permission);
}
// All users have implict access to read the root connection group
permissions.add(new ConnectionGroupPermission(
ConnectionGroupPermission.Type.READ,
MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER
));
// All users have implict access to update the root connection group
permissions.add(new ConnectionGroupPermission(
ConnectionGroupPermission.Type.UPDATE,
MySQLConstants.CONNECTION_GROUP_ROOT_IDENTIFIER
));
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 creation permission
else if(systemPermission.getPermission().equals(MySQLConstants.SYSTEM_CONNECTION_GROUP_CREATE))
permissions.add(new SystemPermission(SystemPermission.Type.CREATE_CONNECTION_GROUP));
// 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 connection group permissions
allPermissions.addAll(retrieveConnectionGroupPermissions(userID));
// Add system permissions
allPermissions.addAll(retrieveSystemPermissions(userID));
return allPermissions;
}
}

View File

@@ -25,7 +25,6 @@ package net.sourceforge.guacamole.net.auth.mysql.service;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.xml.bind.DatatypeConverter; import javax.xml.bind.DatatypeConverter;
/** /**
@@ -34,16 +33,6 @@ import javax.xml.bind.DatatypeConverter;
*/ */
public class SHA256PasswordEncryptionService implements PasswordEncryptionService { 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 @Override
public byte[] createPasswordHash(String password, byte[] salt) { public byte[] createPasswordHash(String password, byte[] salt) {
@@ -72,4 +61,5 @@ public class SHA256PasswordEncryptionService implements PasswordEncryptionServic
} }
} }
} }

View File

@@ -22,24 +22,13 @@
package net.sourceforge.guacamole.net.auth.mysql.service; package net.sourceforge.guacamole.net.auth.mysql.service;
import com.google.common.collect.Lists;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; 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 org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.Credentials; import org.glyptodon.guacamole.net.auth.Credentials;
import net.sourceforge.guacamole.net.auth.mysql.MySQLUser; import net.sourceforge.guacamole.net.auth.mysql.MySQLUser;
import net.sourceforge.guacamole.net.auth.mysql.dao.DirectoryObjectMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.UserMapper; 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.UserModel;
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 * Service which provides convenience methods for creating, retrieving, and
@@ -47,13 +36,13 @@ import net.sourceforge.guacamole.net.auth.mysql.model.UserWithBLOBs;
* *
* @author Michael Jumper, James Muehlner * @author Michael Jumper, James Muehlner
*/ */
public class UserService { public class UserService extends DirectoryObjectService<MySQLUser, UserModel> {
/** /**
* DAO for accessing users. * Mapper for accessing users.
*/ */
@Inject @Inject
private UserMapper userDAO; private UserMapper userMapper;
/** /**
* Provider for creating users. * Provider for creating users.
@@ -61,106 +50,16 @@ public class UserService {
@Inject @Inject
private Provider<MySQLUser> mySQLUserProvider; private Provider<MySQLUser> mySQLUserProvider;
/** @Override
* Service for checking permissions. protected DirectoryObjectMapper<UserModel> getObjectMapper() {
*/ return userMapper;
@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(org.glyptodon.guacamole.net.auth.User user) throws GuacamoleException {
MySQLUser mySQLUser = mySQLUserProvider.get();
mySQLUser.init(user);
return mySQLUser;
} }
/** @Override
* Create a new MySQLUser based on the provided database record. protected MySQLUser getObjectInstance(UserModel model) {
* MySQLUser user = mySQLUserProvider.get();
* @param user The database record describing the user. user.setModel(model);
* @return A new MySQLUser object, populated with the data of the given return user;
* 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));
} }
/** /**
@@ -173,194 +72,18 @@ public class UserService {
*/ */
public MySQLUser retrieveUser(Credentials credentials) { public MySQLUser retrieveUser(Credentials credentials) {
// No null users in database // Get username and password
if (credentials.getUsername() == null) String username = credentials.getUsername();
String password = credentials.getPassword();
// Retrieve user model, if the user exists
UserModel userModel = userMapper.selectByCredentials(username, password);
if (userModel == null)
return null; return null;
// Query user // Return corresponding user
UserExample userExample = new UserExample(); return getObjectInstance(userModel);
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

@@ -1,136 +0,0 @@
<?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">
<!--
Copyright (C) 2013 Glyptodon LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<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_group"
catalog="${guacamole.database.catalog}"
schema="${guacamole.database.schema}"
domainObjectName="ConnectionGroup" >
<property name="useActualColumnNames" value="true"/>
<property name="ignoreQualifiersAtRuntime" value="true"/>
<generatedKey column="connection_group_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_connection_group_permission"
catalog="${guacamole.database.catalog}"
schema="${guacamole.database.schema}"
domainObjectName="ConnectionGroupPermission" >
<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>

View File

@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<!--
Copyright (C) 2015 Glyptodon LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<mapper namespace="net.sourceforge.guacamole.net.auth.mysql.dao.UserMapper" >
<!-- Result mapper for user objects -->
<resultMap id="UserResultMap" type="net.sourceforge.guacamole.net.auth.mysql.model.UserModel" >
<id column="user_id" property="userID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="password_hash" property="passwordHash" jdbcType="BINARY"/>
<result column="password_salt" property="passwordSalt" jdbcType="BINARY"/>
</resultMap>
<!-- Select all usernames -->
<select id="selectIdentifiers" resultType="string">
SELECT username
FROM guacamole_user
</select>
<!-- Select multiple users by username -->
<select id="select" resultMap="UserResultMap">
SELECT
user_id,
username,
password_hash,
password_salt
FROM guacamole_user
WHERE username IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
</select>
<select id="selectByCredentials" resultMap="UserResultMap">
SELECT
user_id,
username,
password_hash,
password_salt
FROM guacamole_user
WHERE
username = #{username,jdbcType=VARCHAR}
AND password_hash = UNHEX(SHA2(CONCAT(#{password,jdbcType=VARCHAR}, HEX(password_salt)), 256))
</select>
<!-- Delete single user by username -->
<delete id="delete">
DELETE FROM guacamole_user
WHERE username = #{identifier,jdbcType=VARCHAR}
</delete>
<!-- Insert single user -->
<insert id="insert" parameterType="net.sourceforge.guacamole.net.auth.mysql.model.UserModel">
INSERT INTO guacamole_user (
username,
password_hash,
password_salt
)
VALUES (
#{username,jdbcType=VARCHAR},
#{passwordHash,jdbcType=BINARY},
#{passwordSalt,jdbcType=BINARY}
)
<selectKey resultType="java.lang.Integer" keyProperty="userID" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
</insert>
<!-- Update single user -->
<update id="update" parameterType="net.sourceforge.guacamole.net.auth.mysql.model.UserModel">
UPDATE guacamole_user
SET password_hash = #{passwordHash,jdbcType=BINARY},
password_salt = #{passwordSalt,jdbcType=BINARY}
WHERE user_id = #{userID,jdbcType=VARCHAR}
</update>
</mapper>