diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java index 25604baad..a1063dab8 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java @@ -42,7 +42,6 @@ import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.name.Names; -import java.util.List; import java.util.Properties; import net.sourceforge.guacamole.GuacamoleException; import net.sourceforge.guacamole.net.auth.AuthenticationProvider; @@ -55,8 +54,6 @@ import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionPermissionMapper; import net.sourceforge.guacamole.net.auth.mysql.dao.SystemPermissionMapper; import net.sourceforge.guacamole.net.auth.mysql.dao.UserMapper; import net.sourceforge.guacamole.net.auth.mysql.dao.UserPermissionMapper; -import net.sourceforge.guacamole.net.auth.mysql.model.UserExample; -import net.sourceforge.guacamole.net.auth.mysql.model.UserWithBLOBs; import net.sourceforge.guacamole.net.auth.mysql.properties.MySQLGuacamoleProperties; import net.sourceforge.guacamole.net.auth.mysql.service.ConfigurationTranslationService; import net.sourceforge.guacamole.net.auth.mysql.service.PasswordEncryptionService; @@ -65,6 +62,7 @@ import net.sourceforge.guacamole.net.auth.mysql.service.ProviderService; import net.sourceforge.guacamole.net.auth.mysql.service.SaltService; import net.sourceforge.guacamole.net.auth.mysql.service.SecureRandomSaltService; import net.sourceforge.guacamole.net.auth.mysql.service.Sha256PasswordEncryptionService; +import net.sourceforge.guacamole.net.auth.mysql.service.UserService; import net.sourceforge.guacamole.properties.GuacamoleProperties; import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; import org.mybatis.guice.MyBatisModule; @@ -93,43 +91,19 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider { @Override public UserContext getUserContext(Credentials credentials) throws GuacamoleException { - // No null users in database - if (credentials.getUsername() == null) - return null; + // Get user service + UserService userService = injector.getInstance(UserService.class); + + // Get user + MySQLUser authenticatedUser = userService.retrieveUser(credentials); + if (authenticatedUser != null) { + MySQLUserContext context = injector.getInstance(MySQLUserContext.class); + context.init(authenticatedUser.getUserID()); + return context; + } - // Get user DAO - UserMapper userDAO = injector.getInstance(UserMapper.class); - - // Query user - UserExample userExample = new UserExample(); - userExample.createCriteria().andUsernameEqualTo(credentials.getUsername()); - List users = userDAO.selectByExampleWithBLOBs(userExample); - - // The unique constraint on the table should prevent this. - if (users.size() > 1) - throw new GuacamoleException( - "Multiple users found with the same username: " - + credentials.getUsername()); - - // Check that a user was found - if (users.isEmpty()) - throw new GuacamoleException("No user found with the supplied credentials"); - - // Get first (and only) user - UserWithBLOBs user = users.get(0); - - // Get password service - PasswordEncryptionService passwordService = - injector.getInstance(PasswordEncryptionService.class); - - // Check password, if invalid return null - if (!passwordService.checkPassword(credentials.getPassword(), - user.getPassword_hash(), user.getPassword_salt())) - return null; - - MySQLUserContext context = injector.getInstance(MySQLUserContext.class); - context.init(user.getUser_id()); - return context; + // Otherwise, unauthorized + return null; } @@ -192,6 +166,7 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider { bind(PasswordEncryptionService.class).to(Sha256PasswordEncryptionService.class); bind(PermissionCheckService.class); bind(ProviderService.class); + bind(UserService.class); bind(ConfigurationTranslationService.class); bind(ActiveConnectionSet.class).toInstance(activeConnectionSet); diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnectionRecord.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnectionRecord.java index 552698cb3..499853792 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnectionRecord.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLConnectionRecord.java @@ -42,10 +42,9 @@ import java.util.Date; import net.sourceforge.guacamole.net.auth.Connection; import net.sourceforge.guacamole.net.auth.ConnectionRecord; import net.sourceforge.guacamole.net.auth.User; -import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionMapper; -import net.sourceforge.guacamole.net.auth.mysql.dao.UserMapper; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionHistory; import net.sourceforge.guacamole.net.auth.mysql.service.ProviderService; +import net.sourceforge.guacamole.net.auth.mysql.service.UserService; /** * A ConnectionRecord which is based on data stored in MySQL. @@ -60,16 +59,10 @@ public class MySQLConnectionRecord implements ConnectionRecord { private ConnectionHistory connectionHistory; /** - * DAO for accessing users. + * Service for accessing users. */ @Inject - private UserMapper userDAO; - - /** - * DAO for accessing connections. - */ - @Inject - private ConnectionMapper connectionDAO; + private UserService userService; /** * Service for creating and retrieving objects. @@ -100,7 +93,9 @@ public class MySQLConnectionRecord implements ConnectionRecord { @Override public User getUser() { - return providerService.getExistingMySQLUser(connectionHistory.getUser_id()); + // FIXME: This will be SLOW - history is queried in bulk. When listed + // to the user in the webapp, this will result in one query per record. + return userService.retrieveUser(connectionHistory.getUser_id()); } @Override diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUserContext.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUserContext.java index 308b9c4db..94cc3991e 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUserContext.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLUserContext.java @@ -43,7 +43,7 @@ import net.sourceforge.guacamole.net.auth.Connection; import net.sourceforge.guacamole.net.auth.Directory; import net.sourceforge.guacamole.net.auth.User; import net.sourceforge.guacamole.net.auth.UserContext; -import net.sourceforge.guacamole.net.auth.mysql.service.ProviderService; +import net.sourceforge.guacamole.net.auth.mysql.service.UserService; /** * The MySQL representation of a UserContext. @@ -72,10 +72,10 @@ public class MySQLUserContext implements UserContext { private ConnectionDirectory connectionDirectory; /** - * Service for retrieving existing objects or creating new ones. + * Service for accessing users. */ @Inject - private ProviderService providerService; + private UserService userService; /** * Initializes the user and directories associated with this context. @@ -90,7 +90,7 @@ public class MySQLUserContext implements UserContext { @Override public User self() { - return providerService.getExistingMySQLUser(user_id); + return userService.retrieveUser(user_id); } @Override diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/UserDirectory.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/UserDirectory.java index 2aab36cdc..22c12a242 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/UserDirectory.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/UserDirectory.java @@ -52,7 +52,6 @@ import net.sourceforge.guacamole.net.auth.Directory; import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionMapper; import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionPermissionMapper; import net.sourceforge.guacamole.net.auth.mysql.dao.SystemPermissionMapper; -import net.sourceforge.guacamole.net.auth.mysql.dao.UserMapper; import net.sourceforge.guacamole.net.auth.mysql.dao.UserPermissionMapper; import net.sourceforge.guacamole.net.auth.mysql.model.Connection; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionExample; @@ -60,15 +59,12 @@ import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionExampl 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.User; -import net.sourceforge.guacamole.net.auth.mysql.model.UserExample; 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.model.UserWithBLOBs; 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.ProviderService; import net.sourceforge.guacamole.net.auth.mysql.service.SaltService; +import net.sourceforge.guacamole.net.auth.mysql.service.UserService; import net.sourceforge.guacamole.net.auth.permission.ConnectionPermission; import net.sourceforge.guacamole.net.auth.permission.Permission; import net.sourceforge.guacamole.net.auth.permission.SystemPermission; @@ -88,10 +84,10 @@ public class UserDirectory implements Directory dbUsers = userDAO.selectByExample(userExample); + List users = userService.retrieveUsersByUsername(usernames); // Build map of found users, indexed by username - Map dbUserMap = new HashMap(); - for (User dbUser : dbUsers) { - dbUserMap.put(dbUser.getUsername(), dbUser); - } + Map userMap = new HashMap(); + for (MySQLUser user : users) + userMap.put(user.getUsername(), user); for (UserPermission permission : permissions) { // Get user - User dbAffectedUser = dbUserMap.get(permission.getObjectIdentifier()); - if (dbAffectedUser == null) + MySQLUser affectedUser = + userMap.get(permission.getObjectIdentifier()); + if (affectedUser == null) throw new GuacamoleException( "User '" + permission.getObjectIdentifier() + "' not found."); // Verify that the user actually has permission to administrate // every one of these users - if (!administerableUsers.contains(dbAffectedUser.getUser_id())) + if (!administerableUsers.contains(affectedUser.getUserID())) throw new GuacamoleSecurityException( "User #" + this.user_id + " does not have permission to administrate user " - + dbAffectedUser.getUser_id()); + + affectedUser.getUsername()); // Create new permission UserPermissionKey newPermission = new UserPermissionKey(); - newPermission.setAffected_user_id(dbAffectedUser.getUser_id()); + newPermission.setAffected_user_id(affectedUser.getUserID()); newPermission.setPermission(permission.getType().name()); newPermission.setUser_id(user_id); userPermissionDAO.insert(newPermission); @@ -383,35 +360,33 @@ public class UserDirectory implements Directory dbUsers = userDAO.selectByExample(userExample); + List users = userService.retrieveUsersByUsername(usernames); List userIDs = new ArrayList(); // Build map of found users, indexed by username - Map dbUserMap = new HashMap(); - for (User dbUser : dbUsers) { - dbUserMap.put(dbUser.getUsername(), dbUser); - userIDs.add(dbUser.getUser_id()); + Map userMap = new HashMap(); + for (MySQLUser user : users) { + userMap.put(user.getUsername(), user); + userIDs.add(user.getUserID()); } // Verify we have permission to delete each user permission. for (UserPermission permission : permissions) { // Get user - User dbAffectedUser = dbUserMap.get(permission.getObjectIdentifier()); - if (dbAffectedUser == null) + MySQLUser affectedUser = userMap.get(permission.getObjectIdentifier()); + if (affectedUser == null) throw new GuacamoleException( "User '" + permission.getObjectIdentifier() + "' not found."); // Verify that the user actually has permission to administrate // every one of these users - if (!administerableUsers.contains(dbAffectedUser.getUser_id())) + if (!administerableUsers.contains(affectedUser.getUserID())) throw new GuacamoleSecurityException( "User #" + this.user_id + " does not have permission to administrate user " - + dbAffectedUser.getUser_id()); + + affectedUser.getUsername()); } if(!userIDs.isEmpty()) { @@ -663,22 +638,9 @@ public class UserDirectory implements Directory userDBOjects = userDAO.selectByExampleWithBLOBs(example); - - // Build set of MySQLUsers from retrieved user data - Set affectedUsers = new HashSet(); - for(UserWithBLOBs affectedUser : userDBOjects) { - MySQLUser mySQLUser = mySQLUserProvider.get(); - mySQLUser.init(affectedUser.getUsername()); - affectedUsers.add(mySQLUser); - } - - return affectedUsers; + return new HashSet(userService.retrieveUsersByID( + Lists.newArrayList(affectedUserIDs))); } @@ -803,21 +788,6 @@ public class PermissionCheckService { return connections.get(0); } - /** - * Get a user object by username. - * @param userName - * @return - */ - private User getUser(String username) { - UserExample example = new UserExample(); - example.createCriteria().andUsernameEqualTo(username); - List users = userDAO.selectByExample(example); - if(users.isEmpty()) - return null; - - return users.get(0); - } - /** * Get all permissions a given user has. * @param userID @@ -841,16 +811,14 @@ public class PermissionCheckService { affectedUserIDs.add(userPermission.getAffected_user_id()); // Query all affected users, store in map indexed by user ID - UserExample userExample = new UserExample(); - userExample.createCriteria().andUser_idIn(affectedUserIDs); - List users = userDAO.selectByExample(userExample); - Map userMap = new HashMap(); - for(User user : users) - userMap.put(user.getUser_id(), user); + List users = userService.retrieveUsersByID(affectedUserIDs); + Map userMap = new HashMap(); + for (MySQLUser user : users) + userMap.put(user.getUserID(), user); // Add user permissions for(UserPermissionKey userPermission : userPermissions) { - User affectedUser = userMap.get(userPermission.getAffected_user_id()); + MySQLUser affectedUser = userMap.get(userPermission.getAffected_user_id()); UserPermission newPermission = new UserPermission( UserPermission.Type.valueOf(userPermission.getPermission()), affectedUser.getUsername() diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/ProviderService.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/ProviderService.java index c2f5b3902..a562a1629 100644 --- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/ProviderService.java +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/ProviderService.java @@ -42,22 +42,17 @@ import java.util.Collections; import java.util.List; import net.sourceforge.guacamole.GuacamoleException; import net.sourceforge.guacamole.net.auth.Connection; -import net.sourceforge.guacamole.net.auth.User; 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.MySQLUser; 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.UserMapper; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionExample; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionHistory; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionHistoryExample; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionParameter; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionParameterExample; -import net.sourceforge.guacamole.net.auth.mysql.model.UserExample; -import net.sourceforge.guacamole.net.auth.mysql.model.UserWithBLOBs; import net.sourceforge.guacamole.protocol.ConfiguredGuacamoleSocket; import net.sourceforge.guacamole.protocol.GuacamoleConfiguration; @@ -67,9 +62,6 @@ import net.sourceforge.guacamole.protocol.GuacamoleConfiguration; */ public class ProviderService { - @Inject - private UserMapper userDAO; - @Inject private ConnectionMapper connectionDAO; @@ -79,9 +71,6 @@ public class ProviderService { @Inject private ConnectionHistoryMapper connectionHistoryDAO; - @Inject - private Provider mySQLUserProvider; - @Inject private Provider mySQLConnectionProvider; @@ -91,92 +80,6 @@ public class ProviderService { @Inject private Provider mySQLGuacamoleSocketProvider; - /** - * Service for checking permissions. - */ - @Inject - private PermissionCheckService permissionCheckService; - - /** - * Create a new user based on the provided object. - * @param user - * @return the new MySQLUser object. - * @throws GuacamoleException - */ - public MySQLUser getNewMySQLUser(User user) throws GuacamoleException { - MySQLUser mySQLUser = mySQLUserProvider.get(); - mySQLUser.init(user); - return mySQLUser; - } - - /** - * Get the user based on the username of the provided object. - * @param user - * @return the new MySQLUser object. - * @throws GuacamoleException - */ - public MySQLUser getExistingMySQLUser(User user) throws GuacamoleException { - return getExistingMySQLUser(user.getUsername()); - } - - /** - * Get the user based on the username of the provided object. - * @param name - * @return the new MySQLUser object. - * @throws GuacamoleException - */ - public MySQLUser getExistingMySQLUser(String name) throws GuacamoleException { - - // Query user by ID - UserExample example = new UserExample(); - example.createCriteria().andUsernameEqualTo(name); - List users = userDAO.selectByExampleWithBLOBs(example); - - // If no user found, return null - if(users.isEmpty()) - return null; - - // Otherwise, return found user - return getExistingMySQLUser(users.get(0)); - - } - - /** - * Get an existing MySQLUser from a user database record. - * @param user - * @return the existing MySQLUser object. - */ - public MySQLUser getExistingMySQLUser(UserWithBLOBs user) { - MySQLUser mySQLUser = mySQLUserProvider.get(); - mySQLUser.init( - user.getUser_id(), - user.getUsername(), - null, - permissionCheckService.getAllPermissions(user.getUser_id()) - ); - - return mySQLUser; - } - - /** - * Get an existing MySQLUser from a user ID. - * @param id - * @return the existing MySQLUser object if found, null if not. - */ - public MySQLUser getExistingMySQLUser(Integer 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 getExistingMySQLUser(user); - - } - /** * Get the connection based on the connection name of the provided object. * @param connection diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/UserService.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/UserService.java new file mode 100644 index 000000000..26fae323a --- /dev/null +++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/UserService.java @@ -0,0 +1,382 @@ + +package net.sourceforge.guacamole.net.auth.mysql.service; + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is guacamole-auth-mysql. + * + * The Initial Developer of the Original Code is + * James Muehlner. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +import com.google.inject.Inject; +import com.google.inject.Provider; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import net.sourceforge.guacamole.GuacamoleException; +import net.sourceforge.guacamole.net.auth.Credentials; +import net.sourceforge.guacamole.net.auth.User; +import net.sourceforge.guacamole.net.auth.mysql.MySQLUser; +import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionPermissionMapper; +import net.sourceforge.guacamole.net.auth.mysql.dao.SystemPermissionMapper; +import net.sourceforge.guacamole.net.auth.mysql.dao.UserMapper; +import net.sourceforge.guacamole.net.auth.mysql.dao.UserPermissionMapper; +import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionExample; +import net.sourceforge.guacamole.net.auth.mysql.model.SystemPermissionExample; +import net.sourceforge.guacamole.net.auth.mysql.model.UserExample; +import net.sourceforge.guacamole.net.auth.mysql.model.UserPermissionExample; +import net.sourceforge.guacamole.net.auth.mysql.model.UserWithBLOBs; + +/** + * Service which provides convenience methods for creating, retrieving, and + * manipulating users. + * + * @author Michael Jumper, James Muehlner + */ +public class UserService { + + /** + * DAO for accessing users. + */ + @Inject + private UserMapper userDAO; + + /** + * DAO for accessing user permissions, which will be injected. + */ + @Inject + private UserPermissionMapper userPermissionDAO; + + /** + * DAO for accessing connection permissions, which will be injected. + */ + @Inject + private ConnectionPermissionMapper connectionPermissionDAO; + + /** + * DAO for accessing system permissions, which will be injected. + */ + @Inject + private SystemPermissionMapper systemPermissionDAO; + + /** + * Provider for creating users. + */ + @Inject + private Provider mySQLUserProvider; + + /** + * Service for checking permissions. + */ + @Inject + private PermissionCheckService permissionCheckService; + + /** + * Service for encrypting passwords. + */ + @Inject + private PasswordEncryptionService passwordService; + + /** + * Service for generating random salts. + */ + @Inject + private SaltService saltService; + + /** + * Create a new MySQLUser based on the provided User. + * + * @param user The User to use when populating the data of the given + * MySQLUser. + * @return A new MySQLUser object, populated with the data of the given + * user. + * + * @throws GuacamoleException If an error occurs while reading the data + * of the provided User. + */ + public MySQLUser toMySQLUser(User user) throws GuacamoleException { + MySQLUser mySQLUser = mySQLUserProvider.get(); + mySQLUser.init(user); + return mySQLUser; + } + + /** + * Create a new MySQLUser based on the provided database record. + * + * @param user The database record describing the user. + * @return A new MySQLUser object, populated with the data of the given + * database record. + */ + private MySQLUser toMySQLUser(UserWithBLOBs user) { + + // Retrieve user from provider + MySQLUser mySQLUser = mySQLUserProvider.get(); + + // Init with data from given database user + mySQLUser.init( + user.getUser_id(), + user.getUsername(), + null, + permissionCheckService.getAllPermissions(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(Integer 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 users having the given IDs from the database. + * + * @param ids The IDs of the users to retrieve. + * @return A list of existing MySQLUser objects. + */ + public List retrieveUsersByID(List ids) { + + // If no IDs given, just return empty list + if (ids.isEmpty()) + return Collections.EMPTY_LIST; + + // Query users by ID + UserExample example = new UserExample(); + example.createCriteria().andUser_idIn(ids); + List users = userDAO.selectByExampleWithBLOBs(example); + + // Convert to MySQLUser list + List mySQLUsers = new ArrayList(users.size()); + for (UserWithBLOBs user : users) + mySQLUsers.add(toMySQLUser(user)); + + // Return found users + return mySQLUsers; + + } + + /** + * Retrieves the users having the given usernames from the database. + * + * @param names The usernames of the users to retrieve. + * @return A list of existing MySQLUser objects. + */ + public List retrieveUsersByUsername(List names) { + + // If no names given, just return empty list + if (names.isEmpty()) + return Collections.EMPTY_LIST; + + // Query users by ID + UserExample example = new UserExample(); + example.createCriteria().andUsernameIn(names); + List users = userDAO.selectByExampleWithBLOBs(example); + + // Convert to MySQLUser list + List mySQLUsers = new ArrayList(users.size()); + for (UserWithBLOBs user : users) + mySQLUsers.add(toMySQLUser(user)); + + // Return found users + return mySQLUsers; + + } + + /** + * Retrieves the user having the given username from the database. + * + * @param name The username of the user to retrieve. + * @return The existing MySQLUser object if found, null otherwise. + */ + public MySQLUser retrieveUser(String name) { + + // Query user by ID + UserExample example = new UserExample(); + example.createCriteria().andUsernameEqualTo(name); + List users = userDAO.selectByExampleWithBLOBs(example); + + // If no user found, return null + if(users.isEmpty()) + return null; + + // Otherwise, return found user + return toMySQLUser(users.get(0)); + + } + + /** + * Retrieves the user corresponding to the given credentials from the + * database. + * + * @param credentials The credentials to use when locating the user. + * @return The existing MySQLUser object if the credentials given are + * valid, null otherwise. + */ + public MySQLUser retrieveUser(Credentials credentials) { + + // No null users in database + if (credentials.getUsername() == null) + return null; + + // Query user + UserExample userExample = new UserExample(); + userExample.createCriteria().andUsernameEqualTo(credentials.getUsername()); + List users = userDAO.selectByExampleWithBLOBs(userExample); + + // Check that a user was found + if (users.isEmpty()) + return null; + + // Assert only one user found + assert users.size() == 1 : "Multiple users with same username."; + + // Get first (and only) user + UserWithBLOBs user = users.get(0); + + // Check password, if invalid return null + if (!passwordService.checkPassword(credentials.getPassword(), + user.getPassword_hash(), user.getPassword_salt())) + return null; + + // Return found user + return toMySQLUser(user); + + } + + /** + * 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 username from the database + * @param username The username of the user to delete. + */ + public void deleteUser(String username) { + + // Get specified user + MySQLUser mySQLUser = retrieveUser(username); + int user_id = mySQLUser.getUserID(); + + // Delete all user permissions + UserPermissionExample userPermissionExample = new UserPermissionExample(); + userPermissionExample.createCriteria().andUser_idEqualTo(user_id); + userPermissionDAO.deleteByExample(userPermissionExample); + + // Delete all connection permissions + ConnectionPermissionExample connectionPermissionExample = new ConnectionPermissionExample(); + connectionPermissionExample.createCriteria().andUser_idEqualTo(user_id); + connectionPermissionDAO.deleteByExample(connectionPermissionExample); + + // Delete all system permissions + SystemPermissionExample systemPermissionExample = new SystemPermissionExample(); + systemPermissionExample.createCriteria().andUser_idEqualTo(user_id); + systemPermissionDAO.deleteByExample(systemPermissionExample); + + // Delete all permissions that refer to this user + userPermissionExample.clear(); + userPermissionExample.createCriteria().andAffected_user_idEqualTo(user_id); + userPermissionDAO.deleteByExample(userPermissionExample); + + // Delete the user in the database + 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); + + } + + +}