Ticket #269: Fix user create/update/delete, fix permission update, reorganize.

This commit is contained in:
Michael Jumper
2013-02-26 00:05:34 -08:00
parent eb466c7f70
commit 7d8fc88b53
8 changed files with 293 additions and 246 deletions

View File

@@ -65,10 +65,10 @@ import org.mybatis.guice.transactional.Transactional;
public class ConnectionDirectory implements Directory<String, Connection>{
/**
* The user who this connection directory belongs to.
* The ID of the user who this connection directory belongs to.
* Access is based on his/her permission settings.
*/
private MySQLUser user;
private int user_id;
@Inject
PermissionCheckService permissionCheckUtility;
@@ -87,16 +87,17 @@ public class ConnectionDirectory implements Directory<String, Connection>{
/**
* Set the user for this directory.
* @param user
*
* @param user_id The ID of the user owning this connection directory.
*/
void init(MySQLUser user) {
this.user = user;
void init(int user_id) {
this.user_id = user_id;
}
@Transactional
@Override
public Connection get(String identifier) throws GuacamoleException {
permissionCheckUtility.verifyConnectionReadAccess(this.user.getUserID(), identifier);
permissionCheckUtility.verifyConnectionReadAccess(this.user_id, identifier);
return providerUtility.getExistingMySQLConnection(identifier);
}
@@ -104,7 +105,7 @@ public class ConnectionDirectory implements Directory<String, Connection>{
@Override
public Set<String> getIdentifiers() throws GuacamoleException {
Set<String> connectionNameSet = new HashSet<String>();
Set<MySQLConnection> connections = permissionCheckUtility.getReadableConnections(this.user.getUserID());
Set<MySQLConnection> connections = permissionCheckUtility.getReadableConnections(this.user_id);
for(MySQLConnection mySQLConnection : connections) {
connectionNameSet.add(mySQLConnection.getIdentifier());
}
@@ -114,7 +115,7 @@ public class ConnectionDirectory implements Directory<String, Connection>{
@Transactional
@Override
public void add(Connection object) throws GuacamoleException {
permissionCheckUtility.verifyCreateConnectionPermission(this.user.getUserID());
permissionCheckUtility.verifyCreateConnectionPermission(this.user_id);
MySQLConnection mySQLConnection = providerUtility.getNewMySQLConnection(object);
connectionDAO.insert(mySQLConnection.getConnection());
@@ -123,7 +124,7 @@ public class ConnectionDirectory implements Directory<String, Connection>{
//finally, give the current user full access to the newly created connection.
ConnectionPermissionKey newConnectionPermission = new ConnectionPermissionKey();
newConnectionPermission.setUser_id(this.user.getUserID());
newConnectionPermission.setUser_id(this.user_id);
newConnectionPermission.setConnection_id(mySQLConnection.getConnectionID());
newConnectionPermission.setPermission(MySQLConstants.USER_READ);
connectionPermissionDAO.insert(newConnectionPermission);
@@ -205,7 +206,7 @@ public class ConnectionDirectory implements Directory<String, Connection>{
@Transactional
@Override
public void update(Connection object) throws GuacamoleException {
permissionCheckUtility.verifyConnectionUpdateAccess(this.user.getUserID(), object.getIdentifier());
permissionCheckUtility.verifyConnectionUpdateAccess(this.user_id, object.getIdentifier());
MySQLConnection mySQLConnection = providerUtility.getExistingMySQLConnection(object);
connectionDAO.updateByPrimaryKey(mySQLConnection.getConnection());
@@ -216,7 +217,7 @@ public class ConnectionDirectory implements Directory<String, Connection>{
@Transactional
@Override
public void remove(String identifier) throws GuacamoleException {
permissionCheckUtility.verifyConnectionDeleteAccess(this.user.getUserID(), identifier);
permissionCheckUtility.verifyConnectionDeleteAccess(this.user_id, identifier);
MySQLConnection mySQLConnection = providerUtility.getExistingMySQLConnection(identifier);

View File

@@ -42,6 +42,7 @@ 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;
@@ -54,6 +55,8 @@ 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;
@@ -94,9 +97,39 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider {
if (credentials.getUsername() == null)
return null;
// 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.checkCredentials(credentials,
user.getPassword_hash(), user.getUsername(), user.getPassword_salt()))
return null;
MySQLUserContext context = injector.getInstance(MySQLUserContext.class);
context.init(credentials);
context.init(user.getUser_id());
return context;
}
/**

View File

@@ -36,16 +36,12 @@
package net.sourceforge.guacamole.net.auth.mysql;
import com.google.inject.Inject;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.sourceforge.guacamole.GuacamoleException;
import net.sourceforge.guacamole.net.auth.Credentials;
import net.sourceforge.guacamole.net.auth.AbstractUser;
import net.sourceforge.guacamole.net.auth.User;
import net.sourceforge.guacamole.net.auth.mysql.dao.UserMapper;
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.service.PasswordEncryptionService;
import net.sourceforge.guacamole.net.auth.mysql.service.PermissionCheckService;
@@ -56,13 +52,13 @@ import net.sourceforge.guacamole.net.auth.permission.Permission;
* A MySQL based implementation of the User object.
* @author James Muehlner
*/
public class MySQLUser implements User {
private UserWithBLOBs user;
@Inject
UserMapper userDAO;
public class MySQLUser extends AbstractUser {
/**
* The ID of this user in the database, if any.
*/
private Integer userID;
@Inject
PasswordEncryptionService passwordUtility;
@@ -75,7 +71,7 @@ public class MySQLUser implements User {
/**
* The set of current permissions a user has.
*/
private Set<Permission> permissions;
private Set<Permission> permissions = new HashSet<Permission>();
/**
* Any newly added permissions that have yet to be committed.
@@ -87,6 +83,49 @@ public class MySQLUser implements User {
*/
private Set<Permission> removedPermissions = new HashSet<Permission>();
/**
* Creates a new, empty MySQLUser.
*/
public MySQLUser() {
}
/**
* Initializes a new MySQLUser having the given username.
*
* @param name The name to assign to this MySQLUser.
*/
public void init(String name) {
setUsername(name);
}
/**
* 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 {
setUsername(user.getUsername());
setPassword(user.getPassword());
permissions.addAll(user.getPermissions());
}
/**
* Initializes a new MySQLUser initialized from the given data from the
* database.
*
* @param user The user object, as retrieved from the database.
*/
public void init(UserWithBLOBs user) {
this.userID = user.getUser_id();
setUsername(user.getUsername());
permissions.addAll(
permissionCheckUtility.getAllPermissions(user.getUser_id()));
}
/**
* Get the current set of permissions this user has.
* @return the current set of permissions.
@@ -121,127 +160,22 @@ public class MySQLUser implements User {
}
/**
* Create a default, empty user.
* 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.
*/
MySQLUser() {
user = new UserWithBLOBs();
permissions = new HashSet<Permission>();
public Integer getUserID() {
return userID;
}
/**
* Create the user, throwing an exception if the credentials do not match what's in the database.
* @param credentials
* @throws GuacamoleException
* Sets the ID of this user to the given value.
*
* @param userID The ID to assign to this user.
*/
void init(Credentials credentials) throws GuacamoleException {
// 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
user = users.get(0);
// Check password
if (!passwordUtility.checkCredentials(credentials,
user.getPassword_hash(), user.getUsername(), user.getPassword_salt()))
throw new GuacamoleException("No user found with the supplied credentials");
// Init permissions
this.permissions = permissionCheckUtility.getAllPermissions(user.getUser_id());
}
/**
* Create a new user from the provided information. This represents a user that has not yet been inserted.
* @param user
* @throws GuacamoleException
*/
public void initNew (User user) throws GuacamoleException {
this.setPassword(user.getPassword());
this.setUsername(user.getUsername());
this.permissions = user.getPermissions();
}
/**
* Loads a user by username.
* @param userName
* @throws GuacamoleException
*/
public void initExisting (String username) throws GuacamoleException {
UserExample example = new UserExample();
example.createCriteria().andUsernameEqualTo(username);
List<UserWithBLOBs> userList = userDAO.selectByExampleWithBLOBs(example);
if(userList.size() > 1) // this should never happen; the unique constraint should prevent it
throw new GuacamoleException("Multiple users found with username '" + username + "'.");
if(userList.isEmpty())
throw new GuacamoleException("No user found with username '" + username + "'.");
this.user = userList.get(0);
this.permissions = permissionCheckUtility.getAllPermissions(user.getUser_id());
}
/**
* Initialize from a database record.
* @param user
*/
public void init(UserWithBLOBs user) {
this.user = user;
this.permissions = permissionCheckUtility.getAllPermissions(user.getUser_id());
}
/**
* Get the user id.
* @return
*/
public int getUserID() {
return user.getUser_id();
}
/**
* Return the database record held by this object.
* @return
*/
public UserWithBLOBs getUser() {
return user;
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public void setUsername(String username) {
user.setUsername(username);
}
@Override
public String getPassword() {
try {
return new String(user.getPassword_hash(), "UTF-8");
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException(ex); // should not happen
}
}
@Override
public void setPassword(String password) {
byte[] salt = saltUtility.generateSalt();
user.setPassword_salt(salt);
byte[] hash = passwordUtility.createPasswordHash(password, salt);
user.setPassword_hash(hash);
public void setUserID(Integer userID) {
this.userID = userID;
}
@Override
@@ -268,22 +202,32 @@ public class MySQLUser implements User {
removedPermissions.add(permission);
}
@Override
public boolean equals(Object other) {
if(!(other instanceof MySQLUser))
return false;
boolean idsAreEqual = ((MySQLUser)other).getUserID() == this.getUserID();
// they are both new, check if they have the same name
if(idsAreEqual && this.getUserID() == 0)
return this.getUsername().equals(((MySQLUser)other).getUsername());
return idsAreEqual;
/**
* Converts this MySQLUser into an object that can be inserted/updated
* into the database. Beware that this object does not have associated
* permissions. The permissions of this MySQLUser must be dealt with
* separately.
*
* @return A new UserWithBLOBs containing all associated data of this
* MySQLUser.
*/
public UserWithBLOBs toUserWithBLOBs() {
// Create new user
UserWithBLOBs user = new UserWithBLOBs();
user.setUser_id(userID);
user.setUsername(getUsername());
// Set password if specified
if (getPassword() != null) {
byte[] salt = saltUtility.generateSalt();
user.setPassword_salt(salt);
user.setPassword_hash(
passwordUtility.createPasswordHash(getPassword(), salt));
}
return user;
}
@Override
public int hashCode() {
int hash = 7;
hash = 73 * hash + getUserID();
hash = 73 * hash + getUsername().hashCode();
return hash;
}
}

View File

@@ -40,10 +40,10 @@ package net.sourceforge.guacamole.net.auth.mysql;
import com.google.inject.Inject;
import net.sourceforge.guacamole.GuacamoleException;
import net.sourceforge.guacamole.net.auth.Connection;
import net.sourceforge.guacamole.net.auth.Credentials;
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;
/**
* The MySQL representation of a UserContext.
@@ -52,11 +52,10 @@ import net.sourceforge.guacamole.net.auth.UserContext;
public class MySQLUserContext implements UserContext {
/**
* The user owning this context. The permissions of this user dictate
* the access given via the user and connection directories.
* The ID of the user owning this context. The permissions of this user
* dictate the access given via the user and connection directories.
*/
@Inject
private MySQLUser user;
private int user_id;
/**
* User directory restricted by the permissions of the user associated
@@ -72,23 +71,26 @@ public class MySQLUserContext implements UserContext {
@Inject
private ConnectionDirectory connectionDirectory;
/**
* Service for retrieving existing objects or creating new ones.
*/
@Inject
private ProviderService providerService;
/**
* Initializes the user and directories associated with this context.
*
* @param credentials The credentials of the user owning this context.
* @throws GuacamoleException If the credentials given are not valid,
* or an error occurs while initializing the
* directories.
* @param user_id The ID of the user owning this context.
*/
void init(Credentials credentials) throws GuacamoleException {
user.init(credentials);
userDirectory.init(user);
connectionDirectory.init(user);
void init(int user_id) {
this.user_id = user_id;
userDirectory.init(user_id);
connectionDirectory.init(user_id);
}
@Override
public User self() {
return user;
return providerService.getExistingMySQLUser(user_id);
}
@Override

View File

@@ -64,8 +64,11 @@ 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.permission.ConnectionDirectoryPermission;
import net.sourceforge.guacamole.net.auth.permission.ConnectionPermission;
import net.sourceforge.guacamole.net.auth.permission.Permission;
@@ -81,10 +84,10 @@ import org.mybatis.guice.transactional.Transactional;
public class UserDirectory implements Directory<String, net.sourceforge.guacamole.net.auth.User> {
/**
* The user who this user directory belongs to.
* The ID of the user who this user directory belongs to.
* Access is based on his/her permission settings.
*/
private MySQLUser user;
private int user_id;
/**
* DAO for accessing users, which will be injected.
@@ -128,22 +131,28 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
*/
@Inject
ProviderService providerUtility;
@Inject
PasswordEncryptionService passwordUtility;
@Inject
SaltService saltUtility;
/**
* Set the user for this directory.
*
* @param user The user whose permissions define the visibility of other
* users in this directory.
* @param user_id The ID of the user whose permissions define the visibility
* of other users in this directory.
*/
void init(MySQLUser user) {
this.user = user;
void init(int user_id) {
this.user_id = user_id;
}
@Transactional
@Override
public net.sourceforge.guacamole.net.auth.User get(String identifier)
throws GuacamoleException {
permissionCheckUtility.verifyUserReadAccess(this.user.getUserID(), identifier);
permissionCheckUtility.verifyUserReadAccess(this.user_id, identifier);
return providerUtility.getExistingMySQLUser(identifier);
}
@@ -152,7 +161,7 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
public Set<String> getIdentifiers() throws GuacamoleException {
// Get set of all readable users
Set<MySQLUser> users = permissionCheckUtility.getReadableUsers(user.getUserID());
Set<MySQLUser> users = permissionCheckUtility.getReadableUsers(this.user_id);
// Build set of usernames of readable users
Set<String> userNameSet = new HashSet<String>();
@@ -168,20 +177,30 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
throws GuacamoleException {
// Verify current user has permission to create users
permissionCheckUtility.verifyCreateUserPermission(this.user.getUserID());
permissionCheckUtility.verifyCreateUserPermission(this.user_id);
Preconditions.checkNotNull(object);
// Create user in database
MySQLUser mySQLUser = providerUtility.getNewMySQLUser(object);
userDAO.insert(mySQLUser.getUser());
UserWithBLOBs user = new UserWithBLOBs();
user.setUsername(object.getUsername());
// Set password if specified
if (object.getPassword() != null) {
byte[] salt = saltUtility.generateSalt();
user.setPassword_salt(salt);
user.setPassword_hash(
passwordUtility.createPasswordHash(object.getPassword(), salt));
}
userDAO.insert(user);
// Create permissions of new user in database
updatePermissions(mySQLUser);
createPermissions(user.getUser_id(), object.getPermissions());
// Give the current user full access to the newly created user.
UserPermissionKey newUserPermission = new UserPermissionKey();
newUserPermission.setUser_id(this.user.getUserID());
newUserPermission.setAffected_user_id(mySQLUser.getUserID());
newUserPermission.setUser_id(this.user_id);
newUserPermission.setAffected_user_id(user.getUser_id());
// READ permission on new user
newUserPermission.setPermission(MySQLConstants.USER_READ);
@@ -210,14 +229,14 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
* @throws GuacamoleException If an error occurs while updating the
* permissions of the given user.
*/
private void updatePermissions(MySQLUser user) throws GuacamoleException {
private void createPermissions(int user_id, Set<Permission> permissions) throws GuacamoleException {
// Partition given permissions by permission type
List<UserPermission> newUserPermissions = new ArrayList<UserPermission>();
List<ConnectionPermission> newConnectionPermissions = new ArrayList<ConnectionPermission>();
List<SystemPermission> newSystemPermissions = new ArrayList<SystemPermission>();
for (Permission permission : user.getNewPermissions()) {
for (Permission permission : permissions) {
if (permission instanceof UserPermission)
newUserPermissions.add((UserPermission) permission);
@@ -228,13 +247,23 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
else if (permission instanceof SystemPermission)
newSystemPermissions.add((SystemPermission) permission);
}
// Create the new permissions
createUserPermissions(newUserPermissions, user_id);
createConnectionPermissions(newConnectionPermissions, user_id);
createSystemPermissions(newSystemPermissions, user_id);
}
private void removePermissions(int user_id, Set<Permission> permissions) throws GuacamoleException {
// Partition given permissions by permission type
List<UserPermission> removedUserPermissions = new ArrayList<UserPermission>();
List<ConnectionPermission> removedConnectionPermissions = new ArrayList<ConnectionPermission>();
List<SystemPermission> removedSystemPermissions = new ArrayList<SystemPermission>();
for (Permission permission : user.getRemovedPermissions()) {
for (Permission permission : permissions) {
if (permission instanceof UserPermission)
removedUserPermissions.add((UserPermission) permission);
@@ -246,19 +275,11 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
removedSystemPermissions.add((SystemPermission) permission);
}
// Create the new permissions
createUserPermissions(newUserPermissions, user);
createConnectionPermissions(newConnectionPermissions, user);
createSystemPermissions(newSystemPermissions, user);
// Delete the removed permissions.
deleteUserPermissions(removedUserPermissions, user);
deleteConnectionPermissions(removedConnectionPermissions, user);
deleteSystemPermissions(removedSystemPermissions, user);
deleteUserPermissions(removedUserPermissions, user_id);
deleteConnectionPermissions(removedConnectionPermissions, user_id);
deleteSystemPermissions(removedSystemPermissions, user_id);
// The appropriate permissions have been inserted and deleted, so
// reset the new and removed permission sets.
user.resetPermissions();
}
/**
@@ -266,12 +287,12 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
*
* @param permissions The new permissions the given user should have when
* this operation completes.
* @param user The user to change the permissions of.
* @param user_id The ID of the user to change the permissions of.
* @throws GuacamoleException If permission to alter the access permissions
* of affected objects is denied.
*/
private void createUserPermissions(Collection<UserPermission> permissions,
MySQLUser user)
int user_id)
throws GuacamoleException {
if(permissions.isEmpty())
@@ -279,7 +300,7 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
// Get set of administerable users
Set<Integer> administerableUsers =
permissionCheckUtility.getAdministerableUserIDs(this.user.getUserID());
permissionCheckUtility.getAdministerableUserIDs(this.user_id);
// Get list of usernames for all given user permissions.
List<String> usernames = new ArrayList<String>();
@@ -310,15 +331,15 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
// every one of these users
if (!administerableUsers.contains(dbAffectedUser.getUser_id()))
throw new GuacamoleSecurityException(
"User '" + this.user.getUsername()
+ "' does not have permission to administrate user "
"User #" + this.user_id
+ " does not have permission to administrate user "
+ dbAffectedUser.getUser_id());
// Create new permission
UserPermissionKey newPermission = new UserPermissionKey();
newPermission.setAffected_user_id(dbAffectedUser.getUser_id());
newPermission.setPermission(permission.getType().name());
newPermission.setUser_id(user.getUserID());
newPermission.setUser_id(user_id);
userPermissionDAO.insert(newPermission);
}
}
@@ -328,12 +349,12 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
*
* @param permissions The permissions the given user should no longer have
* when this operation completes.
* @param user The user to change the permissions of.
* @param user_id The ID of the user to change the permissions of.
* @throws GuacamoleException If permission to alter the access permissions
* of affected objects is denied.
*/
private void deleteUserPermissions(Collection<UserPermission> permissions,
MySQLUser user)
int user_id)
throws GuacamoleException {
if(permissions.isEmpty())
@@ -341,7 +362,7 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
// Get set of administerable users
Set<Integer> administerableUsers =
permissionCheckUtility.getAdministerableUserIDs(this.user.getUserID());
permissionCheckUtility.getAdministerableUserIDs(this.user_id);
// Get list of usernames for all given user permissions.
List<String> usernames = new ArrayList<String>();
@@ -375,14 +396,14 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
// every one of these users
if (!administerableUsers.contains(dbAffectedUser.getUser_id()))
throw new GuacamoleSecurityException(
"User '" + this.user.getUsername()
+ "' does not have permission to administrate user "
"User #" + this.user_id
+ " does not have permission to administrate user "
+ dbAffectedUser.getUser_id());
}
if(!userIDs.isEmpty()) {
UserPermissionExample userPermissionExample = new UserPermissionExample();
userPermissionExample.createCriteria().andUser_idEqualTo(user.getUserID())
userPermissionExample.createCriteria().andUser_idEqualTo(user_id)
.andAffected_user_idIn(userIDs);
userPermissionDAO.deleteByExample(userPermissionExample);
}
@@ -394,12 +415,12 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
*
* @param permissions The new permissions the user should have after this
* operation completes.
* @param user The user to assign or remove permissions from.
* @param user_id The ID of the user to assign or remove permissions from.
* @throws GuacamoleException If permission to alter the access permissions
* of affected objects is deniedD
*/
private void createConnectionPermissions(
Collection<ConnectionPermission> permissions, MySQLUser user)
Collection<ConnectionPermission> permissions, int user_id)
throws GuacamoleException {
if(permissions.isEmpty())
@@ -407,7 +428,7 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
// Get adminsterable connection identifiers
Set<Integer> administerableConnections =
permissionCheckUtility.getAdministerableConnectionIDs(this.user.getUserID());
permissionCheckUtility.getAdministerableConnectionIDs(this.user_id);
// Build list of affected connection names from the permissions given
List<String> connectionNames = new ArrayList<String>();
@@ -439,8 +460,8 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
// is not granted
if (!administerableConnections.contains(dbConnection.getConnection_id()))
throw new GuacamoleSecurityException(
"User '" + this.user.getUsername()
+ "' does not have permission to administrate connection "
"User #" + this.user_id
+ " does not have permission to administrate connection "
+ dbConnection.getConnection_id());
@@ -448,7 +469,7 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
ConnectionPermissionKey newPermission = new ConnectionPermissionKey();
newPermission.setConnection_id(dbConnection.getConnection_id());
newPermission.setPermission(permission.getType().name());
newPermission.setConnection_id(user.getUserID());
newPermission.setConnection_id(user_id);
connectionPermissionDAO.insert(newPermission);
}
}
@@ -458,12 +479,12 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
*
* @param permissions The permissions the given user should no longer have
* when this operation completes.
* @param user The user to change the permissions of.
* @param user_id The ID of the user to change the permissions of.
* @throws GuacamoleException If permission to alter the access permissions
* of affected objects is denied.
*/
private void deleteConnectionPermissions(Collection<ConnectionPermission> permissions,
MySQLUser user)
int user_id)
throws GuacamoleException {
if(permissions.isEmpty())
@@ -471,7 +492,7 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
// Get set of administerable users
Set<Integer> administerableConnections =
permissionCheckUtility.getAdministerableConnectionIDs(this.user.getUserID());
permissionCheckUtility.getAdministerableConnectionIDs(this.user_id);
// Get list of identifiers for all given user permissions.
List<String> identifiers = new ArrayList<String>();
@@ -505,14 +526,14 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
// every one of these connections
if (!administerableConnections.contains(dbConnection.getConnection_id()))
throw new GuacamoleSecurityException(
"User '" + this.user.getUsername()
+ "' does not have permission to administrate connection "
"User #" + this.user_id
+ " does not have permission to administrate connection "
+ dbConnection.getConnection_id());
}
if(!connectionIDs.isEmpty()) {
ConnectionPermissionExample connectionPermissionExample = new ConnectionPermissionExample();
connectionPermissionExample.createCriteria().andUser_idEqualTo(user.getUserID())
connectionPermissionExample.createCriteria().andUser_idEqualTo(user_id)
.andConnection_idIn(connectionIDs);
connectionPermissionDAO.deleteByExample(connectionPermissionExample);
}
@@ -524,10 +545,10 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
*
* @param permissions The new system permissions that the given user should
* have when this operation completes.
* @param user The user whose permissions should be updated.
* @param user_id The ID of the user whose permissions should be updated.
*/
private void createSystemPermissions(Collection<SystemPermission> permissions,
MySQLUser user) {
int user_id) {
if(permissions.isEmpty())
return;
@@ -575,22 +596,24 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
// Insert permission
SystemPermissionKey newSystemPermission = new SystemPermissionKey();
newSystemPermission.setUser_id(user.getUserID());
newSystemPermission.setUser_id(user_id);
newSystemPermission.setPermission(systemPermissionType);
systemPermissionDAO.insert(newSystemPermission);
}
}/**
}
/**
* Delete system permissions for a given user. All permissions in
* the given list will be removed from the user.
*
* @param permissions The permissions the given user should no longer have
* when this operation completes.
* @param user The user whose permissions should be updated.
* @param user_id The ID of the user whose permissions should be updated.
*/
private void deleteSystemPermissions(Collection<SystemPermission> permissions,
MySQLUser user) {
int user_id) {
if(permissions.isEmpty())
return;
@@ -636,7 +659,7 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
// Finally, delete the requested system permissions for this user
if(!systemPermissionTypes.isEmpty()) {
SystemPermissionExample systemPermissionExample = new SystemPermissionExample();
systemPermissionExample.createCriteria().andUser_idEqualTo(user.getUserID())
systemPermissionExample.createCriteria().andUser_idEqualTo(user_id)
.andPermissionIn(systemPermissionTypes);
systemPermissionDAO.deleteByExample(systemPermissionExample);
}
@@ -647,16 +670,26 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
public void update(net.sourceforge.guacamole.net.auth.User object)
throws GuacamoleException {
// If user not actually from this auth provider, we can't handle updated
// permissions.
if (!(object instanceof MySQLUser))
throw new GuacamoleException("User not from database.");
// Validate permission to update this user is granted
permissionCheckUtility.verifyUserUpdateAccess(this.user.getUserID(),
permissionCheckUtility.verifyUserUpdateAccess(this.user_id,
object.getUsername());
// Update the user in the database
MySQLUser mySQLUser = providerUtility.getExistingMySQLUser(object);
userDAO.updateByPrimaryKey(mySQLUser.getUser());
MySQLUser mySQLUser = (MySQLUser) object;
userDAO.updateByPrimaryKeySelective(mySQLUser.toUserWithBLOBs());
// Update permissions in database
updatePermissions(mySQLUser);
createPermissions(0 /* STUB */, mySQLUser.getNewPermissions());
removePermissions(0 /* STUB */, mySQLUser.getRemovedPermissions());
// The appropriate permissions have been inserted and deleted, so
// reset the new and removed permission sets.
mySQLUser.resetPermissions();
}
@@ -665,14 +698,14 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
public void remove(String identifier) throws GuacamoleException {
// Validate current user has permission to remove the specified user
permissionCheckUtility.verifyUserDeleteAccess(this.user.getUserID(),
permissionCheckUtility.verifyUserDeleteAccess(this.user_id,
identifier);
// Get specified user
MySQLUser mySQLUser = providerUtility.getExistingMySQLUser(identifier);
// Delete all the user permissions in the database
deleteAllPermissions(mySQLUser);
deleteAllPermissions(mySQLUser.getUserID());
// Delete the user in the database
userDAO.deleteByPrimaryKey(mySQLUser.getUserID());
@@ -683,28 +716,28 @@ public class UserDirectory implements Directory<String, net.sourceforge.guacamol
* Delete all permissions associated with the provided user. This is only
* used when deleting a user.
*
* @param user The user to delete all permissions of.
* @param user_id The ID of the user to delete all permissions of.
*/
private void deleteAllPermissions(MySQLUser user) {
private void deleteAllPermissions(int user_id) {
// Delete all user permissions
UserPermissionExample userPermissionExample = new UserPermissionExample();
userPermissionExample.createCriteria().andUser_idEqualTo(user.getUserID());
userPermissionExample.createCriteria().andUser_idEqualTo(user_id);
userPermissionDAO.deleteByExample(userPermissionExample);
// Delete all connection permissions
ConnectionPermissionExample connectionPermissionExample = new ConnectionPermissionExample();
connectionPermissionExample.createCriteria().andUser_idEqualTo(user.getUserID());
connectionPermissionExample.createCriteria().andUser_idEqualTo(user_id);
connectionPermissionDAO.deleteByExample(connectionPermissionExample);
// Delete all system permissions
SystemPermissionExample systemPermissionExample = new SystemPermissionExample();
systemPermissionExample.createCriteria().andUser_idEqualTo(user.getUserID());
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.getUserID());
userPermissionExample.createCriteria().andAffected_user_idEqualTo(user_id);
userPermissionDAO.deleteByExample(userPermissionExample);
}

View File

@@ -374,11 +374,23 @@ public class PermissionCheckService {
* @param permissionType
* @return the list of all users this user has access to
*/
@Deprecated /* FIXME: Totally useless (we only ever need usernames, and querying ALL USER DATA will take ages) */
private Set<MySQLUser> getUsers(int userID, String permissionType) {
// Get all IDs of all users that the given user can perform the given
// operation on
Set<Integer> affectedUserIDs = getUserIDs(userID, permissionType);
// If no affected users at all, return empty set
if (affectedUserIDs.isEmpty())
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();
@@ -387,6 +399,7 @@ public class PermissionCheckService {
}
return affectedUsers;
}
/**

View File

@@ -38,6 +38,7 @@ 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.Collections;
import java.util.List;
import net.sourceforge.guacamole.GuacamoleException;
import net.sourceforge.guacamole.net.auth.Connection;
@@ -90,7 +91,7 @@ public class ProviderService {
*/
public MySQLUser getNewMySQLUser(User user) throws GuacamoleException {
MySQLUser mySQLUser = mySQLUserProvider.get();
mySQLUser.initNew(user);
mySQLUser.init(user);
return mySQLUser;
}
@@ -111,9 +112,19 @@ public class ProviderService {
* @throws GuacamoleException
*/
public MySQLUser getExistingMySQLUser(String name) throws GuacamoleException {
MySQLUser mySQLUser = mySQLUserProvider.get();
mySQLUser.initExisting(name);
return mySQLUser;
// 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));
}
/**
@@ -133,12 +144,19 @@ public class ProviderService {
* @return the existing MySQLUser object if found, null if not.
*/
public MySQLUser getExistingMySQLUser(Integer id) {
// Query user by ID
UserExample example = new UserExample();
example.createCriteria().andUser_idEqualTo(id);
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));
}

View File

@@ -186,6 +186,9 @@
password_salt)
values (#{user_id,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR}, #{password_hash,jdbcType=BINARY},
#{password_salt,jdbcType=BINARY})
<selectKey keyProperty="user_id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
</insert>
<insert id="insertSelective" parameterType="net.sourceforge.guacamole.net.auth.mysql.model.UserWithBLOBs">
<!--
@@ -329,4 +332,4 @@
set username = #{username,jdbcType=VARCHAR}
where user_id = #{user_id,jdbcType=INTEGER}
</update>
</mapper>
</mapper>