GUAC-1101: Move JDBC-related auth into single parent project.

This commit is contained in:
Michael Jumper
2015-02-27 21:24:11 -08:00
parent 2d175f8792
commit a271550bcb
78 changed files with 151 additions and 132 deletions

View File

@@ -0,0 +1,2 @@
target/
*~

View File

@@ -0,0 +1,85 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.glyptodon.guacamole</groupId>
<artifactId>guacamole-auth-jdbc-base</artifactId>
<packaging>jar</packaging>
<version>0.9.5</version>
<name>guacamole-auth-jdbc-base</name>
<url>http://guac-dev.org/</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<!-- Written for 1.6 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Guacamole Java API -->
<dependency>
<groupId>org.glyptodon.guacamole</groupId>
<artifactId>guacamole-common</artifactId>
<version>0.9.4</version>
<scope>provided</scope>
</dependency>
<!-- Guacamole Extension API -->
<dependency>
<groupId>org.glyptodon.guacamole</groupId>
<artifactId>guacamole-ext</artifactId>
<version>0.9.5</version>
<scope>provided</scope>
</dependency>
<!-- SLF4J - logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>
<!-- MyBatis Guice -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-guice</artifactId>
<version>3.6</version>
</dependency>
<!-- Guice -->
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId>
<version>3.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,125 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc;
import org.glyptodon.guacamole.auth.jdbc.user.MySQLUserContext;
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.MySQLRootConnectionGroup;
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.MySQLConnectionGroup;
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ConnectionGroupDirectory;
import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionDirectory;
import org.glyptodon.guacamole.auth.jdbc.connection.MySQLGuacamoleConfiguration;
import org.glyptodon.guacamole.auth.jdbc.connection.MySQLConnection;
import org.glyptodon.guacamole.auth.jdbc.permission.MySQLSystemPermissionSet;
import org.glyptodon.guacamole.auth.jdbc.user.MySQLUser;
import org.glyptodon.guacamole.auth.jdbc.user.UserDirectory;
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ConnectionGroupMapper;
import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionMapper;
import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionRecordMapper;
import org.glyptodon.guacamole.auth.jdbc.connection.ParameterMapper;
import org.glyptodon.guacamole.auth.jdbc.permission.SystemPermissionMapper;
import org.glyptodon.guacamole.auth.jdbc.user.UserMapper;
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ConnectionGroupService;
import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionService;
import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService;
import org.glyptodon.guacamole.auth.jdbc.security.PasswordEncryptionService;
import org.glyptodon.guacamole.auth.jdbc.security.SHA256PasswordEncryptionService;
import org.glyptodon.guacamole.auth.jdbc.security.SaltService;
import org.glyptodon.guacamole.auth.jdbc.security.SecureRandomSaltService;
import org.glyptodon.guacamole.auth.jdbc.permission.SystemPermissionService;
import org.glyptodon.guacamole.auth.jdbc.socket.UnrestrictedGuacamoleSocketService;
import org.glyptodon.guacamole.auth.jdbc.user.UserService;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.glyptodon.guacamole.environment.Environment;
import org.mybatis.guice.MyBatisModule;
import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider;
/**
* Guice module which configures the injections used by the JDBC authentication
* provider base. This module MUST be included in the Guice injector, or
* authentication providers based on JDBC will not function.
*
* @author Michael Jumper
* @author James Muehlner
*/
public class JDBCAuthenticationProviderModule extends MyBatisModule {
/**
* The environment of the Guacamole server.
*/
private final Environment environment;
/**
* Creates a new JDBC authentication provider module that configures the
* various injected base classes using the given environment.
*
* @param environment
* The environment to use to configure injected classes.
*/
public JDBCAuthenticationProviderModule(Environment environment) {
this.environment = environment;
}
@Override
protected void initialize() {
// Datasource
bindDataSourceProviderType(PooledDataSourceProvider.class);
// Transaction factory
bindTransactionFactoryType(JdbcTransactionFactory.class);
// Add MyBatis mappers
addMapperClass(ConnectionMapper.class);
addMapperClass(ConnectionGroupMapper.class);
addMapperClass(ConnectionRecordMapper.class);
addMapperClass(ParameterMapper.class);
addMapperClass(SystemPermissionMapper.class);
addMapperClass(UserMapper.class);
// Bind core implementations of guacamole-ext classes
bind(Environment.class).toInstance(environment);
bind(ConnectionDirectory.class);
bind(ConnectionGroupDirectory.class);
bind(MySQLConnection.class);
bind(MySQLConnectionGroup.class);
bind(MySQLGuacamoleConfiguration.class);
bind(MySQLUser.class);
bind(MySQLUserContext.class);
bind(MySQLRootConnectionGroup.class);
bind(MySQLSystemPermissionSet.class);
bind(UserDirectory.class);
// Bind services
bind(ConnectionService.class);
bind(ConnectionGroupService.class);
bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class);
bind(SaltService.class).to(SecureRandomSaltService.class);
bind(SystemPermissionService.class);
bind(UserService.class);
// Bind appropriate socket service based on policy
bind(GuacamoleSocketService.class).to(UnrestrictedGuacamoleSocketService.class);
}
}

View File

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

View File

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

View File

