GUAC-1101: Implement querying of connection permissions.

This commit is contained in:
Michael Jumper
2015-02-28 18:53:07 -08:00
parent 7d399a0fbe
commit 820ffed959
9 changed files with 287 additions and 53 deletions

View File

@@ -49,6 +49,9 @@ 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.auth.jdbc.permission.ConnectionPermissionMapper;
import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionPermissionService;
import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionPermissionSet;
import org.glyptodon.guacamole.environment.Environment;
import org.mybatis.guice.MyBatisModule;
import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider;
@@ -91,6 +94,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
// Add MyBatis mappers
addMapperClass(ConnectionMapper.class);
addMapperClass(ConnectionGroupMapper.class);
addMapperClass(ConnectionPermissionMapper.class);
addMapperClass(ConnectionRecordMapper.class);
addMapperClass(ParameterMapper.class);
addMapperClass(SystemPermissionMapper.class);
@@ -105,11 +109,13 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
bind(ModeledGuacamoleConfiguration.class);
bind(ModeledUser.class);
bind(RootConnectionGroup.class);
bind(ConnectionPermissionSet.class);
bind(SystemPermissionSet.class);
bind(UserContext.class);
bind(UserDirectory.class);
// Bind services
bind(ConnectionPermissionService.class);
bind(ConnectionService.class);
bind(ConnectionGroupService.class);
bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class);

View File

@@ -0,0 +1,30 @@
/*
* 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 connection permissions.
*
* @author Michael Jumper
*/
public interface ConnectionPermissionMapper extends ObjectPermissionMapper {}

View File

