GUACAMOLE-220: Merge add database support for user groups.

This commit is contained in:
Nick Couchman
2018-10-01 13:33:07 -04:00
133 changed files with 8377 additions and 1132 deletions

View File

@@ -109,33 +109,33 @@
<dependency> <dependency>
<groupId>org.mybatis</groupId> <groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId> <artifactId>mybatis</artifactId>
<version>3.2.8</version> <version>3.4.6</version>
</dependency> </dependency>
<!-- MyBatis Guice --> <!-- MyBatis Guice -->
<dependency> <dependency>
<groupId>org.mybatis</groupId> <groupId>org.mybatis</groupId>
<artifactId>mybatis-guice</artifactId> <artifactId>mybatis-guice</artifactId>
<version>3.6</version> <version>3.10</version>
</dependency> </dependency>
<!-- Guice --> <!-- Guice -->
<dependency> <dependency>
<groupId>com.google.inject</groupId> <groupId>com.google.inject</groupId>
<artifactId>guice</artifactId> <artifactId>guice</artifactId>
<version>3.0</version> <version>4.1.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.google.inject.extensions</groupId> <groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId> <artifactId>guice-multibindings</artifactId>
<version>3.0</version> <version>4.1.0</version>
</dependency> </dependency>
<!-- Guava - Utility Library --> <!-- Guava - Utility Library -->
<dependency> <dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
<version>18.0</version> <version>19.0</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -59,10 +59,15 @@ import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissio
import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionSet; import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionSet;
import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionService; import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionService;
import org.apache.guacamole.auth.jdbc.activeconnection.TrackedActiveConnection; import org.apache.guacamole.auth.jdbc.activeconnection.TrackedActiveConnection;
import org.apache.guacamole.auth.jdbc.base.EntityMapper;
import org.apache.guacamole.auth.jdbc.base.EntityService;
import org.apache.guacamole.auth.jdbc.connection.ConnectionParameterMapper; import org.apache.guacamole.auth.jdbc.connection.ConnectionParameterMapper;
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionMapper; import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionMapper;
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService; import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService;
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionSet; import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionSet;
import org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionMapper;
import org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionService;
import org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionSet;
import org.apache.guacamole.auth.jdbc.security.PasswordPolicyService; import org.apache.guacamole.auth.jdbc.security.PasswordPolicyService;
import org.apache.guacamole.auth.jdbc.sharing.ConnectionSharingService; import org.apache.guacamole.auth.jdbc.sharing.ConnectionSharingService;
import org.apache.guacamole.auth.jdbc.sharing.HashSharedConnectionMap; import org.apache.guacamole.auth.jdbc.sharing.HashSharedConnectionMap;
@@ -77,8 +82,16 @@ import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileService;
import org.apache.guacamole.auth.jdbc.tunnel.RestrictedGuacamoleTunnelService; import org.apache.guacamole.auth.jdbc.tunnel.RestrictedGuacamoleTunnelService;
import org.apache.guacamole.auth.jdbc.user.PasswordRecordMapper; import org.apache.guacamole.auth.jdbc.user.PasswordRecordMapper;
import org.apache.guacamole.auth.jdbc.user.UserRecordMapper; import org.apache.guacamole.auth.jdbc.user.UserRecordMapper;
import org.apache.guacamole.auth.jdbc.usergroup.ModeledUserGroup;
import org.apache.guacamole.auth.jdbc.usergroup.UserGroupDirectory;
import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMapper;
import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserGroupMapper;
import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserMapper;
import org.apache.guacamole.auth.jdbc.usergroup.UserGroupParentUserGroupMapper;
import org.apache.guacamole.auth.jdbc.usergroup.UserGroupService;
import org.mybatis.guice.MyBatisModule; import org.mybatis.guice.MyBatisModule;
import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider; import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider;
import org.apache.guacamole.auth.jdbc.user.UserParentUserGroupMapper;
/** /**
* Guice module which configures the injections used by the JDBC authentication * Guice module which configures the injections used by the JDBC authentication
@@ -120,12 +133,19 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
addMapperClass(ConnectionPermissionMapper.class); addMapperClass(ConnectionPermissionMapper.class);
addMapperClass(ConnectionRecordMapper.class); addMapperClass(ConnectionRecordMapper.class);
addMapperClass(ConnectionParameterMapper.class); addMapperClass(ConnectionParameterMapper.class);
addMapperClass(EntityMapper.class);
addMapperClass(PasswordRecordMapper.class); addMapperClass(PasswordRecordMapper.class);
addMapperClass(SystemPermissionMapper.class); addMapperClass(SystemPermissionMapper.class);
addMapperClass(SharingProfileMapper.class); addMapperClass(SharingProfileMapper.class);
addMapperClass(SharingProfileParameterMapper.class); addMapperClass(SharingProfileParameterMapper.class);
addMapperClass(SharingProfilePermissionMapper.class); addMapperClass(SharingProfilePermissionMapper.class);
addMapperClass(UserGroupMapper.class);
addMapperClass(UserGroupMemberUserGroupMapper.class);
addMapperClass(UserGroupMemberUserMapper.class);
addMapperClass(UserGroupParentUserGroupMapper.class);
addMapperClass(UserGroupPermissionMapper.class);
addMapperClass(UserMapper.class); addMapperClass(UserMapper.class);
addMapperClass(UserParentUserGroupMapper.class);
addMapperClass(UserPermissionMapper.class); addMapperClass(UserPermissionMapper.class);
addMapperClass(UserRecordMapper.class); addMapperClass(UserRecordMapper.class);
@@ -143,12 +163,15 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
bind(ModeledSharingProfile.class); bind(ModeledSharingProfile.class);
bind(ModeledUser.class); bind(ModeledUser.class);
bind(ModeledUserContext.class); bind(ModeledUserContext.class);
bind(ModeledUserGroup.class);
bind(RootConnectionGroup.class); bind(RootConnectionGroup.class);
bind(SharingProfileDirectory.class); bind(SharingProfileDirectory.class);
bind(SharingProfilePermissionSet.class); bind(SharingProfilePermissionSet.class);
bind(SystemPermissionSet.class); bind(SystemPermissionSet.class);
bind(TrackedActiveConnection.class); bind(TrackedActiveConnection.class);
bind(UserDirectory.class); bind(UserDirectory.class);
bind(UserGroupDirectory.class);
bind(UserGroupPermissionSet.class);
bind(UserPermissionSet.class); bind(UserPermissionSet.class);
// Bind services // Bind services
@@ -159,6 +182,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
bind(ConnectionPermissionService.class); bind(ConnectionPermissionService.class);
bind(ConnectionSharingService.class); bind(ConnectionSharingService.class);
bind(ConnectionService.class); bind(ConnectionService.class);
bind(EntityService.class);
bind(GuacamoleTunnelService.class).to(RestrictedGuacamoleTunnelService.class); bind(GuacamoleTunnelService.class).to(RestrictedGuacamoleTunnelService.class);
bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class); bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class);
bind(PasswordPolicyService.class); bind(PasswordPolicyService.class);
@@ -168,6 +192,8 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
bind(SharingProfilePermissionService.class); bind(SharingProfilePermissionService.class);
bind(SharingProfileService.class); bind(SharingProfileService.class);
bind(SystemPermissionService.class); bind(SystemPermissionService.class);
bind(UserGroupService.class);
bind(UserGroupPermissionService.class);
bind(UserPermissionService.class); bind(UserPermissionService.class);
bind(UserService.class); bind(UserService.class);

View File

@@ -22,6 +22,7 @@ package org.apache.guacamole.auth.jdbc;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.environment.LocalEnvironment; import org.apache.guacamole.environment.LocalEnvironment;
import org.apache.guacamole.auth.jdbc.security.PasswordPolicy; import org.apache.guacamole.auth.jdbc.security.PasswordPolicy;
import org.apache.ibatis.session.SqlSession;
/** /**
* A JDBC-specific implementation of Environment that defines generic properties * A JDBC-specific implementation of Environment that defines generic properties
@@ -137,4 +138,18 @@ public abstract class JDBCEnvironment extends LocalEnvironment {
*/ */
public abstract PasswordPolicy getPasswordPolicy(); public abstract PasswordPolicy getPasswordPolicy();
/**
* Returns whether the database supports recursive queries. Many database
* engines support recursive queries through CTEs. If recursive queries are
* not supported, queries that are intended to be recursive may need to be
* invoked multiple times to retrieve the same data.
*
* @param session
* The SqlSession provided by MyBatis for the current transaction.
*
* @return
* true if the database supports recursive queries, false otherwise.
*/
public abstract boolean isRecursiveQuerySupported(SqlSession session);
} }

View File

@@ -23,17 +23,17 @@ import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
import org.apache.guacamole.auth.jdbc.permission.AbstractPermissionService; import org.apache.guacamole.auth.jdbc.permission.AbstractPermissionService;
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionService; import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionService;
import org.apache.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord; import org.apache.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord;
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
@@ -58,32 +58,32 @@ public class ActiveConnectionPermissionService
private Provider<ActiveConnectionPermissionSet> activeConnectionPermissionSetProvider; private Provider<ActiveConnectionPermissionSet> activeConnectionPermissionSetProvider;
@Override @Override
public ObjectPermission retrievePermission(ModeledAuthenticatedUser user, public boolean hasPermission(ModeledAuthenticatedUser user,
ModeledUser targetUser, ObjectPermission.Type type, ModeledPermissions<? extends EntityModel> targetEntity,
String identifier) throws GuacamoleException { ObjectPermission.Type type, String identifier,
Set<String> effectiveGroups) throws GuacamoleException {
// Retrieve permissions // Retrieve permissions
Set<ObjectPermission> permissions = retrievePermissions(user, targetUser); Set<ObjectPermission> permissions = retrievePermissions(user,
targetEntity, effectiveGroups);
// If retrieved permissions contains the requested permission, return it // Permission is granted if retrieved permissions contains the
// requested permission
ObjectPermission permission = new ObjectPermission(type, identifier); ObjectPermission permission = new ObjectPermission(type, identifier);
if (permissions.contains(permission)) return permissions.contains(permission);
return permission;
// Otherwise, no such permission
return null;
} }
@Override @Override
public Set<ObjectPermission> retrievePermissions(ModeledAuthenticatedUser user, public Set<ObjectPermission> retrievePermissions(ModeledAuthenticatedUser user,
ModeledUser targetUser) throws GuacamoleException { ModeledPermissions<? extends EntityModel> targetEntity,
Set<String> effectiveGroups) throws GuacamoleException {
// Retrieve permissions only if allowed // Retrieve permissions only if allowed
if (canReadPermissions(user, targetUser)) { if (canReadPermissions(user, targetEntity)) {
// Only administrators may access active connections // Only administrators may access active connections
boolean isAdmin = targetUser.isAdministrator(); boolean isAdmin = targetEntity.isAdministrator();
// Get all active connections // Get all active connections
Collection<ActiveConnectionRecord> records = tunnelService.getActiveConnections(user); Collection<ActiveConnectionRecord> records = tunnelService.getActiveConnections(user);
@@ -112,10 +112,12 @@ public class ActiveConnectionPermissionService
@Override @Override
public Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user, public Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
ModeledUser targetUser, Collection<ObjectPermission.Type> permissionTypes, ModeledPermissions<? extends EntityModel> targetEntity,
Collection<String> identifiers) throws GuacamoleException { Collection<ObjectPermission.Type> permissionTypes,
Collection<String> identifiers, Set<String> effectiveGroups)
throws GuacamoleException {
Set<ObjectPermission> permissions = retrievePermissions(user, targetUser); Set<ObjectPermission> permissions = retrievePermissions(user, targetEntity, effectiveGroups);
Collection<String> accessibleObjects = new ArrayList<String>(permissions.size()); Collection<String> accessibleObjects = new ArrayList<String>(permissions.size());
// For each identifier/permission combination // For each identifier/permission combination
@@ -138,11 +140,12 @@ public class ActiveConnectionPermissionService
@Override @Override
public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
ModeledUser targetUser) throws GuacamoleException { ModeledPermissions<? extends EntityModel> targetEntity,
Set<String> effectiveGroups) throws GuacamoleException {
// Create permission set for requested user // Create permission set for requested entity
ActiveConnectionPermissionSet permissionSet = activeConnectionPermissionSetProvider.get(); ActiveConnectionPermissionSet permissionSet = activeConnectionPermissionSetProvider.get();
permissionSet.init(user, targetUser); permissionSet.init(user, targetEntity, effectiveGroups);
return permissionSet; return permissionSet;
@@ -150,7 +153,8 @@ public class ActiveConnectionPermissionService
@Override @Override
public void createPermissions(ModeledAuthenticatedUser user, public void createPermissions(ModeledAuthenticatedUser user,
ModeledUser targetUser, Collection<ObjectPermission> permissions) ModeledPermissions<? extends EntityModel> targetEntity,
Collection<ObjectPermission> permissions)
throws GuacamoleException { throws GuacamoleException {
// Creating active connection permissions is not implemented // Creating active connection permissions is not implemented
@@ -160,7 +164,8 @@ public class ActiveConnectionPermissionService
@Override @Override
public void deletePermissions(ModeledAuthenticatedUser user, public void deletePermissions(ModeledAuthenticatedUser user,
ModeledUser targetUser, Collection<ObjectPermission> permissions) ModeledPermissions<? extends EntityModel> targetEntity,
Collection<ObjectPermission> permissions)
throws GuacamoleException { throws GuacamoleException {
// Deleting active connection permissions is not implemented // Deleting active connection permissions is not implemented

View File

@@ -0,0 +1,80 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.base;
import java.util.Collection;
import java.util.Set;
import org.apache.ibatis.annotations.Param;
/**
* Mapper for entities. An entity is the base concept behind a user or user
* group, and serves as a common point for granting permissions and defining
* group membership.
*/
public interface EntityMapper {
/**
* Inserts the given entity into the database. If the entity already
* exists, this will result in an error.
*
* @param entity
* The entity to insert.
*
* @return
* The number of rows inserted.
*/
int insert(@Param("entity") EntityModel entity);
/**
* Returns the set of all group identifiers of which the given entity is a
* member, taking into account the given collection of known group
* memberships which are not necessarily defined within the database.
*
* NOTE: This query is expected to handle recursion through the membership
* graph on its own. If the database engine does not support recursive
* queries (isRecursiveQuerySupported() of JDBCEnvironment returns false),
* then this query will only return one level of depth past the effective
* groups given and will need to be invoked multiple times.
*
* @param entity
* The entity whose effective groups should be returned.
*
* @param effectiveGroups
* The identifiers of any known effective groups that should be taken
* into account, such as those defined externally to the database.
*
* @param recursive
* Whether the query should leverage database engine features to return
* absolutely all effective groups, including those inherited through
* group membership. If false, this query will return only one level of
* depth and may need to be executed multiple times. If it is known
* that the database engine in question will always support (or always
* not support) recursive queries, this parameter may be ignored.
*
* @return
* The set of identifiers of all groups that the given entity is a
* member of, including those where membership is inherited through
* membership in other groups.
*/
Set<String> selectEffectiveGroupIdentifiers(@Param("entity") EntityModel entity,
@Param("effectiveGroups") Collection<String> effectiveGroups,
@Param("recursive") boolean recursive);
}

View File

@@ -0,0 +1,113 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.base;
/**
* Base representation of a Guacamole object that can be granted permissions
* (an "entity"), such as a user or user group, as represented in the database.
* Each entity has three base properties:
*
* 1. The "entityID", which points to the common entry in the
* guacamole_entity table and is common to any type of entity.
*
* 2. The "objectID", which points to the type-specific entry for the object
* in question (ie: an entry in guacamole_user or guacamole_user_group).
*
* 3. The "identifier", which contains the unique "name" value defined for
* the entity within the guacamole_entity table.
*/
public abstract class EntityModel extends ObjectModel {
/**
* The ID of the entity entry which corresponds to this object in the
* database, if any. Note that this is distinct from the objectID,
* inherited from ObjectModel, which is specific to the actual type of
* object represented by the entity.
*/
private Integer entityID;
/**
* The type of object represented by the entity (user or user group).
*/
private EntityType type;
/**
* Creates a new, empty entity.
*/
public EntityModel() {
}
/**
* Creates a new entity of the given type which is otherwise empty.
*
* @param type
* The type to assign to the new entity.
*/
public EntityModel(EntityType type) {
this.type = type;
}
/**
* Returns the ID of the entity entry which corresponds to this object in
* the database, if it exists. Note that this is distinct from the objectID,
* inherited from ObjectModel, which is specific to the actual type of
* object represented by the entity.
*
* @return
* The ID of this entity in the database, or null if this entity was
* not retrieved from the database.
*/
public Integer getEntityID() {
return entityID;
}
/**
* Sets the ID of this entity to the given value.
*
* @param entityID
* The ID to assign to this entity.
*/
public void setEntityID(Integer entityID) {
this.entityID = entityID;
}
/**
* Returns the type of object represented by the entity. Each entity may be
* either a user or a user group.
*
* @return
* The type of object represented by the entity.
*/
public EntityType getEntityType() {
return type;
}
/**
* Sets the type of object represented by the entity. Each entity may be
* either a user or a user group.
*
* @param type
* The type of object represented by the entity.
*/
public void setEntityType(EntityType type) {
this.type = type;
}
}

View File

@@ -0,0 +1,98 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.base;
import com.google.inject.Inject;
import java.util.Collection;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.guice.transactional.Transactional;
/**
* Service which provides convenience methods for creating, retrieving, and
* manipulating entities.
*/
public class EntityService {
/**
* The Guacamole server environment.
*/
@Inject
private JDBCEnvironment environment;
/**
* Mapper for Entity model objects.
*/
@Inject
private EntityMapper entityMapper;
/**
* The current SQL session used by MyBatis.
*/
@Inject
private SqlSession sqlSession;
/**
* Returns the set of all group identifiers of which the given entity is a
* member, taking into account the given collection of known group
* memberships which are not necessarily defined within the database.
*
* Note that group visibility with respect to the queried entity is NOT
* taken into account. If the entity is a member of a group, the identifier
* of that group will be included in the returned set even if the current
* user lacks "READ" permission for that group.
*
* @param entity
* The entity whose effective groups should be returned.
*
* @param effectiveGroups
* The identifiers of any known effective groups that should be taken
* into account, such as those defined externally to the database.
*
* @return
* The set of identifiers of all groups that the given entity is a
* member of, including those where membership is inherited through
* membership in other groups.
*/
@Transactional
public Set<String> retrieveEffectiveGroups(ModeledPermissions<? extends EntityModel> entity,
Collection<String> effectiveGroups) {
// Retrieve the effective user groups of the given entity, recursively if possible
boolean recursive = environment.isRecursiveQuerySupported(sqlSession);
Set<String> identifiers = entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), effectiveGroups, recursive);
// If the set of user groups retrieved was not produced recursively,
// manually repeat the query to expand the set until all effective
// groups have been found
if (!recursive && !identifiers.isEmpty()) {
Set<String> previousIdentifiers;
do {
previousIdentifiers = identifiers;
identifiers = entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), previousIdentifiers, false);
} while (identifiers.size() > previousIdentifiers.size());
}
return identifiers;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.base;
/**
* The type of object represented by an entity. Each entity may represent
* either a user or a user group.
*/
public enum EntityType {
/**
* An individual user.
*/
USER,
/**
* A group of users and/or other groups.
*/
USER_GROUP
}

View File

@@ -53,7 +53,8 @@ public abstract class ModeledChildDirectoryObjectService<InternalType extends Mo
/** /**
* Returns the permission set associated with the given user and related * Returns the permission set associated with the given user and related
* to the type of objects which can be parents of the child objects handled * to the type of objects which can be parents of the child objects handled
* by this directory object service. * by this directory object service, taking into account permission
* inheritance via user groups.
* *
* @param user * @param user
* The user whose permissions are being retrieved. * The user whose permissions are being retrieved.
@@ -66,7 +67,7 @@ public abstract class ModeledChildDirectoryObjectService<InternalType extends Mo
* @throws GuacamoleException * @throws GuacamoleException
* If permission to read the user's permissions is denied. * If permission to read the user's permissions is denied.
*/ */
protected abstract ObjectPermissionSet getParentPermissionSet( protected abstract ObjectPermissionSet getParentEffectivePermissionSet(
ModeledAuthenticatedUser user) throws GuacamoleException; ModeledAuthenticatedUser user) throws GuacamoleException;
/** /**
@@ -155,7 +156,7 @@ public abstract class ModeledChildDirectoryObjectService<InternalType extends Mo
Collection<String> modifiedParents = getModifiedParents(user, identifier, model); Collection<String> modifiedParents = getModifiedParents(user, identifier, model);
if (!modifiedParents.isEmpty()) { if (!modifiedParents.isEmpty()) {
ObjectPermissionSet permissionSet = getParentPermissionSet(user); ObjectPermissionSet permissionSet = getParentEffectivePermissionSet(user);
Collection<String> updateableParents = permissionSet.getAccessibleObjects( Collection<String> updateableParents = permissionSet.getAccessibleObjects(
Collections.singleton(ObjectPermission.Type.UPDATE), Collections.singleton(ObjectPermission.Type.UPDATE),
modifiedParents modifiedParents

View File

@@ -57,10 +57,15 @@ public interface ModeledDirectoryObjectMapper<ModelType> {
* The user whose permissions should determine whether an identifier * The user whose permissions should determine whether an identifier
* is returned. * is returned.
* *
* @param effectiveGroups
* The identifiers of any known effective groups that should be taken
* into account, such as those defined externally to the database.
*
* @return * @return
* A Set containing all identifiers of all readable objects. * A Set containing all identifiers of all readable objects.
*/ */
Set<String> selectReadableIdentifiers(@Param("user") UserModel user); Set<String> selectReadableIdentifiers(@Param("user") UserModel user,
@Param("effectiveGroups") Collection<String> effectiveGroups);
/** /**
* Selects all objects which have the given identifiers. If an identifier * Selects all objects which have the given identifiers. If an identifier
@@ -91,11 +96,16 @@ public interface ModeledDirectoryObjectMapper<ModelType> {
* @param identifiers * @param identifiers
* The identifiers of the objects to return. * The identifiers of the objects to return.
* *
* @param effectiveGroups
* The identifiers of any known effective groups that should be taken
* into account, such as those defined externally to the database.
*
* @return * @return
* A Collection of all objects having the given identifiers. * A Collection of all objects having the given identifiers.
*/ */
Collection<ModelType> selectReadable(@Param("user") UserModel user, Collection<ModelType> selectReadable(@Param("user") UserModel user,
@Param("identifiers") Collection<String> identifiers); @Param("identifiers") Collection<String> identifiers,
@Param("effectiveGroups") Collection<String> effectiveGroups);
/** /**
* Inserts the given object into the database. If the object already * Inserts the given object into the database. If the object already

View File

@@ -126,7 +126,8 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
/** /**
* Returns whether the given user has permission to create the type of * Returns whether the given user has permission to create the type of
* objects that this directory object service manages. * objects that this directory object service manages, taking into account
* permission inheritance through user groups.
* *
* @param user * @param user
* The user being checked. * The user being checked.
@@ -143,7 +144,8 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
/** /**
* Returns whether the given user has permission to perform a certain * Returns whether the given user has permission to perform a certain
* action on a specific object managed by this directory object service. * action on a specific object managed by this directory object service,
* taking into account permission inheritance through user groups.
* *
* @param user * @param user
* The user being checked. * The user being checked.
@@ -166,7 +168,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
throws GuacamoleException { throws GuacamoleException {
// Get object permissions // Get object permissions
ObjectPermissionSet permissionSet = getPermissionSet(user); ObjectPermissionSet permissionSet = getEffectivePermissionSet(user);
// Return whether permission is granted // Return whether permission is granted
return user.getUser().isAdministrator() return user.getUser().isAdministrator()
@@ -176,7 +178,8 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
/** /**
* Returns the permission set associated with the given user and related * Returns the permission set associated with the given user and related
* to the type of objects handled by this directory object service. * to the type of objects handled by this directory object service, taking
* into account permission inheritance via user groups.
* *
* @param user * @param user
* The user whose permissions are being retrieved. * The user whose permissions are being retrieved.
@@ -189,7 +192,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
* @throws GuacamoleException * @throws GuacamoleException
* If permission to read the user's permissions is denied. * If permission to read the user's permissions is denied.
*/ */
protected abstract ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user) protected abstract ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException; throws GuacamoleException;
/** /**
@@ -398,7 +401,8 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
// Otherwise only return explicitly readable identifiers // Otherwise only return explicitly readable identifiers
else else
objects = getObjectMapper().selectReadable(user.getUser().getModel(), identifiers); objects = getObjectMapper().selectReadable(user.getUser().getModel(),
identifiers, user.getEffectiveUserGroups());
// Return collection of requested objects // Return collection of requested objects
return getObjectInstances(user, objects); return getObjectInstances(user, objects);
@@ -432,8 +436,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
// Create model which grants this permission to the current user // Create model which grants this permission to the current user
ObjectPermissionModel permissionModel = new ObjectPermissionModel(); ObjectPermissionModel permissionModel = new ObjectPermissionModel();
permissionModel.setUserID(userModel.getObjectID()); permissionModel.setEntityID(userModel.getEntityID());
permissionModel.setUsername(userModel.getIdentifier());
permissionModel.setType(permission); permissionModel.setType(permission);
permissionModel.setObjectIdentifier(model.getIdentifier()); permissionModel.setObjectIdentifier(model.getIdentifier());
@@ -510,7 +513,8 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
// Otherwise only return explicitly readable identifiers // Otherwise only return explicitly readable identifiers
else else
return getObjectMapper().selectReadableIdentifiers(user.getUser().getModel()); return getObjectMapper().selectReadableIdentifiers(user.getUser().getModel(),
user.getEffectiveUserGroups());
} }

View File

@@ -0,0 +1,271 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.base;
import com.google.inject.Inject;
import java.util.Collections;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.permission.SystemPermissionService;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionService;
import org.apache.guacamole.auth.jdbc.permission.ConnectionGroupPermissionService;
import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionService;
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService;
import org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionService;
import org.apache.guacamole.auth.jdbc.permission.UserPermissionService;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.net.auth.Permissions;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermission;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
/**
* An implementation of the base Permissions interface which is common to both
* Users and UserGroups, backed by a database model.
*
* @param <ModelType>
* The type of model object that corresponds to this object.
*/
public abstract class ModeledPermissions<ModelType extends EntityModel>
extends ModeledDirectoryObject<ModelType> implements Permissions {
/**
* Service for retrieving entity details.
*/
@Inject
private EntityService entityService;
/**
* Service for retrieving system permissions.
*/
@Inject
private SystemPermissionService systemPermissionService;
/**
* Service for retrieving connection permissions.
*/
@Inject
private ConnectionPermissionService connectionPermissionService;
/**
* Service for retrieving connection group permissions.
*/
@Inject
private ConnectionGroupPermissionService connectionGroupPermissionService;
/**
* Service for retrieving sharing profile permissions.
*/
@Inject
private SharingProfilePermissionService sharingProfilePermissionService;
/**
* Service for retrieving active connection permissions.
*/
@Inject
private ActiveConnectionPermissionService activeConnectionPermissionService;
/**
* Service for retrieving user permissions.
*/
@Inject
private UserPermissionService userPermissionService;
/**
* Service for retrieving user group permissions.
*/
@Inject
private UserGroupPermissionService userGroupPermissionService;
/**
* Returns whether the underlying entity is a user. Entities may be either
* users or user groups.
*
* @return
* true if the underlying entity is a user, false otherwise.
*/
public boolean isUser() {
return getModel().getEntityType() == EntityType.USER;
}
/**
* Returns whether the underlying entity is a user group. Entities may be
* either users or user groups.
*
* @return
* true if the underlying entity is a user group, false otherwise.
*/
public boolean isUserGroup() {
return getModel().getEntityType() == EntityType.USER_GROUP;
}
/**
* Returns whether this entity is a system administrator, and thus is not
* restricted by permissions, taking into account permission inheritance
* via user groups.
*
* @return
* true if this entity is a system administrator, false otherwise.
*
* @throws GuacamoleException
* If an error occurs while determining the entity's system administrator
* status.
*/
public boolean isAdministrator() throws GuacamoleException {
SystemPermissionSet systemPermissionSet = getEffective().getSystemPermissions();
return systemPermissionSet.hasPermission(SystemPermission.Type.ADMINISTER);
}
@Override
public SystemPermissionSet getSystemPermissions()
throws GuacamoleException {
return systemPermissionService.getPermissionSet(getCurrentUser(), this,
Collections.<String>emptySet());
}
@Override
public ObjectPermissionSet getConnectionPermissions()
throws GuacamoleException {
return connectionPermissionService.getPermissionSet(getCurrentUser(),
this, Collections.<String>emptySet());
}
@Override
public ObjectPermissionSet getConnectionGroupPermissions()
throws GuacamoleException {
return connectionGroupPermissionService.getPermissionSet(
getCurrentUser(), this, Collections.<String>emptySet());
}
@Override
public ObjectPermissionSet getSharingProfilePermissions()
throws GuacamoleException {
return sharingProfilePermissionService.getPermissionSet(
getCurrentUser(), this, Collections.<String>emptySet());
}
@Override
public ObjectPermissionSet getActiveConnectionPermissions()
throws GuacamoleException {
return activeConnectionPermissionService.getPermissionSet(
getCurrentUser(), this, Collections.<String>emptySet());
}
@Override
public ObjectPermissionSet getUserPermissions()
throws GuacamoleException {
return userPermissionService.getPermissionSet(getCurrentUser(), this,
Collections.<String>emptySet());
}
@Override
public ObjectPermissionSet getUserGroupPermissions() throws GuacamoleException {
return userGroupPermissionService.getPermissionSet(getCurrentUser(),
this, Collections.<String>emptySet());
}
/**
* Returns the identifiers of all user groups defined within the database
* which apply to this user, including any groups inherited through
* membership in yet more groups.
*
* @return
* The identifiers of all user groups defined within the database which
* apply to this user.
*/
public Set<String> getEffectiveUserGroups() {
return entityService.retrieveEffectiveGroups(this,
Collections.<String>emptySet());
}
/**
* Returns a Permissions object which represents all permissions granted to
* this entity, including any permissions inherited through group
* membership.
*
* @return
* A Permissions object which represents all permissions granted to
* this entity.
*/
public Permissions getEffective() {
final ModeledAuthenticatedUser authenticatedUser = getCurrentUser();
final Set<String> effectiveGroups;
// If this user is the currently-authenticated user, include any
// additional effective groups declared by the authentication system
if (authenticatedUser.getIdentifier().equals(getIdentifier()))
effectiveGroups = entityService.retrieveEffectiveGroups(this,
authenticatedUser.getEffectiveUserGroups());
// Otherwise, just include effective groups from the database
else
effectiveGroups = getEffectiveUserGroups();
// Return a permissions object which describes all effective
// permissions, including any permissions inherited via user groups
return new Permissions() {
@Override
public ObjectPermissionSet getActiveConnectionPermissions()
throws GuacamoleException {
return activeConnectionPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
}
@Override
public ObjectPermissionSet getConnectionGroupPermissions()
throws GuacamoleException {
return connectionGroupPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
}
@Override
public ObjectPermissionSet getConnectionPermissions()
throws GuacamoleException {
return connectionPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
}
@Override
public ObjectPermissionSet getSharingProfilePermissions()
throws GuacamoleException {
return sharingProfilePermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
}
@Override
public SystemPermissionSet getSystemPermissions()
throws GuacamoleException {
return systemPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
}
@Override
public ObjectPermissionSet getUserPermissions()
throws GuacamoleException {
return userPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
}
@Override
public ObjectPermissionSet getUserGroupPermissions()
throws GuacamoleException {
return userGroupPermissionService.getPermissionSet(getCurrentUser(), ModeledPermissions.this, effectiveGroups);
}
};
}
}

View File

@@ -0,0 +1,126 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.base;
import java.util.Collection;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.UserModel;
import org.apache.ibatis.annotations.Param;
/**
* Mapper for the relations represented by a particular RelatedObjectSet
* implementation.
*
* @param <ParentModelType>
* The underlying database model of the object on the parent side of the
* one-to-many relationship represented by the RelatedObjectSet mapped by
* this ObjectRelationMapper.
*/
public interface ObjectRelationMapper<ParentModelType extends ObjectModel> {
/**
* Inserts rows as necessary to establish the one-to-many relationship
* represented by the RelatedObjectSet between the given parent and
* children. If the relation for any parent/child pair is already present,
* no attempt is made to insert a new row for that relation.
*
* @param parent
* The model of the object on the parent side of the one-to-many
* relationship represented by the RelatedObjectSet.
*
* @param children
* The identifiers of the objects on the child side of the one-to-many
* relationship represented by the RelatedObjectSet.
*
* @return
* The number of rows inserted.
*/
int insert(@Param("parent") ParentModelType parent,
@Param("children") Collection<String> children);
/**
* Deletes rows as necessary to modify the one-to-many relationship
* represented by the RelatedObjectSet between the given parent and
* children. If the relation for any parent/child pair does not exist,
* that specific relation is ignored, and deletion proceeds with the
* remaining relations.
*
* @param parent
* The model of the object on the parent side of the one-to-many
* relationship represented by the RelatedObjectSet.
*
* @param children
* The identifiers of the objects on the child side of the one-to-many
* relationship represented by the RelatedObjectSet.
*
* @return
* The number of rows deleted.
*/
int delete(@Param("parent") ParentModelType parent,
@Param("children") Collection<String> children);
/**
* Retrieves the identifiers of all objects on the child side of the
* one-to-many relationship represented by the RelatedObjectSet mapped by
* this ObjectRelationMapper. 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
* selectReadableChildIdentifiers() instead.
*
* @param parent
* The model of the object on the parent side of the one-to-many
* relationship represented by the RelatedObjectSet.
*
* @return
* A Set containing the identifiers of all objects on the child side
* of the one-to-many relationship.
*/
Set<String> selectChildIdentifiers(@Param("parent") ParentModelType parent);
/**
* Retrieves the identifiers of all objects on the child side of the
* one-to-many relationship represented by the RelatedObjectSet mapped by
* this ObjectRelationMapper, including only those objects which 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 selectChildIdentifiers() instead.
*
* @param user
* The user whose permissions should determine whether an identifier
* is returned.
*
* @param effectiveGroups
* The identifiers of any known effective groups that should be taken
* into account, such as those defined externally to the database.
*
* @param parent
* The model of the object on the parent side of the one-to-many
* relationship represented by the RelatedObjectSet.
*
* @return
* A Set containing the identifiers of all readable objects on the
* child side of the one-to-many relationship.
*/
Set<String> selectReadableChildIdentifiers(@Param("user") UserModel user,
@Param("effectiveGroups") Collection<String> effectiveGroups,
@Param("parent") ParentModelType parent);
}

View File

@@ -0,0 +1,211 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.base;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
/**
* A database implementation of RelatedObjectSet which provides access to a
* parent object and corresponding set of objects related to the parent, subject
* to object-level permissions. Though the parent and child objects have
* specific types, only the parent object's type is enforced through type
* parameters, as child objects are represented by identifiers only.
*
* @param <ParentObjectType>
* The type of object that represents the parent side of the relation.
*
* @param <ParentModelType>
* The underlying database model of the parent object.
*/
public abstract class RelatedObjectSet<ParentObjectType extends ModeledDirectoryObject<ParentModelType>, ParentModelType extends ObjectModel>
extends RestrictedObject implements org.apache.guacamole.net.auth.RelatedObjectSet {
/**
* The parent object which shares some arbitrary relation with the objects
* within this set.
*/
private ParentObjectType parent;
/**
* Creates a new RelatedObjectSet. The resulting object set must still be
* initialized by a call to init().
*/
public RelatedObjectSet() {
}
/**
* Initializes this RelatedObjectSet with the current user and the single
* object on the parent side of the one-to-many relation represented by the
* set.
*
* @param currentUser
* The user who queried this RelatedObjectSet, and whose permissions
* dictate the access level of all operations performed on this set.
*
* @param parent
* The parent object which shares some arbitrary relation with the
* objects within this set.
*/
public void init(ModeledAuthenticatedUser currentUser, ParentObjectType parent) {
super.init(currentUser);
this.parent = parent;
}
/**
* Returns the mapper which provides low-level access to the the database
* models which drive the relation represented by this RelatedObjectSet.
*
* @return
* The mapper which provides low-level access to the the database
* models which drive the relation represented by this
* RelatedObjectSet.
*/
protected abstract ObjectRelationMapper<ParentModelType> getObjectRelationMapper();
/**
* Returns the permission set which exposes the effective permissions
* available to the current user regarding the objects on the parent side
* of the one-to-many relationship represented by this RelatedObjectSet.
* Permission inheritance through user groups is taken into account.
*
* @return
* The permission set which exposes the effective permissions
* available to the current user regarding the objects on the parent
* side of the one-to-many relationship represented by this
* RelatedObjectSet.
*
* @throws GuacamoleException
* If permission to query permission status is denied.
*/
protected abstract ObjectPermissionSet getParentObjectEffectivePermissionSet()
throws GuacamoleException;
/**
* Returns the permission set which exposes the effective permissions
* available to the current user regarding the objects on the child side
* of the one-to-many relationship represented by this RelatedObjectSet.
* Permission inheritance through user groups is taken into account.
*
* @return
* The permission set which exposes the effective permissions
* available to the current user regarding the objects on the child
* side of the one-to-many relationship represented by this
* RelatedObjectSet.
*
* @throws GuacamoleException
* If permission to query permission status is denied.
*/
protected abstract ObjectPermissionSet getChildObjectEffectivePermissionSet()
throws GuacamoleException;
/**
* Returns whether the current user has permission to alter the status of
* the relation between the parent object and the given child objects.
*
* @param identifiers
* The identifiers of all objects on the child side of the one-to-many
* relation being changed.
*
* @return
* true if the user has permission to make the described changes,
* false otherwise.
*
* @throws GuacamoleException
* If permission to query permission status is denied.
*/
private boolean canAlterRelation(Collection<String> identifiers)
throws GuacamoleException {
// System administrators may alter any relations
if (getCurrentUser().getUser().isAdministrator())
return true;
// Non-admin users require UPDATE permission on the parent object ...
if (!getParentObjectEffectivePermissionSet().hasPermission(
ObjectPermission.Type.UPDATE, parent.getIdentifier()))
return false;
// ... as well as UPDATE permission on all child objects being changed
Collection<String> accessibleIdentifiers =
getChildObjectEffectivePermissionSet().getAccessibleObjects(
Collections.singleton(ObjectPermission.Type.UPDATE),
identifiers);
return accessibleIdentifiers.size() == identifiers.size();
}
@Override
public Set<String> getObjects() throws GuacamoleException {
// Bypass permission checks if the user is a system admin
ModeledAuthenticatedUser user = getCurrentUser();
if (user.getUser().isAdministrator())
return getObjectRelationMapper().selectChildIdentifiers(parent.getModel());
// Otherwise only return explicitly readable identifiers
return getObjectRelationMapper().selectReadableChildIdentifiers(
user.getUser().getModel(), user.getEffectiveUserGroups(),
parent.getModel());
}
@Override
public void addObjects(Set<String> identifiers) throws GuacamoleException {
// Nothing to do if nothing provided
if (identifiers.isEmpty())
return;
// Create relations only if permission is granted
if (canAlterRelation(identifiers))
getObjectRelationMapper().insert(parent.getModel(), identifiers);
// User lacks permission to add user groups
else
throw new GuacamoleSecurityException("Permission denied.");
}
@Override
public void removeObjects(Set<String> identifiers) throws GuacamoleException {
// Nothing to do if nothing provided
if (identifiers.isEmpty())
return;
// Delete relations only if permission is granted
if (canAlterRelation(identifiers))
getObjectRelationMapper().delete(parent.getModel(), identifiers);
// User lacks permission to remove user groups
else
throw new GuacamoleSecurityException("Permission denied.");
}
}

View File

@@ -19,6 +19,7 @@
package org.apache.guacamole.auth.jdbc.connection; package org.apache.guacamole.auth.jdbc.connection;
import java.util.Collection;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper; import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
import org.apache.guacamole.auth.jdbc.user.UserModel; import org.apache.guacamole.auth.jdbc.user.UserModel;
@@ -61,11 +62,18 @@ public interface ConnectionMapper extends ModeledDirectoryObjectMapper<Connectio
* The identifier of the parent connection group, or null if the root * The identifier of the parent connection group, or null if the root
* connection group is to be queried. * connection group is to be queried.
* *
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the user. If
* no groups are given, only permissions directly granted to the user
* will be used.
*
* @return * @return
* A Set containing all identifiers of all readable objects. * A Set containing all identifiers of all readable objects.
*/ */
Set<String> selectReadableIdentifiersWithin(@Param("user") UserModel user, Set<String> selectReadableIdentifiersWithin(@Param("user") UserModel user,
@Param("parentIdentifier") String parentIdentifier); @Param("parentIdentifier") String parentIdentifier,
@Param("effectiveGroups") Collection<String> effectiveGroups);
/** /**
* Selects the connection within the given parent group and having the * Selects the connection within the given parent group and having the

View File

@@ -102,12 +102,19 @@ public interface ConnectionRecordMapper {
* @param limit * @param limit
* The maximum number of records that should be returned. * The maximum number of records that should be returned.
* *
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the user. If
* no groups are given, only permissions directly granted to the user
* will be used.
*
* @return * @return
* The results of the search performed with the given parameters. * The results of the search performed with the given parameters.
*/ */
List<ConnectionRecordModel> searchReadable(@Param("user") UserModel user, List<ConnectionRecordModel> searchReadable(@Param("user") UserModel user,
@Param("terms") Collection<ActivityRecordSearchTerm> terms, @Param("terms") Collection<ActivityRecordSearchTerm> terms,
@Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates, @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
@Param("limit") int limit); @Param("limit") int limit,
@Param("effectiveGroups") Collection<String> effectiveGroups);
} }

View File

@@ -131,26 +131,26 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
throws GuacamoleException { throws GuacamoleException {
// Return whether user has explicit connection creation permission // Return whether user has explicit connection creation permission
SystemPermissionSet permissionSet = user.getUser().getSystemPermissions(); SystemPermissionSet permissionSet = user.getUser().getEffectivePermissions().getSystemPermissions();
return permissionSet.hasPermission(SystemPermission.Type.CREATE_CONNECTION); return permissionSet.hasPermission(SystemPermission.Type.CREATE_CONNECTION);
} }
@Override @Override
protected ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user) protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException { throws GuacamoleException {
// Return permissions related to connections // Return permissions related to connections
return user.getUser().getConnectionPermissions(); return user.getUser().getEffectivePermissions().getConnectionPermissions();
} }
@Override @Override
protected ObjectPermissionSet getParentPermissionSet(ModeledAuthenticatedUser user) protected ObjectPermissionSet getParentEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException { throws GuacamoleException {
// Connections are contained by connection groups // Connections are contained by connection groups
return user.getUser().getConnectionGroupPermissions(); return user.getUser().getEffectivePermissions().getConnectionGroupPermissions();
} }
@@ -303,7 +303,9 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
// Otherwise only return explicitly readable identifiers // Otherwise only return explicitly readable identifiers
else else
return connectionMapper.selectReadableIdentifiersWithin(user.getUser().getModel(), identifier); return connectionMapper.selectReadableIdentifiersWithin(
user.getUser().getModel(), identifier,
user.getEffectiveUserGroups());
} }
@@ -475,8 +477,9 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
// Otherwise only return explicitly readable history records // Otherwise only return explicitly readable history records
else else
searchResults = connectionRecordMapper.searchReadable(user.getUser().getModel(), searchResults = connectionRecordMapper.searchReadable(
requiredContents, sortPredicates, limit); user.getUser().getModel(), requiredContents, sortPredicates,
limit, user.getEffectiveUserGroups());
return getObjectInstances(searchResults); return getObjectInstances(searchResults);