@@ -0,0 +1,443 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.base;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.GuacamoleSecurityException;
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
/**
* Service which provides convenience methods for creating, retrieving, and
* manipulating users. This service will automatically enforce the
* permissions of the current user.
*
* @author Michael Jumper
* @param <InternalType>
* The specific internal implementation of the type of object this service
* provides access to.
*
* @param <ExternalType>
* The external interface or implementation of the type of object this
* service provides access to, as defined by the guacamole-ext API.
*
* @param <ModelType>
* The underlying model object used to represent InternalType in the
* database.
*/
public abstract class DirectoryObjectService<InternalType extends DirectoryObject<ModelType>,
ExternalType, ModelType extends ObjectModel> {
/**
* Returns an instance of a mapper for the type of object used by this
* service.
*
* @return
* A mapper which provides access to the model objects associated with
* the objects used by this service.
*/
protected abstract DirectoryObjectMapper<ModelType> getObjectMapper();
/**
* Returns an instance of an object which is backed by the given model
* object.
*
* @param currentUser
* The user for whom this object is being created.
*
* @param model
* The model object to use to back the returned object.
*
* @return
* An object which is backed by the given model object.
*/
protected abstract InternalType getObjectInstance(AuthenticatedUser currentUser,
ModelType model);
/**
* Returns an instance of a model object which is based on the given
* object.
*
* @param currentUser
* The user for whom this model object is being created.
*
* @param object
* The object to use to produce the returned model object.
*
* @return
* A model object which is based on the given object.
*/
protected abstract ModelType getModelInstance(AuthenticatedUser currentUser,
ExternalType object);
/**
* Returns whether the given user has permission to create the type of
* objects that this directory object service manages.
*
* @param user
* The user being checked.
*
* @return
* true if the user has object creation permission relevant to this
* directory object service, false otherwise.
*
* @throws GuacamoleException
* If permission to read the user's permissions is denied.
*/
protected abstract boolean hasCreatePermission(AuthenticatedUser user)
throws GuacamoleException;
/**
* Returns whether the given user has permission to perform a certain
* action on a specific object managed by this directory object service.
*
* @param user
* The user being checked.
*
* @param identifier
* The identifier of the object to check.
*
* @param type
* The type of action that will be performed.
*
* @return
* true if the user has object permission relevant described, false
* otherwise.
*
* @throws GuacamoleException
* If permission to read the user's permissions is denied.
*/
protected boolean hasObjectPermission(AuthenticatedUser user,
String identifier, ObjectPermission.Type type)
throws GuacamoleException {
// Get object permissions
ObjectPermissionSet permissionSet = getPermissionSet(user);
// Return whether permission is granted
return user.getUser().isAdministrator()
|| permissionSet.hasPermission(type, identifier);
}
/**
* Returns the permission set associated with the given user and related
* to the type of objects handled by this directory object service.
*
* @param user
* The user whose permissions are being retrieved.
*
* @return
* A permission set which contains the permissions associated with the
* given user and related to the type of objects handled by this
* directory object service.
*
* @throws GuacamoleException
* If permission to read the user's permissions is denied.
*/
protected abstract ObjectPermissionSet getPermissionSet(AuthenticatedUser user)
throws GuacamoleException;
/**
* Returns a collection of objects which are backed by the models in the
* given collection.
*
* @param currentUser
* The user for whom these objects are being created.
*
* @param models
* The model objects to use to back the objects within the returned
* collection.
*
* @return
* A collection of objects which are backed by the models in the given
* collection.
*/
protected Collection<InternalType> getObjectInstances(AuthenticatedUser currentUser,
Collection<ModelType> models) {
// Create new collection of objects by manually converting each model
Collection<InternalType> objects = new ArrayList<InternalType>(models.size());
for (ModelType model : models)
objects.add(getObjectInstance(currentUser, model));
return objects;
}
/**
* Returns whether the given object is valid and can be created as-is. The
* object does not yet exist in the database, but the user desires to
* create a new object with the given values. This function will be called
* prior to any creation operation, and provides a means for the
* implementation to abort prior to completion. The default implementation
* does nothing.
*
* @param user
* The user creating the object.
*
* @param object
* The object to validate.
*
* @throws GuacamoleException
* If the object is invalid, or an error prevents validating the given
* object.
*/
protected void validateNewObject(AuthenticatedUser user,
ExternalType object) throws GuacamoleException {
// By default, do nothing.
}
/**
* Returns whether the given object is valid and can updated as-is. The
* object already exists in the database, but the user desires to update
* the object to the given values. This function will be called prior to
* update operation, and provides a means for the implementation to abort
* prior to completion. The default implementation does nothing.
*
* @param user
* The user updating the existing object.
*
* @param object
* The object to validate.
*
* @throws GuacamoleException
* If the object is invalid, or an error prevents validating the given
* object.
*/
protected void validateExistingObject(AuthenticatedUser user,
InternalType object) throws GuacamoleException {
// By default, do nothing.
}
/**
* Retrieves the single object that has the given identifier, if it exists
* and the user has permission to read it.
*
* @param user
* The user retrieving the object.
*
* @param identifier
* The identifier of the object to retrieve.
*
* @return
* The object having the given identifier, or null if no such object
* exists.
*
* @throws GuacamoleException
* If an error occurs while retrieving the requested object.
*/
public InternalType retrieveObject(AuthenticatedUser user,
String identifier) throws GuacamoleException {
// Pull objects having given identifier
Collection<InternalType> objects = retrieveObjects(user, Collections.singleton(identifier));
// If no such object, return null
if (objects.isEmpty())
return null;
// The object collection will have exactly one element unless the
// database has seriously lost integrity
assert(objects.size() == 1);
// Return first and only object
return objects.iterator().next();
}
/**
* Retrieves all objects that have the identifiers in the given collection.
* Only objects that the user has permission to read will be returned.
*
* @param user
* The user retrieving the objects.
*
* @param identifiers
* The identifiers of the objects to retrieve.
*
* @return
* The objects having the given identifiers.
*
* @throws GuacamoleException
* If an error occurs while retrieving the requested objects.
*/
public Collection<InternalType> retrieveObjects(AuthenticatedUser user,
Collection<String> identifiers) throws GuacamoleException {
// Do not query if no identifiers given
if (identifiers.isEmpty())
return Collections.EMPTY_LIST;
Collection<ModelType> objects;
// Bypass permission checks if the user is a system admin
if (user.getUser().isAdministrator())
objects = getObjectMapper().select(identifiers);
// Otherwise only return explicitly readable identifiers
else
objects = getObjectMapper().selectReadable(user.getUser().getModel(), identifiers);
// Return collection of requested objects
return getObjectInstances(user, objects);
}
/**
* Creates the given object within the database. If the object already
* exists, an error will be thrown. The internal model object will be
* updated appropriately to contain the new database ID.
*
* @param user
* The user creating the object.
*
* @param object
* The object to create.
*
* @return
* The newly-created object.
*
* @throws GuacamoleException
* If the user lacks permission to create the object, or an error
* occurs while creating the object.
*/
public InternalType createObject(AuthenticatedUser user, ExternalType object)
throws GuacamoleException {
// Only create object if user has permission to do so
if (user.getUser().isAdministrator() || hasCreatePermission(user)) {
// Validate object prior to creation
validateNewObject(user, object);
// Create object
ModelType model = getModelInstance(user, object);
getObjectMapper().insert(model);
// FIXME: Insert implicit object permissions, too.
return getObjectInstance(user, model);
}
// User lacks permission to create
throw new GuacamoleSecurityException("Permission denied.");
}
/**
* Deletes the object having the given identifier. If no such object
* exists, this function has no effect.
*
* @param user
* The user deleting the object.
*
* @param identifier
* The identifier of the object to delete.
*
* @throws GuacamoleException
* If the user lacks permission to delete the object, or an error
* occurs while deleting the object.
*/
public void deleteObject(AuthenticatedUser user, String identifier)
throws GuacamoleException {
// Only delete object if user has permission to do so
if (hasObjectPermission(user, identifier, ObjectPermission.Type.DELETE)) {
getObjectMapper().delete(identifier);
return;
}
// User lacks permission to delete
throw new GuacamoleSecurityException("Permission denied.");
}
/**
* Updates the given object in the database, applying any changes that have
* been made. If no such object exists, this function has no effect.
*
* @param user
* The user updating the object.
*
* @param object
* The object to update.
*
* @throws GuacamoleException
* If the user lacks permission to update the object, or an error
* occurs while updating the object.
*/
public void updateObject(AuthenticatedUser user, InternalType object)
throws GuacamoleException {
// Only update object if user has permission to do so
if (hasObjectPermission(user, object.getIdentifier(), ObjectPermission.Type.UPDATE)) {
// Validate object prior to creation
validateExistingObject(user, object);
// Update object
getObjectMapper().update(object.getModel());
return;
}
// User lacks permission to update
throw new GuacamoleSecurityException("Permission denied.");
}
/**
* Returns the set of all identifiers for all objects in the database that
* the user has read access to.
*
* @param user
* The user retrieving the identifiers.
*
* @return
* The set of all identifiers for all objects in the database.
*
* @throws GuacamoleException
* If an error occurs while reading identifiers.
*/
public Set<String> getIdentifiers(AuthenticatedUser user)
throws GuacamoleException {
// Bypass permission checks if the user is a system admin
if (user.getUser().isAdministrator())
return getObjectMapper().selectIdentifiers();
// Otherwise only return explicitly readable identifiers
else
return getObjectMapper().selectReadableIdentifiers(user.getUser().getModel());
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.base;
/**
* Object representation of a Guacamole object, such as a user or connection,
* as represented in the database.
*
* @author Michael Jumper
*/
public abstract class ObjectModel {
/**
* The ID of this object in the database, if any.
*/
private Integer objectID;
/**
* The unique identifier which identifies this object.
*/
private String identifier;
/**
* Creates a new, empty object.
*/
public ObjectModel() {
}
/**
* Returns the identifier that uniquely identifies this object.
*
* @return
* The identifier that uniquely identifies this object.
*/
public String getIdentifier() {
return identifier;
}
/**
* Sets the identifier that uniquely identifies this object.
*
* @param identifier
* The identifier that uniquely identifies this object.
*/
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
/**
* Returns the ID of this object in the database, if it exists.
*
* @return
* The ID of this object in the database, or null if this object was
* not retrieved from the database.
*/
public Integer getObjectID() {
return objectID;
}
/**
* Sets the ID of this object to the given value.
*
* @param objectID
* The ID to assign to this object.
*/
public void setObjectID(Integer objectID) {
this.objectID = objectID;
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.base;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
/**
* Common base class for objects that are associated with the users that
* query them, and have an underlying model.
*
* @author Michael Jumper
* @param <ModelType>
* The type of model object which corresponds to this object.
*/
public abstract class RestrictedObject<ModelType> {
/**
* The user this object belongs to. Access is based on his/her permission
* settings.
*/
private AuthenticatedUser currentUser;
/**
* The internal model object containing the values which represent this
* object in the database.
*/
private ModelType model;
/**
* Initializes this object, associating it with the current authenticated
* user and populating it with data from the given model object
*
* @param currentUser
* The user that created or retrieved this object.
*
* @param model
* The backing model object.
*/
public void init(AuthenticatedUser currentUser, ModelType model) {
setCurrentUser(currentUser);
setModel(model);
}
/**
* Returns the user that created or queried this object. This user's
* permissions dictate what operations can be performed on or through this
* object.
*
* @return
* The user that created or queried this object.
*/
public AuthenticatedUser getCurrentUser() {
return currentUser;
}
/**
* Sets the user that created or queried this object. This user's
* permissions dictate what operations can be performed on or through this
* object.
*
* @param currentUser
* The user that created or queried this object.
*/
public void setCurrentUser(AuthenticatedUser currentUser) {
this.currentUser = currentUser;
}
/**
* Returns the backing model object. Changes to the model object will
* affect this object, and changes to this object will affect the model
* object.
*
* @return
* The backing model object.
*/
public ModelType getModel() {
return model;
}
/**
* Sets the backing model object. This will effectively replace all data
* contained within this object.
*
* @param model
* The backing model object.
*/
public void setModel(ModelType model) {
this.model = model;
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Base classes supporting the MySQL authentication provider and defining the
* relationships between the model and the implementations of guacamole-ext
* classes.
*/
package org.glyptodon.guacamole.auth.jdbc.base;

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connection;
import com.google.inject.Inject;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.Connection;
import org.glyptodon.guacamole.net.auth.Directory;
import org.mybatis.guice.transactional.Transactional;
/**
* A MySQL based implementation of the Connection Directory.
*
* @author James Muehlner
* @author Michael Jumper
*/
public class ConnectionDirectory implements Directory<Connection> {
/**
* The user this connection directory belongs to. Access is based on
* his/her permission settings.
*/
private AuthenticatedUser currentUser;
/**
* Service for managing connection objects.
*/
@Inject
private ConnectionService connectionService;
/**
* Set the user for this directory.
*
* @param currentUser
* The user whose permissions define the visibility of connections in
* this directory.
*/
public void init(AuthenticatedUser currentUser) {
this.currentUser = currentUser;
}
@Override
public Connection get(String identifier) throws GuacamoleException {
return connectionService.retrieveObject(currentUser, identifier);
}
@Override
@Transactional
public Collection<Connection> getAll(Collection<String> identifiers) throws GuacamoleException {
Collection<MySQLConnection> objects = connectionService.retrieveObjects(currentUser, identifiers);
return Collections.<Connection>unmodifiableCollection(objects);
}
@Override
@Transactional
public Set<String> getIdentifiers() throws GuacamoleException {
return connectionService.getIdentifiers(currentUser);
}
@Override
@Transactional
public void add(Connection object) throws GuacamoleException {
connectionService.createObject(currentUser, object);
}
@Override
@Transactional
public void update(Connection object) throws GuacamoleException {
MySQLConnection connection = (MySQLConnection) object;
connectionService.updateObject(currentUser, connection);
}
@Override
@Transactional
public void remove(String identifier) throws GuacamoleException {
connectionService.deleteObject(currentUser, identifier);
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connection;
import java.util.Set;
import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectMapper;
import org.glyptodon.guacamole.auth.jdbc.user.UserModel;
import org.apache.ibatis.annotations.Param;
/**
* Mapper for connection objects.
*
* @author Michael Jumper
*/
public interface ConnectionMapper extends DirectoryObjectMapper<ConnectionModel> {
/**
* Selects the identifiers of all connections within the given parent
* connection group, regardless of whether they are readable by any
* particular user. This should only be called on behalf of a system
* administrator. If identifiers are needed by a non-administrative user
* who must have explicit read rights, use
* selectReadableIdentifiersWithin() instead.
*
* @param parentIdentifier
* The identifier of the parent connection group, or null if the root
* connection group is to be queried.
*
* @return
* A Set containing all identifiers of all objects.
*/
Set<String> selectIdentifiersWithin(@Param("parentIdentifier") String parentIdentifier);
/**
* Selects the identifiers of all connections within the given parent
* connection group that are explicitly readable by the given user. If
* identifiers are needed by a system administrator (who, by definition,
* does not need explicit read rights), use selectIdentifiersWithin()
* instead.
*
* @param user
* The user whose permissions should determine whether an identifier
* is returned.
*
* @param parentIdentifier
* The identifier of the parent connection group, or null if the root
* connection group is to be queried.
*
* @return
* A Set containing all identifiers of all readable objects.
*/
Set<String> selectReadableIdentifiersWithin(@Param("user") UserModel user,
@Param("parentIdentifier") String parentIdentifier);
}

View File

@@ -0,0 +1,139 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connection;
import org.glyptodon.guacamole.auth.jdbc.base.ObjectModel;
/**
* Object representation of a Guacamole connection, as represented in the
* database.
*
* @author Michael Jumper
*/
public class ConnectionModel extends ObjectModel {
/**
* The identifier of the parent connection group in the database, or null
* if the parent connection group is the root group.
*/
private String parentIdentifier;
/**
* The human-readable name associated with this connection.
*/
private String name;
/**
* The name of the protocol to use when connecting to this connection.
*/
private String protocol;
/**
* Creates a new, empty connection.
*/
public ConnectionModel() {
}
/**
* Returns the name associated with this connection.
*
* @return
* The name associated with this connection.
*/
public String getName() {
return name;
}
/**
* Sets the name associated with this connection.
*
* @param name
* The name to associate with this connection.
*/
public void setName(String name) {
this.name = name;
}
/**
* Returns the name of the protocol to use when connecting to this
* connection.
*
* @return
* The name of the protocol to use when connecting to this connection.
*/
public String getProtocol() {
return protocol;
}
/**
* Sets the name of the protocol to use when connecting to this connection.
*
* @param protocol
* The name of the protocol to use when connecting to this connection.
*/
public void setProtocol(String protocol) {
this.protocol = protocol;
}
/**
* Returns the identifier of the parent connection group, or null if the
* parent connection group is the root connection group.
*
* @return
* The identifier of the parent connection group, or null if the parent
* connection group is the root connection group.
*/
public String getParentIdentifier() {
return parentIdentifier;
}
/**
* Sets the identifier of the parent connection group.
*
* @param parentIdentifier
* The identifier of the parent connection group, or null if the parent
* connection group is the root connection group.
*/
public void setParentIdentifier(String parentIdentifier) {
this.parentIdentifier = parentIdentifier;
}
@Override
public String getIdentifier() {
// If no associated ID, then no associated identifier
Integer id = getObjectID();
if (id == null)
return null;
// Otherwise, the identifier is the ID as a string
return id.toString();
}
@Override
public void setIdentifier(String identifier) {
throw new UnsupportedOperationException("Connection identifiers are derived from IDs. They cannot be set.");
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connection;
import java.util.List;
import org.apache.ibatis.annotations.Param;
/**
* Mapper for connection record objects.
*
* @author Michael Jumper
*/
public interface ConnectionRecordMapper {
/**
* Returns a collection of all connection records associated with the
* connection having the given identifier.
*
* @param identifier
* The identifier of the connection whose records are to be retrieved.
*
* @return
* A collection of all connection records associated with the
* connection having the given identifier. This collection will be
* empty if no such connection exists.
*/
List<ConnectionRecordModel> select(@Param("identifier") String identifier);
/**
* Inserts the given connection record.
*
* @param record
* The connection record to insert.
*
* @return
* The number of rows inserted.
*/
int insert(@Param("record") ConnectionRecordModel record);
}

View File

@@ -0,0 +1,170 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connection;
import java.util.Date;
/**
* A single connection record representing a past usage of a particular
* connection.
*
* @author Michael Jumper
*/
public class ConnectionRecordModel {
/**
* The identifier of the connection associated with this connection record.
*/
private String connectionIdentifier;
/**
* The database ID of the user associated with this connection record.
*/
private Integer userID;
/**
* The username of the user associated with this connection record.
*/
private String username;
/**
* The time the connection was initiated by the associated user.
*/
private Date startDate;
/**
* The time the connection ended, or null if the end time is not known or
* the connection is still running.
*/
private Date endDate;
/**
* Returns the identifier of the connection associated with this connection
* record.
*
* @return
* The identifier of the connection associated with this connection
* record.
*/
public String getConnectionIdentifier() {
return connectionIdentifier;
}
/**
* Sets the identifier of the connection associated with this connection
* record.
*
* @param connectionIdentifier
* The identifier of the connection to associate with this connection
* record.
*/
public void setConnectionIdentifier(String connectionIdentifier) {
this.connectionIdentifier = connectionIdentifier;
}
/**
* Returns the database ID of the user associated with this connection
* record.
*
* @return
* The database ID of the user associated with this connection record.
*/
public Integer getUserID() {
return userID;
}
/**
* Sets the database ID of the user associated with this connection record.
*
* @param userID
* The database ID of the user to associate with this connection
* record.
*/
public void setUserID(Integer userID) {
this.userID = userID;
}
/**
* Returns the username of the user associated with this connection record.
*
* @return
* The username of the user associated with this connection record.
*/
public String getUsername() {
return username;
}
/**
* Sets the username of the user associated with this connection record.
*
* @param username
* The username of the user to associate with this connection record.
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Returns the date that the associated connection was established.
*
* @return
* The date the associated connection was established.
*/
public Date getStartDate() {
return startDate;
}
/**
* Sets the date that the associated connection was established.
*
* @param startDate
* The date that the associated connection was established.
*/
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
/**
* Returns the date that the associated connection ended, or null if no
* end date was recorded. The lack of an end date does not necessarily
* mean that the connection is still active.
*
* @return
* The date the associated connection ended, or null if no end date was
* recorded.
*/
public Date getEndDate() {
return endDate;
}
/**
* Sets the date that the associated connection ended.
*
* @param endDate
* The date that the associated connection ended.
*/
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
}

View File

@@ -0,0 +1,394 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connection;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectMapper;
import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectService;
import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService;
import org.glyptodon.guacamole.GuacamoleClientException;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.GuacamoleSecurityException;
import org.glyptodon.guacamole.net.GuacamoleSocket;
import org.glyptodon.guacamole.net.auth.Connection;
import org.glyptodon.guacamole.net.auth.ConnectionRecord;
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
/**
* Service which provides convenience methods for creating, retrieving, and
* manipulating connections.
*
* @author Michael Jumper, James Muehlner
*/
public class ConnectionService extends DirectoryObjectService<MySQLConnection, Connection, ConnectionModel> {
/**
* Mapper for accessing connections.
*/
@Inject
private ConnectionMapper connectionMapper;
/**
* Mapper for accessing connection parameters.
*/
@Inject
private ParameterMapper parameterMapper;
/**
* Mapper for accessing connection history.
*/
@Inject
private ConnectionRecordMapper connectionRecordMapper;
/**
* Provider for creating connections.
*/
@Inject
private Provider<MySQLConnection> mySQLConnectionProvider;
/**
* Service for creating and tracking sockets.
*/
@Inject
private GuacamoleSocketService socketService;
@Override
protected DirectoryObjectMapper<ConnectionModel> getObjectMapper() {
return connectionMapper;
}
@Override
protected MySQLConnection getObjectInstance(AuthenticatedUser currentUser,
ConnectionModel model) {
MySQLConnection connection = mySQLConnectionProvider.get();
connection.init(currentUser, model);
return connection;
}
@Override
protected ConnectionModel getModelInstance(AuthenticatedUser currentUser,
final Connection object) {
// Create new MySQLConnection backed by blank model
ConnectionModel model = new ConnectionModel();
MySQLConnection connection = getObjectInstance(currentUser, model);
// Set model contents through MySQLConnection, copying the provided connection
connection.setParentIdentifier(object.getParentIdentifier());
connection.setName(object.getName());
connection.setConfiguration(object.getConfiguration());
return model;
}
@Override
protected boolean hasCreatePermission(AuthenticatedUser user)
throws GuacamoleException {
// Return whether user has explicit connection creation permission
SystemPermissionSet permissionSet = user.getUser().getSystemPermissions();
return permissionSet.hasPermission(SystemPermission.Type.CREATE_CONNECTION);
}
@Override
protected ObjectPermissionSet getPermissionSet(AuthenticatedUser user)
throws GuacamoleException {
// Return permissions related to connections
return user.getUser().getConnectionPermissions();
}
@Override
protected void validateNewObject(AuthenticatedUser user, Connection object)
throws GuacamoleException {
// Name must not be blank
if (object.getName().trim().isEmpty())
throw new GuacamoleClientException("Connection names must not be blank.");
// FIXME: Do not attempt to create duplicate connections
}
@Override
protected void validateExistingObject(AuthenticatedUser user,
MySQLConnection object) throws GuacamoleException {
// Name must not be blank
if (object.getName().trim().isEmpty())
throw new GuacamoleClientException("Connection names must not be blank.");
// FIXME: Check whether such a connection is already present
}
/**
* Given an arbitrary Guacamole connection, produces a collection of
* parameter model objects containing the name/value pairs of that
* connection's parameters.
*
* @param connection
* The connection whose configuration should be used to produce the
* collection of parameter models.
*
* @return
* A collection of parameter models containing the name/value pairs
* of the given connection's parameters.
*/
private Collection<ParameterModel> getParameterModels(MySQLConnection connection) {
Map<String, String> parameters = connection.getConfiguration().getParameters();
// Convert parameters to model objects
Collection<ParameterModel> parameterModels = new ArrayList(parameters.size());
for (Map.Entry<String, String> parameterEntry : parameters.entrySet()) {
// Get parameter name and value
String name = parameterEntry.getKey();
String value = parameterEntry.getValue();
// There is no need to insert empty parameters
if (value.isEmpty())
continue;
// Produce model object from parameter
ParameterModel model = new ParameterModel();
model.setConnectionIdentifier(connection.getIdentifier());
model.setName(name);
model.setValue(value);
// Add model to list
parameterModels.add(model);
}
return parameterModels;
}
@Override
public MySQLConnection createObject(AuthenticatedUser user, Connection object)
throws GuacamoleException {
// Create connection
MySQLConnection connection = super.createObject(user, object);
connection.setConfiguration(object.getConfiguration());
// Insert new parameters, if any
Collection<ParameterModel> parameterModels = getParameterModels(connection);
if (!parameterModels.isEmpty())
parameterMapper.insert(parameterModels);
return connection;
}
@Override
public void updateObject(AuthenticatedUser user, MySQLConnection object)
throws GuacamoleException {
// Update connection
super.updateObject(user, object);
// Replace existing parameters with new parameters
Collection<ParameterModel> parameterModels = getParameterModels(object);
parameterMapper.delete(object.getIdentifier());
parameterMapper.insert(parameterModels);
}
/**
* Returns the set of all identifiers for all connections within the
* connection group having the given identifier. Only connections that the
* user has read access to will be returned.
*
* Permission to read the connection group having the given identifier is
* NOT checked.
*
* @param user
* The user retrieving the identifiers.
*
* @param identifier
* The identifier of the parent connection group, or null to check the
* root connection group.
*
* @return
* The set of all identifiers for all connections in the connection
* group having the given identifier that the user has read access to.
*
* @throws GuacamoleException
* If an error occurs while reading identifiers.
*/
public Set<String> getIdentifiersWithin(AuthenticatedUser user,
String identifier)
throws GuacamoleException {
// Bypass permission checks if the user is a system admin
if (user.getUser().isAdministrator())
return connectionMapper.selectIdentifiersWithin(identifier);
// Otherwise only return explicitly readable identifiers
else
return connectionMapper.selectReadableIdentifiersWithin(user.getUser().getModel(), identifier);
}
/**
* Retrieves all parameters visible to the given user and associated with
* the connection having the given identifier. If the given user has no
* access to such parameters, or no such connection exists, the returned
* map will be empty.
*
* @param user
* The user retrieving connection parameters.
*
* @param identifier
* The identifier of the connection whose parameters are being
* retrieved.
*
* @return
* A new map of all parameter name/value pairs that the given user has
* access to.
*/
public Map<String, String> retrieveParameters(AuthenticatedUser user,
String identifier) {
Map<String, String> parameterMap = new HashMap<String, String>();
// Determine whether we have permission to read parameters
boolean canRetrieveParameters;
try {
canRetrieveParameters = hasObjectPermission(user, identifier,
ObjectPermission.Type.UPDATE);
}
// Provide empty (but mutable) map if unable to check permissions
catch (GuacamoleException e) {
return parameterMap;
}
// Populate parameter map if we have permission to do so
if (canRetrieveParameters) {
for (ParameterModel parameter : parameterMapper.select(identifier))
parameterMap.put(parameter.getName(), parameter.getValue());
}
return parameterMap;
}
/**
* Retrieves the connection history of the given connection, including any
* active connections.
*
* @param user
* The user retrieving the connection history.
*
* @param connection
* The connection whose history is being retrieved.
*
* @return
* The connection history of the given connection, including any
* active connections.
*
* @throws GuacamoleException
* If permission to read the connection history is denied.
*/
public List<ConnectionRecord> retrieveHistory(AuthenticatedUser user,
MySQLConnection connection) throws GuacamoleException {
String identifier = connection.getIdentifier();
// Retrieve history only if READ permission is granted
if (hasObjectPermission(user, identifier, ObjectPermission.Type.READ)) {
// Retrieve history
List<ConnectionRecordModel> models = connectionRecordMapper.select(identifier);
// Get currently-active connections
List<ConnectionRecord> records = new ArrayList<ConnectionRecord>(socketService.getActiveConnections(connection));
// Add past connections from model objects
for (ConnectionRecordModel model : models)
records.add(new MySQLConnectionRecord(model));
// Return converted history list
return records;
}
// The user does not have permission to read the history
throw new GuacamoleSecurityException("Permission denied.");
}
/**
* Connects to the given connection as the given user, using the given
* client information. If the user does not have permission to read the
* connection, permission will be denied.
*
* @param user
* The user connecting to the connection.
*
* @param connection
* The connection being connected to.
*
* @param info
* Information associated with the connecting client.
*
* @return
* A connected GuacamoleSocket associated with a newly-established
* connection.
*
* @throws GuacamoleException
* If permission to connect to this connection is denied.
*/
public GuacamoleSocket connect(AuthenticatedUser user,
MySQLConnection connection, GuacamoleClientInformation info)
throws GuacamoleException {
// Connect only if READ permission is granted
if (hasObjectPermission(user, connection.getIdentifier(), ObjectPermission.Type.READ))
return socketService.getGuacamoleSocket(user, connection, info);
// The user does not have permission to connect
throw new GuacamoleSecurityException("Permission denied.");
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connection;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.List;
import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObject;
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.MySQLRootConnectionGroup;
import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.GuacamoleSocket;
import org.glyptodon.guacamole.net.auth.Connection;
import org.glyptodon.guacamole.net.auth.ConnectionRecord;
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
/**
* A MySQL based implementation of the Connection object.
* @author James Muehlner
*/
public class MySQLConnection extends DirectoryObject<ConnectionModel>
implements Connection {
/**
* Service for managing connections.
*/
@Inject
private ConnectionService connectionService;
/**
* Service for creating and tracking sockets.
*/
@Inject
private GuacamoleSocketService socketService;
/**
* Provider for lazy-loaded, permission-controlled configurations.
*/
@Inject
private Provider<MySQLGuacamoleConfiguration> configProvider;
/**
* The manually-set GuacamoleConfiguration, if any.
*/
private GuacamoleConfiguration config = null;
/**
* Creates a new, empty MySQLConnection.
*/
public MySQLConnection() {
}
@Override
public String getName() {
return getModel().getName();
}
@Override
public void setName(String name) {
getModel().setName(name);
}
@Override
public String getParentIdentifier() {
// Translate null parent to proper identifier
String parentIdentifier = getModel().getParentIdentifier();
if (parentIdentifier == null)
return MySQLRootConnectionGroup.IDENTIFIER;
return parentIdentifier;
}
@Override
public void setParentIdentifier(String parentIdentifier) {
// Translate root identifier back into null
if (parentIdentifier != null
&& parentIdentifier.equals(MySQLRootConnectionGroup.IDENTIFIER))
parentIdentifier = null;
getModel().setParentIdentifier(parentIdentifier);
}
@Override
public GuacamoleConfiguration getConfiguration() {
// If configuration has been manually set, return that
if (config != null)
return config;
// Otherwise, return permission-controlled configuration
MySQLGuacamoleConfiguration restrictedConfig = configProvider.get();
restrictedConfig.init(getCurrentUser(), getModel());
return restrictedConfig;
}
@Override
public void setConfiguration(GuacamoleConfiguration config) {
// Store manually-set configuration internally
this.config = config;
// Update model
getModel().setProtocol(config.getProtocol());
}
@Override
public List<? extends ConnectionRecord> getHistory() throws GuacamoleException {
return connectionService.retrieveHistory(getCurrentUser(), this);
}
@Override
public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
return connectionService.connect(getCurrentUser(), this, info);
}
@Override
public int getActiveConnections() {
return socketService.getActiveConnections(this).size();
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connection;
import java.util.Date;
import org.glyptodon.guacamole.net.auth.ConnectionRecord;
/**
* A ConnectionRecord which is based on data stored in MySQL.
*
* @author James Muehlner
* @author Michael Jumper
*/
public class MySQLConnectionRecord implements ConnectionRecord {
/**
* The model object backing this connection record.
*/
private ConnectionRecordModel model;
/**
* Creates a new MySQLConnectionRecord backed by the given model object.
* Changes to this record will affect the backing model object, and changes
* to the backing model object will affect this record.
*
* @param model
* The model object to use to back this connection record.
*/
public MySQLConnectionRecord(ConnectionRecordModel model) {
this.model = model;
}
@Override
public Date getStartDate() {
return model.getStartDate();
}
@Override
public Date getEndDate() {
return model.getEndDate();
}
@Override
public String getUsername() {
return model.getUsername();
}
@Override
public boolean isActive() {
return false;
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connection;
import com.google.inject.Inject;
import java.util.Map;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
/**
* Implementation of GuacamoleConfiguration which loads parameter values only
* if necessary, and only if allowed.
*
* @author Michael Jumper
*/
public class MySQLGuacamoleConfiguration extends GuacamoleConfiguration {
/**
* The user this configuration belongs to. Access is based on his/her
* permission settings.
*/
private AuthenticatedUser currentUser;
/**
* The internal model object containing the values which represent the
* connection associated with this configuration.
*/
private ConnectionModel connectionModel;
/**
* Service for managing connection parameters.
*/
@Inject
private ConnectionService connectionService;
/**
* The manually-set parameter map, if any.
*/
private Map<String, String> parameters = null;
/**
* Creates a new, empty MySQLGuacamoleConfiguration.
*/
public MySQLGuacamoleConfiguration() {
}
/**
* Initializes this configuration, associating it with the current
* authenticated user and populating it with data from the given model
* object.
*
* @param currentUser
* The user that created or retrieved this configuration.
*
* @param connectionModel
* The model object backing this configuration.
*/
public void init(AuthenticatedUser currentUser, ConnectionModel connectionModel) {
this.currentUser = currentUser;
this.connectionModel = connectionModel;
}
@Override
public String getProtocol() {
return connectionModel.getProtocol();
}
@Override
public void setProtocol(String protocol) {
super.setProtocol(protocol);
connectionModel.setProtocol(protocol);
}
@Override
public void setParameters(Map<String, String> parameters) {
this.parameters = parameters;
super.setParameters(parameters);
}
@Override
public Map<String, String> getParameters() {
// Retrieve visible parameters, if not overridden by setParameters()
if (parameters == null) {
// Retrieve all visible parameters
Map<String, String> visibleParameters =
connectionService.retrieveParameters(currentUser, connectionModel.getIdentifier());
// Use retrieved parameters to back future operations
super.setParameters(visibleParameters);
}
return super.getParameters();
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connection;
import java.util.Collection;
import org.apache.ibatis.annotations.Param;
/**
* Mapper for connection parameter objects.
*
* @author Michael Jumper
*/
public interface ParameterMapper {
/**
* Returns a collection of all parameters associated with the connection
* having the given identifier.
*
* @param identifier
* The identifier of the connection whose parameters are to be
* retrieved.
*
* @return
* A collection of all parameters associated with the connection
* having the given identifier. This collection will be empty if no
* such connection exists.
*/
Collection<ParameterModel> select(@Param("identifier") String identifier);
/**
* Inserts each of the parameter model objects in the given collection as
* new connection parameters.
*
* @param parameters
* The connection parameters to insert.
*
* @return
* The number of rows inserted.
*/
int insert(@Param("parameters") Collection<ParameterModel> parameters);
/**
* Deletes all parameters associated with the connection having the given
* identifier.
*
* @param identifier
* The identifier of the connection whose parameters should be
* deleted.
*
* @return
* The number of rows deleted.
*/
int delete(@Param("identifier") String identifier);
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connection;
/**
* A single parameter name/value pair belonging to a connection.
*
* @author Michael Jumper
*/
public class ParameterModel {
/**
* The identifier of the connection associated with this parameter.
*/
private String connectionIdentifier;
/**
* The name of the parameter.
*/
private String name;
/**
* The value the parameter is set to.
*/
private String value;
/**
* Returns the identifier of the connection associated with this parameter.
*
* @return
* The identifier of the connection associated with this parameter.
*/
public String getConnectionIdentifier() {
return connectionIdentifier;
}
/**
* Sets the identifier of the connection associated with this parameter.
*
* @param connectionIdentifier
* The identifier of the connection to associate with this parameter.
*/
public void setConnectionIdentifier(String connectionIdentifier) {
this.connectionIdentifier = connectionIdentifier;
}
/**
* Returns the name of this parameter.
*
* @return
* The name of this parameter.
*/
public String getName() {
return name;
}
/**
* Sets the name of this parameter.
*
* @param name
* The name of this parameter.
*/
public void setName(String name) {
this.name = name;
}
/**
* Returns the value of this parameter.
*
* @return
* The value of this parameter.
*/
public String getValue() {
return value;
}
/**
* Sets the value of this parameter.
*
* @param value
* The value of this parameter.
*/
public void setValue(String value) {
this.value = value;
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Classes related to connections and their parameters and history.
*/
package org.glyptodon.guacamole.auth.jdbc.connection;

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connectiongroup;
import com.google.inject.Inject;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.net.auth.Directory;
import org.mybatis.guice.transactional.Transactional;
/**
* A MySQL based implementation of the ConnectionGroup Directory.
*
* @author James Muehlner
* @author Michael Jumper
*/
public class ConnectionGroupDirectory implements Directory<ConnectionGroup> {
/**
* The user this connection group directory belongs to. Access is based on
* his/her permission settings.
*/
private AuthenticatedUser currentUser;
/**
* Service for managing connection group objects.
*/
@Inject
private ConnectionGroupService connectionGroupService;
/**
* Set the user for this directory.
*
* @param currentUser
* The user whose permissions define the visibility of connection
* groups in this directory.
*/
public void init(AuthenticatedUser currentUser) {
this.currentUser = currentUser;
}
@Override
public ConnectionGroup get(String identifier) throws GuacamoleException {
return connectionGroupService.retrieveObject(currentUser, identifier);
}
@Override
@Transactional
public Collection<ConnectionGroup> getAll(Collection<String> identifiers) throws GuacamoleException {
Collection<MySQLConnectionGroup> objects = connectionGroupService.retrieveObjects(currentUser, identifiers);
return Collections.<ConnectionGroup>unmodifiableCollection(objects);
}
@Override
@Transactional
public Set<String> getIdentifiers() throws GuacamoleException {
return connectionGroupService.getIdentifiers(currentUser);
}
@Override
@Transactional
public void add(ConnectionGroup object) throws GuacamoleException {
connectionGroupService.createObject(currentUser, object);
}
@Override
@Transactional
public void update(ConnectionGroup object) throws GuacamoleException {
MySQLConnectionGroup connectionGroup = (MySQLConnectionGroup) object;
connectionGroupService.updateObject(currentUser, connectionGroup);
}
@Override
@Transactional
public void remove(String identifier) throws GuacamoleException {
connectionGroupService.deleteObject(currentUser, identifier);
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connectiongroup;
import java.util.Set;
import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectMapper;
import org.glyptodon.guacamole.auth.jdbc.user.UserModel;
import org.apache.ibatis.annotations.Param;
/**
* Mapper for connection group objects.
*
* @author Michael Jumper
*/
public interface ConnectionGroupMapper extends DirectoryObjectMapper<ConnectionGroupModel> {
/**
* Selects the identifiers of all connection groups within the given parent
* connection group, regardless of whether they are readable by any
* particular user. This should only be called on behalf of a system
* administrator. If identifiers are needed by a non-administrative user
* who must have explicit read rights, use
* selectReadableIdentifiersWithin() instead.
*
* @param parentIdentifier
* The identifier of the parent connection group, or null if the root
* connection group is to be queried.
*
* @return
* A Set containing all identifiers of all objects.
*/
Set<String> selectIdentifiersWithin(@Param("parentIdentifier") String parentIdentifier);
/**
* Selects the identifiers of all connection groups within the given parent
* connection group that are explicitly readable by the given user. If
* identifiers are needed by a system administrator (who, by definition,
* does not need explicit read rights), use selectIdentifiersWithin()
* instead.
*
* @param user
* The user whose permissions should determine whether an identifier
* is returned.
*
* @param parentIdentifier
* The identifier of the parent connection group, or null if the root
* connection group is to be queried.
*
* @return
* A Set containing all identifiers of all readable objects.
*/
Set<String> selectReadableIdentifiersWithin(@Param("user") UserModel user,
@Param("parentIdentifier") String parentIdentifier);
}

View File

@@ -0,0 +1,141 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connectiongroup;
import org.glyptodon.guacamole.auth.jdbc.base.ObjectModel;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
/**
* Object representation of a Guacamole connection group, as represented in the
* database.
*
* @author Michael Jumper
*/
public class ConnectionGroupModel extends ObjectModel {
/**
* The identifier of the parent connection group in the database, or null
* if the parent connection group is the root group.
*/
private String parentIdentifier;
/**
* The human-readable name associated with this connection group.
*/
private String name;
/**
* The type of this connection group, such as organizational or balancing.
*/
private ConnectionGroup.Type type;
/**
* Creates a new, empty connection group.
*/
public ConnectionGroupModel() {
}
/**
* Returns the name associated with this connection group.
*
* @return
* The name associated with this connection group.
*/
public String getName() {
return name;
}
/**
* Sets the name associated with this connection group.
*
* @param name
* The name to associate with this connection group.
*/
public void setName(String name) {
this.name = name;
}
/**
* Returns the identifier of the parent connection group, or null if the
* parent connection group is the root connection group.
*
* @return
* The identifier of the parent connection group, or null if the parent
* connection group is the root connection group.
*/
public String getParentIdentifier() {
return parentIdentifier;
}
/**
* Sets the identifier of the parent connection group.
*
* @param parentIdentifier
* The identifier of the parent connection group, or null if the parent
* connection group is the root connection group.
*/
public void setParentIdentifier(String parentIdentifier) {
this.parentIdentifier = parentIdentifier;
}
/**
* Returns the type of this connection group, such as organizational or
* balancing.
*
* @return
* The type of this connection group.
*/
public ConnectionGroup.Type getType() {
return type;
}
/**
* Sets the type of this connection group, such as organizational or
* balancing.
*
* @param type
* The type of this connection group.
*/
public void setType(ConnectionGroup.Type type) {
this.type = type;
}
@Override
public String getIdentifier() {
// If no associated ID, then no associated identifier
Integer id = getObjectID();
if (id == null)
return null;
// Otherwise, the identifier is the ID as a string
return id.toString();
}
@Override
public void setIdentifier(String identifier) {
throw new UnsupportedOperationException("Connection group identifiers are derived from IDs. They cannot be set.");
}
}

View File

@@ -0,0 +1,214 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connectiongroup;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.Set;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectMapper;
import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectService;
import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService;
import org.glyptodon.guacamole.GuacamoleClientException;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.GuacamoleSecurityException;
import org.glyptodon.guacamole.net.GuacamoleSocket;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
/**
* Service which provides convenience methods for creating, retrieving, and
* manipulating connection groups.
*
* @author Michael Jumper, James Muehlner
*/
public class ConnectionGroupService extends DirectoryObjectService<MySQLConnectionGroup,
ConnectionGroup, ConnectionGroupModel> {
/**
* Mapper for accessing connection groups.
*/
@Inject
private ConnectionGroupMapper connectionGroupMapper;
/**
* Provider for creating connection groups.
*/
@Inject
private Provider<MySQLConnectionGroup> connectionGroupProvider;
/**
* Service for creating and tracking sockets.
*/
@Inject
private GuacamoleSocketService socketService;
@Override
protected DirectoryObjectMapper<ConnectionGroupModel> getObjectMapper() {
return connectionGroupMapper;
}
@Override
protected MySQLConnectionGroup getObjectInstance(AuthenticatedUser currentUser,
ConnectionGroupModel model) {
MySQLConnectionGroup connectionGroup = connectionGroupProvider.get();
connectionGroup.init(currentUser, model);
return connectionGroup;
}
@Override
protected ConnectionGroupModel getModelInstance(AuthenticatedUser currentUser,
final ConnectionGroup object) {
// Create new MySQLConnectionGroup backed by blank model
ConnectionGroupModel model = new ConnectionGroupModel();
MySQLConnectionGroup connectionGroup = getObjectInstance(currentUser, model);
// Set model contents through MySQLConnection, copying the provided connection group
connectionGroup.setParentIdentifier(object.getParentIdentifier());
connectionGroup.setName(object.getName());
connectionGroup.setType(object.getType());
return model;
}
@Override
protected boolean hasCreatePermission(AuthenticatedUser user)
throws GuacamoleException {
// Return whether user has explicit connection group creation permission
SystemPermissionSet permissionSet = user.getUser().getSystemPermissions();
return permissionSet.hasPermission(SystemPermission.Type.CREATE_CONNECTION_GROUP);
}
@Override
protected ObjectPermissionSet getPermissionSet(AuthenticatedUser user)
throws GuacamoleException {
// Return permissions related to connection groups
return user.getUser().getConnectionGroupPermissions();
}
@Override
protected void validateNewObject(AuthenticatedUser user, ConnectionGroup object)
throws GuacamoleException {
// Name must not be blank
if (object.getName().trim().isEmpty())
throw new GuacamoleClientException("Connection group names must not be blank.");
// FIXME: Do not attempt to create duplicate connection groups
}
@Override
protected void validateExistingObject(AuthenticatedUser user,
MySQLConnectionGroup object) throws GuacamoleException {
// Name must not be blank
if (object.getName().trim().isEmpty())
throw new GuacamoleClientException("Connection group names must not be blank.");
// FIXME: Check whether such a connection group is already present
}
/**
* Returns the set of all identifiers for all connection groups within the
* connection group having the given identifier. Only connection groups
* that the user has read access to will be returned.
*
* Permission to read the connection group having the given identifier is
* NOT checked.
*
* @param user
* The user retrieving the identifiers.
*
* @param identifier
* The identifier of the parent connection group, or null to check the
* root connection group.
*
* @return
* The set of all identifiers for all connection groups in the
* connection group having the given identifier that the user has read
* access to.
*
* @throws GuacamoleException
* If an error occurs while reading identifiers.
*/
public Set<String> getIdentifiersWithin(AuthenticatedUser user,
String identifier)
throws GuacamoleException {
// Bypass permission checks if the user is a system admin
if (user.getUser().isAdministrator())
return connectionGroupMapper.selectIdentifiersWithin(identifier);
// Otherwise only return explicitly readable identifiers
else
return connectionGroupMapper.selectReadableIdentifiersWithin(user.getUser().getModel(), identifier);
}
/**
* Connects to the given connection group as the given user, using the
* given client information. If the user does not have permission to read
* the connection group, permission will be denied.
*
* @param user
* The user connecting to the connection group.
*
* @param connectionGroup
* The connectionGroup being connected to.
*
* @param info
* Information associated with the connecting client.
*
* @return
* A connected GuacamoleSocket associated with a newly-established
* connection.
*
* @throws GuacamoleException
* If permission to connect to this connection is denied.
*/
public GuacamoleSocket connect(AuthenticatedUser user,
MySQLConnectionGroup connectionGroup, GuacamoleClientInformation info)
throws GuacamoleException {
// Connect only if READ permission is granted
if (hasObjectPermission(user, connectionGroup.getIdentifier(), ObjectPermission.Type.READ))
return socketService.getGuacamoleSocket(user, connectionGroup, info);
// The user does not have permission to connect
throw new GuacamoleSecurityException("Permission denied.");
}
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connectiongroup;
import com.google.inject.Inject;
import java.util.Set;
import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObject;
import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionService;
import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.GuacamoleSocket;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
/**
* A MySQL based implementation of the ConnectionGroup object.
*
* @author James Muehlner
*/
public class MySQLConnectionGroup extends DirectoryObject<ConnectionGroupModel>
implements ConnectionGroup {
/**
* Service for managing connections.
*/
@Inject
private ConnectionService connectionService;
/**
* Service for managing connection groups.
*/
@Inject
private ConnectionGroupService connectionGroupService;
/**
* Service for creating and tracking sockets.
*/
@Inject
private GuacamoleSocketService socketService;
/**
* Creates a new, empty MySQLConnection.
*/
public MySQLConnectionGroup() {
}
@Override
public String getName() {
return getModel().getName();
}
@Override
public void setName(String name) {
getModel().setName(name);
}
@Override
public String getParentIdentifier() {
// Translate null parent to proper identifier
String parentIdentifier = getModel().getParentIdentifier();
if (parentIdentifier == null)
return MySQLRootConnectionGroup.IDENTIFIER;
return parentIdentifier;
}
@Override
public void setParentIdentifier(String parentIdentifier) {
// Translate root identifier back into null
if (parentIdentifier != null
&& parentIdentifier.equals(MySQLRootConnectionGroup.IDENTIFIER))
parentIdentifier = null;
getModel().setParentIdentifier(parentIdentifier);
}
@Override
public GuacamoleSocket connect(GuacamoleClientInformation info)
throws GuacamoleException {
return connectionGroupService.connect(getCurrentUser(), this, info);
}
@Override
public int getActiveConnections() {
return socketService.getActiveConnections(this).size();
}
@Override
public void setType(Type type) {
getModel().setType(type);
}
@Override
public Type getType() {
return getModel().getType();
}
@Override
public Set<String> getConnectionIdentifiers()
throws GuacamoleException {
return connectionService.getIdentifiersWithin(getCurrentUser(), getIdentifier());
}
@Override
public Set<String> getConnectionGroupIdentifiers()
throws GuacamoleException {
return connectionGroupService.getIdentifiersWithin(getCurrentUser(), getIdentifier());
}
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.connectiongroup;
import com.google.inject.Inject;
import java.util.Set;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionService;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.GuacamoleSecurityException;
import org.glyptodon.guacamole.net.GuacamoleSocket;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
/**
* The root connection group, here represented as its own dedicated object as
* the database does not contain an actual root group.
*
* @author Michael Jumper
*/
public class MySQLRootConnectionGroup implements ConnectionGroup {
/**
* The identifier used to represent the root connection group. There is no
* corresponding entry in the database, thus a reserved identifier that
* cannot collide with database-generated identifiers is needed.
*/
public static final String IDENTIFIER = "ROOT";
/**
* The human-readable name of this connection group. The name of the root
* group is not normally visible, and may even be replaced by the web
* interface for the sake of translation.
*/
public static final String NAME = "ROOT";
/**
* The user this group belongs to. Access is based on his/her permission
* settings.
*/
private AuthenticatedUser currentUser;
/**
* Service for managing connection objects.
*/
@Inject
private ConnectionService connectionService;
/**
* Service for managing connection group objects.
*/
@Inject
private ConnectionGroupService connectionGroupService;
/**
* Creates a new, empty MySQLRootConnectionGroup.
*/
public MySQLRootConnectionGroup() {
}
/**
* Initializes this root connection group, associating it with the current
* authenticated user.
*
* @param currentUser
* The user that created or retrieved this object.
*/
public void init(AuthenticatedUser currentUser) {
this.currentUser = currentUser;
}
@Override
public String getName() {
return NAME;
}
@Override
public void setName(String name) {
throw new UnsupportedOperationException("The root connection group cannot be modified.");
}
@Override
public String getParentIdentifier() {
return null;
}
@Override
public void setParentIdentifier(String parentIdentifier) {
throw new UnsupportedOperationException("The root connection group cannot be modified.");
}
@Override
public Type getType() {
return ConnectionGroup.Type.ORGANIZATIONAL;
}
@Override
public void setType(Type type) {
throw new UnsupportedOperationException("The root connection group cannot be modified.");
}
@Override
public Set<String> getConnectionIdentifiers() throws GuacamoleException {
return connectionService.getIdentifiersWithin(currentUser, null);
}
@Override
public Set<String> getConnectionGroupIdentifiers()
throws GuacamoleException {
return connectionGroupService.getIdentifiersWithin(currentUser, null);
}
@Override
public String getIdentifier() {
return IDENTIFIER;
}
@Override
public void setIdentifier(String identifier) {
throw new UnsupportedOperationException("The root connection group cannot be modified.");
}
@Override
public GuacamoleSocket connect(GuacamoleClientInformation info)
throws GuacamoleException {
throw new GuacamoleSecurityException("Permission denied.");
}
@Override
public int getActiveConnections() {
return 0;
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Classes related to connection groups.
*/
package org.glyptodon.guacamole.auth.jdbc.connectiongroup;

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* The base JDBC authentication provider. This authentication provider serves
* as a basis for other JDBC authentication provider implementations which are
* driven by relatively-common schemas. The only difference between such
* implementations are maintained within database-specific MyBatis mappings.
*/
package org.glyptodon.guacamole.auth.jdbc;

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.permission;
import org.glyptodon.guacamole.auth.jdbc.user.MySQLUser;
import com.google.inject.Inject;
import java.util.Collections;
import java.util.Set;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
/**
* A database implementation of SystemPermissionSet which uses an injected
* service to query and manipulate the system permissions associated with a
* particular user.
*
* @author Michael Jumper
*/
public class MySQLSystemPermissionSet implements SystemPermissionSet {
/**
* The user that queried this permission set. Access is based on his/her
* permission settings.
*/
private AuthenticatedUser currentUser;
/**
* The user associated with this permission set. Each of the permissions in
* this permission set is granted to this user.
*/
private MySQLUser user;
/**
* Service for reading and manipulating system permissions.
*/
@Inject
private SystemPermissionService systemPermissionService;
/**
* Creates a new MySQLSystemPermissionSet. The resulting permission set
* must still be initialized by a call to init(), or the information
* necessary to read and modify this set will be missing.
*/
public MySQLSystemPermissionSet() {
}
/**
* Initializes this permission set with the current user and the user
* to whom the permissions in this set are granted.
*
* @param currentUser
* The user who queried this permission set, and whose permissions
* dictate the access level of all operations performed on this set.
*
* @param user
* The user to whom the permissions in this set are granted.
*/
public void init(AuthenticatedUser currentUser, MySQLUser user) {
this.currentUser = currentUser;
this.user = user;
}
@Override
public Set<SystemPermission> getPermissions() throws GuacamoleException {
return systemPermissionService.retrievePermissions(currentUser, user);
}
@Override
public boolean hasPermission(SystemPermission.Type permission)
throws GuacamoleException {
return systemPermissionService.retrievePermission(currentUser, user, permission) != null;
}
@Override
public void addPermission(SystemPermission.Type permission)
throws GuacamoleException {
addPermissions(Collections.singleton(new SystemPermission(permission)));
}
@Override
public void removePermission(SystemPermission.Type permission)
throws GuacamoleException {
removePermissions(Collections.singleton(new SystemPermission(permission)));
}
@Override
public void addPermissions(Set<SystemPermission> permissions)
throws GuacamoleException {
systemPermissionService.createPermissions(currentUser, user, permissions);
}
@Override
public void removePermissions(Set<SystemPermission> permissions)
throws GuacamoleException {
systemPermissionService.deletePermissions(currentUser, user, permissions);
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.permission;
/**
* Mapper for object-related permissions.
*
* @author Michael Jumper
*/
public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissionModel> {
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.permission;
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
/**
* Object representation of an object-related Guacamole permission, as
* represented in the database.
*
* @author Michael Jumper
*/
public class ObjectPermissionModel extends PermissionModel<ObjectPermission.Type> {
/**
* The database ID of the object affected by this permission.
*/
private Integer affectedID;
/**
* The unique identifier of the object affected by this permission.
*/
private String affectedIdentifier;
/**
* Creates a new, empty object permission.
*/
public ObjectPermissionModel() {
}
/**
* Returns the database ID of the object affected by this permission.
*
* @return
* The database ID of the object affected by this permission.
*/
public Integer getAffectedID() {
return affectedID;
}
/**
* Sets the database ID of the object affected by this permission.
*
* @param affectedID
* The database ID of the object affected by this permission.
*/
public void setAffectedID(Integer affectedID) {
this.affectedID = affectedID;
}
/**
* Returns the unique identifier of the object affected by this permission.
*
* @return
* The unique identifier of the object affected by this permission.
*/
public String getAffectedIdentifier() {
return affectedIdentifier;
}
/**
* Sets the unique identifier of the object affected by this permission.
*
* @param affectedIdentifier
* The unique identifier of the object affected by this permission.
*/
public void setAffectedIdentifier(String affectedIdentifier) {
this.affectedIdentifier = affectedIdentifier;
}
}

View File

@@ -0,0 +1,159 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.permission;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.auth.jdbc.user.MySQLUser;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.GuacamoleSecurityException;
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
/**
* Service which provides convenience methods for creating, retrieving, and
* deleting object permissions. This service will automatically enforce the
* permissions of the current user.
*
* @author Michael Jumper
* @param <ModelType>
* The underlying model object used to represent PermissionType in the
* database.
*/
public abstract class ObjectPermissionService<ModelType>
extends PermissionService<ObjectPermissionSet, ObjectPermission, ModelType> {
/**
* Returns the permission set associated with the given user and related
* to the type of objects affected the permissions handled by this
* permission service.
*
* @param user
* The user whose permissions are being retrieved.
*
* @return
* A permission set which contains the permissions associated with the
* given user and related to the type of objects handled by this
* directory object service.
*
* @throws GuacamoleException
* If permission to read the user's permissions is denied.
*/
protected abstract ObjectPermissionSet getAffectedPermissionSet(AuthenticatedUser user)
throws GuacamoleException;
/**
* Determines whether the current user has permission to update the given
* target user, adding or removing the given permissions. Such permission
* depends on whether the current user is a system administrator, whether
* they have explicit UPDATE permission on the target user, and whether
* they have explicit ADMINISTER permission on all affected objects.
*
* @param user
* The user who is changing permissions.
*
* @param targetUser
* The user whose permissions are being changed.
*
* @param permissions
* The permissions that are being added or removed from the target
* user.
*
* @return
* true if the user has permission to change the target users
* permissions as specified, false otherwise.
*
* @throws GuacamoleException
* If an error occurs while checking permission status, or if
* permission is denied to read the current user's permissions.
*/
protected boolean canAlterPermissions(AuthenticatedUser user, MySQLUser targetUser,
Collection<ObjectPermission> permissions)
throws GuacamoleException {
// A system adminstrator can do anything
if (user.getUser().isAdministrator())
return true;
// Verify user has update permission on the target user
ObjectPermissionSet userPermissionSet = user.getUser().getUserPermissions();
if (!userPermissionSet.hasPermission(ObjectPermission.Type.UPDATE, targetUser.getIdentifier()))
return false;
// Produce collection of affected identifiers
Collection<String> affectedIdentifiers = new HashSet(permissions.size());
for (ObjectPermission permission : permissions)
affectedIdentifiers.add(permission.getObjectIdentifier());
// Determine subset of affected identifiers that we have admin access to
ObjectPermissionSet affectedPermissionSet = getAffectedPermissionSet(user);
Collection<String> allowedSubset = affectedPermissionSet.getAccessibleObjects(
Collections.singleton(ObjectPermission.Type.ADMINISTER),
affectedIdentifiers
);
// The permissions can be altered if and only if the set of objects we
// are allowed to administer is equal to the set of objects we will be
// affecting.
return affectedIdentifiers.size() == allowedSubset.size();
}
@Override
public void createPermissions(AuthenticatedUser user, MySQLUser targetUser,
Collection<ObjectPermission> permissions)
throws GuacamoleException {
// Create permissions only if user has permission to do so
if (canAlterPermissions(user, targetUser, permissions)) {
Collection<ModelType> models = getModelInstances(targetUser, permissions);
getPermissionMapper().insert(models);
return;
}
// User lacks permission to create object permissions
throw new GuacamoleSecurityException("Permission denied.");
}
@Override
public void deletePermissions(AuthenticatedUser user, MySQLUser targetUser,
Collection<ObjectPermission> permissions)
throws GuacamoleException {
// Delete permissions only if user has permission to do so
if (canAlterPermissions(user, targetUser, permissions)) {
Collection<ModelType> models = getModelInstances(targetUser, permissions);
getPermissionMapper().delete(models);
return;
}
// User lacks permission to delete object permissions
throw new GuacamoleSecurityException("Permission denied.");
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.permission;
import java.util.Collection;
import org.glyptodon.guacamole.auth.jdbc.user.UserModel;
import org.apache.ibatis.annotations.Param;
/**
* Generic base for mappers which handle permissions.
*
* @author Michael Jumper
* @param <PermissionType>
* The type of permission model object handled by this mapper.
*/
public interface PermissionMapper<PermissionType> {
/**
* Retrieves all permissions associated with the given user.
*
* @param user
* The user to retrieve permissions for.
*
* @return
* All permissions associated with the given user.
*/
Collection<PermissionType> select(@Param("user") UserModel user);
/**
* Inserts the given permissions into the database. If any permissions
* already exist, they will be ignored.
*
* @param permissions
* The permissions to insert.
*
* @return
* The number of rows inserted.
*/
int insert(@Param("permissions") Collection<PermissionType> permissions);
/**
* Deletes the given permissions from the database. If any permissions do
* not exist, they will be ignored.
*
* @param permissions
* The permissions to delete.
*
* @return
* The number of rows deleted.
*/
int delete(@Param("permissions") Collection<PermissionType> permissions);
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.permission;
/**
* Generic base permission model which grants a permission of a particular type
* to a specific user.
*
* @author Michael Jumper
* @param <PermissionType>
* The type of permissions allowed within this model.
*/
public abstract class PermissionModel<PermissionType> {
/**
* The database ID of the user to whom this permission is granted.
*/
private Integer userID;
/**
* The username of the user to whom this permission is granted.
*/
private String username;
/**
* The type of action granted by this permission.
*/
private PermissionType type;
/**
* Returns the database ID of the user to whom this permission is granted.
*
* @return
* The database ID of the user to whom this permission is granted.
*/
public Integer getUserID() {
return userID;
}
/**
* Sets the database ID of the user to whom this permission is granted.
*
* @param userID
* The database ID of the user to whom this permission is granted.
*/
public void setUserID(Integer userID) {
this.userID = userID;
}
/**
* Returns the username of the user to whom this permission is granted.
*
* @return
* The username of the user to whom this permission is granted.
*/
public String getUsername() {
return username;
}
/**
* Sets the username of the user to whom this permission is granted.
*
* @param username
* The username of the user to whom this permission is granted.
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Returns the type of action granted by this permission.
*
* @return
* The type of action granted by this permission.
*/
public PermissionType getType() {
return type;
}
/**
* Sets the type of action granted by this permission.
*
* @param type
* The type of action granted by this permission.
*/
public void setType(PermissionType type) {
this.type = type;
}
}

View File

@@ -0,0 +1,238 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.permission;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.auth.jdbc.user.MySQLUser;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.GuacamoleSecurityException;
import org.glyptodon.guacamole.net.auth.permission.Permission;
import org.glyptodon.guacamole.net.auth.permission.PermissionSet;
/**
* Service which provides convenience methods for creating, retrieving, and
* deleting permissions, and for obtaining the permission sets that contain
* these permissions. This service will automatically enforce the permissions
* of the current user.
*
* @author Michael Jumper
* @param <PermissionSetType>
* The type of permission sets this service provides access to.
*
* @param <PermissionType>
* The type of permission this service provides access to.
*
* @param <ModelType>
* The underlying model object used to represent PermissionType in the
* database.
*/
public abstract class PermissionService<PermissionSetType extends PermissionSet<PermissionType>,
PermissionType extends Permission, ModelType> {
/**
* Returns an instance of a mapper for the type of permission used by this
* service.
*
* @return
* A mapper which provides access to the model objects associated with
* the permissions used by this service.
*/
protected abstract PermissionMapper<ModelType> getPermissionMapper();
/**
* Returns an instance of a permission which is based on the given model
* object.
*
* @param model
* The model object to use to produce the returned permission.
*
* @return
* A permission which is based on the given model object.
*/
protected abstract PermissionType getPermissionInstance(ModelType model);
/**
* Returns a collection of permissions which are based on the models in
* the given collection.
*
* @param models
* The model objects to use to produce the permissions within the
* returned set.
*
* @return
* A set of permissions which are based on the models in the given
* collection.
*/
protected Set<PermissionType> getPermissionInstances(Collection<ModelType> models) {
// Create new collection of permissions by manually converting each model
Set<PermissionType> permissions = new HashSet<PermissionType>(models.size());
for (ModelType model : models)
permissions.add(getPermissionInstance(model));
return permissions;
}
/**
* Returns an instance of a model object which is based on the given
* permission and target user.
*
* @param targetUser
* The user to whom this permission is granted.
*
* @param permission
* The permission to use to produce the returned model object.
*
* @return
* A model object which is based on the given permission and target
* user.
*/
protected abstract ModelType getModelInstance(MySQLUser targetUser,
PermissionType permission);
/**
* Returns a collection of model objects which are based on the given
* permissions and target user.
*
* @param targetUser
* The user to whom this permission is granted.
*
* @param permissions
* The permissions to use to produce the returned model objects.
*
* @return
* A collection of model objects which are based on the given
* permissions and target user.
*/
protected Collection<ModelType> getModelInstances(MySQLUser targetUser,
Collection<PermissionType> permissions) {
// Create new collection of models by manually converting each permission
Collection<ModelType> models = new ArrayList<ModelType>(permissions.size());
for (PermissionType permission : permissions)
models.add(getModelInstance(targetUser, permission));
return models;
}
/**
* Returns a permission set that can be used to retrieve and manipulate the
* permissions of the given user.
*
* @param user
* The user who will be retrieving or manipulating permissions through
* the returned permission set.
*
* @param targetUser
* The user to whom the permissions in the returned permission set are
* granted.
*
* @return
* A permission set that contains all permissions associated with the
* given user, and can be used to manipulate that user's permissions.
*
* @throws GuacamoleException
* If an error occurs while retrieving the permissions of the given
* user, or if permission to retrieve the permissions of the given
* user is denied.
*/
public abstract PermissionSetType getPermissionSet(AuthenticatedUser user,
MySQLUser targetUser) throws GuacamoleException;
/**
* Retrieves all permissions associated with the given user.
*
* @param user
* The user retrieving the permissions.
*
* @param targetUser
* The user associated with the permissions to be retrieved.
*
* @return
* The permissions associated with the given user.
*
* @throws GuacamoleException
* If an error occurs while retrieving the requested permissions.
*/
public Set<PermissionType> retrievePermissions(AuthenticatedUser user,
MySQLUser targetUser) throws GuacamoleException {
// Only an admin can read permissions that aren't his own
if (user.getUser().getIdentifier().equals(targetUser.getIdentifier())
|| user.getUser().isAdministrator())
return getPermissionInstances(getPermissionMapper().select(targetUser.getModel()));
// User cannot read this user's permissions
throw new GuacamoleSecurityException("Permission denied.");
}
/**
* Creates the given permissions within the database. If any permissions
* already exist, they will be ignored.
*
* @param user
* The user creating the permissions.
*
* @param targetUser
* The user associated with the permissions to be created.
*
* @param permissions
* The permissions to create.
*
* @throws GuacamoleException
* If the user lacks permission to create the permissions, or an error
* occurs while creating the permissions.
*/
public abstract void createPermissions(AuthenticatedUser user,
MySQLUser targetUser,
Collection<PermissionType> permissions) throws GuacamoleException;
/**
* Deletes the given permissions. If any permissions do not exist, they
* will be ignored.
*
* @param user
* The user deleting the permissions.
*
* @param targetUser
* The user associated with the permissions to be deleted.
*
* @param permissions
* The permissions to delete.
*
* @throws GuacamoleException
* If the user lacks permission to delete the permissions, or an error
* occurs while deleting the permissions.
*/
public abstract void deletePermissions(AuthenticatedUser user,
MySQLUser targetUser,
Collection<PermissionType> permissions) throws GuacamoleException;
}

View File

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

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.permission;
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
/**
* Object representation of an system-level Guacamole permission, as
* represented in the database.
*
* @author Michael Jumper
*/
public class SystemPermissionModel extends PermissionModel<SystemPermission.Type> {
/**
* Creates a new, empty System permission.
*/
public SystemPermissionModel() {
}
}

View File

@@ -0,0 +1,166 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.permission;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.Collection;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.auth.jdbc.user.MySQLUser;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.GuacamoleSecurityException;
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
/**
* Service which provides convenience methods for creating, retrieving, and
* deleting system permissions. This service will automatically enforce
* the permissions of the current user.
*
* @author Michael Jumper
*/
public class SystemPermissionService
extends PermissionService<MySQLSystemPermissionSet, SystemPermission, SystemPermissionModel> {
/**
* Mapper for system-level permissions.
*/
@Inject
private SystemPermissionMapper systemPermissionMapper;
/**
* Provider for creating system permission sets.
*/
@Inject
private Provider<MySQLSystemPermissionSet> systemPermissionSetProvider;
@Override
protected SystemPermissionMapper getPermissionMapper() {
return systemPermissionMapper;
}
@Override
protected SystemPermission getPermissionInstance(SystemPermissionModel model) {
return new SystemPermission(model.getType());
}
@Override
protected SystemPermissionModel getModelInstance(final MySQLUser targetUser,
final SystemPermission permission) {
SystemPermissionModel model = new SystemPermissionModel();
// Populate model object with data from user and permission
model.setUserID(targetUser.getModel().getObjectID());
model.setUsername(targetUser.getModel().getIdentifier());
model.setType(permission.getType());
return model;
}
@Override
public MySQLSystemPermissionSet getPermissionSet(AuthenticatedUser user,
MySQLUser targetUser) throws GuacamoleException {
// Create permission set for requested user
MySQLSystemPermissionSet permissionSet = systemPermissionSetProvider.get();
permissionSet.init(user, targetUser);
return permissionSet;
}
@Override
public void createPermissions(AuthenticatedUser user, MySQLUser targetUser,
Collection<SystemPermission> permissions) throws GuacamoleException {
// Only an admin can create system permissions
if (user.getUser().isAdministrator()) {
Collection<SystemPermissionModel> models = getModelInstances(targetUser, permissions);
systemPermissionMapper.insert(models);
return;
}
// User lacks permission to create system permissions
throw new GuacamoleSecurityException("Permission denied.");
}
@Override
public void deletePermissions(AuthenticatedUser user, MySQLUser targetUser,
Collection<SystemPermission> permissions) throws GuacamoleException {
// Only an admin can delete system permissions
if (user.getUser().isAdministrator()) {
Collection<SystemPermissionModel> models = getModelInstances(targetUser, permissions);
systemPermissionMapper.delete(models);
return;
}
// User lacks permission to delete system permissions
throw new GuacamoleSecurityException("Permission denied.");
}
/**
* Retrieves the permission of the given type associated with the given
* user, if it exists. If no such permission exists, null is returned.
*
* @param user
* The user retrieving the permission.
*
* @param targetUser
* The user associated with the permission to be retrieved.
*
* @param type
* The type of permission to retrieve.
*
* @return
* The permission of the given type associated with the given user, or
* null if no such permission exists.
*
* @throws GuacamoleException
* If an error occurs while retrieving the requested permission.
*/
public SystemPermission retrievePermission(AuthenticatedUser user,
MySQLUser targetUser, SystemPermission.Type type) throws GuacamoleException {
// Only an admin can read permissions that aren't his own
if (user.getUser().getIdentifier().equals(targetUser.getIdentifier())
|| user.getUser().isAdministrator()) {
// Read permission from database, return null if not found
SystemPermissionModel model = getPermissionMapper().selectOne(targetUser.getModel(), type);
if (model == null)
return null;
return getPermissionInstance(model);
}
// User cannot read this user's permissions
throw new GuacamoleSecurityException("Permission denied.");
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Classes related to object- and system-level permissions.
*/
package org.glyptodon.guacamole.auth.jdbc.permission;

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.security;
/**
* A service to perform password encryption and checking.
* @author James Muehlner
*/
public interface PasswordEncryptionService {
/**
* Creates a password hash based on the provided username, password, and
* salt.
*
* @param password The password to hash.
* @param salt The salt to use when hashing the password.
* @return The generated password hash.
*/
public byte[] createPasswordHash(String password, byte[] salt);
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.security;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.xml.bind.DatatypeConverter;
/**
* Provides a SHA-256 based implementation of the password encryption functionality.
* @author James Muehlner
*/
public class SHA256PasswordEncryptionService implements PasswordEncryptionService {
@Override
public byte[] createPasswordHash(String password, byte[] salt) {
try {
// Build salted password
StringBuilder builder = new StringBuilder();
builder.append(password);
builder.append(DatatypeConverter.printHexBinary(salt));
// Hash UTF-8 bytes of salted password
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(builder.toString().getBytes("UTF-8"));
return md.digest();
}
// Should not happen
catch (UnsupportedEncodingException ex) {
throw new RuntimeException(ex);
}
// Should not happen
catch (NoSuchAlgorithmException ex) {
throw new RuntimeException(ex);
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.security;
/**
* A service to generate password salts.
* @author James Muehlner
*/
public interface SaltService {
/**
* Generates a new String that can be used as a password salt.
* @return a new salt for password encryption.
*/
public byte[] generateSalt();
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.security;
import java.security.SecureRandom;
/**
* Generates password salts via SecureRandom.
* @author James Muehlner
*/
public class SecureRandomSaltService implements SaltService {
/**
* Instance of SecureRandom for generating the salt.
*/
private SecureRandom secureRandom = new SecureRandom();
@Override
public byte[] generateSalt() {
byte[] salt = new byte[32];
secureRandom.nextBytes(salt);
return salt;
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Classes related to hashing or encryption.
*/
package org.glyptodon.guacamole.auth.jdbc.security;

View File

@@ -0,0 +1,288 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.socket;
import com.google.inject.Inject;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.auth.jdbc.connection.MySQLConnection;
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.MySQLConnectionGroup;
import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionRecordMapper;
import org.glyptodon.guacamole.auth.jdbc.connection.ParameterMapper;
import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionModel;
import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionRecordModel;
import org.glyptodon.guacamole.auth.jdbc.connection.ParameterModel;
import org.glyptodon.guacamole.auth.jdbc.user.UserModel;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.environment.Environment;
import org.glyptodon.guacamole.net.GuacamoleSocket;
import org.glyptodon.guacamole.net.InetGuacamoleSocket;
import org.glyptodon.guacamole.net.auth.Connection;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.net.auth.ConnectionRecord;
import org.glyptodon.guacamole.protocol.ConfiguredGuacamoleSocket;
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
import org.glyptodon.guacamole.token.StandardTokens;
import org.glyptodon.guacamole.token.TokenFilter;
/**
* Base implementation of the GuacamoleSocketService, handling retrieval of
* connection parameters, load balancing, and connection usage counts. The
* implementation of concurrency rules is up to policy-specific subclasses.
*
* @author Michael Jumper
*/
public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketService {
/**
* The environment of the Guacamole server.
*/
@Inject
private Environment environment;
/**
* Mapper for accessing connection parameters.
*/
@Inject
private ParameterMapper parameterMapper;
/**
* Mapper for accessing connection history.
*/
@Inject
private ConnectionRecordMapper connectionRecordMapper;
/**
* The current number of concurrent uses of the connection having a given
* identifier.
*/
private final Map<String, LinkedList<ConnectionRecord>> activeConnections =
new HashMap<String, LinkedList<ConnectionRecord>>();
/**
* Atomically increments the current usage count for the given connection.
*
* @param connection
* The connection which is being used.
*/
private void addActiveConnection(Connection connection, ConnectionRecord record) {
synchronized (activeConnections) {
String identifier = connection.getIdentifier();
// Get set of active connection records, creating if necessary
LinkedList<ConnectionRecord> connections = activeConnections.get(identifier);
if (connections == null) {
connections = new LinkedList<ConnectionRecord>();
activeConnections.put(identifier, connections);
}
// Add active connection
connections.addFirst(record);
}
}
/**
* Atomically decrements the current usage count for the given connection.
* If a combination of incrementUsage() and decrementUsage() calls result
* in the usage counter being reduced to zero, it is guaranteed that one
* of those decrementUsage() calls will remove the value from the map.
*
* @param connection
* The connection which is no longer being used.
*/
private void removeActiveConnection(Connection connection, ConnectionRecord record) {
synchronized (activeConnections) {
String identifier = connection.getIdentifier();
// Get set of active connection records
LinkedList<ConnectionRecord> connections = activeConnections.get(identifier);
assert(connections != null);
// Remove old record
connections.remove(record);
// If now empty, clean the tracking entry
if (connections.isEmpty())
activeConnections.remove(identifier);
}
}
/**
* Acquires possibly-exclusive access to the given connection on behalf of
* the given user. If access is denied for any reason, an exception is
* thrown.
*
* @param user
* The user acquiring access.
*
* @param connection
* The connection being accessed.
*
* @throws GuacamoleException
* If access is denied to the given user for any reason.
*/
protected abstract void acquire(AuthenticatedUser user,
MySQLConnection connection) throws GuacamoleException;
/**
* Releases possibly-exclusive access to the given connection on behalf of
* the given user. If the given user did not already have access, the
* behavior of this function is undefined.
*
* @param user
* The user releasing access.
*
* @param connection
* The connection being released.
*/
protected abstract void release(AuthenticatedUser user,
MySQLConnection connection);
@Override
public GuacamoleSocket getGuacamoleSocket(final AuthenticatedUser user,
final MySQLConnection connection, GuacamoleClientInformation info)
throws GuacamoleException {
// Create record for active connection
final ActiveConnectionRecord activeConnection = new ActiveConnectionRecord(user);
// Generate configuration from available data
GuacamoleConfiguration config = new GuacamoleConfiguration();
// Set protocol from connection
ConnectionModel model = connection.getModel();
config.setProtocol(model.getProtocol());
// Set parameters from associated data
Collection<ParameterModel> parameters = parameterMapper.select(connection.getIdentifier());
for (ParameterModel parameter : parameters)
config.setParameter(parameter.getName(), parameter.getValue());
// Build token filter containing credential tokens
TokenFilter tokenFilter = new TokenFilter();
StandardTokens.addStandardTokens(tokenFilter, user.getCredentials());
// Filter the configuration
tokenFilter.filterValues(config.getParameters());
// Return new socket
try {
// Atomically gain access to connection
acquire(user, connection);
addActiveConnection(connection, activeConnection);
// Return newly-reserved connection
return new ConfiguredGuacamoleSocket(
new InetGuacamoleSocket(
environment.getRequiredProperty(Environment.GUACD_HOSTNAME),
environment.getRequiredProperty(Environment.GUACD_PORT)
),
config
) {
@Override
public void close() throws GuacamoleException {
// Attempt to close connection
super.close();
// Release connection upon close
removeActiveConnection(connection, activeConnection);
release(user, connection);
UserModel userModel = user.getUser().getModel();
ConnectionRecordModel recordModel = new ConnectionRecordModel();
// Copy user information and timestamps into new record
recordModel.setUserID(userModel.getObjectID());
recordModel.setUsername(userModel.getIdentifier());
recordModel.setConnectionIdentifier(connection.getIdentifier());
recordModel.setStartDate(activeConnection.getStartDate());
recordModel.setEndDate(new Date());
// Insert connection record
connectionRecordMapper.insert(recordModel);
}
};
}
// Release connection in case of error
catch (GuacamoleException e) {
// Atomically release access to connection
removeActiveConnection(connection, activeConnection);
release(user, connection);
throw e;
}
}
@Override
public List<ConnectionRecord> getActiveConnections(Connection connection) {
synchronized (activeConnections) {
String identifier = connection.getIdentifier();
// Get set of active connection records
LinkedList<ConnectionRecord> connections = activeConnections.get(identifier);
if (connections != null)
return Collections.unmodifiableList(connections);
return Collections.EMPTY_LIST;
}
}
@Override
public GuacamoleSocket getGuacamoleSocket(AuthenticatedUser user,
MySQLConnectionGroup connectionGroup,
GuacamoleClientInformation info) throws GuacamoleException {
// STUB
throw new UnsupportedOperationException("STUB");
}
@Override
public List<ConnectionRecord> getActiveConnections(ConnectionGroup connectionGroup) {
// STUB
return Collections.EMPTY_LIST;
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.socket;
import java.util.Date;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.net.auth.ConnectionRecord;
/**
* A connection record implementation that describes an active connection. As
* the associated connection has not yet ended, getEndDate() will always return
* null, and isActive() will always return true. The associated start date will
* be the time of this objects creation.
*
* @author Michael Jumper
*/
public class ActiveConnectionRecord implements ConnectionRecord {
/**
* The user that connected to the connection associated with this connection
* record.
*/
private final AuthenticatedUser user;
/**
* The time this connection record was created.
*/
private final Date startDate = new Date();
/**
* Creates a new connection record associated with the given user. The
* start date of this connection record will be the time of its creation.
*
* @param user
* The user that connected to the connection associated with this
* connection record.
*/
public ActiveConnectionRecord(AuthenticatedUser user) {
this.user = user;
}
@Override
public Date getStartDate() {
return startDate;
}
@Override
public Date getEndDate() {
// Active connections have not yet ended
return null;
}
@Override
public String getUsername() {
return user.getUser().getIdentifier();
}
@Override
public boolean isActive() {
// Active connections are active by definition
return true;
}
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.socket;
import java.util.List;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.auth.jdbc.connection.MySQLConnection;
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.MySQLConnectionGroup;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.GuacamoleSocket;
import org.glyptodon.guacamole.net.auth.Connection;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.net.auth.ConnectionRecord;
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
/**
* Service which creates pre-configured GuacamoleSocket instances for
* connections and balancing groups, applying concurrent usage rules.
*
* @author Michael Jumper
*/
public interface GuacamoleSocketService {
/**
* Creates a socket for the given user which connects to the given
* connection. The given client information will be passed to guacd when
* the connection is established. This function will apply any concurrent
* usage rules in effect, but will NOT test object- or system-level
* permissions.
*
* @param user
* The user for whom the connection is being established.
*
* @param connection
* The connection the user is connecting to.
*
* @param info
* Information describing the Guacamole client connecting to the given
* connection.
*
* @return
* A new GuacamoleSocket which is configured and connected to the given
* connection.
*
* @throws GuacamoleException
* If the connection cannot be established due to concurrent usage
* rules.
*/
GuacamoleSocket getGuacamoleSocket(AuthenticatedUser user,
MySQLConnection connection, GuacamoleClientInformation info)
throws GuacamoleException;
/**
* Returns a list containing connection records representing all currently-
* active connections using the given connection. These records will have
* usernames and start dates, but no end date.
*
* @param connection
* The connection to check.
*
* @return
* A list containing connection records representing all currently-
* active connections.
*/
public List<ConnectionRecord> getActiveConnections(Connection connection);
/**
* Creates a socket for the given user which connects to the given
* connection group. The given client information will be passed to guacd
* when the connection is established. This function will apply any
* concurrent usage rules in effect, but will NOT test object- or
* system-level permissions.
*
* @param user
* The user for whom the connection is being established.
*
* @param connectionGroup
* The connection group the user is connecting to.
*
* @param info
* Information describing the Guacamole client connecting to the given
* connection group.
*
* @return
* A new GuacamoleSocket which is configured and connected to the given
* connection group.
*
* @throws GuacamoleException
* If the connection cannot be established due to concurrent usage
* rules, or if the connection group is not balancing.
*/
GuacamoleSocket getGuacamoleSocket(AuthenticatedUser user,
MySQLConnectionGroup connectionGroup,
GuacamoleClientInformation info)
throws GuacamoleException;
/**
* Returns a list containing connection records representing all currently-
* active connections using the given connection group. These records will
* have usernames and start dates, but no end date.
*
* @param connectionGroup
* The connection group to check.
*
* @return
* A list containing connection records representing all currently-
* active connections.
*/
public List<ConnectionRecord> getActiveConnections(ConnectionGroup connectionGroup);
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.socket;
import com.google.inject.Singleton;
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.auth.jdbc.connection.MySQLConnection;
import org.glyptodon.guacamole.GuacamoleException;
/**
* GuacamoleSocketService implementation which imposes no restrictions
* whatsoever on the number of concurrent or duplicate connections.
*
* @author Michael Jumper
*/
@Singleton
public class UnrestrictedGuacamoleSocketService
extends AbstractGuacamoleSocketService {
@Override
protected void acquire(AuthenticatedUser user, MySQLConnection connection)
throws GuacamoleException {
// Do nothing
}
@Override
protected void release(AuthenticatedUser user, MySQLConnection connection) {
// Do nothing
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Classes related to obtaining/configuring Guacamole sockets, and restricting
* access to those sockets.
*/
package org.glyptodon.guacamole.auth.jdbc.socket;

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.user;
import org.glyptodon.guacamole.net.auth.Credentials;
/**
* Associates a user with the credentials they used to authenticate.
*
* @author Michael Jumper
*/
public class AuthenticatedUser {
/**
* The user that authenticated.
*/
private final MySQLUser user;
/**
* The credentials given when this user authenticated.
*/
private final Credentials credentials;
/**
* Creates a new AuthenticatedUser associating the given user with their
* corresponding credentials.
*
* @param user
* The user this object should represent.
*
* @param credentials
* The credentials given by the user when they authenticated.
*/
public AuthenticatedUser(MySQLUser user, Credentials credentials) {
this.user = user;
this.credentials = credentials;
}
/**
* Returns the user that authenticated.
*
* @return
* The user that authenticated.
*/
public MySQLUser getUser() {
return user;
}
/**
* Returns the credentials given during authentication by this user.
*
* @return
* The credentials given during authentication by this user.
*/
public Credentials getCredentials() {
return credentials;
}
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.user;
import com.google.inject.Inject;
import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObject;
import org.glyptodon.guacamole.auth.jdbc.security.PasswordEncryptionService;
import org.glyptodon.guacamole.auth.jdbc.security.SaltService;
import org.glyptodon.guacamole.auth.jdbc.permission.SystemPermissionService;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.User;
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
import org.glyptodon.guacamole.net.auth.simple.SimpleObjectPermissionSet;
/**
* A MySQL based implementation of the User object.
* @author James Muehlner
*/
public class MySQLUser extends DirectoryObject<UserModel> implements User {
/**
* Service for hashing passwords.
*/
@Inject
private PasswordEncryptionService encryptionService;
/**
* Service for providing secure, random salts.
*/
@Inject
private SaltService saltService;
/**
* Service for retrieving system permissions.
*/
@Inject
private SystemPermissionService systemPermissionService;
/**
* The plaintext password previously set by a call to setPassword(), if
* any. The password of a user cannot be retrieved once saved into the
* database, so this serves to ensure getPassword() returns a reasonable
* value if setPassword() is called. If no password has been set, or the
* user was retrieved from the database, this will be null.
*/
private String password = null;
/**
* Creates a new, empty MySQLUser.
*/
public MySQLUser() {
}
@Override
public String getPassword() {
return password;
}
@Override
public void setPassword(String password) {
UserModel userModel = getModel();
// Store plaintext password internally
this.password = password;
// If no password provided, clear password salt and hash
if (password == null) {
userModel.setPasswordSalt(null);
userModel.setPasswordHash(null);
}
// Otherwise generate new salt and hash given password using newly-generated salt
else {
byte[] salt = saltService.generateSalt();
byte[] hash = encryptionService.createPasswordHash(password, salt);
// Set stored salt and hash
userModel.setPasswordSalt(salt);
userModel.setPasswordHash(hash);
}
}
/**
* Returns whether this user is a system administrator, and thus is not
* restricted by permissions.
*
* @return
* true if this user is a system administrator, false otherwise.
*
* @throws GuacamoleException
* If an error occurs while determining the user's system administrator
* status.
*/
public boolean isAdministrator() throws GuacamoleException {
SystemPermissionSet systemPermissionSet = getSystemPermissions();
return systemPermissionSet.hasPermission(SystemPermission.Type.ADMINISTER);
}
@Override
public SystemPermissionSet getSystemPermissions()
throws GuacamoleException {
return systemPermissionService.getPermissionSet(getCurrentUser(), this);
}
@Override
public ObjectPermissionSet getConnectionPermissions()
throws GuacamoleException {
// STUB
return new SimpleObjectPermissionSet();
}
@Override
public ObjectPermissionSet getConnectionGroupPermissions()
throws GuacamoleException {
// STUB
return new SimpleObjectPermissionSet();
}
@Override
public ObjectPermissionSet getUserPermissions()
throws GuacamoleException {
// STUB
return new SimpleObjectPermissionSet();
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.user;
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.MySQLRootConnectionGroup;
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ConnectionGroupDirectory;
import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionDirectory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.Connection;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.net.auth.Directory;
import org.glyptodon.guacamole.net.auth.User;
import org.glyptodon.guacamole.net.auth.UserContext;
/**
* The MySQL representation of a UserContext.
* @author James Muehlner
*/
public class MySQLUserContext implements UserContext {
/**
* The the user owning this context.
*/
private AuthenticatedUser currentUser;
/**
* User directory restricted by the permissions of the user associated
* with this context.
*/
@Inject
private UserDirectory userDirectory;
/**
* Connection directory restricted by the permissions of the user
* associated with this context.
*/
@Inject
private ConnectionDirectory connectionDirectory;
/**
* Connection group directory restricted by the permissions of the user
* associated with this context.
*/
@Inject
private ConnectionGroupDirectory connectionGroupDirectory;
/**
* Provider for creating the root group.
*/
@Inject
private Provider<MySQLRootConnectionGroup> rootGroupProvider;
/**
* Initializes the user and directories associated with this context.
*
* @param currentUser
* The user owning this context.
*/
public void init(AuthenticatedUser currentUser) {
this.currentUser = currentUser;
// Init directories
userDirectory.init(currentUser);
connectionDirectory.init(currentUser);
connectionGroupDirectory.init(currentUser);
}
@Override
public User self() {
return currentUser.getUser();
}
@Override
public Directory<User> getUserDirectory() throws GuacamoleException {
return userDirectory;
}
@Override
public Directory<Connection> getConnectionDirectory() throws GuacamoleException {
return connectionDirectory;
}
@Override
public Directory<ConnectionGroup> getConnectionGroupDirectory() throws GuacamoleException {
return connectionGroupDirectory;
}
@Override
public ConnectionGroup getRootConnectionGroup() throws GuacamoleException {
// Build and return a root group for the current user
MySQLRootConnectionGroup rootGroup = rootGroupProvider.get();
rootGroup.init(currentUser);
return rootGroup;
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.user;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.Credentials;
import org.glyptodon.guacamole.net.auth.UserContext;
/**
* Service which creates new UserContext instances for valid users based on
* credentials.
*
* @author Michael Jumper
*/
public class UserContextService {
/**
* Service for accessing users.
*/
@Inject
private UserService userService;
/**
* Provider for retrieving UserContext instances.
*/
@Inject
private Provider<MySQLUserContext> userContextProvider;
/**
* Authenticates the user having the given credentials, returning a new
* UserContext instance if the credentials are valid.
*
* @param credentials
* The credentials to use to produce the UserContext.
*
* @return
* A new UserContext instance for the user identified by the given
* credentials, or null if the credentials are not valid.
*
* @throws GuacamoleException
* If an error occurs during authentication.
*/
public UserContext getUserContext(Credentials credentials)
throws GuacamoleException {
// Authenticate user
MySQLUser user = userService.retrieveUser(credentials);
if (user != null) {
// Upon successful authentication, return new user context
MySQLUserContext context = userContextProvider.get();
context.init(user.getCurrentUser());
return context;
}
// Otherwise, unauthorized
return null;
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.user;
import com.google.inject.Inject;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.Directory;
import org.glyptodon.guacamole.net.auth.User;
import org.mybatis.guice.transactional.Transactional;
/**
* A MySQL based implementation of the User Directory.
*
* @author James Muehlner
* @author Michael Jumper
*/
public class UserDirectory implements Directory<User> {
/**
* The user this user directory belongs to. Access is based on his/her
* permission settings.
*/
private AuthenticatedUser currentUser;
/**
* Service for managing user objects.
*/
@Inject
private UserService userService;
/**
* Set the user for this directory.
*
* @param currentUser
* The user whose permissions define the visibility of other users in
* this directory.
*/
public void init(AuthenticatedUser currentUser) {
this.currentUser = currentUser;
}
@Override
public User get(String identifier) throws GuacamoleException {
return userService.retrieveObject(currentUser, identifier);
}
@Override
@Transactional
public Collection<User> getAll(Collection<String> identifiers) throws GuacamoleException {
Collection<MySQLUser> objects = userService.retrieveObjects(currentUser, identifiers);
return Collections.<User>unmodifiableCollection(objects);
}
@Override
@Transactional
public Set<String> getIdentifiers() throws GuacamoleException {
return userService.getIdentifiers(currentUser);
}
@Override
@Transactional
public void add(User object) throws GuacamoleException {
userService.createObject(currentUser, object);
}
@Override
@Transactional
public void update(User object) throws GuacamoleException {
MySQLUser user = (MySQLUser) object;
userService.updateObject(currentUser, user);
}
@Override
@Transactional
public void remove(String identifier) throws GuacamoleException {
userService.deleteObject(currentUser, identifier);
}
}

View File

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

View File

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

View File

@@ -0,0 +1,171 @@
/*
* Copyright (C) 2013 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.auth.jdbc.user;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.Collection;
import java.util.Collections;
import org.glyptodon.guacamole.net.auth.Credentials;
import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectMapper;
import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectService;
import org.glyptodon.guacamole.GuacamoleClientException;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.User;
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
/**
* Service which provides convenience methods for creating, retrieving, and
* manipulating users.
*
* @author Michael Jumper, James Muehlner
*/
public class UserService extends DirectoryObjectService<MySQLUser, User, UserModel> {
/**
* Mapper for accessing users.
*/
@Inject
private UserMapper userMapper;
/**
* Provider for creating users.
*/
@Inject
private Provider<MySQLUser> mySQLUserProvider;
@Override
protected DirectoryObjectMapper<UserModel> getObjectMapper() {
return userMapper;
}
@Override
protected MySQLUser getObjectInstance(AuthenticatedUser currentUser,
UserModel model) {
MySQLUser user = mySQLUserProvider.get();
user.init(currentUser, model);
return user;
}
@Override
protected UserModel getModelInstance(AuthenticatedUser currentUser,
final User object) {
// Create new MySQLUser backed by blank model
UserModel model = new UserModel();
MySQLUser user = getObjectInstance(currentUser, model);
// Set model contents through MySQLUser, copying the provided user
user.setIdentifier(object.getIdentifier());
user.setPassword(object.getPassword());
return model;
}
@Override
protected boolean hasCreatePermission(AuthenticatedUser user)
throws GuacamoleException {
// Return whether user has explicit user creation permission
SystemPermissionSet permissionSet = user.getUser().getSystemPermissions();
return permissionSet.hasPermission(SystemPermission.Type.CREATE_USER);
}
@Override
protected ObjectPermissionSet getPermissionSet(AuthenticatedUser user)
throws GuacamoleException {
// Return permissions related to users
return user.getUser().getUserPermissions();
}
@Override
protected void validateNewObject(AuthenticatedUser user, User object)
throws GuacamoleException {
// Username must not be blank
if (object.getIdentifier().trim().isEmpty())
throw new GuacamoleClientException("The username must not be blank.");
// Do not create duplicate users
Collection<UserModel> existing = userMapper.select(Collections.singleton(object.getIdentifier()));
if (!existing.isEmpty())
throw new GuacamoleClientException("User \"" + object.getIdentifier() + "\" already exists.");
}
@Override
protected void validateExistingObject(AuthenticatedUser user,
MySQLUser object) throws GuacamoleException {
// Username must not be blank
if (object.getIdentifier().trim().isEmpty())
throw new GuacamoleClientException("The username must not be blank.");
// Check whether such a user is already present
MySQLUser existing = retrieveObject(user, object.getIdentifier());
if (existing != null) {
UserModel existingModel = existing.getModel();
UserModel updatedModel = object.getModel();
// Do not rename to existing user
if (!existingModel.getObjectID().equals(updatedModel.getObjectID()))
throw new GuacamoleClientException("User \"" + object.getIdentifier() + "\" already exists.");
}
}
/**
* 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) {
// Get username and password
String username = credentials.getUsername();
String password = credentials.getPassword();
// Retrieve user model, if the user exists
UserModel userModel = userMapper.selectByCredentials(username, password);
if (userModel == null)
return null;
// Return corresponding user, set up cyclic reference
MySQLUser user = getObjectInstance(null, userModel);
user.setCurrentUser(new AuthenticatedUser(user, credentials));
return user;
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2015 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Classes related to Guacamole users.
*/
package org.glyptodon.guacamole.auth.jdbc.user;