@@ -0,0 +1,69 @@
/*
* 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 org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.auth.jdbc.user.ModeledUser;
/**
* Service which provides convenience methods for creating, retrieving, and
* deleting connection permissions. This service will automatically enforce the
* permissions of the current user.
*
* @author Michael Jumper
*/
public class ConnectionPermissionService extends ObjectPermissionService {
/**
* Mapper for connection permissions.
*/
@Inject
private ConnectionPermissionMapper connectionPermissionMapper;
/**
* Provider for connection permission sets.
*/
@Inject
private Provider<ConnectionPermissionSet> connectionPermissionSetProvider;
@Override
protected ObjectPermissionMapper getPermissionMapper() {
return connectionPermissionMapper;
}
@Override
public ObjectPermissionSet getPermissionSet(AuthenticatedUser user,
ModeledUser targetUser) throws GuacamoleException {
// Create permission set for requested user
ObjectPermissionSet permissionSet = connectionPermissionSetProvider.get();
permissionSet.init(user, targetUser);
return permissionSet;
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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 com.google.inject.Inject;
/**
* A database implementation of ObjectPermissionSet which uses an injected
* service to query and manipulate the connection permissions associated with
* a particular user.
*
* @author Michael Jumper
*/
public class ConnectionPermissionSet extends ObjectPermissionSet {
/**
* Service for querying and manipulating connection permissions.
*/
@Inject
private ConnectionPermissionService connectionPermissionService;
@Override
protected ObjectPermissionService getObjectPermissionService() {
return connectionPermissionService;
}
}

View File

@@ -32,15 +32,10 @@ import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
*/
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;
private String objectIdentifier;
/**
* Creates a new, empty object permission.
@@ -48,44 +43,24 @@ public class ObjectPermissionModel extends PermissionModel<ObjectPermission.Type
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;
public String getObjectIdentifier() {
return objectIdentifier;
}
/**
* Sets the unique identifier of the object affected by this permission.
*
* @param affectedIdentifier
* @param objectIdentifier
* The unique identifier of the object affected by this permission.
*/
public void setAffectedIdentifier(String affectedIdentifier) {
this.affectedIdentifier = affectedIdentifier;
public void setObjectIdentifier(String objectIdentifier) {
this.objectIdentifier = objectIdentifier;
}
}

View File

@@ -45,24 +45,26 @@ public abstract class ObjectPermissionService
@Override
protected abstract ObjectPermissionMapper getPermissionMapper();
/**
* 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;
@Override
protected ObjectPermission getPermissionInstance(ObjectPermissionModel model) {
return new ObjectPermission(model.getType(), model.getObjectIdentifier());
}
@Override
protected ObjectPermissionModel getModelInstance(ModeledUser targetUser,
ObjectPermission permission) {
ObjectPermissionModel model = new ObjectPermissionModel();
// Populate model object with data from user and permission
model.setUserID(targetUser.getModel().getObjectID());
model.setUsername(targetUser.getModel().getIdentifier());
model.setType(permission.getType());
model.setObjectIdentifier(permission.getObjectIdentifier());
return model;
}
/**
* Determines whether the current user has permission to update the given
@@ -108,7 +110,7 @@ public abstract class ObjectPermissionService
affectedIdentifiers.add(permission.getObjectIdentifier());
// Determine subset of affected identifiers that we have admin access to
ObjectPermissionSet affectedPermissionSet = getAffectedPermissionSet(user);
ObjectPermissionSet affectedPermissionSet = getPermissionSet(user, user.getUser());
Collection<String> allowedSubset = affectedPermissionSet.getAccessibleObjects(
Collections.singleton(ObjectPermission.Type.ADMINISTER),
affectedIdentifiers

View File

@@ -28,6 +28,7 @@ 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.auth.jdbc.permission.ConnectionPermissionService;
import org.glyptodon.guacamole.net.auth.User;
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
@@ -60,6 +61,12 @@ public class ModeledUser extends DirectoryObject<UserModel> implements User {
@Inject
private SystemPermissionService systemPermissionService;
/**
* Service for retrieving connection permissions.
*/
@Inject
private ConnectionPermissionService connectionPermissionService;
/**
* The plaintext password previously set by a call to setPassword(), if
* any. The password of a user cannot be retrieved once saved into the
@@ -131,8 +138,7 @@ public class ModeledUser extends DirectoryObject<UserModel> implements User {
@Override
public ObjectPermissionSet getConnectionPermissions()
throws GuacamoleException {
// STUB
return new SimpleObjectPermissionSet();
return connectionPermissionService.getPermissionSet(getCurrentUser(), this);
}
@Override

View File

@@ -63,7 +63,7 @@
<select id="selectReadableIdentifiersWithin" resultType="string">
SELECT guacamole_connection_group.connection_group_id
FROM guacamole_connection_group
JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection.group_connection_group_id
JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group.connection_group_id
WHERE
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=VARCHAR}</if>
<if test="parentIdentifier == null">parent_id IS NULL</if>

View File

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<!--
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.
-->
<mapper namespace="org.glyptodon.guacamole.auth.jdbc.permission.ConnectionPermissionMapper" >
<!-- Result mapper for connection permissions -->
<resultMap id="ConnectionPermissionResultMap" type="org.glyptodon.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.glyptodon.guacamole.net.auth.permission.ObjectPermission$Type"/>
<result column="connection_id" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap>
<!-- Select all permissions for a given user -->
<select id="select" resultMap="ConnectionPermissionResultMap">
SELECT
guacamole_connection_permission.user_id,
username,
permission,
connection_id
FROM guacamole_connection_permission
JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id
WHERE guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
</select>
<!-- Select the single permission matching the given criteria -->
<select id="selectOne" resultMap="ConnectionPermissionResultMap">
SELECT
guacamole_connection_permission.user_id,
username,
permission,
connection_id
FROM guacamole_connection_permission
JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id
WHERE
guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = #{type,jdbcType=VARCHAR}
</select>
<!-- Delete all given permissions -->
<delete id="delete" parameterType="org.glyptodon.guacamole.auth.jdbc.permission.ObjectPermissionModel">
DELETE FROM guacamole_connection_permission
WHERE (user_id, permission, connection_id) IN
<foreach collection="permissions" item="permission"
open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach>
</delete>
<!-- Insert all given permissions -->
<insert id="insert" parameterType="org.glyptodon.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT IGNORE INTO guacamole_connection_permission (
user_id,
permission,
connection_id
)
VALUES
<foreach collection="permissions" item="permission" separator=",">
(#{permission.userID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach>
</insert>
</mapper>