View File

@@ -19,6 +19,7 @@
package org.apache.guacamole.auth.jdbc.connectiongroup; package org.apache.guacamole.auth.jdbc.connectiongroup;
import java.util.Collection;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper; import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
import org.apache.guacamole.auth.jdbc.user.UserModel; import org.apache.guacamole.auth.jdbc.user.UserModel;
@@ -61,11 +62,18 @@ public interface ConnectionGroupMapper extends ModeledDirectoryObjectMapper<Conn
* The identifier of the parent connection group, or null if the root * The identifier of the parent connection group, or null if the root
* connection group is to be queried. * connection group is to be queried.
* *
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the user. If
* no groups are given, only permissions directly granted to the user
* will be used.
*
* @return * @return
* A Set containing all identifiers of all readable objects. * A Set containing all identifiers of all readable objects.
*/ */
Set<String> selectReadableIdentifiersWithin(@Param("user") UserModel user, Set<String> selectReadableIdentifiersWithin(@Param("user") UserModel user,
@Param("parentIdentifier") String parentIdentifier); @Param("parentIdentifier") String parentIdentifier,
@Param("effectiveGroups") Collection<String> effectiveGroups);
/** /**
* Selects the connection group within the given parent group and having * Selects the connection group within the given parent group and having

View File

@@ -112,26 +112,26 @@ public class ConnectionGroupService extends ModeledChildDirectoryObjectService<M
throws GuacamoleException { throws GuacamoleException {
// Return whether user has explicit connection group creation permission // Return whether user has explicit connection group creation permission
SystemPermissionSet permissionSet = user.getUser().getSystemPermissions(); SystemPermissionSet permissionSet = user.getUser().getEffectivePermissions().getSystemPermissions();
return permissionSet.hasPermission(SystemPermission.Type.CREATE_CONNECTION_GROUP); return permissionSet.hasPermission(SystemPermission.Type.CREATE_CONNECTION_GROUP);
} }
@Override @Override
protected ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user) protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException { throws GuacamoleException {
// Return permissions related to connection groups // Return permissions related to connection groups
return user.getUser().getConnectionGroupPermissions(); return user.getUser().getEffectivePermissions().getConnectionGroupPermissions();
} }
@Override @Override
protected ObjectPermissionSet getParentPermissionSet(ModeledAuthenticatedUser user) protected ObjectPermissionSet getParentEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException { throws GuacamoleException {
// Connection groups are contained by other connection groups // Connection groups are contained by other connection groups
return user.getUser().getConnectionGroupPermissions(); return user.getUser().getEffectivePermissions().getConnectionGroupPermissions();
} }
@@ -223,7 +223,9 @@ public class ConnectionGroupService extends ModeledChildDirectoryObjectService<M
// Otherwise only return explicitly readable identifiers // Otherwise only return explicitly readable identifiers
else else
return connectionGroupMapper.selectReadableIdentifiersWithin(user.getUser().getModel(), identifier); return connectionGroupMapper.selectReadableIdentifiersWithin(
user.getUser().getModel(), identifier,
user.getEffectiveUserGroups());
} }

View File

@@ -20,8 +20,10 @@
package org.apache.guacamole.auth.jdbc.permission; package org.apache.guacamole.auth.jdbc.permission;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.Permission; import org.apache.guacamole.net.auth.permission.Permission;
@@ -41,17 +43,51 @@ public abstract class AbstractPermissionService<PermissionSetType extends Permis
PermissionType extends Permission> PermissionType extends Permission>
implements PermissionService<PermissionSetType, PermissionType> { implements PermissionService<PermissionSetType, PermissionType> {
/**
* Returns the ObjectPermissionSet related to the type of the given entity.
* If the given entity represents a user, then the ObjectPermissionSet
* containing user permissions is returned. If the given entity represents
* a user group, then the ObjectPermissionSet containing user group
* permissions is returned.
*
* @param user
* The user to retrieve the ObjectPermissionSet from.
*
* @param targetEntity
* The entity whose type dictates the ObjectPermissionSet returned.
*
* @return
* The ObjectPermissionSet related to the type of the given entity.
*
* @throws GuacamoleException
* If the relevant ObjectPermissionSet cannot be retrieved.
*/
protected ObjectPermissionSet getRelevantPermissionSet(ModeledUser user,
ModeledPermissions<? extends EntityModel> targetEntity)
throws GuacamoleException {
if (targetEntity.isUser())
return user.getUserPermissions();
if (targetEntity.isUserGroup())
return user.getUserGroupPermissions();
// Entities should be only users or groups
throw new UnsupportedOperationException("Unexpected entity type.");
}
/** /**
* Determines whether the given user can read the permissions currently * Determines whether the given user can read the permissions currently
* granted to the given target user. If the reading user and the target * granted to the given target entity. If the reading user and the target
* user are not the same, then explicit READ or SYSTEM_ADMINISTER access is * entity are not the same, then explicit READ or SYSTEM_ADMINISTER access
* required. * is required. Permission inheritance via user groups is taken into account.
* *
* @param user * @param user
* The user attempting to read permissions. * The user attempting to read permissions.
* *
* @param targetUser * @param targetEntity
* The user whose permissions are being read. * The entity whose permissions are being read.
* *
* @return * @return
* true if permission is granted, false otherwise. * true if permission is granted, false otherwise.
@@ -61,19 +97,20 @@ public abstract class AbstractPermissionService<PermissionSetType extends Permis
* permission is denied to read the current user's permissions. * permission is denied to read the current user's permissions.
*/ */
protected boolean canReadPermissions(ModeledAuthenticatedUser user, protected boolean canReadPermissions(ModeledAuthenticatedUser user,
ModeledUser targetUser) throws GuacamoleException { ModeledPermissions<? extends EntityModel> targetEntity)
throws GuacamoleException {
// A user can always read their own permissions // A user can always read their own permissions
if (user.getUser().getIdentifier().equals(targetUser.getIdentifier())) if (targetEntity.isUser() && user.getUser().getIdentifier().equals(targetEntity.getIdentifier()))
return true; return true;
// A system adminstrator can do anything // A system adminstrator can do anything
if (user.getUser().isAdministrator()) if (user.getUser().isAdministrator())
return true; return true;
// Can read permissions on target user if explicit READ is granted // Can read permissions on target entity if explicit READ is granted
ObjectPermissionSet userPermissionSet = user.getUser().getUserPermissions(); ObjectPermissionSet permissionSet = getRelevantPermissionSet(user.getUser(), targetEntity);
return userPermissionSet.hasPermission(ObjectPermission.Type.READ, targetUser.getIdentifier()); return permissionSet.hasPermission(ObjectPermission.Type.READ, targetEntity.getIdentifier());
} }

View File

@@ -21,9 +21,11 @@ package org.apache.guacamole.auth.jdbc.permission;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
/** /**
* Service which provides convenience methods for creating, retrieving, and * Service which provides convenience methods for creating, retrieving, and
@@ -51,11 +53,12 @@ public class ConnectionGroupPermissionService extends ModeledObjectPermissionSer
@Override @Override
public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
ModeledUser targetUser) throws GuacamoleException { ModeledPermissions<? extends EntityModel> targetEntity,
Set<String> effectiveGroups) throws GuacamoleException {
// Create permission set for requested user // Create permission set for requested entity
ObjectPermissionSet permissionSet = connectionGroupPermissionSetProvider.get(); ObjectPermissionSet permissionSet = connectionGroupPermissionSetProvider.get();
permissionSet.init(user, targetUser); permissionSet.init(user, targetEntity, effectiveGroups);
return permissionSet; return permissionSet;

View File

@@ -21,9 +21,11 @@ package org.apache.guacamole.auth.jdbc.permission;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
/** /**
* Service which provides convenience methods for creating, retrieving, and * Service which provides convenience methods for creating, retrieving, and
@@ -51,11 +53,12 @@ public class ConnectionPermissionService extends ModeledObjectPermissionService
@Override @Override
public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
ModeledUser targetUser) throws GuacamoleException { ModeledPermissions<? extends EntityModel> targetEntity,
Set<String> effectiveGroups) throws GuacamoleException {
// Create permission set for requested user // Create permission set for requested entity
ObjectPermissionSet permissionSet = connectionPermissionSetProvider.get(); ObjectPermissionSet permissionSet = connectionPermissionSetProvider.get();
permissionSet.init(user, targetUser); permissionSet.init(user, targetEntity, effectiveGroups);
return permissionSet; return permissionSet;

View File

@@ -22,10 +22,12 @@ package org.apache.guacamole.auth.jdbc.permission;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
@@ -47,14 +49,14 @@ public abstract class ModeledObjectPermissionService
} }
@Override @Override
protected ObjectPermissionModel getModelInstance(ModeledUser targetUser, protected ObjectPermissionModel getModelInstance(
ModeledPermissions<? extends EntityModel> targetEntity,
ObjectPermission permission) { ObjectPermission permission) {
ObjectPermissionModel model = new ObjectPermissionModel(); ObjectPermissionModel model = new ObjectPermissionModel();
// Populate model object with data from user and permission // Populate model object with data from entity and permission
model.setUserID(targetUser.getModel().getObjectID()); model.setEntityID(targetEntity.getModel().getEntityID());
model.setUsername(targetUser.getModel().getIdentifier());
model.setType(permission.getType()); model.setType(permission.getType());
model.setObjectIdentifier(permission.getObjectIdentifier()); model.setObjectIdentifier(permission.getObjectIdentifier());
@@ -64,30 +66,32 @@ public abstract class ModeledObjectPermissionService
/** /**
* Determines whether the current user has permission to update the given * Determines whether the current user has permission to update the given
* target user, adding or removing the given permissions. Such permission * target entity, adding or removing the given permissions. Such permission
* depends on whether the current user is a system administrator, whether * 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 UPDATE permission on the target entity, and whether
* they have explicit ADMINISTER permission on all affected objects. * they have explicit ADMINISTER permission on all affected objects.
* Permission inheritance via user groups is taken into account.
* *
* @param user * @param user
* The user who is changing permissions. * The user who is changing permissions.
* *
* @param targetUser * @param targetEntity
* The user whose permissions are being changed. * The entity whose permissions are being changed.
* *
* @param permissions * @param permissions
* The permissions that are being added or removed from the target * The permissions that are being added or removed from the target
* user. * entity.
* *
* @return * @return
* true if the user has permission to change the target users * true if the user has permission to change the target entity's
* permissions as specified, false otherwise. * permissions as specified, false otherwise.
* *
* @throws GuacamoleException * @throws GuacamoleException
* If an error occurs while checking permission status, or if * If an error occurs while checking permission status, or if
* permission is denied to read the current user's permissions. * permission is denied to read the current user's permissions.
*/ */
protected boolean canAlterPermissions(ModeledAuthenticatedUser user, ModeledUser targetUser, protected boolean canAlterPermissions(ModeledAuthenticatedUser user,
ModeledPermissions<? extends EntityModel> targetEntity,
Collection<ObjectPermission> permissions) Collection<ObjectPermission> permissions)
throws GuacamoleException { throws GuacamoleException {
@@ -95,9 +99,9 @@ public abstract class ModeledObjectPermissionService
if (user.getUser().isAdministrator()) if (user.getUser().isAdministrator())
return true; return true;
// Verify user has update permission on the target user // Verify user has update permission on the target entity
ObjectPermissionSet userPermissionSet = user.getUser().getUserPermissions(); ObjectPermissionSet permissionSet = getRelevantPermissionSet(user.getUser(), targetEntity);
if (!userPermissionSet.hasPermission(ObjectPermission.Type.UPDATE, targetUser.getIdentifier())) if (!permissionSet.hasPermission(ObjectPermission.Type.UPDATE, targetEntity.getIdentifier()))
return false; return false;
// Produce collection of affected identifiers // Produce collection of affected identifiers
@@ -106,7 +110,7 @@ public abstract class ModeledObjectPermissionService
affectedIdentifiers.add(permission.getObjectIdentifier()); affectedIdentifiers.add(permission.getObjectIdentifier());
// Determine subset of affected identifiers that we have admin access to // Determine subset of affected identifiers that we have admin access to
ObjectPermissionSet affectedPermissionSet = getPermissionSet(user, user.getUser()); ObjectPermissionSet affectedPermissionSet = getPermissionSet(user, user.getUser(), user.getEffectiveUserGroups());
Collection<String> allowedSubset = affectedPermissionSet.getAccessibleObjects( Collection<String> allowedSubset = affectedPermissionSet.getAccessibleObjects(
Collections.singleton(ObjectPermission.Type.ADMINISTER), Collections.singleton(ObjectPermission.Type.ADMINISTER),
affectedIdentifiers affectedIdentifiers
@@ -121,13 +125,14 @@ public abstract class ModeledObjectPermissionService
} }
@Override @Override
public void createPermissions(ModeledAuthenticatedUser user, ModeledUser targetUser, public void createPermissions(ModeledAuthenticatedUser user,
ModeledPermissions<? extends EntityModel> targetEntity,
Collection<ObjectPermission> permissions) Collection<ObjectPermission> permissions)
throws GuacamoleException { throws GuacamoleException {
// Create permissions only if user has permission to do so // Create permissions only if user has permission to do so
if (canAlterPermissions(user, targetUser, permissions)) { if (canAlterPermissions(user, targetEntity, permissions)) {
Collection<ObjectPermissionModel> models = getModelInstances(targetUser, permissions); Collection<ObjectPermissionModel> models = getModelInstances(targetEntity, permissions);
getPermissionMapper().insert(models); getPermissionMapper().insert(models);
return; return;
} }
@@ -138,13 +143,14 @@ public abstract class ModeledObjectPermissionService
} }
@Override @Override
public void deletePermissions(ModeledAuthenticatedUser user, ModeledUser targetUser, public void deletePermissions(ModeledAuthenticatedUser user,
ModeledPermissions<? extends EntityModel> targetEntity,
Collection<ObjectPermission> permissions) Collection<ObjectPermission> permissions)
throws GuacamoleException { throws GuacamoleException {
// Delete permissions only if user has permission to do so // Delete permissions only if user has permission to do so
if (canAlterPermissions(user, targetUser, permissions)) { if (canAlterPermissions(user, targetEntity, permissions)) {
Collection<ObjectPermissionModel> models = getModelInstances(targetUser, permissions); Collection<ObjectPermissionModel> models = getModelInstances(targetEntity, permissions);
getPermissionMapper().delete(models); getPermissionMapper().delete(models);
return; return;
} }
@@ -155,49 +161,43 @@ public abstract class ModeledObjectPermissionService
} }
@Override @Override
public ObjectPermission retrievePermission(ModeledAuthenticatedUser user, public boolean hasPermission(ModeledAuthenticatedUser user,
ModeledUser targetUser, ObjectPermission.Type type, ModeledPermissions<? extends EntityModel> targetEntity,
String identifier) throws GuacamoleException { ObjectPermission.Type type, String identifier,
Set<String> effectiveGroups) throws GuacamoleException {
// Retrieve permissions only if allowed // Retrieve permissions only if allowed
if (canReadPermissions(user, targetUser)) { if (canReadPermissions(user, targetEntity))
return getPermissionMapper().selectOne(targetEntity.getModel(),
type, identifier, effectiveGroups) != null;
// Read permission from database, return null if not found // User cannot read this entity's permissions
ObjectPermissionModel model = getPermissionMapper().selectOne(targetUser.getModel(), type, identifier);
if (model == null)
return null;
return getPermissionInstance(model);
}
// User cannot read this user's permissions
throw new GuacamoleSecurityException("Permission denied."); throw new GuacamoleSecurityException("Permission denied.");
} }
@Override @Override
public Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user, public Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
ModeledUser targetUser, Collection<ObjectPermission.Type> permissions, ModeledPermissions<? extends EntityModel> targetEntity,
Collection<String> identifiers) throws GuacamoleException { Collection<ObjectPermission.Type> permissions,
Collection<String> identifiers, Set<String> effectiveGroups)
throws GuacamoleException {
// Nothing is always accessible // Nothing is always accessible
if (identifiers.isEmpty()) if (identifiers.isEmpty())
return identifiers; return identifiers;
// Retrieve permissions only if allowed
if (canReadPermissions(user, targetUser)) {
// If user is an admin, everything is accessible // If user is an admin, everything is accessible
if (user.getUser().isAdministrator()) if (user.getUser().isAdministrator())
return identifiers; return identifiers;
// Otherwise, return explicitly-retrievable identifiers // Otherwise, return explicitly-retrievable identifiers only if allowed
return getPermissionMapper().selectAccessibleIdentifiers(targetUser.getModel(), permissions, identifiers); if (canReadPermissions(user, targetEntity))
return getPermissionMapper().selectAccessibleIdentifiers(
targetEntity.getModel(), permissions, identifiers,
effectiveGroups);
} // User cannot read this entity's permissions
// User cannot read this user's permissions
throw new GuacamoleSecurityException("Permission denied."); throw new GuacamoleSecurityException("Permission denied.");
} }

View File

@@ -24,9 +24,10 @@ import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
import org.apache.guacamole.net.auth.permission.Permission; import org.apache.guacamole.net.auth.permission.Permission;
import org.apache.guacamole.net.auth.permission.PermissionSet; import org.apache.guacamole.net.auth.permission.PermissionSet;
@@ -97,42 +98,44 @@ public abstract class ModeledPermissionService<PermissionSetType extends Permiss
/** /**
* Returns an instance of a model object which is based on the given * Returns an instance of a model object which is based on the given
* permission and target user. * permission and target entity.
* *
* @param targetUser * @param targetEntity
* The user to whom this permission is granted. * The entity to whom this permission is granted.
* *
* @param permission * @param permission
* The permission to use to produce the returned model object. * The permission to use to produce the returned model object.
* *
* @return * @return
* A model object which is based on the given permission and target * A model object which is based on the given permission and target
* user. * entity.
*/ */
protected abstract ModelType getModelInstance(ModeledUser targetUser, protected abstract ModelType getModelInstance(
ModeledPermissions<? extends EntityModel> targetEntity,
PermissionType permission); PermissionType permission);
/** /**
* Returns a collection of model objects which are based on the given * Returns a collection of model objects which are based on the given
* permissions and target user. * permissions and target entity.
* *
* @param targetUser * @param targetEntity
* The user to whom this permission is granted. * The entity to whom this permission is granted.
* *
* @param permissions * @param permissions
* The permissions to use to produce the returned model objects. * The permissions to use to produce the returned model objects.
* *
* @return * @return
* A collection of model objects which are based on the given * A collection of model objects which are based on the given
* permissions and target user. * permissions and target entity.
*/ */
protected Collection<ModelType> getModelInstances(ModeledUser targetUser, protected Collection<ModelType> getModelInstances(
ModeledPermissions<? extends EntityModel> targetEntity,
Collection<PermissionType> permissions) { Collection<PermissionType> permissions) {
// Create new collection of models by manually converting each permission // Create new collection of models by manually converting each permission
Collection<ModelType> models = new ArrayList<ModelType>(permissions.size()); Collection<ModelType> models = new ArrayList<ModelType>(permissions.size());
for (PermissionType permission : permissions) for (PermissionType permission : permissions)
models.add(getModelInstance(targetUser, permission)); models.add(getModelInstance(targetEntity, permission));
return models; return models;
@@ -140,13 +143,14 @@ public abstract class ModeledPermissionService<PermissionSetType extends Permiss
@Override @Override
public Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user, public Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user,
ModeledUser targetUser) throws GuacamoleException { ModeledPermissions<? extends EntityModel> targetEntity,
Set<String> effectiveGroups) throws GuacamoleException {
// Retrieve permissions only if allowed // Retrieve permissions only if allowed
if (canReadPermissions(user, targetUser)) if (canReadPermissions(user, targetEntity))
return getPermissionInstances(getPermissionMapper().select(targetUser.getModel())); return getPermissionInstances(getPermissionMapper().select(targetEntity.getModel(), effectiveGroups));
// User cannot read this user's permissions // User cannot read this entity's permissions
throw new GuacamoleSecurityException("Permission denied."); throw new GuacamoleSecurityException("Permission denied.");
} }

View File

@@ -20,8 +20,8 @@
package org.apache.guacamole.auth.jdbc.permission; package org.apache.guacamole.auth.jdbc.permission;
import java.util.Collection; import java.util.Collection;
import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.guacamole.auth.jdbc.user.UserModel;
import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermission;
/** /**
@@ -31,11 +31,11 @@ public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissio
/** /**
* Retrieve the permission of the given type associated with the given * Retrieve the permission of the given type associated with the given
* user and object, if it exists. If no such permission exists, null is * entity and object, if it exists. If no such permission exists, null is
* returned. * returned.
* *
* @param user * @param entity
* The user to retrieve permissions for. * The entity to retrieve permissions for.
* *
* @param type * @param type
* The type of permission to return. * The type of permission to return.
@@ -43,20 +43,27 @@ public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissio
* @param identifier * @param identifier
* The identifier of the object affected by the permission to return. * The identifier of the object affected by the permission to return.
* *
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the user. If
* no groups are given, only permissions directly granted to the user
* will be used.
*
* @return * @return
* The requested permission, or null if no such permission is granted * The requested permission, or null if no such permission is granted
* to the given user for the given object. * to the given entity for the given object.
*/ */
ObjectPermissionModel selectOne(@Param("user") UserModel user, ObjectPermissionModel selectOne(@Param("entity") EntityModel entity,
@Param("type") ObjectPermission.Type type, @Param("type") ObjectPermission.Type type,
@Param("identifier") String identifier); @Param("identifier") String identifier,
@Param("effectiveGroups") Collection<String> effectiveGroups);
/** /**
* Retrieves the subset of the given identifiers for which the given user * Retrieves the subset of the given identifiers for which the given entity
* has at least one of the given permissions. * has at least one of the given permissions.
* *
* @param user * @param entity
* The user to check permissions of. * The entity to check permissions of.
* *
* @param permissions * @param permissions
* The permissions to check. An identifier will be included in the * The permissions to check. An identifier will be included in the
@@ -67,12 +74,19 @@ public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissio
* The identifiers of the objects affected by the permissions being * The identifiers of the objects affected by the permissions being
* checked. * checked.
* *
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the user. If
* no groups are given, only permissions directly granted to the user
* will be used.
*
* @return * @return
* A collection containing the subset of identifiers for which at least * A collection containing the subset of identifiers for which at least
* one of the specified permissions is granted. * one of the specified permissions is granted.
*/ */
Collection<String> selectAccessibleIdentifiers(@Param("user") UserModel user, Collection<String> selectAccessibleIdentifiers(@Param("entity") EntityModel entity,
@Param("permissions") Collection<ObjectPermission.Type> permissions, @Param("permissions") Collection<ObjectPermission.Type> permissions,
@Param("identifiers") Collection<String> identifiers); @Param("identifiers") Collection<String> identifiers,
@Param("effectiveGroups") Collection<String> effectiveGroups);
} }

View File

@@ -20,9 +20,11 @@
package org.apache.guacamole.auth.jdbc.permission; package org.apache.guacamole.auth.jdbc.permission;
import java.util.Collection; import java.util.Collection;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
@@ -35,14 +37,14 @@ public interface ObjectPermissionService
extends PermissionService<ObjectPermissionSet, ObjectPermission> { extends PermissionService<ObjectPermissionSet, ObjectPermission> {
/** /**
* Retrieves the permission of the given type associated with the given * Returns whether the permission of the given type and associated with the
* user and object, if it exists. If no such permission exists, null is * given object has been granted to the given entity.
* *
* @param user * @param user
* The user retrieving the permission. * The user retrieving the permission.
* *
* @param targetUser * @param targetEntity
* The user associated with the permission to be retrieved. * The entity associated with the permission to be retrieved.
* *
* @param type * @param type
* The type of permission to retrieve. * The type of permission to retrieve.
@@ -50,26 +52,33 @@ public interface ObjectPermissionService
* @param identifier * @param identifier
* The identifier of the object affected by the permission to return. * The identifier of the object affected by the permission to return.
* *
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the entity.
* If no groups are given, only permissions directly granted to the
* entity will be used.
*
* @return * @return
* The permission of the given type associated with the given user and * true if permission of the given type and associated with the given
* object, or null if no such permission exists. * object has been granted to the given entity, false otherwise.
* *
* @throws GuacamoleException * @throws GuacamoleException
* If an error occurs while retrieving the requested permission. * If an error occurs while retrieving the requested permission.
*/ */
ObjectPermission retrievePermission(ModeledAuthenticatedUser user, boolean hasPermission(ModeledAuthenticatedUser user,
ModeledUser targetUser, ObjectPermission.Type type, ModeledPermissions<? extends EntityModel> targetEntity,
String identifier) throws GuacamoleException; ObjectPermission.Type type, String identifier,
Set<String> effectiveGroups) throws GuacamoleException;
/** /**
* Retrieves the subset of the given identifiers for which the given user * Retrieves the subset of the given identifiers for which the given entity
* has at least one of the given permissions. * has at least one of the given permissions.
* *
* @param user * @param user
* The user checking the permissions. * The user checking the permissions.
* *
* @param targetUser * @param targetEntity
* The user to check permissions of. * The entity to check permissions of.
* *
* @param permissions * @param permissions
* The permissions to check. An identifier will be included in the * The permissions to check. An identifier will be included in the
@@ -80,6 +89,12 @@ public interface ObjectPermissionService
* The identifiers of the objects affected by the permissions being * The identifiers of the objects affected by the permissions being
* checked. * checked.
* *
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the entity.
* If no groups are given, only permissions directly granted to the
* entity will be used.
*
* @return * @return
* A collection containing the subset of identifiers for which at least * A collection containing the subset of identifiers for which at least
* one of the specified permissions is granted. * one of the specified permissions is granted.
@@ -88,7 +103,9 @@ public interface ObjectPermissionService
* If an error occurs while retrieving permissions. * If an error occurs while retrieving permissions.
*/ */
Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user, Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
ModeledUser targetUser, Collection<ObjectPermission.Type> permissions, ModeledPermissions<? extends EntityModel> targetEntity,
Collection<String> identifiers) throws GuacamoleException; Collection<ObjectPermission.Type> permissions,
Collection<String> identifiers, Set<String> effectiveGroups)
throws GuacamoleException;
} }

