Ticket #269: Refactor all user access into UserService, remove usage of UserMapper outside UserService.

This commit is contained in:
Michael Jumper
2013-02-27 18:10:45 -08:00
parent 64c2faa61d
commit c105b62615
7 changed files with 453 additions and 299 deletions

View File

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

View File

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

View File

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

View File

@@ -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<String, net.sourceforge.guacamol
private int user_id;
/**
* DAO for accessing users, which will be injected.
* Service for accessing users.
*/
@Inject
private UserMapper userDAO;
private UserService userService;
/**
* DAO for accessing connections, which will be injected.
@@ -123,13 +119,6 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
@Inject
private PermissionCheckService permissionCheckService;
/**
* Service providing convenient access to object creation and
* retrieval functions.
*/
@Inject
private ProviderService providerService;
/**
* Service for encrypting passwords.
*/
@@ -157,7 +146,7 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
public net.sourceforge.guacamole.net.auth.User get(String identifier)
throws GuacamoleException {
permissionCheckService.verifyUserReadAccess(this.user_id, identifier);
return providerService.getExistingMySQLUser(identifier);
return userService.retrieveUser(identifier);
}
@Transactional
@@ -184,27 +173,17 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
permissionCheckService.verifyCreateUserPermission(this.user_id);
Preconditions.checkNotNull(object);
// Create user in database
UserWithBLOBs user = new UserWithBLOBs();
user.setUsername(object.getUsername());
// Set password if specified
if (object.getPassword() != null) {
byte[] salt = saltService.generateSalt();
user.setPassword_salt(salt);
user.setPassword_hash(
passwordService.createPasswordHash(object.getPassword(), salt));
}
userDAO.insert(user);
// Create new user
MySQLUser user = userService.createUser(object.getUsername(),
object.getPassword());
// Create permissions of new user in database
createPermissions(user.getUser_id(), object.getPermissions());
createPermissions(user.getUserID(), object.getPermissions());
// Give the current user full access to the newly created user.
UserPermissionKey newUserPermission = new UserPermissionKey();
newUserPermission.setUser_id(this.user_id);
newUserPermission.setAffected_user_id(user.getUser_id());
newUserPermission.setAffected_user_id(user.getUserID());
// READ permission on new user
newUserPermission.setPermission(MySQLConstants.USER_READ);
@@ -321,36 +300,34 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
usernames.add(permission.getObjectIdentifier());
// Find all the users by username
UserExample userExample = new UserExample();
userExample.createCriteria().andUsernameIn(usernames);
List<User> dbUsers = userDAO.selectByExample(userExample);
List<MySQLUser> users = userService.retrieveUsersByUsername(usernames);
// Build map of found users, indexed by username
Map<String, User> dbUserMap = new HashMap<String, User>();
for (User dbUser : dbUsers) {
dbUserMap.put(dbUser.getUsername(), dbUser);
}
Map<String, MySQLUser> userMap = new HashMap<String, MySQLUser>();
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<String, net.sourceforge.guacamol
usernames.add(permission.getObjectIdentifier());
// Find all the users by username
UserExample userExample = new UserExample();
userExample.createCriteria().andUsernameIn(usernames);
List<User> dbUsers = userDAO.selectByExample(userExample);
List<MySQLUser> users = userService.retrieveUsersByUsername(usernames);
List<Integer> userIDs = new ArrayList<Integer>();
// Build map of found users, indexed by username
Map<String, User> dbUserMap = new HashMap<String, User>();
for (User dbUser : dbUsers) {
dbUserMap.put(dbUser.getUsername(), dbUser);
userIDs.add(dbUser.getUser_id());
Map<String, MySQLUser> userMap = new HashMap<String, MySQLUser>();
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<String, net.sourceforge.guacamol
permissionCheckService.verifyUserUpdateAccess(this.user_id,
object.getUsername());
// Build database user from non-database structure
MySQLUser mySQLUser = (MySQLUser) object;
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);
MySQLUser mySQLUser = (MySQLUser) object;
userService.updateUser(mySQLUser);
// Update permissions in database
createPermissions(mySQLUser.getUserID(), mySQLUser.getNewPermissions());
@@ -694,48 +656,17 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
@Transactional
public void remove(String identifier) throws GuacamoleException {
// FIXME: Querying permissions here will query the user to determine
// its ID, and that same user will be queried AGAIN later when
// deleted, again - to determine its ID. Perhaps we want cascading
// deletes in the schema?
// Validate current user has permission to remove the specified user
permissionCheckService.verifyUserDeleteAccess(this.user_id,
identifier);
// Get specified user
MySQLUser mySQLUser = providerService.getExistingMySQLUser(identifier);
// Delete all the user permissions in the database
deleteAllPermissions(mySQLUser.getUserID());
// Delete the user in the database
userDAO.deleteByPrimaryKey(mySQLUser.getUserID());
}
/**
* Delete all permissions associated with the provided user. This is only
* used when deleting a user.
*
* @param user_id The ID of the user to delete all permissions of.
*/
private void deleteAllPermissions(int user_id) {
// 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 specified user
userService.deleteUser(identifier);
}

