mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-27 23:23:07 +00:00 
			
		
		
		
	Ticket #390: Added mysql-disallow-duplicate-connections property and enforced connection and connectionGroup access restrictions thereof.
This commit is contained in:
		| @@ -112,6 +112,76 @@ public class ActiveConnectionMap { | ||||
|             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 connectionID;  | ||||
|          | ||||
|         /** | ||||
|          * 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 getConnectionGroupID() { | ||||
|             return connectionID; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * 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 connectionID The connection or connection group ID that this  | ||||
|          *                          ConnectionUser refers to. | ||||
|          * @param userID The user ID that this ConnectionUser refers to. | ||||
|          */ | ||||
|         public ConnectionUser(int connectionID, int userID) { | ||||
|             this.connectionID = connectionID; | ||||
|             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.connectionID == otherConnectionGroupUser.connectionID | ||||
|                     && this.userID == otherConnectionGroupUser.userID; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public int hashCode() { | ||||
|             int hash = 3; | ||||
|             hash = 23 * hash + this.connectionID; | ||||
|             hash = 23 * hash + this.userID; | ||||
|             return hash; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * DAO for accessing connection history. | ||||
| @@ -120,11 +190,160 @@ public class ActiveConnectionMap { | ||||
|     private ConnectionHistoryMapper connectionHistoryDAO; | ||||
|  | ||||
|     /** | ||||
|      * Map of all the connections that are currently active the | ||||
|      * 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 connectionGroups opened by the given user using  | ||||
|      * the given ConnectionGroup. | ||||
|      *  | ||||
|      * @param connectionID 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 = getConnectionGroupUserCount(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 = getConnectionGroupUserCount(connectionID, userID); | ||||
|          | ||||
|         activeConnectionUserMap.put | ||||
|                 (new ConnectionUser(connectionID, userID), currentCount - 1); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Returns the ID of the connection with the lowest number of current | ||||
| @@ -232,9 +451,11 @@ public class ActiveConnectionMap { | ||||
|      * 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 connectionID 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) { | ||||
|     public int openConnection(int connectionID, int userID, Integer connectionGroupID) { | ||||
|  | ||||
|         // Create the connection history record | ||||
|         ConnectionHistory connectionHistory = new ConnectionHistory(); | ||||
| @@ -245,6 +466,13 @@ public class ActiveConnectionMap { | ||||
|  | ||||
|         // 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(); | ||||
|     } | ||||
| @@ -252,11 +480,14 @@ public class ActiveConnectionMap { | ||||
|     /** | ||||
|      * Set a connection as closed. | ||||
|      * @param connectionID The ID of the connection that is being opened. | ||||
|      * @param userID The ID of the user who is opening the connection. | ||||
|      * @param historyID The ID of the history record about the open connection. | ||||
|      * @param connectionID 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 connectionID, int historyID) | ||||
|             throws GuacamoleException { | ||||
|     public void closeConnection(int connectionID, int userID, int historyID,  | ||||
|             Integer connectionGroupID) throws GuacamoleException { | ||||
|  | ||||
|         // Get the existing history record | ||||
|         ConnectionHistory connectionHistory = | ||||
| @@ -271,5 +502,12 @@ public class ActiveConnectionMap { | ||||
|  | ||||
|         // 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); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -145,7 +145,7 @@ public class MySQLConnection extends AbstractConnection { | ||||
|  | ||||
|     @Override | ||||
|     public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException { | ||||
|         return connectionService.connect(this, info, userID); | ||||
|         return connectionService.connect(this, info, userID, null); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -66,25 +66,42 @@ public class MySQLGuacamoleSocket implements GuacamoleSocket { | ||||
|      */ | ||||
|     private int connectionID; | ||||
|  | ||||
|     /** | ||||
|      * The ID of the user who is connecting to the socket. | ||||
|      */ | ||||
|     private int userID; | ||||
|  | ||||
|     /** | ||||
|      * The ID of the history record associated with this instance of the | ||||
|      * connection. | ||||
|      */ | ||||
|     private int historyID; | ||||
|  | ||||
|     /** | ||||
|      * The ID of the balancing connection group that is being connected to;  | ||||
|      * null if not used. | ||||
|      */ | ||||
|     private Integer connectionGroupID; | ||||
|  | ||||
|     /** | ||||
|      * Initialize this MySQLGuacamoleSocket with the provided GuacamoleSocket. | ||||
|      * | ||||
|      * @param socket The ConfiguredGuacamoleSocket to wrap. | ||||
|      * @param connectionID The ID of the connection associated with the given | ||||
|      *                     socket. | ||||
|      * @param userID The ID of the user who is connecting to the socket. | ||||
|      * @param historyID The ID of the history record associated with this | ||||
|      *                  instance of the connection. | ||||
|      * @param connectionGroupID The ID of the balancing connection group that is | ||||
|      *                          being connected to; null if not used. | ||||
|      */ | ||||
|     public void init(GuacamoleSocket socket, int connectionID, int historyID) { | ||||
|     public void init(GuacamoleSocket socket, int connectionID, int userID,  | ||||
|             int historyID, Integer connectionGroupID) { | ||||
|         this.socket = socket; | ||||
|         this.connectionID = connectionID; | ||||
|         this.userID = userID; | ||||
|         this.historyID = historyID; | ||||
|         this.connectionGroupID = connectionGroupID; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -104,7 +121,8 @@ public class MySQLGuacamoleSocket implements GuacamoleSocket { | ||||
|         socket.close(); | ||||
|  | ||||
|         // Mark this connection as inactive | ||||
|         activeConnectionSet.closeConnection(connectionID, historyID); | ||||
|         activeConnectionSet.closeConnection(connectionID, userID,  | ||||
|                 historyID, connectionGroupID); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -109,4 +109,16 @@ public class MySQLGuacamoleProperties { | ||||
|         public String getName() { return "mysql-disallow-simultaneous-connections"; } | ||||
|  | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Whether or not the same user accessing the same connection or connection group at the same time should be disallowed. | ||||
|      */ | ||||
|     public static final BooleanGuacamoleProperty MYSQL_DISALLOW_DUPLICATE_CONNECTIONS = new BooleanGuacamoleProperty() { | ||||
|  | ||||
|         @Override | ||||
|         public String getName() { return "mysql-disallow-duplicate-connections"; } | ||||
|  | ||||
|     }; | ||||
|      | ||||
|      | ||||
| } | ||||
|   | ||||
| @@ -218,12 +218,18 @@ public class ConnectionGroupService { | ||||
|             throw new GuacamoleClientException | ||||
|                     ("Cannot connect. All connections are in use."); | ||||
|          | ||||
|         if(GuacamoleProperties.getProperty( | ||||
|                 MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS, true) | ||||
|                 && activeConnectionMap.isConnectionGroupUserActive(group.getConnectionGroupID(), userID)) | ||||
|             throw new GuacamoleClientException | ||||
|                     ("Cannot connect. Connection group already in use by this user."); | ||||
|          | ||||
|         // Get the connection  | ||||
|         MySQLConnection connection = connectionService | ||||
|                 .retrieveConnection(leastUsedConnectionID, userID); | ||||
|          | ||||
|         // Connect to the connection | ||||
|         return connectionService.connect(connection, info, userID); | ||||
|         return connectionService.connect(connection, info, userID, group.getConnectionGroupID()); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|   | ||||
| @@ -316,6 +316,8 @@ public class ConnectionService { | ||||
|  | ||||
|         return connectionRecords; | ||||
|     } | ||||
|      | ||||
|      | ||||
|  | ||||
|     /** | ||||
|      * Create a MySQLGuacamoleSocket using the provided connection. | ||||
| @@ -324,12 +326,14 @@ public class ConnectionService { | ||||
|      * @param info The information to use when performing the connection | ||||
|      *             handshake. | ||||
|      * @param userID The ID of 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, int userID) | ||||
|             GuacamoleClientInformation info, int userID, Integer connectionGroupID) | ||||
|         throws GuacamoleException { | ||||
|  | ||||
|         // If the given connection is active, and multiple simultaneous | ||||
| @@ -338,6 +342,12 @@ public class ConnectionService { | ||||
|                 MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS, false) | ||||
|                 && activeConnectionMap.isActive(connection.getConnectionID())) | ||||
|             throw new GuacamoleClientException("Cannot connect. This connection is in use."); | ||||
|          | ||||
|         if(GuacamoleProperties.getProperty( | ||||
|                 MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS, true) | ||||
|                 && activeConnectionMap.isConnectionUserActive(connection.getConnectionID(), userID)) | ||||
|             throw new GuacamoleClientException | ||||
|                     ("Cannot connect. Connection already in use by this user."); | ||||
|  | ||||
|         // Get guacd connection information | ||||
|         String host = GuacamoleProperties.getProperty(GuacamoleProperties.GUACD_HOSTNAME); | ||||
| @@ -357,11 +367,14 @@ public class ConnectionService { | ||||
|             ); | ||||
|  | ||||
|         // Mark this connection as active | ||||
|         int historyID = activeConnectionMap.openConnection(connection.getConnectionID(), userID); | ||||
|         int historyID = activeConnectionMap.openConnection(connection.getConnectionID(),  | ||||
|                 userID, connectionGroupID); | ||||
|  | ||||
|         // Return new MySQLGuacamoleSocket | ||||
|         MySQLGuacamoleSocket mySQLGuacamoleSocket = mySQLGuacamoleSocketProvider.get(); | ||||
|         mySQLGuacamoleSocket.init(socket, connection.getConnectionID(), historyID); | ||||
|         mySQLGuacamoleSocket.init(socket, connection.getConnectionID(), userID,  | ||||
|                 historyID, connectionGroupID); | ||||
|          | ||||
|         return mySQLGuacamoleSocket; | ||||
|  | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user