View File

@@ -19,28 +19,35 @@
package org.apache.guacamole.auth.jdbc.permission; package org.apache.guacamole.auth.jdbc.permission;
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
import org.apache.guacamole.auth.jdbc.base.RestrictedObject; import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermission;
/** /**
* A database implementation of ObjectPermissionSet which uses an injected * A database implementation of ObjectPermissionSet which uses an injected
* service to query and manipulate the object-level permissions associated with * service to query and manipulate the object-level permissions associated with
* a particular user. * a particular entity.
*/ */
public abstract class ObjectPermissionSet extends RestrictedObject public abstract class ObjectPermissionSet extends RestrictedObject
implements org.apache.guacamole.net.auth.permission.ObjectPermissionSet { implements org.apache.guacamole.net.auth.permission.ObjectPermissionSet {
/** /**
* The user associated with this permission set. Each of the permissions in * The entity associated with this permission set. Each of the permissions
* this permission set is granted to this user. * in this permission set is granted to this entity.
*/ */
private ModeledUser user; private ModeledPermissions<? extends EntityModel> entity;
/**
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the entity.
*/
private Set<String> effectiveGroups;
/** /**
* Creates a new ObjectPermissionSet. The resulting permission set * Creates a new ObjectPermissionSet. The resulting permission set
@@ -51,19 +58,28 @@ public abstract class ObjectPermissionSet extends RestrictedObject
} }
/** /**
* Initializes this permission set with the current user and the user * Initializes this permission set with the current user and the entity
* to whom the permissions in this set are granted. * to whom the permissions in this set are granted.
* *
* @param currentUser * @param currentUser
* The user who queried this permission set, and whose permissions * The user who queried this permission set, and whose permissions
* dictate the access level of all operations performed on this set. * dictate the access level of all operations performed on this set.
* *
* @param user * @param entity
* The user to whom the permissions in this set are granted. * The entity to whom the permissions in this set are granted.
*
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the entity.
* If no groups are given, only permissions directly granted to the
* entity will be used.
*/ */
public void init(ModeledAuthenticatedUser currentUser, ModeledUser user) { public void init(ModeledAuthenticatedUser currentUser,
ModeledPermissions<? extends EntityModel> entity,
Set<String> effectiveGroups) {
super.init(currentUser); super.init(currentUser);
this.user = user; this.entity = entity;
this.effectiveGroups = effectiveGroups;
} }
/** /**
@@ -78,13 +94,13 @@ public abstract class ObjectPermissionSet extends RestrictedObject
@Override @Override
public Set<ObjectPermission> getPermissions() throws GuacamoleException { public Set<ObjectPermission> getPermissions() throws GuacamoleException {
return getObjectPermissionService().retrievePermissions(getCurrentUser(), user); return getObjectPermissionService().retrievePermissions(getCurrentUser(), entity, effectiveGroups);
} }
@Override @Override
public boolean hasPermission(ObjectPermission.Type permission, public boolean hasPermission(ObjectPermission.Type permission,
String identifier) throws GuacamoleException { String identifier) throws GuacamoleException {
return getObjectPermissionService().retrievePermission(getCurrentUser(), user, permission, identifier) != null; return getObjectPermissionService().hasPermission(getCurrentUser(), entity, permission, identifier, effectiveGroups);
} }
@Override @Override
@@ -102,19 +118,19 @@ public abstract class ObjectPermissionSet extends RestrictedObject
@Override @Override
public Collection<String> getAccessibleObjects(Collection<ObjectPermission.Type> permissions, public Collection<String> getAccessibleObjects(Collection<ObjectPermission.Type> permissions,
Collection<String> identifiers) throws GuacamoleException { Collection<String> identifiers) throws GuacamoleException {
return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), user, permissions, identifiers); return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), entity, permissions, identifiers, effectiveGroups);
} }
@Override @Override
public void addPermissions(Set<ObjectPermission> permissions) public void addPermissions(Set<ObjectPermission> permissions)
throws GuacamoleException { throws GuacamoleException {
getObjectPermissionService().createPermissions(getCurrentUser(), user, permissions); getObjectPermissionService().createPermissions(getCurrentUser(), entity, permissions);
} }
@Override @Override
public void removePermissions(Set<ObjectPermission> permissions) public void removePermissions(Set<ObjectPermission> permissions)
throws GuacamoleException { throws GuacamoleException {
getObjectPermissionService().deletePermissions(getCurrentUser(), user, permissions); getObjectPermissionService().deletePermissions(getCurrentUser(), entity, permissions);
} }
} }

View File

@@ -20,7 +20,7 @@
package org.apache.guacamole.auth.jdbc.permission; package org.apache.guacamole.auth.jdbc.permission;
import java.util.Collection; import java.util.Collection;
import org.apache.guacamole.auth.jdbc.user.UserModel; import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
/** /**
@@ -32,15 +32,23 @@ import org.apache.ibatis.annotations.Param;
public interface PermissionMapper<PermissionType> { public interface PermissionMapper<PermissionType> {
/** /**
* Retrieves all permissions associated with the given user. * Retrieves all permissions associated with the given entity (user or user
* group).
* *
* @param user * @param entity
* The user to retrieve permissions for. * The entity to retrieve permissions for.
*
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the user. If
* no groups are given, only permissions directly granted to the user
* will be used.
* *
* @return * @return
* All permissions associated with the given user. * All permissions associated with the given entity.
*/ */
Collection<PermissionType> select(@Param("user") UserModel user); Collection<PermissionType> select(@Param("entity") EntityModel entity,
@Param("effectiveGroups") Collection<String> effectiveGroups);
/** /**
* Inserts the given permissions into the database. If any permissions * Inserts the given permissions into the database. If any permissions

View File

@@ -21,7 +21,7 @@ package org.apache.guacamole.auth.jdbc.permission;
/** /**
* Generic base permission model which grants a permission of a particular type * Generic base permission model which grants a permission of a particular type
* to a specific user. * to a specific entity (user or user group).
* *
* @param <PermissionType> * @param <PermissionType>
* The type of permissions allowed within this model. * The type of permissions allowed within this model.
@@ -29,14 +29,9 @@ package org.apache.guacamole.auth.jdbc.permission;
public abstract class PermissionModel<PermissionType> { public abstract class PermissionModel<PermissionType> {
/** /**
* The database ID of the user to whom this permission is granted. * The database ID of the entity to whom this permission is granted.
*/ */
private Integer userID; private Integer entityID;
/**
* The username of the user to whom this permission is granted.
*/
private String username;
/** /**
* The type of action granted by this permission. * The type of action granted by this permission.
@@ -44,43 +39,24 @@ public abstract class PermissionModel<PermissionType> {
private PermissionType type; private PermissionType type;
/** /**
* Returns the database ID of the user to whom this permission is granted. * Returns the database ID of the entity to whom this permission is
* granted.
* *
* @return * @return
* The database ID of the user to whom this permission is granted. * The database ID of the entity to whom this permission is granted.
*/ */
public Integer getUserID() { public Integer getEntityID() {
return userID; return entityID;
} }
/** /**
* Sets the database ID of the user to whom this permission is granted. * Sets the database ID of the entity to whom this permission is granted.
* *
* @param userID * @param entityID
* The database ID of the user to whom this permission is granted. * The database ID of the entity to whom this permission is granted.
*/ */
public void setUserID(Integer userID) { public void setEntityID(Integer entityID) {
this.userID = userID; this.entityID = entityID;
}
/**
* 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;
} }
/** /**

View File

@@ -19,16 +19,12 @@
package org.apache.guacamole.auth.jdbc.permission; package org.apache.guacamole.auth.jdbc.permission;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.Permission; import org.apache.guacamole.net.auth.permission.Permission;
import org.apache.guacamole.net.auth.permission.PermissionSet; import org.apache.guacamole.net.auth.permission.PermissionSet;
@@ -49,45 +45,60 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
/** /**
* Returns a permission set that can be used to retrieve and manipulate the * Returns a permission set that can be used to retrieve and manipulate the
* permissions of the given user. * permissions of the given entity.
* *
* @param user * @param user
* The user who will be retrieving or manipulating permissions through * The user who will be retrieving or manipulating permissions through
* the returned permission set. * the returned permission set.
* *
* @param targetUser * @param targetEntity
* The user to whom the permissions in the returned permission set are * The entity to whom the permissions in the returned permission set are
* granted. * granted.
* *
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the entity.
* If no groups are given, only permissions directly granted to the
* entity will be used.
*
* @return * @return
* A permission set that contains all permissions associated with the * A permission set that contains all permissions associated with the
* given user, and can be used to manipulate that user's permissions. * given entity, and can be used to manipulate that entity's
* permissions.
* *
* @throws GuacamoleException * @throws GuacamoleException
* If an error occurs while retrieving the permissions of the given * If an error occurs while retrieving the permissions of the given
* user, or if permission to retrieve the permissions of the given * entity, or if permission to retrieve the permissions of the given
* user is denied. * entity is denied.
*/ */
PermissionSetType getPermissionSet(ModeledAuthenticatedUser user, PermissionSetType getPermissionSet(ModeledAuthenticatedUser user,
ModeledUser targetUser) throws GuacamoleException; ModeledPermissions<? extends EntityModel> targetEntity,
Set<String> effectiveGroups) throws GuacamoleException;
/** /**
* Retrieves all permissions associated with the given user. * Retrieves all permissions associated with the given entity.
* *
* @param user * @param user
* The user retrieving the permissions. * The user retrieving the permissions.
* *
* @param targetUser * @param targetEntity
* The user associated with the permissions to be retrieved. * The entity associated with the permissions to be retrieved.
*
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the entity.
* If no groups are given, only permissions directly granted to the
* entity will be used.
* *
* @return * @return
* The permissions associated with the given user. * The permissions associated with the given entity.
* *
* @throws GuacamoleException * @throws GuacamoleException
* If an error occurs while retrieving the requested permissions. * If an error occurs while retrieving the requested permissions.
*/ */
Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user, Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user,
ModeledUser targetUser) throws GuacamoleException; ModeledPermissions<? extends EntityModel> targetEntity,
Set<String> effectiveGroups) throws GuacamoleException;
/** /**
* Creates the given permissions within the database. If any permissions * Creates the given permissions within the database. If any permissions
@@ -96,8 +107,8 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
* @param user * @param user
* The user creating the permissions. * The user creating the permissions.
* *
* @param targetUser * @param targetEntity
* The user associated with the permissions to be created. * The entity associated with the permissions to be created.
* *
* @param permissions * @param permissions
* The permissions to create. * The permissions to create.
@@ -106,8 +117,10 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
* If the user lacks permission to create the permissions, or an error * If the user lacks permission to create the permissions, or an error
* occurs while creating the permissions. * occurs while creating the permissions.
*/ */
void createPermissions(ModeledAuthenticatedUser user, ModeledUser targetUser, void createPermissions(ModeledAuthenticatedUser user,
Collection<PermissionType> permissions) throws GuacamoleException; ModeledPermissions<? extends EntityModel> targetEntity,
Collection<PermissionType> permissions)
throws GuacamoleException;
/** /**
* Deletes the given permissions. If any permissions do not exist, they * Deletes the given permissions. If any permissions do not exist, they
@@ -116,8 +129,8 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
* @param user * @param user
* The user deleting the permissions. * The user deleting the permissions.
* *
* @param targetUser * @param targetEntity
* The user associated with the permissions to be deleted. * The entity associated with the permissions to be deleted.
* *
* @param permissions * @param permissions
* The permissions to delete. * The permissions to delete.
@@ -126,7 +139,9 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
* If the user lacks permission to delete the permissions, or an error * If the user lacks permission to delete the permissions, or an error
* occurs while deleting the permissions. * occurs while deleting the permissions.
*/ */
void deletePermissions(ModeledAuthenticatedUser user, ModeledUser targetUser, void deletePermissions(ModeledAuthenticatedUser user,
Collection<PermissionType> permissions) throws GuacamoleException; ModeledPermissions<? extends EntityModel> targetEntity,
Collection<PermissionType> permissions)
throws GuacamoleException;
} }

View File

@@ -21,9 +21,11 @@ package org.apache.guacamole.auth.jdbc.permission;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
/** /**
* Service which provides convenience methods for creating, retrieving, and * Service which provides convenience methods for creating, retrieving, and
@@ -51,11 +53,12 @@ public class SharingProfilePermissionService extends ModeledObjectPermissionServ
@Override @Override
public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
ModeledUser targetUser) throws GuacamoleException { ModeledPermissions<? extends EntityModel> targetEntity,
Set<String> effectiveGroups) throws GuacamoleException {
// Create permission set for requested user // Create permission set for requested entity
ObjectPermissionSet permissionSet = sharingProfilePermissionSetProvider.get(); ObjectPermissionSet permissionSet = sharingProfilePermissionSetProvider.get();
permissionSet.init(user, targetUser); permissionSet.init(user, targetEntity, effectiveGroups);
return permissionSet; return permissionSet;

View File

@@ -19,7 +19,8 @@
package org.apache.guacamole.auth.jdbc.permission; package org.apache.guacamole.auth.jdbc.permission;
import org.apache.guacamole.auth.jdbc.user.UserModel; import java.util.Collection;
import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.guacamole.net.auth.permission.SystemPermission; import org.apache.guacamole.net.auth.permission.SystemPermission;
@@ -30,19 +31,26 @@ public interface SystemPermissionMapper extends PermissionMapper<SystemPermissio
/** /**
* Retrieve the permission of the given type associated with the given * Retrieve the permission of the given type associated with the given
* user, if it exists. If no such permission exists, null is returned. * entity, if it exists. If no such permission exists, null is returned.
* *
* @param user * @param entity
* The user to retrieve permissions for. * The entity to retrieve permissions for.
* *
* @param type * @param type
* The type of permission to return. * The type of permission to return.
* *
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the user. If
* no groups are given, only permissions directly granted to the user
* will be used.
*
* @return * @return
* The requested permission, or null if no such permission is granted * The requested permission, or null if no such permission is granted
* to the given user. * to the given entity.
*/ */
SystemPermissionModel selectOne(@Param("user") UserModel user, SystemPermissionModel selectOne(@Param("entity") EntityModel entity,
@Param("type") SystemPermission.Type type); @Param("type") SystemPermission.Type type,
@Param("effectiveGroups") Collection<String> effectiveGroups);
} }

View File

@@ -22,11 +22,13 @@ package org.apache.guacamole.auth.jdbc.permission;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import java.util.Collection; import java.util.Collection;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.GuacamoleUnsupportedException; import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
import org.apache.guacamole.net.auth.permission.SystemPermission; import org.apache.guacamole.net.auth.permission.SystemPermission;
/** /**
@@ -60,14 +62,14 @@ public class SystemPermissionService
} }
@Override @Override
protected SystemPermissionModel getModelInstance(final ModeledUser targetUser, protected SystemPermissionModel getModelInstance(
final ModeledPermissions<? extends EntityModel> targetEntity,
final SystemPermission permission) { final SystemPermission permission) {
SystemPermissionModel model = new SystemPermissionModel(); SystemPermissionModel model = new SystemPermissionModel();
// Populate model object with data from user and permission // Populate model object with data from entity and permission
model.setUserID(targetUser.getModel().getObjectID()); model.setEntityID(targetEntity.getModel().getEntityID());
model.setUsername(targetUser.getModel().getIdentifier());
model.setType(permission.getType()); model.setType(permission.getType());
return model; return model;
@@ -76,23 +78,25 @@ public class SystemPermissionService
@Override @Override
public SystemPermissionSet getPermissionSet(ModeledAuthenticatedUser user, public SystemPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
ModeledUser targetUser) throws GuacamoleException { ModeledPermissions<? extends EntityModel> targetEntity,
Set<String> effectiveGroups) throws GuacamoleException {
// Create permission set for requested user // Create permission set for requested entity
SystemPermissionSet permissionSet = systemPermissionSetProvider.get(); SystemPermissionSet permissionSet = systemPermissionSetProvider.get();
permissionSet.init(user, targetUser); permissionSet.init(user, targetEntity, effectiveGroups);
return permissionSet; return permissionSet;
} }
@Override @Override
public void createPermissions(ModeledAuthenticatedUser user, ModeledUser targetUser, public void createPermissions(ModeledAuthenticatedUser user,
ModeledPermissions<? extends EntityModel> targetEntity,
Collection<SystemPermission> permissions) throws GuacamoleException { Collection<SystemPermission> permissions) throws GuacamoleException {
// Only an admin can create system permissions // Only an admin can create system permissions
if (user.getUser().isAdministrator()) { if (user.getUser().isAdministrator()) {
Collection<SystemPermissionModel> models = getModelInstances(targetUser, permissions); Collection<SystemPermissionModel> models = getModelInstances(targetEntity, permissions);
systemPermissionMapper.insert(models); systemPermissionMapper.insert(models);
return; return;
} }
@@ -103,17 +107,18 @@ public class SystemPermissionService
} }
@Override @Override
public void deletePermissions(ModeledAuthenticatedUser user, ModeledUser targetUser, public void deletePermissions(ModeledAuthenticatedUser user,
ModeledPermissions<? extends EntityModel> targetEntity,
Collection<SystemPermission> permissions) throws GuacamoleException { Collection<SystemPermission> permissions) throws GuacamoleException {
// Only an admin can delete system permissions // Only an admin can delete system permissions
if (user.getUser().isAdministrator()) { if (user.getUser().isAdministrator()) {
// Do not allow users to remove their own admin powers // Do not allow users to remove their own admin powers
if (user.getUser().getIdentifier().equals(targetUser.getIdentifier())) if (user.getUser().getIdentifier().equals(targetEntity.getIdentifier()))
throw new GuacamoleUnsupportedException("Removing your own administrative permissions is not allowed."); throw new GuacamoleUnsupportedException("Removing your own administrative permissions is not allowed.");
Collection<SystemPermissionModel> models = getModelInstances(targetUser, permissions); Collection<SystemPermissionModel> models = getModelInstances(targetEntity, permissions);
systemPermissionMapper.delete(models); systemPermissionMapper.delete(models);
return; return;
} }
@@ -124,41 +129,42 @@ public class SystemPermissionService
} }
/** /**
* Retrieves the permission of the given type associated with the given * Retrieves whether the permission of the given type has been granted to
* user, if it exists. If no such permission exists, null is returned. * the given entity. Permission inheritance through group membership is
* taken into account.
* *
* @param user * @param user
* The user retrieving the permission. * The user retrieving the permission.
* *
* @param targetUser * @param targetEntity
* The user associated with the permission to be retrieved. * The entity associated with the permission to be retrieved.
* *
* @param type * @param type
* The type of permission to retrieve. * The type of permission to retrieve.
* *
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the entity.
* If no groups are given, only permissions directly granted to the
* entity will be used.
*
* @return * @return
* The permission of the given type associated with the given user, or * true if permission of the given type has been granted to the given
* null if no such permission exists. * entity, false otherwise.
* *
* @throws GuacamoleException * @throws GuacamoleException
* If an error occurs while retrieving the requested permission. * If an error occurs while retrieving the requested permission.
*/ */
public SystemPermission retrievePermission(ModeledAuthenticatedUser user, public boolean hasPermission(ModeledAuthenticatedUser user,
ModeledUser targetUser, SystemPermission.Type type) throws GuacamoleException { ModeledPermissions<? extends EntityModel> targetEntity,
SystemPermission.Type type, Set<String> effectiveGroups)
throws GuacamoleException {
// Retrieve permissions only if allowed // Retrieve permissions only if allowed
if (canReadPermissions(user, targetUser)) { if (canReadPermissions(user, targetEntity))
return getPermissionMapper().selectOne(targetEntity.getModel(), type, effectiveGroups) != null;
// Read permission from database, return null if not found // User cannot read this entity's permissions
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."); throw new GuacamoleSecurityException("Permission denied.");
} }

View File

@@ -19,28 +19,35 @@
package org.apache.guacamole.auth.jdbc.permission; package org.apache.guacamole.auth.jdbc.permission;
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
import com.google.inject.Inject; import com.google.inject.Inject;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
import org.apache.guacamole.auth.jdbc.base.RestrictedObject; import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
import org.apache.guacamole.net.auth.permission.SystemPermission; import org.apache.guacamole.net.auth.permission.SystemPermission;
/** /**
* A database implementation of SystemPermissionSet which uses an injected * A database implementation of SystemPermissionSet which uses an injected
* service to query and manipulate the system permissions associated with a * service to query and manipulate the system permissions associated with a
* particular user. * particular entity.
*/ */
public class SystemPermissionSet extends RestrictedObject public class SystemPermissionSet extends RestrictedObject
implements org.apache.guacamole.net.auth.permission.SystemPermissionSet { implements org.apache.guacamole.net.auth.permission.SystemPermissionSet {
/** /**
* The user associated with this permission set. Each of the permissions in * The entity associated with this permission set. Each of the permissions
* this permission set is granted to this user. * in this permission set is granted to this entity.
*/ */
private ModeledUser user; private ModeledPermissions<? extends EntityModel> entity;
/**
* The identifiers of all groups that should be taken into account when
* determining the permissions effectively granted to the entity.
*/
private Set<String> effectiveGroups;
/** /**
* Service for reading and manipulating system permissions. * Service for reading and manipulating system permissions.
@@ -57,30 +64,39 @@ public class SystemPermissionSet extends RestrictedObject
} }
/** /**
* Initializes this permission set with the current user and the user * Initializes this permission set with the current user and the entity
* to whom the permissions in this set are granted. * to whom the permissions in this set are granted.
* *
* @param currentUser * @param currentUser
* The user who queried this permission set, and whose permissions * The user who queried this permission set, and whose permissions
* dictate the access level of all operations performed on this set. * dictate the access level of all operations performed on this set.
* *
* @param user * @param entity
* The user to whom the permissions in this set are granted. * The entity to whom the permissions in this set are granted.
*
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the entity.
* If no groups are given, only permissions directly granted to the
* entity will be used.
*/ */
public void init(ModeledAuthenticatedUser currentUser, ModeledUser user) { public void init(ModeledAuthenticatedUser currentUser,
ModeledPermissions<? extends EntityModel> entity,
Set<String> effectiveGroups) {
super.init(currentUser); super.init(currentUser);
this.user = user; this.entity = entity;
this.effectiveGroups = effectiveGroups;
} }
@Override @Override
public Set<SystemPermission> getPermissions() throws GuacamoleException { public Set<SystemPermission> getPermissions() throws GuacamoleException {
return systemPermissionService.retrievePermissions(getCurrentUser(), user); return systemPermissionService.retrievePermissions(getCurrentUser(), entity, effectiveGroups);
} }
@Override @Override
public boolean hasPermission(SystemPermission.Type permission) public boolean hasPermission(SystemPermission.Type permission)
throws GuacamoleException { throws GuacamoleException {
return systemPermissionService.retrievePermission(getCurrentUser(), user, permission) != null; return systemPermissionService.hasPermission(getCurrentUser(), entity, permission, effectiveGroups);
} }
@Override @Override
@@ -98,13 +114,13 @@ public class SystemPermissionSet extends RestrictedObject
@Override @Override
public void addPermissions(Set<SystemPermission> permissions) public void addPermissions(Set<SystemPermission> permissions)
throws GuacamoleException { throws GuacamoleException {
systemPermissionService.createPermissions(getCurrentUser(), user, permissions); systemPermissionService.createPermissions(getCurrentUser(), entity, permissions);
} }
@Override @Override
public void removePermissions(Set<SystemPermission> permissions) public void removePermissions(Set<SystemPermission> permissions)
throws GuacamoleException { throws GuacamoleException {
systemPermissionService.deletePermissions(getCurrentUser(), user, permissions); systemPermissionService.deletePermissions(getCurrentUser(), entity, permissions);
} }
} }

View File

@@ -0,0 +1,25 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.permission;
/**
* Mapper for user group permissions.
*/
public interface UserGroupPermissionMapper extends ObjectPermissionMapper {}

View File

@@ -0,0 +1,67 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.permission;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
/**
* Service which provides convenience methods for creating, retrieving, and
* deleting user group permissions. This service will automatically enforce the
* permissions of the current user.
*/
public class UserGroupPermissionService extends ModeledObjectPermissionService {
/**
* Mapper for user group permissions.
*/
@Inject
private UserGroupPermissionMapper userGroupPermissionMapper;
/**
* Provider for user group permission sets.
*/
@Inject
private Provider<UserGroupPermissionSet> userGroupPermissionSetProvider;
@Override
protected ObjectPermissionMapper getPermissionMapper() {
return userGroupPermissionMapper;
}
@Override
public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
ModeledPermissions<? extends EntityModel> targetEntity,
Set<String> effectiveGroups) throws GuacamoleException {
// Create permission set for requested entity
ObjectPermissionSet permissionSet = userGroupPermissionSetProvider.get();
permissionSet.init(user, targetEntity, effectiveGroups);
return permissionSet;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.permission;
import com.google.inject.Inject;
/**
* A database implementation of ObjectPermissionSet which uses an injected
* service to query and manipulate the user group permissions associated with a
* particular user.
*/
public class UserGroupPermissionSet extends ObjectPermissionSet {
/**
* Service for querying and manipulating user group permissions.
*/
@Inject
private UserGroupPermissionService userGroupPermissionService;
@Override
protected ObjectPermissionService getObjectPermissionService() {
return userGroupPermissionService;
}
}

View File

@@ -21,9 +21,11 @@ package org.apache.guacamole.auth.jdbc.permission;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.user.ModeledUser; import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
/** /**
* Service which provides convenience methods for creating, retrieving, and * Service which provides convenience methods for creating, retrieving, and
@@ -51,11 +53,12 @@ public class UserPermissionService extends ModeledObjectPermissionService {
@Override @Override
public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user, public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
ModeledUser targetUser) throws GuacamoleException { ModeledPermissions<? extends EntityModel> targetEntity,
Set<String> effectiveGroups) throws GuacamoleException {
// Create permission set for requested user // Create permission set for requested entity
ObjectPermissionSet permissionSet = userPermissionSetProvider.get(); ObjectPermissionSet permissionSet = userPermissionSetProvider.get();
permissionSet.init(user, targetUser); permissionSet.init(user, targetEntity, effectiveGroups);
return permissionSet; return permissionSet;

View File

@@ -20,7 +20,6 @@
package org.apache.guacamole.auth.jdbc.sharing.user; package org.apache.guacamole.auth.jdbc.sharing.user;
import java.util.Collections; import java.util.Collections;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.AuthenticationProvider;
@@ -52,7 +51,8 @@ public class SharedAuthenticatedUser extends RemoteAuthenticatedUser {
* The AuthenticatedUser to copy. * The AuthenticatedUser to copy.
*/ */
public SharedAuthenticatedUser(AuthenticatedUser authenticatedUser) { public SharedAuthenticatedUser(AuthenticatedUser authenticatedUser) {
super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials()); super(authenticatedUser.getAuthenticationProvider(),
authenticatedUser.getCredentials(), Collections.<String>emptySet());
this.shareKey = null; this.shareKey = null;
this.identifier = authenticatedUser.getIdentifier(); this.identifier = authenticatedUser.getIdentifier();
} }
@@ -75,7 +75,7 @@ public class SharedAuthenticatedUser extends RemoteAuthenticatedUser {
*/ */
public SharedAuthenticatedUser(AuthenticationProvider authenticationProvider, public SharedAuthenticatedUser(AuthenticationProvider authenticationProvider,
Credentials credentials, String shareKey) { Credentials credentials, String shareKey) {
super(authenticationProvider, credentials); super(authenticationProvider, credentials, Collections.<String>emptySet());
this.shareKey = shareKey; this.shareKey = shareKey;
this.identifier = AuthenticatedUser.ANONYMOUS_IDENTIFIER; this.identifier = AuthenticatedUser.ANONYMOUS_IDENTIFIER;
} }
@@ -102,9 +102,4 @@ public class SharedAuthenticatedUser extends RemoteAuthenticatedUser {
throw new UnsupportedOperationException("Users authenticated via share keys are immutable."); throw new UnsupportedOperationException("Users authenticated via share keys are immutable.");
} }
@Override
public Set<String> getEffectiveUserGroups() {
return Collections.<String>emptySet();
}
} }

View File

@@ -112,26 +112,26 @@ public class SharingProfileService
throws GuacamoleException { throws GuacamoleException {
// Return whether user has explicit sharing profile creation permission // Return whether user has explicit sharing profile creation permission
SystemPermissionSet permissionSet = user.getUser().getSystemPermissions(); SystemPermissionSet permissionSet = user.getUser().getEffectivePermissions().getSystemPermissions();
return permissionSet.hasPermission(SystemPermission.Type.CREATE_SHARING_PROFILE); return permissionSet.hasPermission(SystemPermission.Type.CREATE_SHARING_PROFILE);
} }
@Override @Override
protected ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user) protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException { throws GuacamoleException {
// Return permissions related to sharing profiles // Return permissions related to sharing profiles
return user.getUser().getSharingProfilePermissions(); return user.getUser().getEffectivePermissions().getSharingProfilePermissions();
} }
@Override @Override
protected ObjectPermissionSet getParentPermissionSet(ModeledAuthenticatedUser user) protected ObjectPermissionSet getParentEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException { throws GuacamoleException {
// Sharing profiles are children of connections // Sharing profiles are children of connections
return user.getUser().getConnectionPermissions(); return user.getUser().getEffectivePermissions().getConnectionPermissions();
} }

View File

@@ -628,7 +628,9 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
identifiers.add(record.getConnection().getIdentifier()); identifiers.add(record.getConnection().getIdentifier());
// Produce collection of readable connection identifiers // Produce collection of readable connection identifiers
Collection<ConnectionModel> connections = connectionMapper.selectReadable(user.getUser().getModel(), identifiers); Collection<ConnectionModel> connections =
connectionMapper.selectReadable(user.getUser().getModel(),
identifiers, user.getEffectiveUserGroups());
// Ensure set contains only identifiers of readable connections // Ensure set contains only identifiers of readable connections
identifiers.clear(); identifiers.clear();

View File

@@ -76,7 +76,7 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser {
*/ */
public ModeledAuthenticatedUser(AuthenticatedUser authenticatedUser, public ModeledAuthenticatedUser(AuthenticatedUser authenticatedUser,
AuthenticationProvider modelAuthenticationProvider, ModeledUser user) { AuthenticationProvider modelAuthenticationProvider, ModeledUser user) {
super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials()); super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials(), authenticatedUser.getEffectiveUserGroups());
this.modelAuthenticationProvider = modelAuthenticationProvider; this.modelAuthenticationProvider = modelAuthenticationProvider;
this.user = user; this.user = user;
} }
@@ -98,7 +98,7 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser {
*/ */
public ModeledAuthenticatedUser(AuthenticationProvider authenticationProvider, public ModeledAuthenticatedUser(AuthenticationProvider authenticationProvider,
ModeledUser user, Credentials credentials) { ModeledUser user, Credentials credentials) {
super(authenticationProvider, credentials); super(authenticationProvider, credentials, user.getEffectiveUserGroups());
this.modelAuthenticationProvider = authenticationProvider; this.modelAuthenticationProvider = authenticationProvider;
this.user = user; this.user = user;
} }
@@ -169,9 +169,4 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser {
user.setIdentifier(identifier); user.setIdentifier(identifier);
} }
@Override
public Set<String> getEffectiveUserGroups() {
return Collections.<String>emptySet();
}
} }

View File