View File

@@ -52,7 +52,6 @@ import net.sourceforge.guacamole.net.auth.mysql.MySQLUser;
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,11 +59,8 @@ 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.permission.ConnectionPermission;
import net.sourceforge.guacamole.net.auth.permission.Permission;
import net.sourceforge.guacamole.net.auth.permission.SystemPermission;
@@ -78,7 +74,7 @@ import net.sourceforge.guacamole.protocol.GuacamoleConfiguration;
public class PermissionCheckService {
@Inject
private UserMapper userDAO;
private UserService userService;
@Inject
private ConnectionMapper connectionDAO;
@@ -274,9 +270,9 @@ public class PermissionCheckService {
* @return
*/
private boolean checkUserAccess(int userID, String affectedUsername, String permissionType) {
User affectedUser = getUser(affectedUsername);
MySQLUser affectedUser = userService.retrieveUser(affectedUsername);
if(affectedUser != null)
return checkUserAccess(userID, affectedUser.getUser_id(), permissionType);
return checkUserAccess(userID, affectedUser.getUserID(), permissionType);
return false;
}
@@ -386,19 +382,8 @@ public class PermissionCheckService {
return Collections.EMPTY_SET;
// Query corresponding user data for each retrieved ID
UserExample example = new UserExample();
example.createCriteria().andUser_idIn(Lists.newArrayList(affectedUserIDs));
List<UserWithBLOBs> userDBOjects = userDAO.selectByExampleWithBLOBs(example);
// Build set of MySQLUsers from retrieved user data
Set<MySQLUser> affectedUsers = new HashSet<MySQLUser>();
for(UserWithBLOBs affectedUser : userDBOjects) {
MySQLUser mySQLUser = mySQLUserProvider.get();
mySQLUser.init(affectedUser.getUsername());
affectedUsers.add(mySQLUser);
}
return affectedUsers;
return new HashSet<MySQLUser>(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<User> 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<User> users = userDAO.selectByExample(userExample);
Map<Integer, User> userMap = new HashMap<Integer, User>();
for(User user : users)
userMap.put(user.getUser_id(), user);
List<MySQLUser> users = userService.retrieveUsersByID(affectedUserIDs);
Map<Integer, MySQLUser> userMap = new HashMap<Integer, MySQLUser>();
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()

View File

@@ -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<MySQLUser> mySQLUserProvider;
@Inject
private Provider<MySQLConnection> mySQLConnectionProvider;
@@ -91,92 +80,6 @@ public class ProviderService {
@Inject
private Provider<MySQLGuacamoleSocket> 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<UserWithBLOBs> 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

View File

@@ -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<MySQLUser> mySQLUserProvider;
/**
* Service for checking permissions.
*/
@Inject
private PermissionCheckService permissionCheckService;
/**
* Service for encrypting passwords.
*/
@Inject
private PasswordEncryptionService passwordService;
/**
* Service for generating random salts.
*/
@Inject
private SaltService saltService;
/**
* Create a new MySQLUser based on the provided User.
*
* @param user The User to use when populating the data of the given
* MySQLUser.
* @return A new MySQLUser object, populated with the data of the given
* user.
*
* @throws GuacamoleException If an error occurs while reading the data
* of the provided User.
*/
public MySQLUser toMySQLUser(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<MySQLUser> retrieveUsersByID(List<Integer> 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<UserWithBLOBs> users = userDAO.selectByExampleWithBLOBs(example);
// Convert to MySQLUser list
List<MySQLUser> mySQLUsers = new ArrayList<MySQLUser>(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<MySQLUser> retrieveUsersByUsername(List<String> 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<UserWithBLOBs> users = userDAO.selectByExampleWithBLOBs(example);
// Convert to MySQLUser list
List<MySQLUser> mySQLUsers = new ArrayList<MySQLUser>(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<UserWithBLOBs> users = userDAO.selectByExampleWithBLOBs(example);
// If no user found, return null
if(users.isEmpty())
return null;
// Otherwise, return found user
return toMySQLUser(users.get(0));
}
/**
* Retrieves the user corresponding to the given credentials from the
* database.
*
* @param credentials The credentials to use when locating the user.
* @return The existing MySQLUser object if the credentials given are
* valid, null otherwise.
*/
public MySQLUser retrieveUser(Credentials credentials) {
// No null users in database
if (credentials.getUsername() == null)
return null;
// Query user
UserExample userExample = new UserExample();
userExample.createCriteria().andUsernameEqualTo(credentials.getUsername());
List<UserWithBLOBs> users = userDAO.selectByExampleWithBLOBs(userExample);
// Check that a user was found
if (users.isEmpty())
return null;
// Assert only one user found
assert users.size() == 1 : "Multiple users with same username.";
// Get first (and only) user
UserWithBLOBs user = users.get(0);
// Check password, if invalid return null
if (!passwordService.checkPassword(credentials.getPassword(),
user.getPassword_hash(), user.getPassword_salt()))
return null;
// Return found user
return toMySQLUser(user);
}
/**
* 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);
}
}