@@ -20,6 +20,7 @@
package org.apache.guacamole.auth.jdbc.user; package org.apache.guacamole.auth.jdbc.user;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider;
import java.sql.Date; import java.sql.Date;
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
@@ -33,16 +34,10 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObject;
import org.apache.guacamole.auth.jdbc.security.PasswordEncryptionService; import org.apache.guacamole.auth.jdbc.security.PasswordEncryptionService;
import org.apache.guacamole.auth.jdbc.security.SaltService; import org.apache.guacamole.auth.jdbc.security.SaltService;
import org.apache.guacamole.auth.jdbc.permission.SystemPermissionService;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionService; import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
import org.apache.guacamole.auth.jdbc.permission.ConnectionGroupPermissionService;
import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionService;
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService;
import org.apache.guacamole.auth.jdbc.permission.UserPermissionService;
import org.apache.guacamole.form.BooleanField; import org.apache.guacamole.form.BooleanField;
import org.apache.guacamole.form.DateField; import org.apache.guacamole.form.DateField;
import org.apache.guacamole.form.EmailField; import org.apache.guacamole.form.EmailField;
@@ -55,18 +50,13 @@ import org.apache.guacamole.net.auth.ActivityRecord;
import org.apache.guacamole.net.auth.Permissions; import org.apache.guacamole.net.auth.Permissions;
import org.apache.guacamole.net.auth.RelatedObjectSet; import org.apache.guacamole.net.auth.RelatedObjectSet;
import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermission;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
import org.apache.guacamole.net.auth.simple.SimpleObjectPermissionSet;
import org.apache.guacamole.net.auth.simple.SimpleRelatedObjectSet;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* An implementation of the User object which is backed by a database model. * An implementation of the User object which is backed by a database model.
*/ */
public class ModeledUser extends ModeledDirectoryObject<UserModel> implements User { public class ModeledUser extends ModeledPermissions<UserModel> implements User {
/** /**
* Logger for this class. * Logger for this class.
@@ -187,40 +177,11 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
private SaltService saltService; private SaltService saltService;
/** /**
* Service for retrieving system permissions. * Provider for RelatedObjectSets containing the user groups of which this
* user is a member.
*/ */
@Inject @Inject
private SystemPermissionService systemPermissionService; private Provider<UserParentUserGroupSet> parentUserGroupSetProvider;
/**
* Service for retrieving connection permissions.
*/
@Inject
private ConnectionPermissionService connectionPermissionService;
/**
* Service for retrieving connection group permissions.
*/
@Inject
private ConnectionGroupPermissionService connectionGroupPermissionService;
/**
* Service for retrieving sharing profile permissions.
*/
@Inject
private SharingProfilePermissionService sharingProfilePermissionService;
/**
* Service for retrieving active connection permissions.
*/
@Inject
private ActiveConnectionPermissionService activeConnectionPermissionService;
/**
* Service for retrieving user permissions.
*/
@Inject
private UserPermissionService userPermissionService;
/** /**
* Whether attributes which control access restrictions should be exposed * Whether attributes which control access restrictions should be exposed
@@ -331,63 +292,6 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
return passwordRecord; return passwordRecord;
} }
/**
* 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 {
return connectionPermissionService.getPermissionSet(getCurrentUser(), this);
}
@Override
public ObjectPermissionSet getConnectionGroupPermissions()
throws GuacamoleException {
return connectionGroupPermissionService.getPermissionSet(getCurrentUser(), this);
}
@Override
public ObjectPermissionSet getSharingProfilePermissions()
throws GuacamoleException {
return sharingProfilePermissionService.getPermissionSet(getCurrentUser(), this);
}
@Override
public ObjectPermissionSet getActiveConnectionPermissions()
throws GuacamoleException {
return activeConnectionPermissionService.getPermissionSet(getCurrentUser(), this);
}
@Override
public ObjectPermissionSet getUserPermissions()
throws GuacamoleException {
return userPermissionService.getPermissionSet(getCurrentUser(), this);
}
@Override
public ObjectPermissionSet getUserGroupPermissions() throws GuacamoleException {
return new SimpleObjectPermissionSet();
}
/** /**
* Stores all restricted (privileged) attributes within the given Map, * Stores all restricted (privileged) attributes within the given Map,
* pulling the values of those attributes from the underlying user model. * pulling the values of those attributes from the underlying user model.
@@ -850,12 +754,14 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
@Override @Override
public RelatedObjectSet getUserGroups() throws GuacamoleException { public RelatedObjectSet getUserGroups() throws GuacamoleException {
return new SimpleRelatedObjectSet(); UserParentUserGroupSet parentUserGroupSet = parentUserGroupSetProvider.get();
parentUserGroupSet.init(getCurrentUser(), this);
return parentUserGroupSet;
} }
@Override @Override
public Permissions getEffectivePermissions() throws GuacamoleException { public Permissions getEffectivePermissions() throws GuacamoleException {
return this; return super.getEffective();
} }
} }

View File

@@ -26,7 +26,6 @@ import org.apache.guacamole.auth.jdbc.connection.ConnectionDirectory;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.RestrictedObject; import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
@@ -37,6 +36,8 @@ import org.apache.guacamole.auth.jdbc.connection.ModeledConnection;
import org.apache.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; import org.apache.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
import org.apache.guacamole.auth.jdbc.sharingprofile.ModeledSharingProfile; import org.apache.guacamole.auth.jdbc.sharingprofile.ModeledSharingProfile;
import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileDirectory; import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileDirectory;
import org.apache.guacamole.auth.jdbc.usergroup.ModeledUserGroup;
import org.apache.guacamole.auth.jdbc.usergroup.UserGroupDirectory;
import org.apache.guacamole.form.Form; import org.apache.guacamole.form.Form;
import org.apache.guacamole.net.auth.ActiveConnection; import org.apache.guacamole.net.auth.ActiveConnection;
import org.apache.guacamole.net.auth.ActivityRecord; import org.apache.guacamole.net.auth.ActivityRecord;
@@ -48,7 +49,6 @@ import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.SharingProfile; import org.apache.guacamole.net.auth.SharingProfile;
import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.UserGroup; import org.apache.guacamole.net.auth.UserGroup;
import org.apache.guacamole.net.auth.simple.SimpleDirectory;
/** /**
* UserContext implementation which is driven by an arbitrary, underlying * UserContext implementation which is driven by an arbitrary, underlying
@@ -64,6 +64,13 @@ public class ModeledUserContext extends RestrictedObject
@Inject @Inject
private UserDirectory userDirectory; private UserDirectory userDirectory;
/**
* User group directory restricted by the permissions of the user associated
* with this context.
*/
@Inject
private UserGroupDirectory userGroupDirectory;
/** /**
* Connection directory restricted by the permissions of the user * Connection directory restricted by the permissions of the user
* associated with this context. * associated with this context.
@@ -128,6 +135,7 @@ public class ModeledUserContext extends RestrictedObject
// Init directories // Init directories
userDirectory.init(currentUser); userDirectory.init(currentUser);
userGroupDirectory.init(currentUser);
connectionDirectory.init(currentUser); connectionDirectory.init(currentUser);
connectionGroupDirectory.init(currentUser); connectionGroupDirectory.init(currentUser);
sharingProfileDirectory.init(currentUser); sharingProfileDirectory.init(currentUser);
@@ -166,7 +174,7 @@ public class ModeledUserContext extends RestrictedObject
@Override @Override
public Directory<UserGroup> getUserGroupDirectory() throws GuacamoleException { public Directory<UserGroup> getUserGroupDirectory() throws GuacamoleException {
return new SimpleDirectory<UserGroup>(); return userGroupDirectory;
} }
@Override @Override
@@ -224,7 +232,7 @@ public class ModeledUserContext extends RestrictedObject
@Override @Override
public Collection<Form> getUserGroupAttributes() { public Collection<Form> getUserGroupAttributes() {
return Collections.<Form>emptyList(); return ModeledUserGroup.ATTRIBUTES;
} }
@Override @Override

View File

@@ -19,6 +19,8 @@
package org.apache.guacamole.auth.jdbc.user; package org.apache.guacamole.auth.jdbc.user;
import java.util.Collections;
import java.util.Set;
import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.AuthenticationProvider;
import org.apache.guacamole.net.auth.Credentials; import org.apache.guacamole.net.auth.Credentials;
@@ -43,6 +45,12 @@ public abstract class RemoteAuthenticatedUser implements AuthenticatedUser {
*/ */
private final String remoteHost; private final String remoteHost;
/**
* The identifiers of any groups of which this user is a member, including
* groups inherited through membership in other groups.
*/
private final Set<String> effectiveGroups;
/** /**
* Creates a new RemoteAuthenticatedUser, deriving the associated remote * Creates a new RemoteAuthenticatedUser, deriving the associated remote
* host from the given credentials. * host from the given credentials.
@@ -52,12 +60,17 @@ public abstract class RemoteAuthenticatedUser implements AuthenticatedUser {
* *
* @param credentials * @param credentials
* The credentials given by the user when they authenticated. * The credentials given by the user when they authenticated.
*
* @param effectiveGroups
* The identifiers of any groups of which this user is a member,
* including groups inherited through membership in other groups.
*/ */
public RemoteAuthenticatedUser(AuthenticationProvider authenticationProvider, public RemoteAuthenticatedUser(AuthenticationProvider authenticationProvider,
Credentials credentials) { Credentials credentials, Set<String> effectiveGroups) {
this.authenticationProvider = authenticationProvider; this.authenticationProvider = authenticationProvider;
this.credentials = credentials; this.credentials = credentials;
this.remoteHost = credentials.getRemoteAddress(); this.remoteHost = credentials.getRemoteAddress();
this.effectiveGroups = Collections.unmodifiableSet(effectiveGroups);
} }
@Override @Override
@@ -75,6 +88,11 @@ public abstract class RemoteAuthenticatedUser implements AuthenticatedUser {
return remoteHost; return remoteHost;
} }
@Override
public Set<String> getEffectiveUserGroups() {
return effectiveGroups;
}
@Override @Override
public AuthenticationProvider getAuthenticationProvider() { public AuthenticationProvider getAuthenticationProvider() {
return authenticationProvider; return authenticationProvider;

View File

@@ -22,12 +22,13 @@ package org.apache.guacamole.auth.jdbc.user;
import java.sql.Date; import java.sql.Date;
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
import org.apache.guacamole.auth.jdbc.base.ObjectModel; import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.EntityType;
/** /**
* Object representation of a Guacamole user, as represented in the database. * Object representation of a Guacamole user, as represented in the database.
*/ */
public class UserModel extends ObjectModel { public class UserModel extends EntityModel {
/** /**
* The SHA-256 hash of the password and salt. * The SHA-256 hash of the password and salt.
@@ -124,6 +125,7 @@ public class UserModel extends ObjectModel {
* Creates a new, empty user. * Creates a new, empty user.
*/ */
public UserModel() { public UserModel() {
super(EntityType.USER);
} }
/** /**

View File

@@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.user;
import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
/**
* Mapper for the one-to-many relationship between a user and the user groups
* of which it is a member.
*/
public interface UserParentUserGroupMapper extends ObjectRelationMapper<UserModel> {}

View File

@@ -0,0 +1,59 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.user;
import com.google.inject.Inject;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
import org.apache.guacamole.auth.jdbc.base.RelatedObjectSet;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
/**
* RelatedObjectSet implementation which represents the one-to-many
* relationship between a particular user and the user groups of which it is a
* member.
*/
public class UserParentUserGroupSet extends RelatedObjectSet<ModeledUser, UserModel> {
/**
* Mapper for the relations between users and the user groups of which they
* are members.
*/
@Inject
private UserParentUserGroupMapper userParentUserGroupMapper;
@Override
protected ObjectRelationMapper<UserModel> getObjectRelationMapper() {
return userParentUserGroupMapper;
}
@Override
protected ObjectPermissionSet
getParentObjectEffectivePermissionSet() throws GuacamoleException {
return getCurrentUser().getUser().getEffectivePermissions().getUserPermissions();
}
@Override
protected ObjectPermissionSet getChildObjectEffectivePermissionSet()
throws GuacamoleException {
return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions();
}
}

View File

@@ -113,12 +113,19 @@ public interface UserRecordMapper {
* @param limit * @param limit
* The maximum number of records that should be returned. * The maximum number of records that should be returned.
* *
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the user. If
* no groups are given, only permissions directly granted to the user
* will be used.
*
* @return * @return
* The results of the search performed with the given parameters. * The results of the search performed with the given parameters.
*/ */
List<ActivityRecordModel> searchReadable(@Param("user") UserModel user, List<ActivityRecordModel> searchReadable(@Param("user") UserModel user,
@Param("terms") Collection<ActivityRecordSearchTerm> terms, @Param("terms") Collection<ActivityRecordSearchTerm> terms,
@Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates, @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
@Param("limit") int limit); @Param("limit") int limit,
@Param("effectiveGroups") Collection<String> effectiveGroups);
} }

View File

@@ -37,8 +37,8 @@ import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel; import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel;
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm; import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate; import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
import org.apache.guacamole.auth.jdbc.base.EntityMapper;
import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecord; import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecord;
import org.apache.guacamole.auth.jdbc.connection.ConnectionRecordModel;
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper; import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel; import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel;
import org.apache.guacamole.auth.jdbc.permission.UserPermissionMapper; import org.apache.guacamole.auth.jdbc.permission.UserPermissionMapper;
@@ -49,7 +49,6 @@ import org.apache.guacamole.form.PasswordField;
import org.apache.guacamole.net.auth.ActivityRecord; import org.apache.guacamole.net.auth.ActivityRecord;
import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.AuthenticationProvider;
import org.apache.guacamole.net.auth.ConnectionRecord;
import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.credentials.CredentialsInfo; import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException; import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
@@ -115,6 +114,12 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
CONFIRM_NEW_PASSWORD CONFIRM_NEW_PASSWORD
)); ));
/**
* Mapper for creating/deleting entities.
*/
@Inject
private EntityMapper entityMapper;
/** /**
* Mapper for accessing users. * Mapper for accessing users.
*/ */
@@ -211,17 +216,17 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
throws GuacamoleException { throws GuacamoleException {
// Return whether user has explicit user creation permission // Return whether user has explicit user creation permission
SystemPermissionSet permissionSet = user.getUser().getSystemPermissions(); SystemPermissionSet permissionSet = user.getUser().getEffectivePermissions().getSystemPermissions();
return permissionSet.hasPermission(SystemPermission.Type.CREATE_USER); return permissionSet.hasPermission(SystemPermission.Type.CREATE_USER);
} }
@Override @Override
protected ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user) protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException { throws GuacamoleException {
// Return permissions related to users // Return permissions related to users
return user.getUser().getUserPermissions(); return user.getUser().getEffectivePermissions().getUserPermissions();
} }
@@ -244,6 +249,9 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
if (object.getPassword() != null) if (object.getPassword() != null)
passwordPolicyService.verifyPassword(object.getIdentifier(), object.getPassword()); passwordPolicyService.verifyPassword(object.getIdentifier(), object.getPassword());
// Create base entity object, implicitly populating underlying entity ID
entityMapper.insert(model);
} }
@Override @Override
@@ -294,8 +302,7 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
for (ObjectPermission.Type permissionType : IMPLICIT_USER_PERMISSIONS) { for (ObjectPermission.Type permissionType : IMPLICIT_USER_PERMISSIONS) {
ObjectPermissionModel permissionModel = new ObjectPermissionModel(); ObjectPermissionModel permissionModel = new ObjectPermissionModel();
permissionModel.setUserID(model.getObjectID()); permissionModel.setEntityID(model.getEntityID());
permissionModel.setUsername(model.getIdentifier());
permissionModel.setType(permissionType); permissionModel.setType(permissionType);
permissionModel.setObjectIdentifier(model.getIdentifier()); permissionModel.setObjectIdentifier(model.getIdentifier());
@@ -584,11 +591,10 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
// Otherwise only return explicitly readable history records // Otherwise only return explicitly readable history records
else else
searchResults = userRecordMapper.searchReadable(user.getUser().getModel(), searchResults = userRecordMapper.searchReadable(user.getUser().getModel(),
requiredContents, sortPredicates, limit); requiredContents, sortPredicates, limit, user.getEffectiveUserGroups());
return getObjectInstances(searchResults); return getObjectInstances(searchResults);
} }
} }

View File

@@ -0,0 +1,206 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.usergroup;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.form.BooleanField;
import org.apache.guacamole.form.Field;
import org.apache.guacamole.form.Form;
import org.apache.guacamole.net.auth.RelatedObjectSet;
import org.apache.guacamole.net.auth.UserGroup;
/**
* An implementation of the UserGroup object which is backed by a database model.
*/
public class ModeledUserGroup extends ModeledPermissions<UserGroupModel>
implements UserGroup {
/**
* The name of the attribute which controls whether a user group is
* disabled.
*/
public static final String DISABLED_ATTRIBUTE_NAME = "disabled";
/**
* All attributes related to restricting user groups, within a logical
* form.
*/
public static final Form ACCOUNT_RESTRICTIONS = new Form("restrictions", Arrays.<Field>asList(
new BooleanField(DISABLED_ATTRIBUTE_NAME, "true")
));
/**
* All possible attributes of user groups organized as individual,
* logical forms.
*/
public static final Collection<Form> ATTRIBUTES = Collections.unmodifiableCollection(Arrays.asList(
ACCOUNT_RESTRICTIONS
));
/**
* The names of all attributes which are explicitly supported by this
* extension's UserGroup objects.
*/
public static final Set<String> ATTRIBUTE_NAMES =
Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
DISABLED_ATTRIBUTE_NAME
)));
/**
* Provider for RelatedObjectSets containing the user groups of which this
* user group is a member.
*/
@Inject
private Provider<UserGroupParentUserGroupSet> parentUserGroupSetProvider;
/**
* Provider for RelatedObjectSets containing the users that are members of
* this user group.
*/
@Inject
private Provider<UserGroupMemberUserSet> memberUserSetProvider;
/**
* Provider for RelatedObjectSets containing the user groups that are
* members of this user group.
*/
@Inject
private Provider<UserGroupMemberUserGroupSet> memberUserGroupSetProvider;
/**
* Whether attributes which control access restrictions should be exposed
* via getAttributes() or allowed to be set via setAttributes().
*/
private boolean exposeRestrictedAttributes = false;
/**
* Initializes this ModeledUserGroup, associating it with the current
* authenticated user and populating it with data from the given user group
* model.
*
* @param currentUser
* The user that created or retrieved this object.
*
* @param model
* The backing model object.
*
* @param exposeRestrictedAttributes
* Whether attributes which control access restrictions should be
* exposed via getAttributes() or allowed to be set via
* setAttributes().
*/
public void init(ModeledAuthenticatedUser currentUser, UserGroupModel model,
boolean exposeRestrictedAttributes) {
super.init(currentUser, model);
this.exposeRestrictedAttributes = exposeRestrictedAttributes;
}
/**
* Stores all restricted (privileged) attributes within the given Map,
* pulling the values of those attributes from the underlying user group
* model. If no value is yet defined for an attribute, that attribute will
* be set to null.
*
* @param attributes
* The Map to store all restricted attributes within.
*/
private void putRestrictedAttributes(Map<String, String> attributes) {
// Set disabled attribute
attributes.put(DISABLED_ATTRIBUTE_NAME, getModel().isDisabled() ? "true" : null);
}
/**
* Stores all restricted (privileged) attributes within the underlying user
* group model, pulling the values of those attributes from the given Map.
*
* @param attributes
* The Map to pull all restricted attributes from.
*/
private void setRestrictedAttributes(Map<String, String> attributes) {
// Translate disabled attribute
getModel().setDisabled("true".equals(attributes.get(DISABLED_ATTRIBUTE_NAME)));
}
@Override
public Set<String> getSupportedAttributeNames() {
return ATTRIBUTE_NAMES;
}
@Override
public Map<String, String> getAttributes() {
// Include any defined arbitrary attributes
Map<String, String> attributes = super.getAttributes();
// Include restricted attributes only if they should be exposed
if (exposeRestrictedAttributes)
putRestrictedAttributes(attributes);
return attributes;
}
@Override
public void setAttributes(Map<String, String> attributes) {
// Set arbitrary attributes
super.setAttributes(attributes);
// Assign restricted attributes only if they are exposed
if (exposeRestrictedAttributes)
setRestrictedAttributes(attributes);
}
@Override
public RelatedObjectSet getUserGroups() throws GuacamoleException {
UserGroupParentUserGroupSet parentUserGroupSet = parentUserGroupSetProvider.get();
parentUserGroupSet.init(getCurrentUser(), this);
return parentUserGroupSet;
}
@Override
public RelatedObjectSet getMemberUsers() throws GuacamoleException {
UserGroupMemberUserSet memberUserSet = memberUserSetProvider.get();
memberUserSet.init(getCurrentUser(), this);
return memberUserSet;
}
@Override
public RelatedObjectSet getMemberUserGroups() throws GuacamoleException {
UserGroupMemberUserGroupSet memberUserGroupSet = memberUserGroupSetProvider.get();
memberUserGroupSet.init(getCurrentUser(), this);
return memberUserGroupSet;
}
}

View File

@@ -0,0 +1,82 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.usergroup;
import com.google.inject.Inject;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.UserGroup;
import org.mybatis.guice.transactional.Transactional;
/**
* Implementation of the UserGroup Directory which is driven by an underlying,
* arbitrary database.
*/
public class UserGroupDirectory extends RestrictedObject
implements Directory<UserGroup> {
/**
* Service for managing user group objects.
*/
@Inject
private UserGroupService userGroupService;
@Override
public UserGroup get(String identifier) throws GuacamoleException {
return userGroupService.retrieveObject(getCurrentUser(), identifier);
}
@Override
@Transactional
public Collection<UserGroup> getAll(Collection<String> identifiers) throws GuacamoleException {
Collection<ModeledUserGroup> objects = userGroupService.retrieveObjects(getCurrentUser(), identifiers);
return Collections.<UserGroup>unmodifiableCollection(objects);
}
@Override
@Transactional
public Set<String> getIdentifiers() throws GuacamoleException {
return userGroupService.getIdentifiers(getCurrentUser());
}
@Override
@Transactional
public void add(UserGroup object) throws GuacamoleException {
userGroupService.createObject(getCurrentUser(), object);
}
@Override
@Transactional
public void update(UserGroup object) throws GuacamoleException {
ModeledUserGroup group = (ModeledUserGroup) object;
userGroupService.updateObject(getCurrentUser(), group);
}
@Override
@Transactional
public void remove(String identifier) throws GuacamoleException {
userGroupService.deleteObject(getCurrentUser(), identifier);
}
}

View File

@@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.usergroup;
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
import org.apache.ibatis.annotations.Param;
/**
* Mapper for user group objects.
*/
public interface UserGroupMapper extends ModeledDirectoryObjectMapper<UserGroupModel> {
/**
* Returns the group having the given name, if any. If no such group
* exists, null is returned.
*
* @param name
* The name of the group to return.
*
* @return
* The group having the given name, or null if no such group exists.
*/
UserGroupModel selectOne(@Param("name") String name);
}

View File

@@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.usergroup;
import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
/**
* Mapper for the one-to-many relationship between a user group and its user
* group members.
*/
public interface UserGroupMemberUserGroupMapper extends ObjectRelationMapper<UserGroupModel> {}

View File

@@ -0,0 +1,57 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.usergroup;
import com.google.inject.Inject;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
import org.apache.guacamole.auth.jdbc.base.RelatedObjectSet;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
/**
* RelatedObjectSet implementation which represents the one-to-many
* relationship between a particular user group and its user group members.
*/
public class UserGroupMemberUserGroupSet extends RelatedObjectSet<ModeledUserGroup, UserGroupModel> {
/**
* Mapper for the relation between user groups and their user group members.
*/
@Inject
private UserGroupMemberUserGroupMapper userGroupMemberUserGroupMapper;
@Override
protected ObjectRelationMapper<UserGroupModel> getObjectRelationMapper() {
return userGroupMemberUserGroupMapper;
}
@Override
protected ObjectPermissionSet
getParentObjectEffectivePermissionSet() throws GuacamoleException {
return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions();
}
@Override
protected ObjectPermissionSet getChildObjectEffectivePermissionSet()
throws GuacamoleException {
return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions();
}
}

View File

@@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.usergroup;
import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
/**
* Mapper for the one-to-many relationship between a user group and its user
* members.
*/
public interface UserGroupMemberUserMapper extends ObjectRelationMapper<UserGroupModel> {}

View File

@@ -0,0 +1,57 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.usergroup;
import com.google.inject.Inject;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
import org.apache.guacamole.auth.jdbc.base.RelatedObjectSet;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
/**
* RelatedObjectSet implementation which represents the one-to-many
* relationship between a particular user group and its user members.
*/
public class UserGroupMemberUserSet extends RelatedObjectSet<ModeledUserGroup, UserGroupModel> {
/**
* Mapper for the relation between user groups and their user members.
*/
@Inject
private UserGroupMemberUserMapper userGroupMemberUserMapper;
@Override
protected ObjectRelationMapper<UserGroupModel> getObjectRelationMapper() {
return userGroupMemberUserMapper;
}
@Override
protected ObjectPermissionSet
getParentObjectEffectivePermissionSet() throws GuacamoleException {
return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions();
}
@Override
protected ObjectPermissionSet getChildObjectEffectivePermissionSet()
throws GuacamoleException {
return getCurrentUser().getUser().getEffectivePermissions().getUserPermissions();
}
}

View File

@@ -0,0 +1,68 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.usergroup;
import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.EntityType;
/**
* Object representation of a Guacamole user group, as represented in the
* database.
*/
public class UserGroupModel extends EntityModel {
/**
* Whether the user group is disabled. Disabled accounts exist and can
* be modified, but cannot be used.
*/
private boolean disabled;
/**
* Creates a new, empty user group.
*/
public UserGroupModel() {
super(EntityType.USER_GROUP);
}
/**
* Returns whether this user group has been disabled. Memberships of
* disabled user groups are treated as non-existent, effectively disabling
* membership in that group.
*
* @return
* true if this user group is disabled, false otherwise.
*/
public boolean isDisabled() {
return disabled;
}
/**
* Sets whether this user group has been disabled. Memberships of disabled
* user groups are treated as non-existent, effectively disabling
* membership in that group.
*
* @param disabled
* true if this user group should be disabled, false otherwise.
*/
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
}

View File

@@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.usergroup;
import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
/**
* Mapper for the one-to-many relationship between a user group and its
* containing user groups.
*/
public interface UserGroupParentUserGroupMapper extends ObjectRelationMapper<UserGroupModel> {}

View File

@@ -0,0 +1,58 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.usergroup;
import com.google.inject.Inject;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
import org.apache.guacamole.auth.jdbc.base.RelatedObjectSet;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
/**
* RelatedObjectSet implementation which represents the one-to-many
* relationship between a particular user group and its containing user groups.
*/
public class UserGroupParentUserGroupSet extends RelatedObjectSet<ModeledUserGroup, UserGroupModel> {
/**
* Mapper for the relation between user groups and their containing user
* groups.
*/
@Inject
private UserGroupParentUserGroupMapper userGroupParentUserGroupMapper;
@Override
protected ObjectRelationMapper<UserGroupModel> getObjectRelationMapper() {
return userGroupParentUserGroupMapper;
}
@Override
protected ObjectPermissionSet
getParentObjectEffectivePermissionSet() throws GuacamoleException {
return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions();
}
@Override
protected ObjectPermissionSet getChildObjectEffectivePermissionSet()
throws GuacamoleException {
return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions();
}
}

View File

@@ -0,0 +1,183 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.jdbc.usergroup;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectService;
import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.EntityMapper;
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
import org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionMapper;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.net.auth.UserGroup;
import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermission;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
/**
* Service which provides convenience methods for creating, retrieving, and
* manipulating user groups.
*/
public class UserGroupService extends ModeledDirectoryObjectService<ModeledUserGroup, UserGroup, UserGroupModel> {
/**
* Mapper for creating/deleting entities.
*/
@Inject
private EntityMapper entityMapper;
/**
* Mapper for accessing user groups.
*/
@Inject
private UserGroupMapper userGroupMapper;
/**
* Mapper for manipulating user group permissions.
*/
@Inject
private UserGroupPermissionMapper userGroupPermissionMapper;
/**
* Provider for creating user groups.
*/
@Inject
private Provider<ModeledUserGroup> userGroupProvider;
@Override
protected ModeledDirectoryObjectMapper<UserGroupModel> getObjectMapper() {
return userGroupMapper;
}
@Override
protected ObjectPermissionMapper getPermissionMapper() {
return userGroupPermissionMapper;
}
@Override
protected ModeledUserGroup getObjectInstance(ModeledAuthenticatedUser currentUser,
UserGroupModel model) throws GuacamoleException {
boolean exposeRestrictedAttributes;
// Expose restricted attributes if the user group does not yet exist
if (model.getObjectID() == null)
exposeRestrictedAttributes = true;
// Otherwise, expose restricted attributes only if the user has
// ADMINISTER permission
else
exposeRestrictedAttributes = hasObjectPermission(currentUser,
model.getIdentifier(), ObjectPermission.Type.ADMINISTER);
// Produce ModeledUserGroup exposing only those attributes for which the
// current user has permission
ModeledUserGroup group = userGroupProvider.get();
group.init(currentUser, model, exposeRestrictedAttributes);
return group;
}
@Override
protected UserGroupModel getModelInstance(ModeledAuthenticatedUser currentUser,
final UserGroup object) throws GuacamoleException {
// Create new ModeledUserGroup backed by blank model
UserGroupModel model = new UserGroupModel();
ModeledUserGroup group = getObjectInstance(currentUser, model);
// Set model contents through ModeledUser, copying the provided group
group.setIdentifier(object.getIdentifier());
group.setAttributes(object.getAttributes());
return model;
}
@Override
protected boolean hasCreatePermission(ModeledAuthenticatedUser user)
throws GuacamoleException {
// Return whether user has explicit user group creation permission
SystemPermissionSet permissionSet = user.getUser().getEffectivePermissions().getSystemPermissions();
return permissionSet.hasPermission(SystemPermission.Type.CREATE_USER);
}
@Override
protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException {
// Return permissions related to user groups
return user.getUser().getEffectivePermissions().getUserGroupPermissions();
}
@Override
protected void beforeCreate(ModeledAuthenticatedUser user, UserGroup object,
UserGroupModel model) throws GuacamoleException {
super.beforeCreate(user, object, model);
// Group name must not be blank
if (model.getIdentifier() == null || model.getIdentifier().trim().isEmpty())
throw new GuacamoleClientException("The group name must not be blank.");
// Do not create duplicate user groups
UserGroupModel existing = userGroupMapper.selectOne(model.getIdentifier());
if (existing != null)
throw new GuacamoleClientException("Group \"" + model.getIdentifier() + "\" already exists.");
// Create base entity object, implicitly populating underlying entity ID
entityMapper.insert(model);
}
@Override
protected void beforeUpdate(ModeledAuthenticatedUser user,
ModeledUserGroup object, UserGroupModel model) throws GuacamoleException {
super.beforeUpdate(user, object, model);
// Group names must not be blank
if (model.getIdentifier() == null || model.getIdentifier().trim().isEmpty())
throw new GuacamoleClientException("The group name must not be blank.");
// Do not allow groups to be renamed if the name collides with that of
// another, existing group
UserGroupModel existing = userGroupMapper.selectOne(model.getIdentifier());
if (existing != null && !existing.getObjectID().equals(model.getObjectID()))
throw new GuacamoleClientException("Group \"" + model.getIdentifier() + "\" already exists.");
}
@Override
protected boolean isValidIdentifier(String identifier) {
// All strings are valid group identifiers
return true;
}
}

View File

@@ -100,6 +100,14 @@
"SECTION_HEADER_RESTRICTIONS" : "Account Restrictions", "SECTION_HEADER_RESTRICTIONS" : "Account Restrictions",
"SECTION_HEADER_PROFILE" : "Profile" "SECTION_HEADER_PROFILE" : "Profile"
},
"USER_GROUP_ATTRIBUTES" : {
"FIELD_HEADER_DISABLED" : "@:USER_ATTRIBUTES.FIELD_HEADER_DISABLED",
"SECTION_HEADER_RESTRICTIONS" : "@:USER_ATTRIBUTES.SECTION_HEADER_RESTRICTIONS"
} }
} }

View File

@@ -78,6 +78,25 @@ CREATE TABLE `guacamole_connection` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of base entities which may each be either a user or user group. Other
-- tables which represent qualities shared by both users and groups will point
-- to guacamole_entity, while tables which represent qualities specific to
-- users or groups will point to guacamole_user or guacamole_user_group.
--
CREATE TABLE `guacamole_entity` (
`entity_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL,
`type` enum('USER',
'USER_GROUP') NOT NULL,
PRIMARY KEY (`entity_id`),
UNIQUE KEY `guacamole_entity_name_scope` (`type`, `name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --
-- Table of users. Each user has a unique username and a hashed password -- Table of users. Each user has a unique username and a hashed password
-- with corresponding salt. Although the authentication system will always set -- with corresponding salt. Although the authentication system will always set
@@ -88,9 +107,9 @@ CREATE TABLE `guacamole_connection` (
CREATE TABLE `guacamole_user` ( CREATE TABLE `guacamole_user` (
`user_id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL AUTO_INCREMENT,
`entity_id` int(11) NOT NULL,
-- Username and optionally-salted password -- Optionally-salted password
`username` varchar(128) NOT NULL,
`password_hash` binary(32) NOT NULL, `password_hash` binary(32) NOT NULL,
`password_salt` binary(32), `password_salt` binary(32),
`password_date` datetime NOT NULL, `password_date` datetime NOT NULL,
@@ -117,7 +136,61 @@ CREATE TABLE `guacamole_user` (
`organizational_role` VARCHAR(256), `organizational_role` VARCHAR(256),
PRIMARY KEY (`user_id`), PRIMARY KEY (`user_id`),
UNIQUE KEY `username` (`username`)
UNIQUE KEY `guacamole_user_single_entity` (`entity_id`),
CONSTRAINT `guacamole_user_entity`
FOREIGN KEY (`entity_id`)
REFERENCES `guacamole_entity` (`entity_id`)
ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of user groups. Each user group may have an arbitrary set of member
-- users and member groups, with those members inheriting the permissions
-- granted to that group.
--
CREATE TABLE `guacamole_user_group` (
`user_group_id` int(11) NOT NULL AUTO_INCREMENT,
`entity_id` int(11) NOT NULL,
-- Group disabled status
`disabled` boolean NOT NULL DEFAULT 0,
PRIMARY KEY (`user_group_id`),
UNIQUE KEY `guacamole_user_group_single_entity` (`entity_id`),
CONSTRAINT `guacamole_user_group_entity`
FOREIGN KEY (`entity_id`)
REFERENCES `guacamole_entity` (`entity_id`)
ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of users which are members of given user groups.
--
CREATE TABLE `guacamole_user_group_member` (
`user_group_id` int(11) NOT NULL,
`member_entity_id` int(11) NOT NULL,
PRIMARY KEY (`user_group_id`, `member_entity_id`),
-- Parent must be a user group
CONSTRAINT `guacamole_user_group_member_parent_id`
FOREIGN KEY (`user_group_id`)
REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE,
-- Member may be either a user or a user group (any entity)
CONSTRAINT `guacamole_user_group_member_entity_id`
FOREIGN KEY (`member_entity_id`)
REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@@ -207,6 +280,28 @@ CREATE TABLE guacamole_user_attribute (
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of arbitrary user group attributes. Each attribute is simply a
-- name/value pair associated with a user group. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_user_group_attribute (
`user_group_id` int(11) NOT NULL,
`attribute_name` varchar(128) NOT NULL,
`attribute_value` varchar(4096) NOT NULL,
PRIMARY KEY (`user_group_id`, `attribute_name`),
KEY `user_group_id` (`user_group_id`),
CONSTRAINT `guacamole_user_group_attribute_ibfk_1`
FOREIGN KEY (`user_group_id`)
REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --
-- Table of arbitrary connection attributes. Each attribute is simply a -- Table of arbitrary connection attributes. Each attribute is simply a
-- name/value pair associated with a connection. Arbitrary attributes are -- name/value pair associated with a connection. Arbitrary attributes are
@@ -274,128 +369,157 @@ CREATE TABLE guacamole_sharing_profile_attribute (
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --
-- Table of connection permissions. Each connection permission grants a user -- Table of connection permissions. Each connection permission grants a user or
-- specific access to a connection. -- user group specific access to a connection.
-- --
CREATE TABLE `guacamole_connection_permission` ( CREATE TABLE `guacamole_connection_permission` (
`user_id` int(11) NOT NULL, `entity_id` int(11) NOT NULL,
`connection_id` int(11) NOT NULL, `connection_id` int(11) NOT NULL,
`permission` enum('READ', `permission` enum('READ',
'UPDATE', 'UPDATE',
'DELETE', 'DELETE',
'ADMINISTER') NOT NULL, 'ADMINISTER') NOT NULL,
PRIMARY KEY (`user_id`,`connection_id`,`permission`), PRIMARY KEY (`entity_id`,`connection_id`,`permission`),
CONSTRAINT `guacamole_connection_permission_ibfk_1` CONSTRAINT `guacamole_connection_permission_ibfk_1`
FOREIGN KEY (`connection_id`) FOREIGN KEY (`connection_id`)
REFERENCES `guacamole_connection` (`connection_id`) ON DELETE CASCADE, REFERENCES `guacamole_connection` (`connection_id`) ON DELETE CASCADE,
CONSTRAINT `guacamole_connection_permission_ibfk_2` CONSTRAINT `guacamole_connection_permission_entity`
FOREIGN KEY (`user_id`) FOREIGN KEY (`entity_id`)
REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --
-- Table of connection group permissions. Each group permission grants a user -- Table of connection group permissions. Each group permission grants a user
-- specific access to a connection group. -- or user group specific access to a connection group.
-- --
CREATE TABLE `guacamole_connection_group_permission` ( CREATE TABLE `guacamole_connection_group_permission` (
`user_id` int(11) NOT NULL, `entity_id` int(11) NOT NULL,
`connection_group_id` int(11) NOT NULL, `connection_group_id` int(11) NOT NULL,
`permission` enum('READ', `permission` enum('READ',
'UPDATE', 'UPDATE',
'DELETE', 'DELETE',
'ADMINISTER') NOT NULL, 'ADMINISTER') NOT NULL,
PRIMARY KEY (`user_id`,`connection_group_id`,`permission`), PRIMARY KEY (`entity_id`,`connection_group_id`,`permission`),
CONSTRAINT `guacamole_connection_group_permission_ibfk_1` CONSTRAINT `guacamole_connection_group_permission_ibfk_1`
FOREIGN KEY (`connection_group_id`) FOREIGN KEY (`connection_group_id`)
REFERENCES `guacamole_connection_group` (`connection_group_id`) ON DELETE CASCADE, REFERENCES `guacamole_connection_group` (`connection_group_id`) ON DELETE CASCADE,
CONSTRAINT `guacamole_connection_group_permission_ibfk_2` CONSTRAINT `guacamole_connection_group_permission_entity`
FOREIGN KEY (`user_id`) FOREIGN KEY (`entity_id`)
REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --
-- Table of sharing profile permissions. Each sharing profile permission grants -- Table of sharing profile permissions. Each sharing profile permission grants
-- a user specific access to a sharing profile. -- a user or user group specific access to a sharing profile.
-- --
CREATE TABLE guacamole_sharing_profile_permission ( CREATE TABLE guacamole_sharing_profile_permission (
`user_id` integer NOT NULL, `entity_id` integer NOT NULL,
`sharing_profile_id` integer NOT NULL, `sharing_profile_id` integer NOT NULL,
`permission` enum('READ', `permission` enum('READ',
'UPDATE', 'UPDATE',
'DELETE', 'DELETE',
'ADMINISTER') NOT NULL, 'ADMINISTER') NOT NULL,
PRIMARY KEY (`user_id`, `sharing_profile_id`, `permission`), PRIMARY KEY (`entity_id`, `sharing_profile_id`, `permission`),
CONSTRAINT `guacamole_sharing_profile_permission_ibfk_1` CONSTRAINT `guacamole_sharing_profile_permission_ibfk_1`
FOREIGN KEY (`sharing_profile_id`) FOREIGN KEY (`sharing_profile_id`)
REFERENCES `guacamole_sharing_profile` (`sharing_profile_id`) ON DELETE CASCADE, REFERENCES `guacamole_sharing_profile` (`sharing_profile_id`) ON DELETE CASCADE,
CONSTRAINT `guacamole_sharing_profile_permission_ibfk_2` CONSTRAINT `guacamole_sharing_profile_permission_entity`
FOREIGN KEY (`user_id`) FOREIGN KEY (`entity_id`)
REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --
-- Table of system permissions. Each system permission grants a user a -- Table of system permissions. Each system permission grants a user or user
-- system-level privilege of some kind. -- group a system-level privilege of some kind.
-- --
CREATE TABLE `guacamole_system_permission` ( CREATE TABLE `guacamole_system_permission` (
`user_id` int(11) NOT NULL, `entity_id` int(11) NOT NULL,
`permission` enum('CREATE_CONNECTION', `permission` enum('CREATE_CONNECTION',
'CREATE_CONNECTION_GROUP', 'CREATE_CONNECTION_GROUP',
'CREATE_SHARING_PROFILE', 'CREATE_SHARING_PROFILE',
'CREATE_USER', 'CREATE_USER',
'CREATE_USER_GROUP',
'ADMINISTER') NOT NULL, 'ADMINISTER') NOT NULL,
PRIMARY KEY (`user_id`,`permission`), PRIMARY KEY (`entity_id`,`permission`),
CONSTRAINT `guacamole_system_permission_ibfk_1` CONSTRAINT `guacamole_system_permission_entity`
FOREIGN KEY (`user_id`) FOREIGN KEY (`entity_id`)
REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --
-- Table of user permissions. Each user permission grants a user access to -- Table of user permissions. Each user permission grants a user or user group
-- another user (the "affected" user) for a specific type of operation. -- access to another user (the "affected" user) for a specific type of
-- operation.
-- --
CREATE TABLE `guacamole_user_permission` ( CREATE TABLE `guacamole_user_permission` (
`user_id` int(11) NOT NULL, `entity_id` int(11) NOT NULL,
`affected_user_id` int(11) NOT NULL, `affected_user_id` int(11) NOT NULL,
`permission` enum('READ', `permission` enum('READ',
'UPDATE', 'UPDATE',
'DELETE', 'DELETE',
'ADMINISTER') NOT NULL, 'ADMINISTER') NOT NULL,
PRIMARY KEY (`user_id`,`affected_user_id`,`permission`), PRIMARY KEY (`entity_id`,`affected_user_id`,`permission`),
CONSTRAINT `guacamole_user_permission_ibfk_1` CONSTRAINT `guacamole_user_permission_ibfk_1`
FOREIGN KEY (`affected_user_id`) FOREIGN KEY (`affected_user_id`)
REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE, REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE,
CONSTRAINT `guacamole_user_permission_ibfk_2` CONSTRAINT `guacamole_user_permission_entity`
FOREIGN KEY (`user_id`) FOREIGN KEY (`entity_id`)
REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of user group permissions. Each user group permission grants a user
-- or user group access to a another user group (the "affected" user group) for
-- a specific type of operation.
--
CREATE TABLE `guacamole_user_group_permission` (
`entity_id` int(11) NOT NULL,
`affected_user_group_id` int(11) NOT NULL,
`permission` enum('READ',
'UPDATE',
'DELETE',
'ADMINISTER') NOT NULL,
PRIMARY KEY (`entity_id`, `affected_user_group_id`, `permission`),
CONSTRAINT `guacamole_user_group_permission_affected_user_group`
FOREIGN KEY (`affected_user_group_id`)
REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE,
CONSTRAINT `guacamole_user_group_permission_entity`
FOREIGN KEY (`entity_id`)
REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@@ -18,32 +18,36 @@
-- --
-- Create default user "guacadmin" with password "guacadmin" -- Create default user "guacadmin" with password "guacadmin"
INSERT INTO guacamole_user (username, password_hash, password_salt, password_date) INSERT INTO guacamole_entity (name, type) VALUES ('guacadmin', 'USER');
VALUES ('guacadmin', INSERT INTO guacamole_user (entity_id, password_hash, password_salt, password_date)
SELECT
entity_id,
x'CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', -- 'guacadmin' x'CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', -- 'guacadmin'
x'FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264', x'FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264',
NOW()); NOW()
FROM guacamole_entity WHERE name = 'guacadmin';
-- Grant this user all system permissions -- Grant this user all system permissions
INSERT INTO guacamole_system_permission INSERT INTO guacamole_system_permission (entity_id, permission)
SELECT user_id, permission SELECT entity_id, permission
FROM ( FROM (
SELECT 'guacadmin' AS username, 'CREATE_CONNECTION' AS permission SELECT 'guacadmin' AS username, 'CREATE_CONNECTION' AS permission
UNION SELECT 'guacadmin' AS username, 'CREATE_CONNECTION_GROUP' AS permission UNION SELECT 'guacadmin' AS username, 'CREATE_CONNECTION_GROUP' AS permission
UNION SELECT 'guacadmin' AS username, 'CREATE_SHARING_PROFILE' AS permission UNION SELECT 'guacadmin' AS username, 'CREATE_SHARING_PROFILE' AS permission
UNION SELECT 'guacadmin' AS username, 'CREATE_USER' AS permission UNION SELECT 'guacadmin' AS username, 'CREATE_USER' AS permission
UNION SELECT 'guacadmin' AS username, 'CREATE_USER_GROUP' AS permission
UNION SELECT 'guacadmin' AS username, 'ADMINISTER' AS permission UNION SELECT 'guacadmin' AS username, 'ADMINISTER' AS permission
) permissions ) permissions
JOIN guacamole_user ON permissions.username = guacamole_user.username; JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER';
-- Grant admin permission to read/update/administer self -- Grant admin permission to read/update/administer self
INSERT INTO guacamole_user_permission INSERT INTO guacamole_user_permission (entity_id, affected_user_id, permission)
SELECT guacamole_user.user_id, affected.user_id, permission SELECT guacamole_entity.entity_id, guacamole_user.user_id, permission
FROM ( FROM (
SELECT 'guacadmin' AS username, 'guacadmin' AS affected_username, 'READ' AS permission SELECT 'guacadmin' AS username, 'guacadmin' AS affected_username, 'READ' AS permission
UNION SELECT 'guacadmin' AS username, 'guacadmin' AS affected_username, 'UPDATE' AS permission UNION SELECT 'guacadmin' AS username, 'guacadmin' AS affected_username, 'UPDATE' AS permission
UNION SELECT 'guacadmin' AS username, 'guacadmin' AS affected_username, 'ADMINISTER' AS permission UNION SELECT 'guacadmin' AS username, 'guacadmin' AS affected_username, 'ADMINISTER' AS permission
) permissions ) permissions
JOIN guacamole_user ON permissions.username = guacamole_user.username JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER'
JOIN guacamole_user affected ON permissions.affected_username = affected.username; JOIN guacamole_entity affected ON permissions.affected_username = affected.name AND guacamole_entity.type = 'USER'
JOIN guacamole_user ON guacamole_user.entity_id = affected.entity_id;

View File

@@ -17,6 +17,319 @@
-- under the License. -- under the License.
-- --
--
-- Add new system-level permission
--
ALTER TABLE `guacamole_system_permission`
MODIFY `permission` enum('CREATE_CONNECTION',
'CREATE_CONNECTION_GROUP',
'CREATE_SHARING_PROFILE',
'CREATE_USER',
'CREATE_USER_GROUP',
'ADMINISTER') NOT NULL;
--
-- Table of base entities which may each be either a user or user group. Other
-- tables which represent qualities shared by both users and groups will point
-- to guacamole_entity, while tables which represent qualities specific to
-- users or groups will point to guacamole_user or guacamole_user_group.
--
CREATE TABLE `guacamole_entity` (
`entity_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL,
`type` enum('USER',
'USER_GROUP') NOT NULL,
PRIMARY KEY (`entity_id`),
UNIQUE KEY `guacamole_entity_name_scope` (`type`, `name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of user groups. Each user group may have an arbitrary set of member
-- users and member groups, with those members inheriting the permissions
-- granted to that group.
--
CREATE TABLE `guacamole_user_group` (
`user_group_id` int(11) NOT NULL AUTO_INCREMENT,
`entity_id` int(11) NOT NULL,
-- Group disabled status
`disabled` boolean NOT NULL DEFAULT 0,
PRIMARY KEY (`user_group_id`),
UNIQUE KEY `guacamole_user_group_single_entity` (`entity_id`),
CONSTRAINT `guacamole_user_group_entity`
FOREIGN KEY (`entity_id`)
REFERENCES `guacamole_entity` (`entity_id`)
ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of users which are members of given user groups.
--
CREATE TABLE `guacamole_user_group_member` (
`user_group_id` int(11) NOT NULL,
`member_entity_id` int(11) NOT NULL,
PRIMARY KEY (`user_group_id`, `member_entity_id`),
-- Parent must be a user group
CONSTRAINT `guacamole_user_group_member_parent_id`
FOREIGN KEY (`user_group_id`)
REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE,
-- Member may be either a user or a user group (any entity)
CONSTRAINT `guacamole_user_group_member_entity_id`
FOREIGN KEY (`member_entity_id`)
REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of user group permissions. Each user group permission grants a user
-- or user group access to a another user group (the "affected" user group) for
-- a specific type of operation.
--
CREATE TABLE `guacamole_user_group_permission` (
`entity_id` int(11) NOT NULL,
`affected_user_group_id` int(11) NOT NULL,
`permission` enum('READ',
'UPDATE',
'DELETE',
'ADMINISTER') NOT NULL,
PRIMARY KEY (`entity_id`, `affected_user_group_id`, `permission`),
CONSTRAINT `guacamole_user_group_permission_affected_user_group`
FOREIGN KEY (`affected_user_group_id`)
REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE,
CONSTRAINT `guacamole_user_group_permission_entity`
FOREIGN KEY (`entity_id`)
REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Modify guacamole_user table to use guacamole_entity as a base
--
-- Add new entity_id column
ALTER TABLE guacamole_user ADD COLUMN entity_id int(11);
-- Create user entities for each guacamole_user entry
INSERT INTO guacamole_entity (name, type)
SELECT username, 'USER' FROM guacamole_user;
-- Update guacamole_user to point to corresponding guacamole_entity
UPDATE guacamole_user SET entity_id = (
SELECT entity_id FROM guacamole_entity
WHERE
username = guacamole_entity.name
AND type = 'USER'
);
-- The entity_id column should now be safely non-NULL
ALTER TABLE guacamole_user MODIFY entity_id int(11) NOT NULL;
-- The entity_id column should now be unique for each user
ALTER TABLE guacamole_user
ADD CONSTRAINT guacamole_user_single_entity
UNIQUE (entity_id);
-- The entity_id column should now safely point to guacamole_entity entries
ALTER TABLE guacamole_user
ADD CONSTRAINT guacamole_user_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id)
ON DELETE CASCADE;
-- The username column can now safely be removed
ALTER TABLE guacamole_user DROP COLUMN username;
--
-- Modify guacamole_connection_permission to use guacamole_entity instead of
-- guacamole_user
--
-- Add new entity_id column
ALTER TABLE guacamole_connection_permission ADD COLUMN entity_id int(11);
-- Update guacamole_connection_permission to point to the guacamole_entity
-- that has been granted the permission
UPDATE guacamole_connection_permission SET entity_id = (
SELECT entity_id FROM guacamole_user
WHERE guacamole_user.user_id = guacamole_connection_permission.user_id
);
-- The entity_id column should now be safely non-NULL
ALTER TABLE guacamole_connection_permission MODIFY entity_id int(11) NOT NULL;
-- The entity_id column should now safely point to guacamole_entity entries
ALTER TABLE guacamole_connection_permission
ADD CONSTRAINT guacamole_connection_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id)
ON DELETE CASCADE;
-- Remove user_id column
ALTER TABLE guacamole_connection_permission DROP FOREIGN KEY guacamole_connection_permission_ibfk_2;
ALTER TABLE guacamole_connection_permission DROP PRIMARY KEY;
ALTER TABLE guacamole_connection_permission DROP COLUMN user_id;
-- Add new primary key which uses entity_id
ALTER TABLE guacamole_connection_permission
ADD PRIMARY KEY (entity_id, connection_id, permission);
--
-- Modify guacamole_connection_group_permission to use guacamole_entity instead
-- of guacamole_user
--
-- Add new entity_id column
ALTER TABLE guacamole_connection_group_permission ADD COLUMN entity_id int(11);
-- Update guacamole_connection_group_permission to point to the guacamole_entity
-- that has been granted the permission
UPDATE guacamole_connection_group_permission SET entity_id = (
SELECT entity_id FROM guacamole_user
WHERE guacamole_user.user_id = guacamole_connection_group_permission.user_id
);
-- The entity_id column should now be safely non-NULL
ALTER TABLE guacamole_connection_group_permission MODIFY entity_id int(11) NOT NULL;
-- The entity_id column should now safely point to guacamole_entity entries
ALTER TABLE guacamole_connection_group_permission
ADD CONSTRAINT guacamole_connection_group_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id)
ON DELETE CASCADE;
-- Remove user_id column
ALTER TABLE guacamole_connection_group_permission DROP FOREIGN KEY guacamole_connection_group_permission_ibfk_2;
ALTER TABLE guacamole_connection_group_permission DROP PRIMARY KEY;
ALTER TABLE guacamole_connection_group_permission DROP COLUMN user_id;
-- Add new primary key which uses entity_id
ALTER TABLE guacamole_connection_group_permission
ADD PRIMARY KEY (entity_id, connection_group_id, permission);
--
-- Modify guacamole_sharing_profile_permission to use guacamole_entity instead
-- of guacamole_user
--
-- Add new entity_id column
ALTER TABLE guacamole_sharing_profile_permission ADD COLUMN entity_id int(11);
-- Update guacamole_sharing_profile_permission to point to the guacamole_entity
-- that has been granted the permission
UPDATE guacamole_sharing_profile_permission SET entity_id = (
SELECT entity_id FROM guacamole_user
WHERE guacamole_user.user_id = guacamole_sharing_profile_permission.user_id
);
-- The entity_id column should now be safely non-NULL
ALTER TABLE guacamole_sharing_profile_permission MODIFY entity_id int(11) NOT NULL;
-- The entity_id column should now safely point to guacamole_entity entries
ALTER TABLE guacamole_sharing_profile_permission
ADD CONSTRAINT guacamole_sharing_profile_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id)
ON DELETE CASCADE;
-- Remove user_id column
ALTER TABLE guacamole_sharing_profile_permission DROP FOREIGN KEY guacamole_sharing_profile_permission_ibfk_2;
ALTER TABLE guacamole_sharing_profile_permission DROP PRIMARY KEY;
ALTER TABLE guacamole_sharing_profile_permission DROP COLUMN user_id;
-- Add new primary key which uses entity_id
ALTER TABLE guacamole_sharing_profile_permission
ADD PRIMARY KEY (entity_id, sharing_profile_id, permission);
--
-- Modify guacamole_user_permission to use guacamole_entity instead of
-- guacamole_user
--
-- Add new entity_id column
ALTER TABLE guacamole_user_permission ADD COLUMN entity_id int(11);
-- Update guacamole_user_permission to point to the guacamole_entity
-- that has been granted the permission
UPDATE guacamole_user_permission SET entity_id = (
SELECT entity_id FROM guacamole_user
WHERE guacamole_user.user_id = guacamole_user_permission.user_id
);
-- The entity_id column should now be safely non-NULL
ALTER TABLE guacamole_user_permission MODIFY entity_id int(11) NOT NULL;
-- The entity_id column should now safely point to guacamole_entity entries
ALTER TABLE guacamole_user_permission
ADD CONSTRAINT guacamole_user_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id)
ON DELETE CASCADE;
-- Remove user_id column
ALTER TABLE guacamole_user_permission DROP FOREIGN KEY guacamole_user_permission_ibfk_2;
ALTER TABLE guacamole_user_permission DROP PRIMARY KEY;
ALTER TABLE guacamole_user_permission DROP COLUMN user_id;
-- Add new primary key which uses entity_id
ALTER TABLE guacamole_user_permission
ADD PRIMARY KEY (entity_id, affected_user_id, permission);
--
-- Modify guacamole_system_permission to use guacamole_entity instead of
-- guacamole_user
--
-- Add new entity_id column
ALTER TABLE guacamole_system_permission ADD COLUMN entity_id int(11);
-- Update guacamole_system_permission to point to the guacamole_entity
-- that has been granted the permission
UPDATE guacamole_system_permission SET entity_id = (
SELECT entity_id FROM guacamole_user
WHERE guacamole_user.user_id = guacamole_system_permission.user_id
);
-- The entity_id column should now be safely non-NULL
ALTER TABLE guacamole_system_permission MODIFY entity_id int(11) NOT NULL;
-- The entity_id column should now safely point to guacamole_entity entries
ALTER TABLE guacamole_system_permission
ADD CONSTRAINT guacamole_system_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id)
ON DELETE CASCADE;
-- Remove user_id column
ALTER TABLE guacamole_system_permission DROP FOREIGN KEY guacamole_system_permission_ibfk_1;
ALTER TABLE guacamole_system_permission DROP PRIMARY KEY;
ALTER TABLE guacamole_system_permission DROP COLUMN user_id;
-- Add new primary key which uses entity_id
ALTER TABLE guacamole_system_permission
ADD PRIMARY KEY (entity_id, permission);
-- --
-- Table of arbitrary user attributes. Each attribute is simply a name/value -- Table of arbitrary user attributes. Each attribute is simply a name/value
-- pair associated with a user. Arbitrary attributes are defined by other -- pair associated with a user. Arbitrary attributes are defined by other
@@ -39,6 +352,28 @@ CREATE TABLE guacamole_user_attribute (
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of arbitrary user group attributes. Each attribute is simply a
-- name/value pair associated with a user group. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_user_group_attribute (
`user_group_id` int(11) NOT NULL,
`attribute_name` varchar(128) NOT NULL,
`attribute_value` varchar(4096) NOT NULL,
PRIMARY KEY (`user_group_id`, `attribute_name`),
KEY `user_group_id` (`user_group_id`),
CONSTRAINT `guacamole_user_group_attribute_ibfk_1`
FOREIGN KEY (`user_group_id`)
REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --
-- Table of arbitrary connection attributes. Each attribute is simply a -- Table of arbitrary connection attributes. Each attribute is simply a
-- name/value pair associated with a connection. Arbitrary attributes are -- name/value pair associated with a connection. Arbitrary attributes are

View File

@@ -19,11 +19,16 @@
package org.apache.guacamole.auth.mysql; package org.apache.guacamole.auth.mysql;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.JDBCEnvironment; import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.apache.guacamole.auth.jdbc.security.PasswordPolicy; import org.apache.guacamole.auth.jdbc.security.PasswordPolicy;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.session.SqlSession;
/** /**
* A MySQL-specific implementation of JDBCEnvironment provides database * A MySQL-specific implementation of JDBCEnvironment provides database
@@ -36,6 +41,16 @@ public class MySQLEnvironment extends JDBCEnvironment {
*/ */
private static final Logger logger = LoggerFactory.getLogger(MySQLEnvironment.class); private static final Logger logger = LoggerFactory.getLogger(MySQLEnvironment.class);
/**
* The earliest version of MariaDB that supported recursive CTEs.
*/
private static final MySQLVersion MARIADB_SUPPORTS_CTE = new MySQLVersion(10, 2, 2, true);
/**
* The earliest version of MySQL that supported recursive CTEs.
*/
private static final MySQLVersion MYSQL_SUPPORTS_CTE = new MySQLVersion(8, 0, 1, false);
/** /**
* The default host to connect to, if MYSQL_HOSTNAME is not specified. * The default host to connect to, if MYSQL_HOSTNAME is not specified.
*/ */
@@ -226,4 +241,40 @@ public class MySQLEnvironment extends JDBCEnvironment {
return getRequiredProperty(MySQLGuacamoleProperties.MYSQL_PASSWORD); return getRequiredProperty(MySQLGuacamoleProperties.MYSQL_PASSWORD);
} }
@Override
public boolean isRecursiveQuerySupported(SqlSession session) {
// Retrieve database version string from JDBC connection
String versionString;
try {
Connection connection = session.getConnection();
DatabaseMetaData metaData = connection.getMetaData();
versionString = metaData.getDatabaseProductVersion();
}
catch (SQLException e) {
throw new PersistenceException("Cannot determine whether "
+ "MySQL / MariaDB supports recursive queries.", e);
}
try {
// Parse MySQL / MariaDB version from version string
MySQLVersion version = new MySQLVersion(versionString);
logger.debug("Database recognized as {}.", version);
// Recursive queries are supported for MariaDB 10.2.2+ and
// MySQL 8.0.1+
return version.isAtLeast(MARIADB_SUPPORTS_CTE)
|| version.isAtLeast(MYSQL_SUPPORTS_CTE);
}
catch (IllegalArgumentException e) {
logger.debug("Unrecognized MySQL / MariaDB version string: "
+ "\"{}\". Assuming database engine does not support "
+ "recursive queries.", session);
return false;
}
}
} }

View File

@@ -0,0 +1,153 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.mysql;
import com.google.common.collect.ComparisonChain;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* The specific version of a MySQL or MariaDB server.
*/
public class MySQLVersion {
/**
* Pattern which matches the version string returned by a MariaDB server,
* extracting the major, minor, and patch numbers.
*/
private final Pattern MARIADB_VERSION = Pattern.compile("^.*-([0-9]+)\\.([0-9]+)\\.([0-9]+)-MariaDB$");
/**
* Pattern which matches the version string returned by a non-MariaDB
* server (including MySQL and Aurora), extracting the major, minor, and
* patch numbers. All non-MariaDB servers use normal MySQL version numbers.
*/
private final Pattern MYSQL_VERSION = Pattern.compile("^([0-9]+)\\.([0-9]+)\\.([0-9]+).*$");
/**
* Whether the associated server is a MariaDB server. All non-MariaDB
* servers use normal MySQL version numbers and are comparable against each
* other.
*/
private final boolean isMariaDB;
/**
* The major component of the MAJOR.MINOR.PATCH version number.
*/
private final int major;
/**
* The minor component of the MAJOR.MINOR.PATCH version number.
*/
private final int minor;
/**
* The patch component of the MAJOR.MINOR.PATCH version number.
*/
private final int patch;
/**
* Creates a new MySQLVersion having the specified major, minor, and patch
* components.
*
* @param major
* The major component of the MAJOR.MINOR.PATCH version number of the
* MariaDB / MySQL server.
*
* @param minor
* The minor component of the MAJOR.MINOR.PATCH version number of the
* MariaDB / MySQL server.
*
* @param patch
* The patch component of the MAJOR.MINOR.PATCH version number of the
* MariaDB / MySQL server.
*
* @param isMariaDB
* Whether the associated server is a MariaDB server.
*/
public MySQLVersion(int major, int minor, int patch, boolean isMariaDB) {
this.major = major;
this.minor = minor;
this.patch = patch;
this.isMariaDB = isMariaDB;
}
public MySQLVersion(String version) throws IllegalArgumentException {
// Extract MariaDB version number if version string appears to be
// a MariaDB version string
Matcher mariadb = MARIADB_VERSION.matcher(version);
if (mariadb.matches()) {
this.major = Integer.parseInt(mariadb.group(1));
this.minor = Integer.parseInt(mariadb.group(2));
this.patch = Integer.parseInt(mariadb.group(3));
this.isMariaDB = true;
return;
}
// If not MariaDB, assume version string is a MySQL version string
// and attempt to extract the version number
Matcher mysql = MYSQL_VERSION.matcher(version);
if (mysql.matches()) {
this.major = Integer.parseInt(mysql.group(1));
this.minor = Integer.parseInt(mysql.group(2));
this.patch = Integer.parseInt(mysql.group(3));
this.isMariaDB = false;
return;
}
throw new IllegalArgumentException("Unrecognized MySQL / MariaDB version string.");
}
/**
* Returns whether this version is at least as recent as the given version.
*
* @param version
* The version to compare against.
*
* @return
* true if the versions are associated with the same database server
* type (MariaDB vs. MySQL) and this version is at least as recent as
* the given version, false otherwise.
*/
public boolean isAtLeast(MySQLVersion version) {
// If the databases use different version numbering schemes, the
// version numbers are not comparable
if (isMariaDB != version.isMariaDB)
return false;
// Compare major, minor, and patch number in order of precedence
return ComparisonChain.start()
.compare(major, version.major)
.compare(minor, version.minor)
.compare(patch, version.patch)
.result() >= 0;
}
@Override
public String toString() {
return String.format("%s %d.%d.%d", isMariaDB ? "MariaDB" : "MySQL",
major, minor, patch);
}
}

View File

@@ -0,0 +1,156 @@
<?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" >
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<mapper namespace="org.apache.guacamole.auth.jdbc.base.EntityMapper" >
<!--
* SQL fragment which tests whether the value of the given column matches
* the given entity ID. If group identifiers are provided, the IDs of the
* entities for all groups having those identifiers are tested, as well.
* Disabled groups are ignored.
*
* @param column
* The name of the column to test. This column MUST contain an entity
* ID (a foreign key into the guacamole_entity table).
*
* @param entityID
* The ID of the specific entity to test the column against.
*
* @param groups
* A collection of group identifiers to additionally test the column
* against. Though this functionality is optional, a collection must
* always be given, even if that collection is empty.
-->
<sql id="isRelatedEntity">
(
${column} = ${entityID}
<if test="!${groups}.isEmpty()">
OR ${column} IN (
SELECT guacamole_entity.entity_id
FROM guacamole_entity
JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id
WHERE
type = 'USER_GROUP'
AND name IN
<foreach collection="${groups}" item="effectiveGroup"
open="(" separator="," close=")">
#{effectiveGroup,jdbcType=VARCHAR}
</foreach>
AND disabled = false
)
</if>
)
</sql>
<!-- Select names of all effective groups (including inherited) -->
<select id="selectEffectiveGroupIdentifiers" resultType="string">
<if test="!recursive">
SELECT
guacamole_entity.name
FROM guacamole_user_group
JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
JOIN guacamole_user_group_member ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
WHERE
guacamole_user_group.disabled = false
AND (
guacamole_user_group_member.member_entity_id = #{entity.entityID}
<if test="!effectiveGroups.isEmpty()">
OR guacamole_user_group_member.member_entity_id IN (
SELECT entity_id FROM guacamole_entity
WHERE type = 'USER_GROUP' AND name IN
<foreach collection="effectiveGroups" item="effectiveGroup"
open="(" separator="," close=")">
#{effectiveGroup,jdbcType=VARCHAR}
</foreach>
)
OR guacamole_user_group.entity_id IN (
SELECT entity_id FROM guacamole_entity
WHERE type = 'USER_GROUP' AND name IN
<foreach collection="effectiveGroups" item="effectiveGroup"
open="(" separator="," close=")">
#{effectiveGroup,jdbcType=VARCHAR}
</foreach>
)
</if>
)
</if>
<if test="recursive">
WITH RECURSIVE related_entity(entity_id) AS (
SELECT
guacamole_user_group.entity_id
FROM guacamole_user_group
JOIN guacamole_user_group_member ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
WHERE
guacamole_user_group_member.member_entity_id = #{entity.entityID}
AND guacamole_user_group.disabled = false
<if test="!effectiveGroups.isEmpty()">
UNION
SELECT
guacamole_entity.entity_id
FROM guacamole_entity
JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id
WHERE
type = 'USER_GROUP'
AND name IN
<foreach collection="effectiveGroups" item="effectiveGroup"
open="(" separator="," close=")">
#{effectiveGroup,jdbcType=VARCHAR}
</foreach>
AND guacamole_user_group.disabled = false
</if>
UNION
SELECT
guacamole_user_group.entity_id
FROM related_entity
JOIN guacamole_user_group_member ON related_entity.entity_id = guacamole_user_group_member.member_entity_id
JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
WHERE
guacamole_user_group.disabled = false
)
SELECT name
FROM related_entity
JOIN guacamole_entity ON related_entity.entity_id = guacamole_entity.entity_id
WHERE
guacamole_entity.type = 'USER_GROUP';
</if>
</select>
<!-- Insert single entity -->
<insert id="insert" useGeneratedKeys="true" keyProperty="entity.entityID"
parameterType="org.apache.guacamole.auth.jdbc.base.EntityModel">
INSERT INTO guacamole_entity (
name,
type
)
VALUES (
#{entity.identifier,jdbcType=VARCHAR},
#{entity.entityType,jdbcType=VARCHAR}
)
</insert>
</mapper>

View File

@@ -68,7 +68,11 @@
SELECT connection_id SELECT connection_id
FROM guacamole_connection_permission FROM guacamole_connection_permission
WHERE WHERE
user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ' AND permission = 'READ'
</select> </select>
@@ -89,7 +93,11 @@
WHERE WHERE
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=VARCHAR}</if> <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=VARCHAR}</if>
<if test="parentIdentifier == null">parent_id IS NULL</if> <if test="parentIdentifier == null">parent_id IS NULL</if>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ' AND permission = 'READ'
</select> </select>
@@ -165,7 +173,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
AND guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_connection_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ' AND permission = 'READ'
GROUP BY guacamole_connection.connection_id; GROUP BY guacamole_connection.connection_id;
@@ -177,7 +189,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ'; AND permission = 'READ';
SELECT SELECT
@@ -191,7 +207,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ'; AND permission = 'READ';
</select> </select>

View File

@@ -79,7 +79,10 @@
#{record.sharingProfileIdentifier,jdbcType=VARCHAR}, #{record.sharingProfileIdentifier,jdbcType=VARCHAR},
#{record.sharingProfileName,jdbcType=VARCHAR}, #{record.sharingProfileName,jdbcType=VARCHAR},
(SELECT user_id FROM guacamole_user (SELECT user_id FROM guacamole_user
WHERE username = #{record.username,jdbcType=VARCHAR}), JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
guacamole_entity.name = #{record.username,jdbcType=VARCHAR}
AND guacamole_entity.type = 'USER'),
#{record.username,jdbcType=VARCHAR}, #{record.username,jdbcType=VARCHAR},
#{record.startDate,jdbcType=TIMESTAMP}, #{record.startDate,jdbcType=TIMESTAMP},
#{record.endDate,jdbcType=TIMESTAMP} #{record.endDate,jdbcType=TIMESTAMP}
@@ -165,13 +168,21 @@
<!-- Restrict to readable connections --> <!-- Restrict to readable connections -->
JOIN guacamole_connection_permission ON JOIN guacamole_connection_permission ON
guacamole_connection_history.connection_id = guacamole_connection_permission.connection_id guacamole_connection_history.connection_id = guacamole_connection_permission.connection_id
AND guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_connection_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND guacamole_connection_permission.permission = 'READ' AND guacamole_connection_permission.permission = 'READ'
<!-- Restrict to readable users --> <!-- Restrict to readable users -->
JOIN guacamole_user_permission ON JOIN guacamole_user_permission ON
guacamole_connection_history.user_id = guacamole_user_permission.affected_user_id guacamole_connection_history.user_id = guacamole_user_permission.affected_user_id
AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND guacamole_user_permission.permission = 'READ' AND guacamole_user_permission.permission = 'READ'
<!-- Search terms --> <!-- Search terms -->
@@ -182,7 +193,10 @@
guacamole_connection_history.user_id IN ( guacamole_connection_history.user_id IN (
SELECT user_id SELECT user_id
FROM guacamole_user FROM guacamole_user
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0 JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'
) )
OR guacamole_connection_history.connection_id IN ( OR guacamole_connection_history.connection_id IN (

View File

@@ -69,7 +69,11 @@
SELECT connection_group_id SELECT connection_group_id
FROM guacamole_connection_group_permission FROM guacamole_connection_group_permission
WHERE WHERE
user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ' AND permission = 'READ'
</select> </select>
@@ -90,7 +94,11 @@
WHERE WHERE
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=VARCHAR}</if> <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=VARCHAR}</if>
<if test="parentIdentifier == null">parent_id IS NULL</if> <if test="parentIdentifier == null">parent_id IS NULL</if>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ' AND permission = 'READ'
</select> </select>
@@ -161,7 +169,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ'; AND permission = 'READ';
SELECT parent_id, guacamole_connection_group.connection_group_id SELECT parent_id, guacamole_connection_group.connection_group_id
@@ -172,7 +184,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ'; AND permission = 'READ';
SELECT parent_id, guacamole_connection.connection_id SELECT parent_id, guacamole_connection.connection_id
@@ -183,7 +199,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ'; AND permission = 'READ';
SELECT SELECT
@@ -197,7 +217,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ'; AND permission = 'READ';
</select> </select>

View File

@@ -25,24 +25,26 @@
<!-- Result mapper for connection permissions --> <!-- Result mapper for connection permissions -->
<resultMap id="ConnectionGroupPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <resultMap id="ConnectionGroupPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/> <result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="permission" property="type" jdbcType="VARCHAR" <result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/> javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
<result column="connection_group_id" property="objectIdentifier" jdbcType="INTEGER"/> <result column="connection_group_id" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap> </resultMap>
<!-- Select all permissions for a given user --> <!-- Select all permissions for a given entity -->
<select id="select" resultMap="ConnectionGroupPermissionResultMap"> <select id="select" resultMap="ConnectionGroupPermissionResultMap">
SELECT SELECT
guacamole_connection_group_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
username,
permission, permission,
connection_group_id connection_group_id
FROM guacamole_connection_group_permission FROM guacamole_connection_group_permission
JOIN guacamole_user ON guacamole_connection_group_permission.user_id = guacamole_user.user_id WHERE
WHERE guacamole_connection_group_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
</select> </select>
@@ -50,26 +52,32 @@
<select id="selectOne" resultMap="ConnectionGroupPermissionResultMap"> <select id="selectOne" resultMap="ConnectionGroupPermissionResultMap">
SELECT SELECT
guacamole_connection_group_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
username,
permission, permission,
connection_group_id connection_group_id
FROM guacamole_connection_group_permission FROM guacamole_connection_group_permission
JOIN guacamole_user ON guacamole_connection_group_permission.user_id = guacamole_user.user_id
WHERE WHERE
guacamole_connection_group_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = #{type,jdbcType=VARCHAR} AND permission = #{type,jdbcType=VARCHAR}
AND connection_group_id = #{identifier,jdbcType=VARCHAR} AND connection_group_id = #{identifier,jdbcType=VARCHAR}
</select> </select>
<!-- Select identifiers accessible by the given user for the given permissions --> <!-- Select identifiers accessible by the given entity for the given permissions -->
<select id="selectAccessibleIdentifiers" resultType="string"> <select id="selectAccessibleIdentifiers" resultType="string">
SELECT DISTINCT connection_group_id SELECT DISTINCT connection_group_id
FROM guacamole_connection_group_permission FROM guacamole_connection_group_permission
WHERE WHERE
user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND connection_group_id IN AND connection_group_id IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
@@ -87,10 +95,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
DELETE FROM guacamole_connection_group_permission DELETE FROM guacamole_connection_group_permission
WHERE (user_id, permission, connection_group_id) IN WHERE (entity_id, permission, connection_group_id) IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER}, (#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}, #{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR}) #{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach> </foreach>
@@ -101,13 +109,13 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT IGNORE INTO guacamole_connection_group_permission ( INSERT IGNORE INTO guacamole_connection_group_permission (
user_id, entity_id,
permission, permission,
connection_group_id connection_group_id
) )
VALUES VALUES
<foreach collection="permissions" item="permission" separator=","> <foreach collection="permissions" item="permission" separator=",">
(#{permission.userID,jdbcType=INTEGER}, (#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}, #{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR}) #{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach> </foreach>

View File

@@ -25,24 +25,26 @@
<!-- Result mapper for connection permissions --> <!-- Result mapper for connection permissions -->
<resultMap id="ConnectionPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <resultMap id="ConnectionPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/> <result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="permission" property="type" jdbcType="VARCHAR" <result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/> javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
<result column="connection_id" property="objectIdentifier" jdbcType="INTEGER"/> <result column="connection_id" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap> </resultMap>
<!-- Select all permissions for a given user --> <!-- Select all permissions for a given entity -->
<select id="select" resultMap="ConnectionPermissionResultMap"> <select id="select" resultMap="ConnectionPermissionResultMap">
SELECT SELECT
guacamole_connection_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
username,
permission, permission,
connection_id connection_id
FROM guacamole_connection_permission FROM guacamole_connection_permission
JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id WHERE
WHERE guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
</select> </select>
@@ -50,26 +52,32 @@
<select id="selectOne" resultMap="ConnectionPermissionResultMap"> <select id="selectOne" resultMap="ConnectionPermissionResultMap">
SELECT SELECT
guacamole_connection_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
username,
permission, permission,
connection_id connection_id
FROM guacamole_connection_permission FROM guacamole_connection_permission
JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id
WHERE WHERE
guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = #{type,jdbcType=VARCHAR} AND permission = #{type,jdbcType=VARCHAR}
AND connection_id = #{identifier,jdbcType=VARCHAR} AND connection_id = #{identifier,jdbcType=VARCHAR}
</select> </select>
<!-- Select identifiers accessible by the given user for the given permissions --> <!-- Select identifiers accessible by the given entity for the given permissions -->
<select id="selectAccessibleIdentifiers" resultType="string"> <select id="selectAccessibleIdentifiers" resultType="string">
SELECT DISTINCT connection_id SELECT DISTINCT connection_id
FROM guacamole_connection_permission FROM guacamole_connection_permission
WHERE WHERE
user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND connection_id IN AND connection_id IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
@@ -87,10 +95,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
DELETE FROM guacamole_connection_permission DELETE FROM guacamole_connection_permission
WHERE (user_id, permission, connection_id) IN WHERE (entity_id, permission, connection_id) IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER}, (#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}, #{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR}) #{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach> </foreach>
@@ -101,13 +109,13 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT IGNORE INTO guacamole_connection_permission ( INSERT IGNORE INTO guacamole_connection_permission (
user_id, entity_id,
permission, permission,
connection_id connection_id
) )
VALUES VALUES
<foreach collection="permissions" item="permission" separator=","> <foreach collection="permissions" item="permission" separator=",">
(#{permission.userID,jdbcType=INTEGER}, (#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}, #{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR}) #{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach> </foreach>

View File

@@ -23,26 +23,28 @@
<mapper namespace="org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionMapper"> <mapper namespace="org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionMapper">
<!-- Result mapper for sharig profile permissions --> <!-- Result mapper for sharing profile permissions -->
<resultMap id="SharingProfilePermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <resultMap id="SharingProfilePermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/> <result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="permission" property="type" jdbcType="VARCHAR" <result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/> javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
<result column="sharing_profile_id" property="objectIdentifier" jdbcType="INTEGER"/> <result column="sharing_profile_id" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap> </resultMap>
<!-- Select all permissions for a given user --> <!-- Select all permissions for a given entity -->
<select id="select" resultMap="SharingProfilePermissionResultMap"> <select id="select" resultMap="SharingProfilePermissionResultMap">
SELECT SELECT
guacamole_sharing_profile_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
username,
permission, permission,
sharing_profile_id sharing_profile_id
FROM guacamole_sharing_profile_permission FROM guacamole_sharing_profile_permission
JOIN guacamole_user ON guacamole_sharing_profile_permission.user_id = guacamole_user.user_id WHERE
WHERE guacamole_sharing_profile_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
</select> </select>
@@ -50,26 +52,32 @@
<select id="selectOne" resultMap="SharingProfilePermissionResultMap"> <select id="selectOne" resultMap="SharingProfilePermissionResultMap">
SELECT SELECT
guacamole_sharing_profile_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
username,
permission, permission,
sharing_profile_id sharing_profile_id
FROM guacamole_sharing_profile_permission FROM guacamole_sharing_profile_permission
JOIN guacamole_user ON guacamole_sharing_profile_permission.user_id = guacamole_user.user_id
WHERE WHERE
guacamole_sharing_profile_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = #{type,jdbcType=VARCHAR} AND permission = #{type,jdbcType=VARCHAR}
AND sharing_profile_id = #{identifier,jdbcType=VARCHAR} AND sharing_profile_id = #{identifier,jdbcType=VARCHAR}
</select> </select>
<!-- Select identifiers accessible by the given user for the given permissions --> <!-- Select identifiers accessible by the given entity for the given permissions -->
<select id="selectAccessibleIdentifiers" resultType="string"> <select id="selectAccessibleIdentifiers" resultType="string">
SELECT DISTINCT sharing_profile_id SELECT DISTINCT sharing_profile_id
FROM guacamole_sharing_profile_permission FROM guacamole_sharing_profile_permission
WHERE WHERE
user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND sharing_profile_id IN AND sharing_profile_id IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
@@ -87,10 +95,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
DELETE FROM guacamole_sharing_profile_permission DELETE FROM guacamole_sharing_profile_permission
WHERE (user_id, permission, sharing_profile_id) IN WHERE (entity_id, permission, sharing_profile_id) IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER}, (#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}, #{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR}) #{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach> </foreach>
@@ -101,13 +109,13 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT IGNORE INTO guacamole_sharing_profile_permission ( INSERT IGNORE INTO guacamole_sharing_profile_permission (
user_id, entity_id,
permission, permission,
sharing_profile_id sharing_profile_id
) )
VALUES VALUES
<foreach collection="permissions" item="permission" separator=","> <foreach collection="permissions" item="permission" separator=",">
(#{permission.userID,jdbcType=INTEGER}, (#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}, #{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR}) #{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach> </foreach>

View File

@@ -25,36 +25,40 @@
<!-- Result mapper for system permissions --> <!-- Result mapper for system permissions -->
<resultMap id="SystemPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel"> <resultMap id="SystemPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/> <result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="permission" property="type" jdbcType="VARCHAR" <result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.permission.SystemPermission$Type"/> javaType="org.apache.guacamole.net.auth.permission.SystemPermission$Type"/>
</resultMap> </resultMap>
<!-- Select all permissions for a given user --> <!-- Select all permissions for a given entity -->
<select id="select" resultMap="SystemPermissionResultMap"> <select id="select" resultMap="SystemPermissionResultMap">
SELECT SELECT DISTINCT
guacamole_system_permission.user_id, #{entity.entityID} AS entity_id,
username,
permission permission
FROM guacamole_system_permission FROM guacamole_system_permission
JOIN guacamole_user ON guacamole_system_permission.user_id = guacamole_user.user_id WHERE
WHERE guacamole_system_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
</select> </select>
<!-- Select the single permission matching the given criteria --> <!-- Select the single permission matching the given criteria -->
<select id="selectOne" resultMap="SystemPermissionResultMap"> <select id="selectOne" resultMap="SystemPermissionResultMap">
SELECT SELECT DISTINCT
guacamole_system_permission.user_id, #{entity.entityID} AS entity_id,
username,
permission permission
FROM guacamole_system_permission FROM guacamole_system_permission
JOIN guacamole_user ON guacamole_system_permission.user_id = guacamole_user.user_id
WHERE WHERE
guacamole_system_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = #{type,jdbcType=VARCHAR} AND permission = #{type,jdbcType=VARCHAR}
</select> </select>
@@ -63,10 +67,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel"> <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
DELETE FROM guacamole_system_permission DELETE FROM guacamole_system_permission
WHERE (user_id, permission) IN WHERE (entity_id, permission) IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER}, (#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}) #{permission.type,jdbcType=VARCHAR})
</foreach> </foreach>
@@ -76,12 +80,12 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel"> <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
INSERT IGNORE INTO guacamole_system_permission ( INSERT IGNORE INTO guacamole_system_permission (
user_id, entity_id,
permission permission
) )
VALUES VALUES
<foreach collection="permissions" item="permission" separator=","> <foreach collection="permissions" item="permission" separator=",">
(#{permission.userID,jdbcType=INTEGER}, (#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}) #{permission.type,jdbcType=VARCHAR})
</foreach> </foreach>

View File

@@ -0,0 +1,149 @@
<?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" >
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<mapper namespace="org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionMapper" >
<!-- Result mapper for user group permissions -->
<resultMap id="UserGroupPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
<result column="affected_name" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap>
<!-- Select all permissions for a given entity -->
<select id="select" resultMap="UserGroupPermissionResultMap">
SELECT
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
affected_entity.name AS affected_name
FROM guacamole_user_group_permission
JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id
WHERE
<include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_group_permission.entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND affected_entity.type = 'USER_GROUP'
</select>
<!-- Select the single permission matching the given criteria -->
<select id="selectOne" resultMap="UserGroupPermissionResultMap">
SELECT
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
affected_entity.name AS affected_name
FROM guacamole_user_group_permission
JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id
WHERE
<include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_group_permission.entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = #{type,jdbcType=VARCHAR}
AND affected_entity.name = #{identifier,jdbcType=VARCHAR}
AND affected_entity.type = 'USER_GROUP'
</select>
<!-- Select identifiers accessible by the given entity for the given permissions -->
<select id="selectAccessibleIdentifiers" resultType="string">
SELECT DISTINCT affected_entity.name
FROM guacamole_user_group_permission
JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id
WHERE
<include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_group_permission.entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND affected_entity.name IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND permission IN
<foreach collection="permissions" item="permission"
open="(" separator="," close=")">
#{permission,jdbcType=VARCHAR}
</foreach>
AND affected_entity.type = 'USER_GROUP'
</select>
<!-- Delete all given permissions -->
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
DELETE FROM guacamole_user_group_permission
USING guacamole_user_group_permission
JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id
WHERE
(guacamole_user_group_permission.entity_id, permission, affected_entity.name) IN
<foreach collection="permissions" item="permission"
open="(" separator="," close=")">
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach>
AND affected_entity.type = 'USER_GROUP'
</delete>
<!-- Insert all given permissions -->
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT IGNORE INTO guacamole_user_group_permission (
entity_id,
permission,
affected_user_group_id
)
SELECT DISTINCT
permissions.entity_id,
permissions.permission,
affected_group.user_group_id
FROM
<foreach collection="permissions" item="permission"
open="(" separator="UNION ALL" close=")">
SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id,
#{permission.type,jdbcType=VARCHAR} AS permission,
#{permission.objectIdentifier,jdbcType=VARCHAR} AS affected_name
</foreach>
AS permissions
JOIN guacamole_entity affected_entity ON
affected_entity.name = permissions.affected_name
AND affected_entity.type = 'USER_GROUP'
JOIN guacamole_user_group affected_group ON affected_group.entity_id = affected_entity.entity_id
</insert>
</mapper>

View File

@@ -25,25 +25,29 @@
<!-- Result mapper for user permissions --> <!-- Result mapper for user permissions -->
<resultMap id="UserPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <resultMap id="UserPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/> <result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="permission" property="type" jdbcType="VARCHAR" <result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/> javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
<result column="affected_username" property="objectIdentifier" jdbcType="INTEGER"/> <result column="affected_name" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap> </resultMap>
<!-- Select all permissions for a given user --> <!-- Select all permissions for a given entity -->
<select id="select" resultMap="UserPermissionResultMap"> <select id="select" resultMap="UserPermissionResultMap">
SELECT SELECT
guacamole_user_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
guacamole_user.username,
permission, permission,
affected.username AS affected_username affected_entity.name AS affected_name
FROM guacamole_user_permission FROM guacamole_user_permission
JOIN guacamole_user ON guacamole_user_permission.user_id = guacamole_user.user_id JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
WHERE guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} WHERE
<include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_permission.entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND affected_entity.type = 'USER'
</select> </select>
@@ -51,29 +55,38 @@
<select id="selectOne" resultMap="UserPermissionResultMap"> <select id="selectOne" resultMap="UserPermissionResultMap">
SELECT SELECT
guacamole_user_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
guacamole_user.username,
permission, permission,
affected.username AS affected_username affected_entity.name AS affected_name
FROM guacamole_user_permission FROM guacamole_user_permission
JOIN guacamole_user ON guacamole_user_permission.user_id = guacamole_user.user_id JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
WHERE WHERE
guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_permission.entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = #{type,jdbcType=VARCHAR} AND permission = #{type,jdbcType=VARCHAR}
AND affected.username = #{identifier,jdbcType=VARCHAR} AND affected_entity.name = #{identifier,jdbcType=VARCHAR}
AND affected_entity.type = 'USER'
</select> </select>
<!-- Select identifiers accessible by the given user for the given permissions --> <!-- Select identifiers accessible by the given entity for the given permissions -->
<select id="selectAccessibleIdentifiers" resultType="string"> <select id="selectAccessibleIdentifiers" resultType="string">
SELECT DISTINCT username SELECT DISTINCT affected_entity.name
FROM guacamole_user_permission FROM guacamole_user_permission
JOIN guacamole_user ON guacamole_user_permission.affected_user_id = guacamole_user.user_id JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
WHERE WHERE
guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
AND username IN <property name="column" value="guacamole_user_permission.entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND affected_entity.name IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
@@ -83,6 +96,7 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{permission,jdbcType=VARCHAR} #{permission,jdbcType=VARCHAR}
</foreach> </foreach>
AND affected_entity.type = 'USER'
</select> </select>
@@ -91,15 +105,17 @@
DELETE FROM guacamole_user_permission DELETE FROM guacamole_user_permission
USING guacamole_user_permission USING guacamole_user_permission
JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
WHERE WHERE
(guacamole_user_permission.user_id, permission, affected.username) IN (guacamole_user_permission.entity_id, permission, affected_entity.name) IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER}, (#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}, #{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR}) #{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach> </foreach>
AND affected_entity.type = 'USER'
</delete> </delete>
@@ -107,19 +123,26 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT IGNORE INTO guacamole_user_permission ( INSERT IGNORE INTO guacamole_user_permission (
user_id, entity_id,
permission, permission,
affected_user_id affected_user_id
) )
SELECT permissions.user_id, permissions.permission, guacamole_user.user_id FROM SELECT DISTINCT
permissions.entity_id,
permissions.permission,
affected_user.user_id
FROM
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="UNION ALL" close=")"> open="(" separator="UNION ALL" close=")">
SELECT #{permission.userID,jdbcType=INTEGER} AS user_id, SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id,
#{permission.type,jdbcType=VARCHAR} AS permission, #{permission.type,jdbcType=VARCHAR} AS permission,
#{permission.objectIdentifier,jdbcType=VARCHAR} AS username #{permission.objectIdentifier,jdbcType=VARCHAR} AS affected_name
</foreach> </foreach>
AS permissions AS permissions
JOIN guacamole_user ON guacamole_user.username = permissions.username; JOIN guacamole_entity affected_entity ON
affected_entity.name = permissions.affected_name
AND affected_entity.type = 'USER'
JOIN guacamole_user affected_user ON affected_user.entity_id = affected_entity.entity_id
</insert> </insert>

View File

@@ -52,7 +52,11 @@
SELECT sharing_profile_id SELECT sharing_profile_id
FROM guacamole_sharing_profile_permission FROM guacamole_sharing_profile_permission
WHERE WHERE
user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ' AND permission = 'READ'
</select> </select>
@@ -99,7 +103,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ'; AND permission = 'READ';
SELECT SELECT
@@ -113,7 +121,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ'; AND permission = 'READ';
</select> </select>

View File

@@ -41,8 +41,9 @@
guacamole_user_password_history.password_date guacamole_user_password_history.password_date
FROM guacamole_user_password_history FROM guacamole_user_password_history
JOIN guacamole_user ON guacamole_user_password_history.user_id = guacamole_user.user_id JOIN guacamole_user ON guacamole_user_password_history.user_id = guacamole_user.user_id
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
guacamole_user.username = #{username,jdbcType=VARCHAR} guacamole_entity.name = #{username,jdbcType=VARCHAR}
ORDER BY ORDER BY
guacamole_user_password_history.password_date DESC guacamole_user_password_history.password_date DESC
LIMIT #{maxHistorySize} LIMIT #{maxHistorySize}

View File

@@ -28,7 +28,8 @@
<!-- User properties --> <!-- User properties -->
<id column="user_id" property="objectID" jdbcType="INTEGER"/> <id column="user_id" property="objectID" jdbcType="INTEGER"/>
<result column="username" property="identifier" jdbcType="VARCHAR"/> <result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="name" property="identifier" jdbcType="VARCHAR"/>
<result column="password_hash" property="passwordHash" jdbcType="BINARY"/> <result column="password_hash" property="passwordHash" jdbcType="BINARY"/>
<result column="password_salt" property="passwordSalt" jdbcType="BINARY"/> <result column="password_salt" property="passwordSalt" jdbcType="BINARY"/>
<result column="password_date" property="passwordDate" jdbcType="TIMESTAMP"/> <result column="password_date" property="passwordDate" jdbcType="TIMESTAMP"/>
@@ -57,17 +58,24 @@
<!-- Select all usernames --> <!-- Select all usernames -->
<select id="selectIdentifiers" resultType="string"> <select id="selectIdentifiers" resultType="string">
SELECT username SELECT name
FROM guacamole_user FROM guacamole_entity
WHERE guacamole_entity.type = 'USER'
</select> </select>
<!-- Select usernames of all readable users --> <!-- Select usernames of all readable users -->
<select id="selectReadableIdentifiers" resultType="string"> <select id="selectReadableIdentifiers" resultType="string">
SELECT username SELECT guacamole_entity.name
FROM guacamole_user FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
WHERE WHERE
guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND guacamole_entity.type = 'USER'
AND permission = 'READ' AND permission = 'READ'
</select> </select>
@@ -77,7 +85,8 @@
SELECT SELECT
guacamole_user.user_id, guacamole_user.user_id,
guacamole_user.username, guacamole_entity.entity_id,
guacamole_entity.name,
password_hash, password_hash,
password_salt, password_salt,
password_date, password_date,
@@ -94,13 +103,15 @@
organizational_role, organizational_role,
MAX(start_date) AS last_active MAX(start_date) AS last_active
FROM guacamole_user FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
WHERE guacamole_user.username IN WHERE guacamole_entity.name IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
GROUP BY guacamole_user.user_id; AND guacamole_entity.type = 'USER'
GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
SELECT SELECT
guacamole_user_attribute.user_id, guacamole_user_attribute.user_id,
@@ -108,11 +119,13 @@
guacamole_user_attribute.attribute_value guacamole_user_attribute.attribute_value
FROM guacamole_user_attribute FROM guacamole_user_attribute
JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
WHERE username IN JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE guacamole_entity.name IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach>; </foreach>
AND guacamole_entity.type = 'USER';
</select> </select>
@@ -122,7 +135,8 @@
SELECT SELECT
guacamole_user.user_id, guacamole_user.user_id,
guacamole_user.username, guacamole_entity.entity_id,
guacamole_entity.name,
password_hash, password_hash,
password_salt, password_salt,
password_date, password_date,
@@ -139,16 +153,22 @@
organizational_role, organizational_role,
MAX(start_date) AS last_active MAX(start_date) AS last_active
FROM guacamole_user FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
WHERE guacamole_user.username IN WHERE guacamole_entity.name IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} AND guacamole_entity.type = 'USER'
AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ' AND permission = 'READ'
GROUP BY guacamole_user.user_id; GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
SELECT SELECT
guacamole_user_attribute.user_id, guacamole_user_attribute.user_id,
@@ -156,13 +176,19 @@
guacamole_user_attribute.attribute_value guacamole_user_attribute.attribute_value
FROM guacamole_user_attribute FROM guacamole_user_attribute
JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
WHERE username IN WHERE guacamole_entity.name IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} AND guacamole_entity.type = 'USER'
AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ'; AND permission = 'READ';
</select> </select>
@@ -173,7 +199,8 @@
SELECT SELECT
guacamole_user.user_id, guacamole_user.user_id,
guacamole_user.username, guacamole_entity.entity_id,
guacamole_entity.name,
password_hash, password_hash,
password_salt, password_salt,
password_date, password_date,
@@ -190,10 +217,12 @@
organizational_role, organizational_role,
MAX(start_date) AS last_active MAX(start_date) AS last_active
FROM guacamole_user FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
WHERE WHERE
guacamole_user.username = #{username,jdbcType=VARCHAR} guacamole_entity.name = #{username,jdbcType=VARCHAR}
GROUP BY guacamole_user.user_id; AND guacamole_entity.type = 'USER'
GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
SELECT SELECT
guacamole_user_attribute.user_id, guacamole_user_attribute.user_id,
@@ -201,14 +230,19 @@
guacamole_user_attribute.attribute_value guacamole_user_attribute.attribute_value
FROM guacamole_user_attribute FROM guacamole_user_attribute
JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
WHERE username = #{username,jdbcType=VARCHAR}; JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
guacamole_entity.name = #{username,jdbcType=VARCHAR}
AND guacamole_entity.type = 'USER'
</select> </select>
<!-- Delete single user by username --> <!-- Delete single user by username -->
<delete id="delete"> <delete id="delete">
DELETE FROM guacamole_user DELETE FROM guacamole_entity
WHERE username = #{identifier,jdbcType=VARCHAR} WHERE
name = #{identifier,jdbcType=VARCHAR}
AND type = 'USER'
</delete> </delete>
<!-- Insert single user --> <!-- Insert single user -->
@@ -216,7 +250,7 @@
parameterType="org.apache.guacamole.auth.jdbc.user.UserModel"> parameterType="org.apache.guacamole.auth.jdbc.user.UserModel">
INSERT INTO guacamole_user ( INSERT INTO guacamole_user (
username, entity_id,
password_hash, password_hash,
password_salt, password_salt,
password_date, password_date,
@@ -233,7 +267,7 @@
organizational_role organizational_role
) )
VALUES ( VALUES (
#{object.identifier,jdbcType=VARCHAR}, #{object.entityID,jdbcType=VARCHAR},
#{object.passwordHash,jdbcType=BINARY}, #{object.passwordHash,jdbcType=BINARY},
#{object.passwordSalt,jdbcType=BINARY}, #{object.passwordSalt,jdbcType=BINARY},
#{object.passwordDate,jdbcType=TIMESTAMP}, #{object.passwordDate,jdbcType=TIMESTAMP},

View File

@@ -0,0 +1,96 @@
<?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" >
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<mapper namespace="org.apache.guacamole.auth.jdbc.user.UserParentUserGroupMapper" >
<!-- Select the names of all parent user groups -->
<select id="selectChildIdentifiers" resultType="string">
SELECT name
FROM guacamole_user_group_member
JOIN guacamole_user_group ON guacamole_user_group_member.user_group_id = guacamole_user_group.user_group_id
JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
WHERE
guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
AND guacamole_entity.type = 'USER_GROUP'
</select>
<!-- Select the names of all readable parent user groups -->
<select id="selectReadableChildIdentifiers" resultType="string">
SELECT guacamole_entity.name
FROM guacamole_user_group_member
JOIN guacamole_user_group ON guacamole_user_group_member.user_group_id = guacamole_user_group.user_group_id
JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
WHERE
<include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_group_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
AND guacamole_entity.type = 'USER_GROUP'
AND permission = 'READ'
</select>
<!-- Delete parent groups by name -->
<delete id="delete">
DELETE FROM guacamole_user_group_member
USING guacamole_user_group_member
JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
WHERE
member_entity_id = #{parent.entityID,jdbcType=INTEGER}
AND guacamole_entity.type = 'USER_GROUP'
AND guacamole_entity.name IN
<foreach collection="children" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
</delete>
<!-- Insert parent groups by name -->
<insert id="insert">
INSERT INTO guacamole_user_group_member (
user_group_id,
member_entity_id
)
SELECT DISTINCT
guacamole_user_group.user_group_id,
#{parent.entityID,jdbcType=INTEGER}
FROM guacamole_user_group
JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
WHERE
guacamole_entity.name IN
<foreach collection="children" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND guacamole_entity.type = 'USER_GROUP'
AND guacamole_user_group.user_group_id NOT IN (
SELECT guacamole_user_group_member.user_group_id
FROM guacamole_user_group_member
WHERE guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
)
</insert>
</mapper>

View File

@@ -44,8 +44,9 @@
guacamole_user_history.end_date guacamole_user_history.end_date
FROM guacamole_user_history FROM guacamole_user_history
JOIN guacamole_user ON guacamole_user_history.user_id = guacamole_user.user_id JOIN guacamole_user ON guacamole_user_history.user_id = guacamole_user.user_id
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
guacamole_user.username = #{username,jdbcType=VARCHAR} guacamole_entity.name = #{username,jdbcType=VARCHAR}
ORDER BY ORDER BY
guacamole_user_history.start_date DESC, guacamole_user_history.start_date DESC,
guacamole_user_history.end_date DESC guacamole_user_history.end_date DESC
@@ -66,7 +67,10 @@
VALUES ( VALUES (
#{record.remoteHost,jdbcType=VARCHAR}, #{record.remoteHost,jdbcType=VARCHAR},
(SELECT user_id FROM guacamole_user (SELECT user_id FROM guacamole_user
WHERE username = #{record.username,jdbcType=VARCHAR}), JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
guacamole_entity.name = #{record.username,jdbcType=VARCHAR}
AND guacamole_entity.type = 'USER'),
#{record.username,jdbcType=VARCHAR}, #{record.username,jdbcType=VARCHAR},
#{record.startDate,jdbcType=TIMESTAMP}, #{record.startDate,jdbcType=TIMESTAMP},
#{record.endDate,jdbcType=TIMESTAMP} #{record.endDate,jdbcType=TIMESTAMP}
@@ -79,7 +83,10 @@
UPDATE guacamole_user_history UPDATE guacamole_user_history
SET remote_host = #{record.remoteHost,jdbcType=VARCHAR}, SET remote_host = #{record.remoteHost,jdbcType=VARCHAR},
user_id = (SELECT user_id FROM guacamole_user user_id = (SELECT user_id FROM guacamole_user
WHERE username = #{record.username,jdbcType=VARCHAR}), JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
guacamole_entity.name = #{record.username,jdbcType=VARCHAR}
AND guacamole_entity.type = 'USER'),
username = #{record.username,jdbcType=VARCHAR}, username = #{record.username,jdbcType=VARCHAR},
start_date = #{record.startDate,jdbcType=TIMESTAMP}, start_date = #{record.startDate,jdbcType=TIMESTAMP},
end_date = #{record.endDate,jdbcType=TIMESTAMP} end_date = #{record.endDate,jdbcType=TIMESTAMP}
@@ -105,7 +112,10 @@
guacamole_user_history.user_id IN ( guacamole_user_history.user_id IN (
SELECT user_id SELECT user_id
FROM guacamole_user FROM guacamole_user
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0 JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'),
) )
<if test="term.startDate != null and term.endDate != null"> <if test="term.startDate != null and term.endDate != null">
@@ -146,7 +156,11 @@
<!-- Restrict to readable users --> <!-- Restrict to readable users -->
JOIN guacamole_user_permission ON JOIN guacamole_user_permission ON
guacamole_user_history.user_id = guacamole_user_permission.affected_user_id guacamole_user_history.user_id = guacamole_user_permission.affected_user_id
AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND guacamole_user_permission.permission = 'READ' AND guacamole_user_permission.permission = 'READ'
<!-- Search terms --> <!-- Search terms -->
@@ -157,7 +171,10 @@
guacamole_user_history.user_id IN ( guacamole_user_history.user_id IN (
SELECT user_id SELECT user_id
FROM guacamole_user FROM guacamole_user
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0 JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'
) )
<if test="term.startDate != null and term.endDate != null"> <if test="term.startDate != null and term.endDate != null">

View File

@@ -0,0 +1,229 @@
<?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" >
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupMapper" >
<!-- Result mapper for user group objects -->
<resultMap id="UserGroupResultMap" type="org.apache.guacamole.auth.jdbc.usergroup.UserGroupModel" >
<!-- User group properties -->
<id column="user_group_id" property="objectID" jdbcType="INTEGER"/>
<result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="name" property="identifier" jdbcType="VARCHAR"/>
<result column="disabled" property="disabled" jdbcType="BOOLEAN"/>
<!-- Arbitrary attributes -->
<collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
column="user_group_id" foreignColumn="user_group_id">
<result property="name" column="attribute_name" jdbcType="VARCHAR"/>
<result property="value" column="attribute_value" jdbcType="VARCHAR"/>
</collection>
</resultMap>
<!-- Select all group names -->
<select id="selectIdentifiers" resultType="string">
SELECT name
FROM guacamole_entity
WHERE guacamole_entity.type = 'USER_GROUP'
</select>
<!-- Select names of all readable groups -->
<select id="selectReadableIdentifiers" resultType="string">
SELECT guacamole_entity.name
FROM guacamole_user_group
JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
WHERE
<include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_group_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND guacamole_entity.type = 'USER_GROUP'
AND permission = 'READ'
</select>
<!-- Select multiple groups by name -->
<select id="select" resultMap="UserGroupResultMap"
resultSets="users,arbitraryAttributes">
SELECT
guacamole_user_group.user_group_id,
guacamole_entity.entity_id,
guacamole_entity.name,
disabled
FROM guacamole_user_group
JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
WHERE guacamole_entity.name IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND guacamole_entity.type = 'USER_GROUP';
SELECT
guacamole_user_group_attribute.user_group_id,
guacamole_user_group_attribute.attribute_name,
guacamole_user_group_attribute.attribute_value
FROM guacamole_user_group_attribute
JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_attribute.user_group_id
JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
WHERE guacamole_entity.name IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND guacamole_entity.type = 'USER_GROUP';
</select>
<!-- Select multiple groups by name only if readable -->
<select id="selectReadable" resultMap="UserGroupResultMap"
resultSets="users,arbitraryAttributes">
SELECT
guacamole_user_group.user_group_id,
guacamole_entity.entity_id,
guacamole_entity.name,
disabled
FROM guacamole_user_group
JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
WHERE guacamole_entity.name IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND guacamole_entity.type = 'USER_GROUP'
AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_group_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ';
SELECT
guacamole_user_group_attribute.user_group_id,
guacamole_user_group_attribute.attribute_name,
guacamole_user_group_attribute.attribute_value
FROM guacamole_user_group_attribute
JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_attribute.user_group_id
JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
WHERE guacamole_entity.name IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND guacamole_entity.type = 'USER_GROUP'
AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_group_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ';
</select>
<!-- Select single group by name -->
<select id="selectOne" resultMap="UserGroupResultMap"
resultSets="users,arbitraryAttributes">
SELECT
guacamole_user_group.user_group_id,
guacamole_entity.entity_id,
guacamole_entity.name,
disabled
FROM guacamole_user_group
JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
WHERE
guacamole_entity.name = #{name,jdbcType=VARCHAR}
AND guacamole_entity.type = 'USER_GROUP';
SELECT
guacamole_user_group_attribute.user_group_id,
guacamole_user_group_attribute.attribute_name,
guacamole_user_group_attribute.attribute_value
FROM guacamole_user_group_attribute
JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_attribute.user_group_id
JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
WHERE
guacamole_entity.name = #{name,jdbcType=VARCHAR}
AND guacamole_entity.type = 'USER_GROUP'
</select>
<!-- Delete single group by name -->
<delete id="delete">
DELETE FROM guacamole_entity
WHERE
name = #{identifier,jdbcType=VARCHAR}
AND type = 'USER_GROUP'
</delete>
<!-- Insert single group -->
<insert id="insert" useGeneratedKeys="true" keyProperty="object.objectID"
parameterType="org.apache.guacamole.auth.jdbc.usergroup.UserGroupModel">
INSERT INTO guacamole_user_group (
entity_id,
disabled
)
VALUES (
#{object.entityID,jdbcType=VARCHAR},
#{object.disabled,jdbcType=BOOLEAN}
)
</insert>
<!-- Update single group -->
<update id="update" parameterType="org.apache.guacamole.auth.jdbc.usergroup.UserGroupModel">
UPDATE guacamole_user_group
SET disabled = #{object.disabled,jdbcType=BOOLEAN}
WHERE user_group_id = #{object.objectID,jdbcType=VARCHAR}
</update>
<!-- Delete attributes associated with group -->
<delete id="deleteAttributes">
DELETE FROM guacamole_user_group_attribute
WHERE user_group_id = #{object.objectID,jdbcType=INTEGER}
</delete>
<!-- Insert attributes for group -->
<insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
INSERT INTO guacamole_user_group_attribute (
user_group_id,
attribute_name,
attribute_value
)
VALUES
<foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
(#{object.objectID,jdbcType=INTEGER},
#{attribute.name,jdbcType=VARCHAR},
#{attribute.value,jdbcType=VARCHAR})
</foreach>
</insert>
</mapper>

View File

@@ -0,0 +1,93 @@
<?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" >
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserGroupMapper" >
<!-- Select the names of all member user groups -->
<select id="selectChildIdentifiers" resultType="string">
SELECT name
FROM guacamole_user_group_member
JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group_member.member_entity_id
WHERE
guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
AND guacamole_entity.type = 'USER_GROUP'
</select>
<!-- Select the names of all readable member user groups -->
<select id="selectReadableChildIdentifiers" resultType="string">
SELECT guacamole_entity.name
FROM guacamole_user_group_member
JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group_member.member_entity_id
JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id
JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
WHERE
<include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_group_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
AND guacamole_entity.type = 'USER_GROUP'
AND permission = 'READ'
</select>
<!-- Delete member groups by name -->
<delete id="delete">
DELETE FROM guacamole_user_group_member
USING guacamole_user_group_member
JOIN guacamole_entity ON guacamole_entity.entity_id = member_entity_id
WHERE
user_group_id = #{parent.objectID,jdbcType=INTEGER}
AND guacamole_entity.type = 'USER_GROUP'
AND guacamole_entity.name IN
<foreach collection="children" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
</delete>
<!-- Insert member groups by name -->
<insert id="insert">
INSERT INTO guacamole_user_group_member (
user_group_id,
member_entity_id
)
SELECT DISTINCT
#{parent.objectID,jdbcType=INTEGER},
guacamole_entity.entity_id
FROM guacamole_entity
WHERE
guacamole_entity.name IN
<foreach collection="children" item="identifier"
open="(" separator="," close=")">
#{identifier}
</foreach>
AND guacamole_entity.type = 'USER_GROUP'
AND guacamole_entity.entity_id NOT IN (
SELECT guacamole_user_group_member.member_entity_id
FROM guacamole_user_group_member
WHERE guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
)
</insert>
</mapper>

View File

@@ -0,0 +1,93 @@
<?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" >
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserMapper" >
<!-- Select the username of all member users -->
<select id="selectChildIdentifiers" resultType="string">
SELECT name
FROM guacamole_user_group_member
JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group_member.member_entity_id
WHERE
guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
AND guacamole_entity.type = 'USER'
</select>
<!-- Select the usernames of all readable member users -->
<select id="selectReadableChildIdentifiers" resultType="string">
SELECT guacamole_entity.name
FROM guacamole_user_group_member
JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group_member.member_entity_id
JOIN guacamole_user ON guacamole_user.entity_id = guacamole_entity.entity_id
JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
WHERE
<include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
AND guacamole_entity.type = 'USER'
AND permission = 'READ'
</select>
<!-- Delete member users by name -->
<delete id="delete">
DELETE FROM guacamole_user_group_member
USING guacamole_user_group_member
JOIN guacamole_entity ON guacamole_entity.entity_id = member_entity_id
WHERE
user_group_id = #{parent.objectID,jdbcType=INTEGER}
AND guacamole_entity.type = 'USER'
AND guacamole_entity.name IN
<foreach collection="children" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
</delete>
<!-- Insert member users by name -->
<insert id="insert">
INSERT INTO guacamole_user_group_member (
user_group_id,
member_entity_id
)
SELECT DISTINCT
#{parent.objectID,jdbcType=INTEGER},
guacamole_entity.entity_id
FROM guacamole_entity
WHERE
guacamole_entity.name IN
<foreach collection="children" item="identifier"
open="(" separator="," close=")">
#{identifier}
</foreach>
AND guacamole_entity.type = 'USER'
AND guacamole_entity.entity_id NOT IN (
SELECT guacamole_user_group_member.member_entity_id
FROM guacamole_user_group_member
WHERE guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
)
</insert>
</mapper>

View File

@@ -0,0 +1,96 @@
<?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" >
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupParentUserGroupMapper" >
<!-- Select the names of all parent user groups -->
<select id="selectChildIdentifiers" resultType="string">
SELECT name
FROM guacamole_user_group_member
JOIN guacamole_user_group ON guacamole_user_group_member.user_group_id = guacamole_user_group.user_group_id
JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
WHERE
guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
AND guacamole_entity.type = 'USER_GROUP'
</select>
<!-- Select the names of all readable parent user groups -->
<select id="selectReadableChildIdentifiers" resultType="string">
SELECT guacamole_entity.name
FROM guacamole_user_group_member
JOIN guacamole_user_group ON guacamole_user_group_member.user_group_id = guacamole_user_group.user_group_id
JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
WHERE
<include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_group_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
AND guacamole_entity.type = 'USER_GROUP'
AND permission = 'READ'
</select>
<!-- Delete parent groups by name -->
<delete id="delete">
DELETE FROM guacamole_user_group_member
USING guacamole_user_group_member
JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
WHERE
member_entity_id = #{parent.entityID,jdbcType=INTEGER}
AND guacamole_entity.type = 'USER_GROUP'
AND guacamole_entity.name IN
<foreach collection="children" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
</delete>
<!-- Insert parent groups by name -->
<insert id="insert">
INSERT INTO guacamole_user_group_member (
user_group_id,
member_entity_id
)
SELECT DISTINCT
guacamole_user_group.user_group_id,
#{parent.entityID,jdbcType=INTEGER}
FROM guacamole_user_group
JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
WHERE
guacamole_entity.name IN
<foreach collection="children" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND guacamole_entity.type = 'USER_GROUP'
AND guacamole_user_group.user_group_id NOT IN (
SELECT guacamole_user_group_member.user_group_id
FROM guacamole_user_group_member
WHERE guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
)
</insert>
</mapper>

View File

@@ -26,6 +26,15 @@ CREATE TYPE guacamole_connection_group_type AS ENUM(
'BALANCING' 'BALANCING'
); );
--
-- Entity types
--
CREATE TYPE guacamole_entity_type AS ENUM(
'USER',
'USER_GROUP'
);
-- --
-- Object permission types -- Object permission types
-- --
@@ -46,6 +55,7 @@ CREATE TYPE guacamole_system_permission_type AS ENUM(
'CREATE_CONNECTION_GROUP', 'CREATE_CONNECTION_GROUP',
'CREATE_SHARING_PROFILE', 'CREATE_SHARING_PROFILE',
'CREATE_USER', 'CREATE_USER',
'CREATE_USER_GROUP',
'ADMINISTER' 'ADMINISTER'
); );
@@ -131,6 +141,26 @@ CREATE TABLE guacamole_connection (
CREATE INDEX guacamole_connection_parent_id CREATE INDEX guacamole_connection_parent_id
ON guacamole_connection(parent_id); ON guacamole_connection(parent_id);
--
-- Table of base entities which may each be either a user or user group. Other
-- tables which represent qualities shared by both users and groups will point
-- to guacamole_entity, while tables which represent qualities specific to
-- users or groups will point to guacamole_user or guacamole_user_group.
--
CREATE TABLE guacamole_entity (
entity_id serial NOT NULL,
name varchar(128) NOT NULL,
type guacamole_entity_type NOT NULL,
PRIMARY KEY (entity_id),
CONSTRAINT guacamole_entity_name_scope
UNIQUE (type, name)
);
-- --
-- Table of users. Each user has a unique username and a hashed password -- Table of users. Each user has a unique username and a hashed password
-- with corresponding salt. Although the authentication system will always set -- with corresponding salt. Although the authentication system will always set
@@ -141,9 +171,9 @@ CREATE INDEX guacamole_connection_parent_id
CREATE TABLE guacamole_user ( CREATE TABLE guacamole_user (
user_id serial NOT NULL, user_id serial NOT NULL,
entity_id integer NOT NULL,
-- Username and optionally-salted password -- Optionally-salted password
username varchar(128) NOT NULL,
password_hash bytea NOT NULL, password_hash bytea NOT NULL,
password_salt bytea, password_salt bytea,
password_date timestamptz NOT NULL, password_date timestamptz NOT NULL,
@@ -171,8 +201,62 @@ CREATE TABLE guacamole_user (
PRIMARY KEY (user_id), PRIMARY KEY (user_id),
CONSTRAINT username CONSTRAINT guacamole_user_single_entity
UNIQUE (username) UNIQUE (entity_id),
CONSTRAINT guacamole_user_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id)
ON DELETE CASCADE
);
--
-- Table of user groups. Each user group may have an arbitrary set of member
-- users and member groups, with those members inheriting the permissions
-- granted to that group.
--
CREATE TABLE guacamole_user_group (
user_group_id serial NOT NULL,
entity_id integer NOT NULL,
-- Group disabled status
disabled boolean NOT NULL DEFAULT FALSE,
PRIMARY KEY (user_group_id),
CONSTRAINT guacamole_user_group_single_entity
UNIQUE (entity_id),
CONSTRAINT guacamole_user_group_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id)
ON DELETE CASCADE
);
--
-- Table of users which are members of given user groups.
--
CREATE TABLE guacamole_user_group_member (
user_group_id integer NOT NULL,
member_entity_id integer NOT NULL,
PRIMARY KEY (user_group_id, member_entity_id),
-- Parent must be a user group
CONSTRAINT guacamole_user_group_member_parent
FOREIGN KEY (user_group_id)
REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE,
-- Member may be either a user or a user group (any entity)
CONSTRAINT guacamole_user_group_member_entity
FOREIGN KEY (member_entity_id)
REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
); );
@@ -275,6 +359,30 @@ CREATE TABLE guacamole_user_attribute (
CREATE INDEX guacamole_user_attribute_user_id CREATE INDEX guacamole_user_attribute_user_id
ON guacamole_user_attribute(user_id); ON guacamole_user_attribute(user_id);
--
-- Table of arbitrary user group attributes. Each attribute is simply a
-- name/value pair associated with a user group. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_user_group_attribute (
user_group_id integer NOT NULL,
attribute_name varchar(128) NOT NULL,
attribute_value varchar(4096) NOT NULL,
PRIMARY KEY (user_group_id, attribute_name),
CONSTRAINT guacamole_user_group_attribute_ibfk_1
FOREIGN KEY (user_group_id)
REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_user_group_attribute_user_group_id
ON guacamole_user_group_attribute(user_group_id);
-- --
-- Table of arbitrary connection attributes. Each attribute is simply a -- Table of arbitrary connection attributes. Each attribute is simply a
-- name/value pair associated with a connection. Arbitrary attributes are -- name/value pair associated with a connection. Arbitrary attributes are
@@ -348,141 +456,172 @@ CREATE INDEX guacamole_sharing_profile_attribute_sharing_profile_id
ON guacamole_sharing_profile_attribute(sharing_profile_id); ON guacamole_sharing_profile_attribute(sharing_profile_id);
-- --
-- Table of connection permissions. Each connection permission grants a user -- Table of connection permissions. Each connection permission grants a user or
-- specific access to a connection. -- user group specific access to a connection.
-- --
CREATE TABLE guacamole_connection_permission ( CREATE TABLE guacamole_connection_permission (
user_id integer NOT NULL, entity_id integer NOT NULL,
connection_id integer NOT NULL, connection_id integer NOT NULL,
permission guacamole_object_permission_type NOT NULL, permission guacamole_object_permission_type NOT NULL,
PRIMARY KEY (user_id,connection_id,permission), PRIMARY KEY (entity_id, connection_id, permission),
CONSTRAINT guacamole_connection_permission_ibfk_1 CONSTRAINT guacamole_connection_permission_ibfk_1
FOREIGN KEY (connection_id) FOREIGN KEY (connection_id)
REFERENCES guacamole_connection (connection_id) ON DELETE CASCADE, REFERENCES guacamole_connection (connection_id) ON DELETE CASCADE,
CONSTRAINT guacamole_connection_permission_ibfk_2 CONSTRAINT guacamole_connection_permission_entity
FOREIGN KEY (user_id) FOREIGN KEY (entity_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
); );
CREATE INDEX guacamole_connection_permission_connection_id CREATE INDEX guacamole_connection_permission_connection_id
ON guacamole_connection_permission(connection_id); ON guacamole_connection_permission(connection_id);
CREATE INDEX guacamole_connection_permission_user_id CREATE INDEX guacamole_connection_permission_entity_id
ON guacamole_connection_permission(user_id); ON guacamole_connection_permission(entity_id);
-- --
-- Table of connection group permissions. Each group permission grants a user -- Table of connection group permissions. Each group permission grants a user
-- specific access to a connection group. -- or user group specific access to a connection group.
-- --
CREATE TABLE guacamole_connection_group_permission ( CREATE TABLE guacamole_connection_group_permission (
user_id integer NOT NULL, entity_id integer NOT NULL,
connection_group_id integer NOT NULL, connection_group_id integer NOT NULL,
permission guacamole_object_permission_type NOT NULL, permission guacamole_object_permission_type NOT NULL,
PRIMARY KEY (user_id,connection_group_id,permission), PRIMARY KEY (entity_id, connection_group_id, permission),
CONSTRAINT guacamole_connection_group_permission_ibfk_1 CONSTRAINT guacamole_connection_group_permission_ibfk_1
FOREIGN KEY (connection_group_id) FOREIGN KEY (connection_group_id)
REFERENCES guacamole_connection_group (connection_group_id) ON DELETE CASCADE, REFERENCES guacamole_connection_group (connection_group_id) ON DELETE CASCADE,
CONSTRAINT guacamole_connection_group_permission_ibfk_2 CONSTRAINT guacamole_connection_group_permission_entity
FOREIGN KEY (user_id) FOREIGN KEY (entity_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
); );
CREATE INDEX guacamole_connection_group_permission_connection_group_id CREATE INDEX guacamole_connection_group_permission_connection_group_id
ON guacamole_connection_group_permission(connection_group_id); ON guacamole_connection_group_permission(connection_group_id);
CREATE INDEX guacamole_connection_group_permission_user_id CREATE INDEX guacamole_connection_group_permission_entity_id
ON guacamole_connection_group_permission(user_id); ON guacamole_connection_group_permission(entity_id);
-- --
-- Table of sharing profile permissions. Each sharing profile permission grants -- Table of sharing profile permissions. Each sharing profile permission grants
-- a user specific access to a sharing profile. -- a user or user group specific access to a sharing profile.
-- --
CREATE TABLE guacamole_sharing_profile_permission ( CREATE TABLE guacamole_sharing_profile_permission (
user_id integer NOT NULL, entity_id integer NOT NULL,
sharing_profile_id integer NOT NULL, sharing_profile_id integer NOT NULL,
permission guacamole_object_permission_type NOT NULL, permission guacamole_object_permission_type NOT NULL,
PRIMARY KEY (user_id,sharing_profile_id,permission), PRIMARY KEY (entity_id, sharing_profile_id, permission),
CONSTRAINT guacamole_sharing_profile_permission_ibfk_1 CONSTRAINT guacamole_sharing_profile_permission_ibfk_1
FOREIGN KEY (sharing_profile_id) FOREIGN KEY (sharing_profile_id)
REFERENCES guacamole_sharing_profile (sharing_profile_id) ON DELETE CASCADE, REFERENCES guacamole_sharing_profile (sharing_profile_id) ON DELETE CASCADE,
CONSTRAINT guacamole_sharing_profile_permission_ibfk_2 CONSTRAINT guacamole_sharing_profile_permission_entity
FOREIGN KEY (user_id) FOREIGN KEY (entity_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
); );
CREATE INDEX guacamole_sharing_profile_permission_sharing_profile_id CREATE INDEX guacamole_sharing_profile_permission_sharing_profile_id
ON guacamole_sharing_profile_permission(sharing_profile_id); ON guacamole_sharing_profile_permission(sharing_profile_id);
CREATE INDEX guacamole_sharing_profile_permission_user_id CREATE INDEX guacamole_sharing_profile_permission_entity_id
ON guacamole_sharing_profile_permission(user_id); ON guacamole_sharing_profile_permission(entity_id);
-- --
-- Table of system permissions. Each system permission grants a user a -- Table of system permissions. Each system permission grants a user or user
-- system-level privilege of some kind. -- group a system-level privilege of some kind.
-- --
CREATE TABLE guacamole_system_permission ( CREATE TABLE guacamole_system_permission (
user_id integer NOT NULL, entity_id integer NOT NULL,
permission guacamole_system_permission_type NOT NULL, permission guacamole_system_permission_type NOT NULL,
PRIMARY KEY (user_id,permission), PRIMARY KEY (entity_id, permission),
CONSTRAINT guacamole_system_permission_ibfk_1 CONSTRAINT guacamole_system_permission_entity
FOREIGN KEY (user_id) FOREIGN KEY (entity_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
); );
CREATE INDEX guacamole_system_permission_user_id CREATE INDEX guacamole_system_permission_entity_id
ON guacamole_system_permission(user_id); ON guacamole_system_permission(entity_id);
-- --
-- Table of user permissions. Each user permission grants a user access to -- Table of user permissions. Each user permission grants a user or user group
-- another user (the "affected" user) for a specific type of operation. -- access to another user (the "affected" user) for a specific type of
-- operation.
-- --
CREATE TABLE guacamole_user_permission ( CREATE TABLE guacamole_user_permission (
user_id integer NOT NULL, entity_id integer NOT NULL,
affected_user_id integer NOT NULL, affected_user_id integer NOT NULL,
permission guacamole_object_permission_type NOT NULL, permission guacamole_object_permission_type NOT NULL,
PRIMARY KEY (user_id,affected_user_id,permission), PRIMARY KEY (entity_id, affected_user_id, permission),
CONSTRAINT guacamole_user_permission_ibfk_1 CONSTRAINT guacamole_user_permission_ibfk_1
FOREIGN KEY (affected_user_id) FOREIGN KEY (affected_user_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE, REFERENCES guacamole_user (user_id) ON DELETE CASCADE,
CONSTRAINT guacamole_user_permission_ibfk_2 CONSTRAINT guacamole_user_permission_entity
FOREIGN KEY (user_id) FOREIGN KEY (entity_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
); );
CREATE INDEX guacamole_user_permission_affected_user_id CREATE INDEX guacamole_user_permission_affected_user_id
ON guacamole_user_permission(affected_user_id); ON guacamole_user_permission(affected_user_id);
CREATE INDEX guacamole_user_permission_user_id CREATE INDEX guacamole_user_permission_entity_id
ON guacamole_user_permission(user_id); ON guacamole_user_permission(entity_id);
--
-- Table of user group permissions. Each user group permission grants a user
-- or user group access to a another user group (the "affected" user group) for
-- a specific type of operation.
--
CREATE TABLE guacamole_user_group_permission (
entity_id integer NOT NULL,
affected_user_group_id integer NOT NULL,
permission guacamole_object_permission_type NOT NULL,
PRIMARY KEY (entity_id, affected_user_group_id, permission),
CONSTRAINT guacamole_user_group_permission_affected_user_group
FOREIGN KEY (affected_user_group_id)
REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE,
CONSTRAINT guacamole_user_group_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_user_group_permission_affected_user_group_id
ON guacamole_user_group_permission(affected_user_group_id);
CREATE INDEX guacamole_user_group_permission_entity_id
ON guacamole_user_group_permission(entity_id);
-- --
-- Table of connection history records. Each record defines a specific user's -- Table of connection history records. Each record defines a specific user's

View File

@@ -17,36 +17,39 @@
-- under the License. -- under the License.
-- --
-- Create default user "guacadmin" with password "guacadmin" -- Create default user "guacadmin" with password "guacadmin"
INSERT INTO guacamole_user (username, password_hash, password_salt, password_date) INSERT INTO guacamole_entity (name, type) VALUES ('guacadmin', 'USER');
VALUES ('guacadmin', INSERT INTO guacamole_user (entity_id, password_hash, password_salt, password_date)
SELECT
entity_id,
decode('CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', 'hex'), -- 'guacadmin' decode('CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', 'hex'), -- 'guacadmin'
decode('FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264', 'hex'), decode('FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264', 'hex'),
CURRENT_TIMESTAMP); CURRENT_TIMESTAMP
FROM guacamole_entity WHERE name = 'guacadmin' AND guacamole_entity.type = 'USER';
-- Grant this user all system permissions -- Grant this user all system permissions
INSERT INTO guacamole_system_permission INSERT INTO guacamole_system_permission (entity_id, permission)
SELECT user_id, permission::guacamole_system_permission_type SELECT entity_id, permission::guacamole_system_permission_type
FROM ( FROM (
VALUES VALUES
('guacadmin', 'CREATE_CONNECTION'), ('guacadmin', 'CREATE_CONNECTION'),
('guacadmin', 'CREATE_CONNECTION_GROUP'), ('guacadmin', 'CREATE_CONNECTION_GROUP'),
('guacadmin', 'CREATE_SHARING_PROFILE'), ('guacadmin', 'CREATE_SHARING_PROFILE'),
('guacadmin', 'CREATE_USER'), ('guacadmin', 'CREATE_USER'),
('guacadmin', 'CREATE_USER_GROUP'),
('guacadmin', 'ADMINISTER') ('guacadmin', 'ADMINISTER')
) permissions (username, permission) ) permissions (username, permission)
JOIN guacamole_user ON permissions.username = guacamole_user.username; JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER';
-- Grant admin permission to read/update/administer self -- Grant admin permission to read/update/administer self
INSERT INTO guacamole_user_permission INSERT INTO guacamole_user_permission (entity_id, affected_user_id, permission)
SELECT guacamole_user.user_id, affected.user_id, permission::guacamole_object_permission_type SELECT guacamole_entity.entity_id, guacamole_user.user_id, permission::guacamole_object_permission_type
FROM ( FROM (
VALUES VALUES
('guacadmin', 'guacadmin', 'READ'), ('guacadmin', 'guacadmin', 'READ'),
('guacadmin', 'guacadmin', 'UPDATE'), ('guacadmin', 'guacadmin', 'UPDATE'),
('guacadmin', 'guacadmin', 'ADMINISTER') ('guacadmin', 'guacadmin', 'ADMINISTER')
) permissions (username, affected_username, permission) ) permissions (username, affected_username, permission)
JOIN guacamole_user ON permissions.username = guacamole_user.username JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER'
JOIN guacamole_user affected ON permissions.affected_username = affected.username; JOIN guacamole_entity affected ON permissions.affected_username = affected.name AND guacamole_entity.type = 'USER'
JOIN guacamole_user ON guacamole_user.entity_id = affected.entity_id;

View File

@@ -17,6 +17,339 @@
-- under the License. -- under the License.
-- --
--
-- Add new system-level permission
--
ALTER TYPE guacamole_system_permission_type
ADD VALUE 'CREATE_USER_GROUP'
AFTER 'CREATE_USER';
--
-- Entity types
--
CREATE TYPE guacamole_entity_type AS ENUM(
'USER',
'USER_GROUP'
);
--
-- Table of base entities which may each be either a user or user group. Other
-- tables which represent qualities shared by both users and groups will point
-- to guacamole_entity, while tables which represent qualities specific to
-- users or groups will point to guacamole_user or guacamole_user_group.
--
CREATE TABLE guacamole_entity (
entity_id serial NOT NULL,
name varchar(128) NOT NULL,
type guacamole_entity_type NOT NULL,
PRIMARY KEY (entity_id),
CONSTRAINT guacamole_entity_name_scope
UNIQUE (type, name)
);
--
-- Table of user groups. Each user group may have an arbitrary set of member
-- users and member groups, with those members inheriting the permissions
-- granted to that group.
--
CREATE TABLE guacamole_user_group (
user_group_id serial NOT NULL,
entity_id integer NOT NULL,
-- Group disabled status
disabled boolean NOT NULL DEFAULT FALSE,
PRIMARY KEY (user_group_id),
CONSTRAINT guacamole_user_group_single_entity
UNIQUE (entity_id),
CONSTRAINT guacamole_user_group_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id)
ON DELETE CASCADE
);
--
-- Table of users which are members of given user groups.
--
CREATE TABLE guacamole_user_group_member (
user_group_id integer NOT NULL,
member_entity_id integer NOT NULL,
PRIMARY KEY (user_group_id, member_entity_id),
-- Parent must be a user group
CONSTRAINT guacamole_user_group_member_parent
FOREIGN KEY (user_group_id)
REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE,
-- Member may be either a user or a user group (any entity)
CONSTRAINT guacamole_user_group_member_entity
FOREIGN KEY (member_entity_id)
REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
);
--
-- Table of user group permissions. Each user group permission grants a user
-- access to a particular user group for a specific type of operation.
--
CREATE TABLE guacamole_user_group_permission (
entity_id integer NOT NULL,
affected_user_group_id integer NOT NULL,
permission guacamole_object_permission_type NOT NULL,
PRIMARY KEY (entity_id, affected_user_group_id, permission),
CONSTRAINT guacamole_user_group_permission_affected_user_group
FOREIGN KEY (affected_user_group_id)
REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE,
CONSTRAINT guacamole_user_group_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_user_group_permission_affected_user_group_id
ON guacamole_user_group_permission(affected_user_group_id);
CREATE INDEX guacamole_user_group_permission_entity_id
ON guacamole_user_group_permission(entity_id);
--
-- Modify guacamole_user table to use guacamole_entity as a base
--
-- Add new entity_id column
ALTER TABLE guacamole_user ADD COLUMN entity_id integer;
-- Create user entities for each guacamole_user entry
INSERT INTO guacamole_entity (name, type)
SELECT username, 'USER' FROM guacamole_user;
-- Update guacamole_user to point to corresponding guacamole_entity
UPDATE guacamole_user SET entity_id = (
SELECT entity_id FROM guacamole_entity
WHERE
username = guacamole_entity.name
AND type = 'USER'
);
-- The entity_id column should now be safely non-NULL
ALTER TABLE guacamole_user
ALTER COLUMN entity_id SET NOT NULL;
-- The entity_id column should now be unique for each user
ALTER TABLE guacamole_user
ADD CONSTRAINT guacamole_user_single_entity
UNIQUE (entity_id);
-- The entity_id column should now safely point to guacamole_entity entries
ALTER TABLE guacamole_user
ADD CONSTRAINT guacamole_user_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id)
ON DELETE CASCADE;
-- The username column can now safely be removed
ALTER TABLE guacamole_user DROP COLUMN username;
--
-- Modify guacamole_connection_permission to use guacamole_entity instead of
-- guacamole_user
--
-- Add new entity_id column
ALTER TABLE guacamole_connection_permission ADD COLUMN entity_id integer;
-- Update guacamole_connection_permission to point to the guacamole_entity
-- that has been granted the permission
UPDATE guacamole_connection_permission SET entity_id = (
SELECT entity_id FROM guacamole_user
WHERE guacamole_user.user_id = guacamole_connection_permission.user_id
);
-- The entity_id column should now be safely non-NULL
ALTER TABLE guacamole_connection_permission
ALTER COLUMN entity_id SET NOT NULL;
-- The entity_id column should now safely point to guacamole_entity entries
ALTER TABLE guacamole_connection_permission
ADD CONSTRAINT guacamole_connection_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id)
ON DELETE CASCADE;
CREATE INDEX guacamole_connection_permission_entity_id
ON guacamole_connection_permission(entity_id);
-- Remove user_id column (implicitly drops associated contraints/keys)
ALTER TABLE guacamole_connection_permission DROP COLUMN user_id;
-- Add new primary key which uses entity_id
ALTER TABLE guacamole_connection_permission
ADD PRIMARY KEY (entity_id, connection_id, permission);
--
-- Modify guacamole_connection_group_permission to use guacamole_entity instead
-- of guacamole_user
--
-- Add new entity_id column
ALTER TABLE guacamole_connection_group_permission ADD COLUMN entity_id integer;
-- Update guacamole_connection_group_permission to point to the guacamole_entity
-- that has been granted the permission
UPDATE guacamole_connection_group_permission SET entity_id = (
SELECT entity_id FROM guacamole_user
WHERE guacamole_user.user_id = guacamole_connection_group_permission.user_id
);
-- The entity_id column should now be safely non-NULL
ALTER TABLE guacamole_connection_group_permission
ALTER COLUMN entity_id SET NOT NULL;
-- The entity_id column should now safely point to guacamole_entity entries
ALTER TABLE guacamole_connection_group_permission
ADD CONSTRAINT guacamole_connection_group_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id)
ON DELETE CASCADE;
CREATE INDEX guacamole_connection_group_permission_entity_id
ON guacamole_connection_group_permission(entity_id);
-- Remove user_id column (implicitly drops associated contraints/keys)
ALTER TABLE guacamole_connection_group_permission DROP COLUMN user_id;
-- Add new primary key which uses entity_id
ALTER TABLE guacamole_connection_group_permission
ADD PRIMARY KEY (entity_id, connection_group_id, permission);
--
-- Modify guacamole_sharing_profile_permission to use guacamole_entity instead
-- of guacamole_user
--
-- Add new entity_id column
ALTER TABLE guacamole_sharing_profile_permission ADD COLUMN entity_id integer;
-- Update guacamole_sharing_profile_permission to point to the guacamole_entity
-- that has been granted the permission
UPDATE guacamole_sharing_profile_permission SET entity_id = (
SELECT entity_id FROM guacamole_user
WHERE guacamole_user.user_id = guacamole_sharing_profile_permission.user_id
);
-- The entity_id column should now be safely non-NULL
ALTER TABLE guacamole_sharing_profile_permission
ALTER COLUMN entity_id SET NOT NULL;
-- The entity_id column should now safely point to guacamole_entity entries
ALTER TABLE guacamole_sharing_profile_permission
ADD CONSTRAINT guacamole_sharing_profile_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id)
ON DELETE CASCADE;
CREATE INDEX guacamole_sharing_profile_permission_entity_id
ON guacamole_sharing_profile_permission(entity_id);
-- Remove user_id column (implicitly drops associated contraints/keys)
ALTER TABLE guacamole_sharing_profile_permission DROP COLUMN user_id;
-- Add new primary key which uses entity_id
ALTER TABLE guacamole_sharing_profile_permission
ADD PRIMARY KEY (entity_id, sharing_profile_id, permission);
--
-- Modify guacamole_user_permission to use guacamole_entity instead of
-- guacamole_user
--
-- Add new entity_id column
ALTER TABLE guacamole_user_permission ADD COLUMN entity_id integer;
-- Update guacamole_user_permission to point to the guacamole_entity
-- that has been granted the permission
UPDATE guacamole_user_permission SET entity_id = (
SELECT entity_id FROM guacamole_user
WHERE guacamole_user.user_id = guacamole_user_permission.user_id
);
-- The entity_id column should now be safely non-NULL
ALTER TABLE guacamole_user_permission
ALTER COLUMN entity_id SET NOT NULL;
-- The entity_id column should now safely point to guacamole_entity entries
ALTER TABLE guacamole_user_permission
ADD CONSTRAINT guacamole_user_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id)
ON DELETE CASCADE;
CREATE INDEX guacamole_user_permission_entity_id
ON guacamole_user_permission(entity_id);
-- Remove user_id column (implicitly drops associated contraints/keys)
ALTER TABLE guacamole_user_permission DROP COLUMN user_id;
-- Add new primary key which uses entity_id
ALTER TABLE guacamole_user_permission
ADD PRIMARY KEY (entity_id, affected_user_id, permission);
--
-- Modify guacamole_system_permission to use guacamole_entity instead of
-- guacamole_user
--
-- Add new entity_id column
ALTER TABLE guacamole_system_permission ADD COLUMN entity_id integer;
-- Update guacamole_system_permission to point to the guacamole_entity
-- that has been granted the permission
UPDATE guacamole_system_permission SET entity_id = (
SELECT entity_id FROM guacamole_user
WHERE guacamole_user.user_id = guacamole_system_permission.user_id
);
-- The entity_id column should now be safely non-NULL
ALTER TABLE guacamole_system_permission
ALTER COLUMN entity_id SET NOT NULL;
-- The entity_id column should now safely point to guacamole_entity entries
ALTER TABLE guacamole_system_permission
ADD CONSTRAINT guacamole_system_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id)
ON DELETE CASCADE;
CREATE INDEX guacamole_system_permission_entity_id
ON guacamole_system_permission(entity_id);
-- Remove user_id column (implicitly drops associated contraints/keys)
ALTER TABLE guacamole_system_permission DROP COLUMN user_id;
-- Add new primary key which uses entity_id
ALTER TABLE guacamole_system_permission
ADD PRIMARY KEY (entity_id, permission);
-- --
-- Table of arbitrary user attributes. Each attribute is simply a name/value -- Table of arbitrary user attributes. Each attribute is simply a name/value
-- pair associated with a user. Arbitrary attributes are defined by other -- pair associated with a user. Arbitrary attributes are defined by other
@@ -41,6 +374,30 @@ CREATE TABLE guacamole_user_attribute (
CREATE INDEX guacamole_user_attribute_user_id CREATE INDEX guacamole_user_attribute_user_id
ON guacamole_user_attribute(user_id); ON guacamole_user_attribute(user_id);
--
-- Table of arbitrary user group attributes. Each attribute is simply a
-- name/value pair associated with a user group. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_user_group_attribute (
user_group_id integer NOT NULL,
attribute_name varchar(128) NOT NULL,
attribute_value varchar(4096) NOT NULL,
PRIMARY KEY (user_group_id, attribute_name),
CONSTRAINT guacamole_user_group_attribute_ibfk_1
FOREIGN KEY (user_group_id)
REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_user_group_attribute_user_group_id
ON guacamole_user_group_attribute(user_group_id);
-- --
-- Table of arbitrary connection attributes. Each attribute is simply a -- Table of arbitrary connection attributes. Each attribute is simply a
-- name/value pair associated with a connection. Arbitrary attributes are -- name/value pair associated with a connection. Arbitrary attributes are

View File

@@ -24,6 +24,7 @@ import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.apache.guacamole.auth.jdbc.security.PasswordPolicy; import org.apache.guacamole.auth.jdbc.security.PasswordPolicy;
import org.apache.ibatis.session.SqlSession;
/** /**
* A PostgreSQL-specific implementation of JDBCEnvironment provides database * A PostgreSQL-specific implementation of JDBCEnvironment provides database
@@ -243,4 +244,9 @@ public class PostgreSQLEnvironment extends JDBCEnvironment {
return getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_PASSWORD); return getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_PASSWORD);
} }
@Override
public boolean isRecursiveQuerySupported(SqlSession session) {
return true; // All versions of PostgreSQL support recursive queries through CTEs
}
} }

View File

@@ -0,0 +1,123 @@
<?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" >
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<mapper namespace="org.apache.guacamole.auth.jdbc.base.EntityMapper" >
<!--
* SQL fragment which tests whether the value of the given column matches
* the given entity ID. If group identifiers are provided, the IDs of the
* entities for all groups having those identifiers are tested, as well.
* Disabled groups are ignored.
*
* @param column
* The name of the column to test. This column MUST contain an entity
* ID (a foreign key into the guacamole_entity table).
*
* @param entityID
* The ID of the specific entity to test the column against.
*
* @param groups
* A collection of group identifiers to additionally test the column
* against. Though this functionality is optional, a collection must
* always be given, even if that collection is empty.
-->
<sql id="isRelatedEntity">
(
${column} = ${entityID}
<if test="!${groups}.isEmpty()">
OR ${column} IN (
SELECT guacamole_entity.entity_id
FROM guacamole_entity
JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id
WHERE
type = 'USER_GROUP'::guacamole_entity_type
AND name IN
<foreach collection="${groups}" item="effectiveGroup"
open="(" separator="," close=")">
#{effectiveGroup,jdbcType=VARCHAR}
</foreach>
AND disabled = false
)
</if>
)
</sql>
<!-- Select names of all effective groups (including inherited) -->
<select id="selectEffectiveGroupIdentifiers" resultType="string">
WITH RECURSIVE related_entity(entity_id) AS (
SELECT
guacamole_user_group.entity_id
FROM guacamole_user_group
JOIN guacamole_user_group_member ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
WHERE
guacamole_user_group_member.member_entity_id = #{entity.entityID}
AND guacamole_user_group.disabled = false
<if test="!effectiveGroups.isEmpty()">
UNION
SELECT
guacamole_entity.entity_id
FROM guacamole_entity
JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id
WHERE
type = 'USER_GROUP'::guacamole_entity_type
AND name IN
<foreach collection="effectiveGroups" item="effectiveGroup"
open="(" separator="," close=")">
#{effectiveGroup,jdbcType=VARCHAR}
</foreach>
AND guacamole_user_group.disabled = false
</if>
UNION
SELECT
guacamole_user_group.entity_id
FROM related_entity
JOIN guacamole_user_group_member ON related_entity.entity_id = guacamole_user_group_member.member_entity_id
JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
WHERE
guacamole_user_group.disabled = false
)
SELECT name
FROM related_entity
JOIN guacamole_entity ON related_entity.entity_id = guacamole_entity.entity_id
WHERE
guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type;
</select>
<!-- Insert single entity -->
<insert id="insert" useGeneratedKeys="true" keyProperty="entity.entityID"
parameterType="org.apache.guacamole.auth.jdbc.base.EntityModel">
INSERT INTO guacamole_entity (
name,
type
)
VALUES (
#{entity.identifier,jdbcType=VARCHAR},
#{entity.entityType,jdbcType=VARCHAR}::guacamole_entity_type
)
</insert>
</mapper>

View File

@@ -68,7 +68,11 @@
SELECT connection_id SELECT connection_id
FROM guacamole_connection_permission FROM guacamole_connection_permission
WHERE WHERE
user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ' AND permission = 'READ'
</select> </select>
@@ -89,7 +93,11 @@
WHERE WHERE
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</if> <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</if>
<if test="parentIdentifier == null">parent_id IS NULL</if> <if test="parentIdentifier == null">parent_id IS NULL</if>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ' AND permission = 'READ'
</select> </select>
@@ -165,7 +173,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer #{identifier,jdbcType=INTEGER}::integer
</foreach> </foreach>
AND guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_connection_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ' AND permission = 'READ'
GROUP BY guacamole_connection.connection_id; GROUP BY guacamole_connection.connection_id;
@@ -177,7 +189,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer #{identifier,jdbcType=INTEGER}::integer
</foreach> </foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ'; AND permission = 'READ';
SELECT SELECT
@@ -191,7 +207,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer #{identifier,jdbcType=INTEGER}::integer
</foreach> </foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ'; AND permission = 'READ';
</select> </select>

View File

@@ -79,7 +79,10 @@
#{record.sharingProfileIdentifier,jdbcType=INTEGER}::integer, #{record.sharingProfileIdentifier,jdbcType=INTEGER}::integer,
#{record.sharingProfileName,jdbcType=VARCHAR}, #{record.sharingProfileName,jdbcType=VARCHAR},
(SELECT user_id FROM guacamole_user (SELECT user_id FROM guacamole_user
WHERE username = #{record.username,jdbcType=VARCHAR}), JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
guacamole_entity.name = #{record.username,jdbcType=VARCHAR}
AND guacamole_entity.type = 'USER'::guacamole_entity_type),
#{record.username,jdbcType=VARCHAR}, #{record.username,jdbcType=VARCHAR},
#{record.startDate,jdbcType=TIMESTAMP}, #{record.startDate,jdbcType=TIMESTAMP},
#{record.endDate,jdbcType=TIMESTAMP} #{record.endDate,jdbcType=TIMESTAMP}
@@ -163,13 +166,21 @@
<!-- Restrict to readable connections --> <!-- Restrict to readable connections -->
JOIN guacamole_connection_permission ON JOIN guacamole_connection_permission ON
guacamole_connection_history.connection_id = guacamole_connection_permission.connection_id guacamole_connection_history.connection_id = guacamole_connection_permission.connection_id
AND guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_connection_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND guacamole_connection_permission.permission = 'READ' AND guacamole_connection_permission.permission = 'READ'
<!-- Restrict to readable users --> <!-- Restrict to readable users -->
JOIN guacamole_user_permission ON JOIN guacamole_user_permission ON
guacamole_connection_history.user_id = guacamole_user_permission.affected_user_id guacamole_connection_history.user_id = guacamole_user_permission.affected_user_id
AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_permission.entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND guacamole_user_permission.permission = 'READ' AND guacamole_user_permission.permission = 'READ'
<!-- Search terms --> <!-- Search terms -->
@@ -180,7 +191,10 @@
guacamole_connection_history.user_id IN ( guacamole_connection_history.user_id IN (
SELECT user_id SELECT user_id
FROM guacamole_user FROM guacamole_user
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0 JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'::guacamole_entity_type
) )
OR guacamole_connection_history.connection_id IN ( OR guacamole_connection_history.connection_id IN (

View File

@@ -69,7 +69,11 @@
SELECT connection_group_id SELECT connection_group_id
FROM guacamole_connection_group_permission FROM guacamole_connection_group_permission
WHERE WHERE
user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ' AND permission = 'READ'
</select> </select>
@@ -90,7 +94,11 @@
WHERE WHERE
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</if> <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</if>
<if test="parentIdentifier == null">parent_id IS NULL</if> <if test="parentIdentifier == null">parent_id IS NULL</if>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ' AND permission = 'READ'
</select> </select>
@@ -161,7 +169,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer #{identifier,jdbcType=INTEGER}::integer
</foreach> </foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ'; AND permission = 'READ';
SELECT parent_id, guacamole_connection_group.connection_group_id SELECT parent_id, guacamole_connection_group.connection_group_id
@@ -172,7 +184,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer #{identifier,jdbcType=INTEGER}::integer
</foreach> </foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ'; AND permission = 'READ';
SELECT parent_id, guacamole_connection.connection_id SELECT parent_id, guacamole_connection.connection_id
@@ -183,7 +199,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer #{identifier,jdbcType=INTEGER}::integer
</foreach> </foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ'; AND permission = 'READ';
SELECT SELECT
@@ -197,7 +217,11 @@
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer #{identifier,jdbcType=INTEGER}::integer
</foreach> </foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER} AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = 'READ'; AND permission = 'READ';
</select> </select>

View File

@@ -25,24 +25,26 @@
<!-- Result mapper for connection permissions --> <!-- Result mapper for connection permissions -->
<resultMap id="ConnectionGroupPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <resultMap id="ConnectionGroupPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/> <result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="permission" property="type" jdbcType="VARCHAR" <result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/> javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
<result column="connection_group_id" property="objectIdentifier" jdbcType="INTEGER"/> <result column="connection_group_id" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap> </resultMap>
<!-- Select all permissions for a given user --> <!-- Select all permissions for a given entity -->
<select id="select" resultMap="ConnectionGroupPermissionResultMap"> <select id="select" resultMap="ConnectionGroupPermissionResultMap">
SELECT SELECT
guacamole_connection_group_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
username,
permission, permission,
connection_group_id connection_group_id
FROM guacamole_connection_group_permission FROM guacamole_connection_group_permission
JOIN guacamole_user ON guacamole_connection_group_permission.user_id = guacamole_user.user_id WHERE
WHERE guacamole_connection_group_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
</select> </select>
@@ -50,26 +52,32 @@
<select id="selectOne" resultMap="ConnectionGroupPermissionResultMap"> <select id="selectOne" resultMap="ConnectionGroupPermissionResultMap">
SELECT SELECT
guacamole_connection_group_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
username,
permission, permission,
connection_group_id connection_group_id
FROM guacamole_connection_group_permission FROM guacamole_connection_group_permission
JOIN guacamole_user ON guacamole_connection_group_permission.user_id = guacamole_user.user_id
WHERE WHERE
guacamole_connection_group_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
AND connection_group_id = #{identifier,jdbcType=INTEGER}::integer AND connection_group_id = #{identifier,jdbcType=INTEGER}::integer
</select> </select>
<!-- Select identifiers accessible by the given user for the given permissions --> <!-- Select identifiers accessible by the given entity for the given permissions -->
<select id="selectAccessibleIdentifiers" resultType="string"> <select id="selectAccessibleIdentifiers" resultType="string">
SELECT DISTINCT connection_group_id SELECT DISTINCT connection_group_id
FROM guacamole_connection_group_permission FROM guacamole_connection_group_permission
WHERE WHERE
user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND connection_group_id IN AND connection_group_id IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
@@ -87,10 +95,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
DELETE FROM guacamole_connection_group_permission DELETE FROM guacamole_connection_group_permission
WHERE (user_id, permission, connection_group_id) IN WHERE (entity_id, permission, connection_group_id) IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER}, (#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
#{permission.objectIdentifier,jdbcType=INTEGER}::integer) #{permission.objectIdentifier,jdbcType=INTEGER}::integer)
</foreach> </foreach>
@@ -101,25 +109,25 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT INTO guacamole_connection_group_permission ( INSERT INTO guacamole_connection_group_permission (
user_id, entity_id,
permission, permission,
connection_group_id connection_group_id
) )
SELECT DISTINCT SELECT DISTINCT
permissions.user_id, permissions.entity_id,
permissions.permission, permissions.permission,
permissions.connection_group_id permissions.connection_group_id
FROM FROM
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="UNION ALL" close=")"> open="(" separator="UNION ALL" close=")">
SELECT #{permission.userID,jdbcType=INTEGER} AS user_id, SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id,
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission,
#{permission.objectIdentifier,jdbcType=INTEGER}::integer AS connection_group_id #{permission.objectIdentifier,jdbcType=INTEGER}::integer AS connection_group_id
</foreach> </foreach>
AS permissions AS permissions
WHERE (user_id, permission, connection_group_id) NOT IN ( WHERE (entity_id, permission, connection_group_id) NOT IN (
SELECT SELECT
guacamole_connection_group_permission.user_id, guacamole_connection_group_permission.entity_id,
guacamole_connection_group_permission.permission, guacamole_connection_group_permission.permission,
guacamole_connection_group_permission.connection_group_id guacamole_connection_group_permission.connection_group_id
FROM guacamole_connection_group_permission FROM guacamole_connection_group_permission

View File

@@ -25,24 +25,26 @@
<!-- Result mapper for connection permissions --> <!-- Result mapper for connection permissions -->
<resultMap id="ConnectionPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <resultMap id="ConnectionPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/> <result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="permission" property="type" jdbcType="VARCHAR" <result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/> javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
<result column="connection_id" property="objectIdentifier" jdbcType="INTEGER"/> <result column="connection_id" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap> </resultMap>
<!-- Select all permissions for a given user --> <!-- Select all permissions for a given entity -->
<select id="select" resultMap="ConnectionPermissionResultMap"> <select id="select" resultMap="ConnectionPermissionResultMap">
SELECT SELECT
guacamole_connection_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
username,
permission, permission,
connection_id connection_id
FROM guacamole_connection_permission FROM guacamole_connection_permission
JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id WHERE
WHERE guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
</select> </select>
@@ -50,26 +52,32 @@
<select id="selectOne" resultMap="ConnectionPermissionResultMap"> <select id="selectOne" resultMap="ConnectionPermissionResultMap">
SELECT SELECT
guacamole_connection_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
username,
permission, permission,
connection_id connection_id
FROM guacamole_connection_permission FROM guacamole_connection_permission
JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id
WHERE WHERE
guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
AND connection_id = #{identifier,jdbcType=INTEGER}::integer AND connection_id = #{identifier,jdbcType=INTEGER}::integer
</select> </select>
<!-- Select identifiers accessible by the given user for the given permissions --> <!-- Select identifiers accessible by the given entity for the given permissions -->
<select id="selectAccessibleIdentifiers" resultType="string"> <select id="selectAccessibleIdentifiers" resultType="string">
SELECT DISTINCT connection_id SELECT DISTINCT connection_id
FROM guacamole_connection_permission FROM guacamole_connection_permission
WHERE WHERE
user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND connection_id IN AND connection_id IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
@@ -87,10 +95,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
DELETE FROM guacamole_connection_permission DELETE FROM guacamole_connection_permission
WHERE (user_id, permission, connection_id) IN WHERE (entity_id, permission, connection_id) IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER}, (#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
#{permission.objectIdentifier,jdbcType=INTEGER}::integer) #{permission.objectIdentifier,jdbcType=INTEGER}::integer)
</foreach> </foreach>
@@ -101,25 +109,25 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT INTO guacamole_connection_permission ( INSERT INTO guacamole_connection_permission (
user_id, entity_id,
permission, permission,
connection_id connection_id
) )
SELECT DISTINCT SELECT DISTINCT
permissions.user_id, permissions.entity_id,
permissions.permission, permissions.permission,
permissions.connection_id permissions.connection_id
FROM FROM
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="UNION ALL" close=")"> open="(" separator="UNION ALL" close=")">
SELECT #{permission.userID,jdbcType=INTEGER} AS user_id, SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id,
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission,
#{permission.objectIdentifier,jdbcType=INTEGER}::integer AS connection_id #{permission.objectIdentifier,jdbcType=INTEGER}::integer AS connection_id
</foreach> </foreach>
AS permissions AS permissions
WHERE (user_id, permission, connection_id) NOT IN ( WHERE (entity_id, permission, connection_id) NOT IN (
SELECT SELECT
guacamole_connection_permission.user_id, guacamole_connection_permission.entity_id,
guacamole_connection_permission.permission, guacamole_connection_permission.permission,
guacamole_connection_permission.connection_id guacamole_connection_permission.connection_id
FROM guacamole_connection_permission FROM guacamole_connection_permission

View File

@@ -25,24 +25,26 @@
<!-- Result mapper for sharing profile permissions --> <!-- Result mapper for sharing profile permissions -->
<resultMap id="SharingProfilePermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <resultMap id="SharingProfilePermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/> <result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="permission" property="type" jdbcType="VARCHAR" <result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/> javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
<result column="sharing_profile_id" property="objectIdentifier" jdbcType="INTEGER"/> <result column="sharing_profile_id" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap> </resultMap>
<!-- Select all permissions for a given user --> <!-- Select all permissions for a given entity -->
<select id="select" resultMap="SharingProfilePermissionResultMap"> <select id="select" resultMap="SharingProfilePermissionResultMap">
SELECT SELECT
guacamole_sharing_profile_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
username,
permission, permission,
sharing_profile_id sharing_profile_id
FROM guacamole_sharing_profile_permission FROM guacamole_sharing_profile_permission
JOIN guacamole_user ON guacamole_sharing_profile_permission.user_id = guacamole_user.user_id WHERE
WHERE guacamole_sharing_profile_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
</select> </select>
@@ -50,26 +52,32 @@
<select id="selectOne" resultMap="SharingProfilePermissionResultMap"> <select id="selectOne" resultMap="SharingProfilePermissionResultMap">
SELECT SELECT
guacamole_sharing_profile_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
username,
permission, permission,
sharing_profile_id sharing_profile_id
FROM guacamole_sharing_profile_permission FROM guacamole_sharing_profile_permission
JOIN guacamole_user ON guacamole_sharing_profile_permission.user_id = guacamole_user.user_id
WHERE WHERE
guacamole_sharing_profile_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
AND sharing_profile_id = #{identifier,jdbcType=INTEGER}::integer AND sharing_profile_id = #{identifier,jdbcType=INTEGER}::integer
</select> </select>
<!-- Select identifiers accessible by the given user for the given permissions --> <!-- Select identifiers accessible by the given entity for the given permissions -->
<select id="selectAccessibleIdentifiers" resultType="string"> <select id="selectAccessibleIdentifiers" resultType="string">
SELECT DISTINCT sharing_profile_id SELECT DISTINCT sharing_profile_id
FROM guacamole_sharing_profile_permission FROM guacamole_sharing_profile_permission
WHERE WHERE
user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND sharing_profile_id IN AND sharing_profile_id IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
@@ -87,10 +95,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
DELETE FROM guacamole_sharing_profile_permission DELETE FROM guacamole_sharing_profile_permission
WHERE (user_id, permission, sharing_profile_id) IN WHERE (entity_id, permission, sharing_profile_id) IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER}, (#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
#{permission.objectIdentifier,jdbcType=INTEGER}::integer) #{permission.objectIdentifier,jdbcType=INTEGER}::integer)
</foreach> </foreach>
@@ -101,25 +109,25 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT INTO guacamole_sharing_profile_permission ( INSERT INTO guacamole_sharing_profile_permission (
user_id, entity_id,
permission, permission,
sharing_profile_id sharing_profile_id
) )
SELECT DISTINCT SELECT DISTINCT
permissions.user_id, permissions.entity_id,
permissions.permission, permissions.permission,
permissions.sharing_profile_id permissions.sharing_profile_id
FROM FROM
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="UNION ALL" close=")"> open="(" separator="UNION ALL" close=")">
SELECT #{permission.userID,jdbcType=INTEGER} AS user_id, SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id,
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission,
#{permission.objectIdentifier,jdbcType=INTEGER}::integer AS sharing_profile_id #{permission.objectIdentifier,jdbcType=INTEGER}::integer AS sharing_profile_id
</foreach> </foreach>
AS permissions AS permissions
WHERE (user_id, permission, sharing_profile_id) NOT IN ( WHERE (entity_id, permission, sharing_profile_id) NOT IN (
SELECT SELECT
guacamole_sharing_profile_permission.user_id, guacamole_sharing_profile_permission.entity_id,
guacamole_sharing_profile_permission.permission, guacamole_sharing_profile_permission.permission,
guacamole_sharing_profile_permission.sharing_profile_id guacamole_sharing_profile_permission.sharing_profile_id
FROM guacamole_sharing_profile_permission FROM guacamole_sharing_profile_permission

View File

@@ -25,36 +25,40 @@
<!-- Result mapper for system permissions --> <!-- Result mapper for system permissions -->
<resultMap id="SystemPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel"> <resultMap id="SystemPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/> <result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="permission" property="type" jdbcType="VARCHAR" <result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.permission.SystemPermission$Type"/> javaType="org.apache.guacamole.net.auth.permission.SystemPermission$Type"/>
</resultMap> </resultMap>
<!-- Select all permissions for a given user --> <!-- Select all permissions for a given entity -->
<select id="select" resultMap="SystemPermissionResultMap"> <select id="select" resultMap="SystemPermissionResultMap">
SELECT SELECT DISTINCT
guacamole_system_permission.user_id, #{entity.entityID} AS entity_id,
username,
permission permission
FROM guacamole_system_permission FROM guacamole_system_permission
JOIN guacamole_user ON guacamole_system_permission.user_id = guacamole_user.user_id WHERE
WHERE guacamole_system_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
</select> </select>
<!-- Select the single permission matching the given criteria --> <!-- Select the single permission matching the given criteria -->
<select id="selectOne" resultMap="SystemPermissionResultMap"> <select id="selectOne" resultMap="SystemPermissionResultMap">
SELECT SELECT DISTINCT
guacamole_system_permission.user_id, #{entity.entityID} AS entity_id,
username,
permission permission
FROM guacamole_system_permission FROM guacamole_system_permission
JOIN guacamole_user ON guacamole_system_permission.user_id = guacamole_user.user_id
WHERE WHERE
guacamole_system_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = #{type,jdbcType=VARCHAR}::guacamole_system_permission_type AND permission = #{type,jdbcType=VARCHAR}::guacamole_system_permission_type
</select> </select>
@@ -63,10 +67,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel"> <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
DELETE FROM guacamole_system_permission DELETE FROM guacamole_system_permission
WHERE (user_id, permission) IN WHERE (entity_id, permission) IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER}, (#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}::guacamole_system_permission_type) #{permission.type,jdbcType=VARCHAR}::guacamole_system_permission_type)
</foreach> </foreach>
@@ -76,22 +80,22 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel"> <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
INSERT INTO guacamole_system_permission ( INSERT INTO guacamole_system_permission (
user_id, entity_id,
permission permission
) )
SELECT DISTINCT SELECT DISTINCT
permissions.user_id, permissions.entity_id,
permissions.permission permissions.permission
FROM FROM
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="UNION ALL" close=")"> open="(" separator="UNION ALL" close=")">
SELECT #{permission.userID,jdbcType=INTEGER} AS user_id, SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id,
#{permission.type,jdbcType=VARCHAR}::guacamole_system_permission_type AS permission #{permission.type,jdbcType=VARCHAR}::guacamole_system_permission_type AS permission
</foreach> </foreach>
AS permissions AS permissions
WHERE (user_id, permission) NOT IN ( WHERE (entity_id, permission) NOT IN (
SELECT SELECT
guacamole_system_permission.user_id, guacamole_system_permission.entity_id,
guacamole_system_permission.permission guacamole_system_permission.permission
FROM guacamole_system_permission FROM guacamole_system_permission
); );

View File

@@ -0,0 +1,156 @@
<?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" >
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<mapper namespace="org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionMapper" >
<!-- Result mapper for user group permissions -->
<resultMap id="UserGroupPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
<result column="affected_name" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap>
<!-- Select all permissions for a given entity -->
<select id="select" resultMap="UserGroupPermissionResultMap">
SELECT
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
affected_entity.name AS affected_name
FROM guacamole_user_group_permission
JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id
WHERE
<include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_group_permission.entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND affected_entity.type = 'USER_GROUP'::guacamole_entity_type
</select>
<!-- Select the single permission matching the given criteria -->
<select id="selectOne" resultMap="UserGroupPermissionResultMap">
SELECT
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
affected_entity.name AS affected_name
FROM guacamole_user_group_permission
JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id
WHERE
<include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_group_permission.entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
AND affected_entity.name = #{identifier,jdbcType=VARCHAR}
AND affected_entity.type = 'USER_GROUP'::guacamole_entity_type
</select>
<!-- Select identifiers accessible by the given entity for the given permissions -->
<select id="selectAccessibleIdentifiers" resultType="string">
SELECT DISTINCT affected_entity.name
FROM guacamole_user_group_permission
JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id
WHERE
<include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_group_permission.entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND affected_entity.name IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND permission IN
<foreach collection="permissions" item="permission"
open="(" separator="," close=")">
#{permission,jdbcType=VARCHAR}::guacamole_object_permission_type
</foreach>
AND affected_entity.type = 'USER_GROUP'::guacamole_entity_type
</select>
<!-- Delete all given permissions -->
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
DELETE FROM guacamole_user_group_permission
USING guacamole_user_group affected_group, guacamole_entity affected_entity
WHERE
guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
AND affected_group.entity_id = affected_entity.entity_id
AND (guacamole_user_group_permission.entity_id, permission, affected_entity.name) IN
<foreach collection="permissions" item="permission"
open="(" separator="," close=")">
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
#{permission.objectIdentifier,jdbcType=INTEGER})
</foreach>
AND affected_entity.type = 'USER_GROUP'::guacamole_entity_type
</delete>
<!-- Insert all given permissions -->
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT INTO guacamole_user_group_permission (
entity_id,
permission,
affected_user_group_id
)
SELECT DISTINCT
permissions.entity_id,
permissions.permission,
affected_group.user_group_id
FROM
<foreach collection="permissions" item="permission"
open="(" separator="UNION ALL" close=")">
SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id,
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission,
#{permission.objectIdentifier,jdbcType=VARCHAR}::text AS affected_name
</foreach>
AS permissions
JOIN guacamole_entity affected_entity ON
affected_entity.name = permissions.affected_name
AND affected_entity.type = 'USER_GROUP'::guacamole_entity_type
JOIN guacamole_user_group affected_group ON affected_group.entity_id = affected_entity.entity_id
WHERE (permissions.entity_id, permissions.permission, affected_group.user_group_id) NOT IN (
SELECT
guacamole_user_group_permission.entity_id,
guacamole_user_group_permission.permission,
guacamole_user_group_permission.affected_user_group_id
FROM guacamole_user_group_permission
);
</insert>
</mapper>

View File

@@ -25,25 +25,29 @@
<!-- Result mapper for user permissions --> <!-- Result mapper for user permissions -->
<resultMap id="UserPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <resultMap id="UserPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/> <result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="permission" property="type" jdbcType="VARCHAR" <result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/> javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
<result column="affected_username" property="objectIdentifier" jdbcType="INTEGER"/> <result column="affected_name" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap> </resultMap>
<!-- Select all permissions for a given user --> <!-- Select all permissions for a given entity -->
<select id="select" resultMap="UserPermissionResultMap"> <select id="select" resultMap="UserPermissionResultMap">
SELECT SELECT
guacamole_user_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
guacamole_user.username,
permission, permission,
affected.username AS affected_username affected_entity.name AS affected_name
FROM guacamole_user_permission FROM guacamole_user_permission
JOIN guacamole_user ON guacamole_user_permission.user_id = guacamole_user.user_id JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
WHERE guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} WHERE
<include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_permission.entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND affected_entity.type = 'USER'::guacamole_entity_type
</select> </select>
@@ -51,38 +55,48 @@
<select id="selectOne" resultMap="UserPermissionResultMap"> <select id="selectOne" resultMap="UserPermissionResultMap">
SELECT SELECT
guacamole_user_permission.user_id, #{entity.entityID,jdbcType=INTEGER} AS entity_id,
guacamole_user.username,
permission, permission,
affected.username AS affected_username affected_entity.name AS affected_name
FROM guacamole_user_permission FROM guacamole_user_permission
JOIN guacamole_user ON guacamole_user_permission.user_id = guacamole_user.user_id JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
WHERE WHERE
guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
<property name="column" value="guacamole_user_permission.entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
AND affected.username = #{identifier,jdbcType=INTEGER} AND affected_entity.name = #{identifier,jdbcType=VARCHAR}
AND affected_entity.type = 'USER'::guacamole_entity_type
</select> </select>
<!-- Select identifiers accessible by the given user for the given permissions --> <!-- Select identifiers accessible by the given entity for the given permissions -->
<select id="selectAccessibleIdentifiers" resultType="string"> <select id="selectAccessibleIdentifiers" resultType="string">
SELECT DISTINCT username SELECT DISTINCT affected_entity.name
FROM guacamole_user_permission FROM guacamole_user_permission
JOIN guacamole_user ON guacamole_user_permission.affected_user_id = guacamole_user.user_id JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
WHERE WHERE
guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
AND username IN <property name="column" value="guacamole_user_permission.entity_id"/>
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/>
</include>
AND affected_entity.name IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
AND permission IN AND permission IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
#{permission,jdbcType=VARCHAR}::guacamole_object_permission_type #{permission,jdbcType=VARCHAR}::guacamole_object_permission_type
</foreach> </foreach>
AND affected_entity.type = 'USER'::guacamole_entity_type
</select> </select>
@@ -90,16 +104,18 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
DELETE FROM guacamole_user_permission DELETE FROM guacamole_user_permission
USING guacamole_user affected USING guacamole_user affected_user, guacamole_entity affected_entity
WHERE WHERE
guacamole_user_permission.affected_user_id = affected.user_id guacamole_user_permission.affected_user_id = affected_user.user_id
AND (guacamole_user_permission.user_id, permission, affected.username) IN AND affected_user.entity_id = affected_entity.entity_id
AND (guacamole_user_permission.entity_id, permission, affected_entity.name) IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER}, (#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
#{permission.objectIdentifier,jdbcType=INTEGER}) #{permission.objectIdentifier,jdbcType=INTEGER})
</foreach> </foreach>
AND affected_entity.type = 'USER'::guacamole_entity_type
</delete> </delete>
@@ -107,26 +123,29 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel"> <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT INTO guacamole_user_permission ( INSERT INTO guacamole_user_permission (
user_id, entity_id,
permission, permission,
affected_user_id affected_user_id
) )
SELECT DISTINCT SELECT DISTINCT
permissions.user_id, permissions.entity_id,
permissions.permission, permissions.permission,
guacamole_user.user_id affected_user.user_id
FROM FROM
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="UNION ALL" close=")"> open="(" separator="UNION ALL" close=")">
SELECT #{permission.userID,jdbcType=INTEGER} AS user_id, SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id,
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission,
#{permission.objectIdentifier,jdbcType=INTEGER} AS username #{permission.objectIdentifier,jdbcType=VARCHAR}::text AS affected_name
</foreach> </foreach>
AS permissions AS permissions
JOIN guacamole_user ON guacamole_user.username = permissions.username JOIN guacamole_entity affected_entity ON
WHERE (permissions.user_id, permissions.permission, guacamole_user.user_id) NOT IN ( affected_entity.name = permissions.affected_name
AND affected_entity.type = 'USER'::guacamole_entity_type
JOIN guacamole_user affected_user ON affected_user.entity_id = affected_entity.entity_id
WHERE (permissions.entity_id, permissions.permission, affected_user.user_id) NOT IN (
SELECT SELECT
guacamole_user_permission.user_id, guacamole_user_permission.entity_id,
guacamole_user_permission.permission, guacamole_user_permission.permission,
guacamole_user_permission.affected_user_id guacamole_user_permission.affected_user_id
FROM guacamole_user_permission FROM guacamole_user_permission

Some files were not shown because too many files have changed in this diff Show More