Merge 1.0.0 changes back to master.

Conflicts:
	extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java
This commit is contained in:
Nick Couchman
2018-10-01 13:51:56 -04:00
133 changed files with 8377 additions and 1132 deletions

View File

@@ -109,33 +109,33 @@
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
<version>3.4.6</version>
</dependency>
<!-- MyBatis Guice -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-guice</artifactId>
<version>3.6</version>
<version>3.10</version>
</dependency>
<!-- Guice -->
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId>
<version>3.0</version>
<version>4.1.0</version>
</dependency>
<!-- Guava - Utility Library -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
<version>19.0</version>
</dependency>
</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.ActiveConnectionService;
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.permission.SharingProfilePermissionMapper;
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService;
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.sharing.ConnectionSharingService;
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.user.PasswordRecordMapper;
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.datasource.builtin.PooledDataSourceProvider;
import org.apache.guacamole.auth.jdbc.user.UserParentUserGroupMapper;
/**
* Guice module which configures the injections used by the JDBC authentication
@@ -120,12 +133,19 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
addMapperClass(ConnectionPermissionMapper.class);
addMapperClass(ConnectionRecordMapper.class);
addMapperClass(ConnectionParameterMapper.class);
addMapperClass(EntityMapper.class);
addMapperClass(PasswordRecordMapper.class);
addMapperClass(SystemPermissionMapper.class);
addMapperClass(SharingProfileMapper.class);
addMapperClass(SharingProfileParameterMapper.class);
addMapperClass(SharingProfilePermissionMapper.class);
addMapperClass(UserGroupMapper.class);
addMapperClass(UserGroupMemberUserGroupMapper.class);
addMapperClass(UserGroupMemberUserMapper.class);
addMapperClass(UserGroupParentUserGroupMapper.class);
addMapperClass(UserGroupPermissionMapper.class);
addMapperClass(UserMapper.class);
addMapperClass(UserParentUserGroupMapper.class);
addMapperClass(UserPermissionMapper.class);
addMapperClass(UserRecordMapper.class);
@@ -143,12 +163,15 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
bind(ModeledSharingProfile.class);
bind(ModeledUser.class);
bind(ModeledUserContext.class);
bind(ModeledUserGroup.class);
bind(RootConnectionGroup.class);
bind(SharingProfileDirectory.class);
bind(SharingProfilePermissionSet.class);
bind(SystemPermissionSet.class);
bind(TrackedActiveConnection.class);
bind(UserDirectory.class);
bind(UserGroupDirectory.class);
bind(UserGroupPermissionSet.class);
bind(UserPermissionSet.class);
// Bind services
@@ -159,6 +182,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
bind(ConnectionPermissionService.class);
bind(ConnectionSharingService.class);
bind(ConnectionService.class);
bind(EntityService.class);
bind(GuacamoleTunnelService.class).to(RestrictedGuacamoleTunnelService.class);
bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class);
bind(PasswordPolicyService.class);
@@ -168,6 +192,8 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
bind(SharingProfilePermissionService.class);
bind(SharingProfileService.class);
bind(SystemPermissionService.class);
bind(UserGroupService.class);
bind(UserGroupPermissionService.class);
bind(UserPermissionService.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.environment.LocalEnvironment;
import org.apache.guacamole.auth.jdbc.security.PasswordPolicy;
import org.apache.ibatis.session.SqlSession;
/**
* A JDBC-specific implementation of Environment that defines generic properties
@@ -137,4 +138,18 @@ public abstract class JDBCEnvironment extends LocalEnvironment {
*/
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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.apache.guacamole.GuacamoleException;
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.ObjectPermissionService;
import org.apache.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord;
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
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.ObjectPermissionSet;
@@ -58,32 +58,32 @@ public class ActiveConnectionPermissionService
private Provider<ActiveConnectionPermissionSet> activeConnectionPermissionSetProvider;
@Override
public ObjectPermission retrievePermission(ModeledAuthenticatedUser user,
ModeledUser targetUser, ObjectPermission.Type type,
String identifier) throws GuacamoleException {
public boolean hasPermission(ModeledAuthenticatedUser user,
ModeledPermissions<? extends EntityModel> targetEntity,
ObjectPermission.Type type, String identifier,
Set<String> effectiveGroups) throws GuacamoleException {
// 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);
if (permissions.contains(permission))
return permission;
// Otherwise, no such permission
return null;
return permissions.contains(permission);
}
@Override
public Set<ObjectPermission> retrievePermissions(ModeledAuthenticatedUser user,
ModeledUser targetUser) throws GuacamoleException {
ModeledPermissions<? extends EntityModel> targetEntity,
Set<String> effectiveGroups) throws GuacamoleException {
// Retrieve permissions only if allowed
if (canReadPermissions(user, targetUser)) {
if (canReadPermissions(user, targetEntity)) {
// Only administrators may access active connections
boolean isAdmin = targetUser.isAdministrator();
boolean isAdmin = targetEntity.isAdministrator();
// Get all active connections
Collection<ActiveConnectionRecord> records = tunnelService.getActiveConnections(user);
@@ -112,10 +112,12 @@ public class ActiveConnectionPermissionService
@Override
public Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
ModeledUser targetUser, Collection<ObjectPermission.Type> permissionTypes,
Collection<String> identifiers) throws GuacamoleException {
ModeledPermissions<? extends EntityModel> targetEntity,
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());
// For each identifier/permission combination
@@ -138,11 +140,12 @@ public class ActiveConnectionPermissionService
@Override
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();
permissionSet.init(user, targetUser);
permissionSet.init(user, targetEntity, effectiveGroups);
return permissionSet;
@@ -150,7 +153,8 @@ public class ActiveConnectionPermissionService
@Override
public void createPermissions(ModeledAuthenticatedUser user,
ModeledUser targetUser, Collection<ObjectPermission> permissions)
ModeledPermissions<? extends EntityModel> targetEntity,
Collection<ObjectPermission> permissions)
throws GuacamoleException {
// Creating active connection permissions is not implemented
@@ -160,7 +164,8 @@ public class ActiveConnectionPermissionService
@Override
public void deletePermissions(ModeledAuthenticatedUser user,
ModeledUser targetUser, Collection<ObjectPermission> permissions)
ModeledPermissions<? extends EntityModel> targetEntity,
Collection<ObjectPermission> permissions)
throws GuacamoleException {
// 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
* 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
* The user whose permissions are being retrieved.
@@ -66,7 +67,7 @@ public abstract class ModeledChildDirectoryObjectService<InternalType extends Mo
* @throws GuacamoleException
* If permission to read the user's permissions is denied.
*/
protected abstract ObjectPermissionSet getParentPermissionSet(
protected abstract ObjectPermissionSet getParentEffectivePermissionSet(
ModeledAuthenticatedUser user) throws GuacamoleException;
/**
@@ -155,7 +156,7 @@ public abstract class ModeledChildDirectoryObjectService<InternalType extends Mo
Collection<String> modifiedParents = getModifiedParents(user, identifier, model);
if (!modifiedParents.isEmpty()) {
ObjectPermissionSet permissionSet = getParentPermissionSet(user);
ObjectPermissionSet permissionSet = getParentEffectivePermissionSet(user);
Collection<String> updateableParents = permissionSet.getAccessibleObjects(
Collections.singleton(ObjectPermission.Type.UPDATE),
modifiedParents

View File

@@ -57,10 +57,15 @@ public interface ModeledDirectoryObjectMapper<ModelType> {
* 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.
*
* @return
* 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
@@ -91,11 +96,16 @@ public interface ModeledDirectoryObjectMapper<ModelType> {
* @param identifiers
* 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
* A Collection of all objects having the given identifiers.
*/
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

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
* objects that this directory object service manages.
* objects that this directory object service manages, taking into account
* permission inheritance through user groups.
*
* @param user
* 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
* 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
* The user being checked.
@@ -166,7 +168,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
throws GuacamoleException {
// Get object permissions
ObjectPermissionSet permissionSet = getPermissionSet(user);
ObjectPermissionSet permissionSet = getEffectivePermissionSet(user);
// Return whether permission is granted
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
* 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
* The user whose permissions are being retrieved.
@@ -189,7 +192,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
* @throws GuacamoleException
* If permission to read the user's permissions is denied.
*/
protected abstract ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user)
protected abstract ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException;
/**
@@ -398,7 +401,8 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
// Otherwise only return explicitly readable identifiers
else
objects = getObjectMapper().selectReadable(user.getUser().getModel(), identifiers);
objects = getObjectMapper().selectReadable(user.getUser().getModel(),
identifiers, user.getEffectiveUserGroups());
// Return collection of requested 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
ObjectPermissionModel permissionModel = new ObjectPermissionModel();
permissionModel.setUserID(userModel.getObjectID());
permissionModel.setUsername(userModel.getIdentifier());
permissionModel.setEntityID(userModel.getEntityID());
permissionModel.setType(permission);
permissionModel.setObjectIdentifier(model.getIdentifier());
@@ -510,7 +513,8 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
// Otherwise only return explicitly readable identifiers
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;
import java.util.Collection;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
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
* 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
* A Set containing all identifiers of all readable objects.
*/
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

View File

@@ -102,12 +102,19 @@ public interface ConnectionRecordMapper {
* @param limit
* 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
* The results of the search performed with the given parameters.
*/
List<ConnectionRecordModel> searchReadable(@Param("user") UserModel user,
@Param("terms") Collection<ActivityRecordSearchTerm> terms,
@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 {
// 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);
}
@Override
protected ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user)
protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException {
// Return permissions related to connections
return user.getUser().getConnectionPermissions();
return user.getUser().getEffectivePermissions().getConnectionPermissions();
}
@Override
protected ObjectPermissionSet getParentPermissionSet(ModeledAuthenticatedUser user)
protected ObjectPermissionSet getParentEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException {
// 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
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
else
searchResults = connectionRecordMapper.searchReadable(user.getUser().getModel(),
requiredContents, sortPredicates, limit);
searchResults = connectionRecordMapper.searchReadable(
user.getUser().getModel(), requiredContents, sortPredicates,
limit, user.getEffectiveUserGroups());
return getObjectInstances(searchResults);

View File

@@ -19,6 +19,7 @@
package org.apache.guacamole.auth.jdbc.connectiongroup;
import java.util.Collection;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
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
* 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
* A Set containing all identifiers of all readable objects.
*/
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

View File

@@ -112,26 +112,26 @@ public class ConnectionGroupService extends ModeledChildDirectoryObjectService<M
throws GuacamoleException {
// 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);
}
@Override
protected ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user)
protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException {
// Return permissions related to connection groups
return user.getUser().getConnectionGroupPermissions();
return user.getUser().getEffectivePermissions().getConnectionGroupPermissions();
}
@Override
protected ObjectPermissionSet getParentPermissionSet(ModeledAuthenticatedUser user)
protected ObjectPermissionSet getParentEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException {
// 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
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;
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.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.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.Permission;
@@ -41,17 +43,51 @@ public abstract class AbstractPermissionService<PermissionSetType extends Permis
PermissionType extends Permission>
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
* granted to the given target user. If the reading user and the target
* user are not the same, then explicit READ or SYSTEM_ADMINISTER access is
* required.
* granted to the given target entity. If the reading user and the target
* entity are not the same, then explicit READ or SYSTEM_ADMINISTER access
* is required. Permission inheritance via user groups is taken into account.
*
* @param user
* The user attempting to read permissions.
*
* @param targetUser
* The user whose permissions are being read.
* @param targetEntity
* The entity whose permissions are being read.
*
* @return
* 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.
*/
protected boolean canReadPermissions(ModeledAuthenticatedUser user,
ModeledUser targetUser) throws GuacamoleException {
ModeledPermissions<? extends EntityModel> targetEntity)
throws GuacamoleException {
// 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;
// A system adminstrator can do anything
if (user.getUser().isAdministrator())
return true;
// Can read permissions on target user if explicit READ is granted
ObjectPermissionSet userPermissionSet = user.getUser().getUserPermissions();
return userPermissionSet.hasPermission(ObjectPermission.Type.READ, targetUser.getIdentifier());
// Can read permissions on target entity if explicit READ is granted
ObjectPermissionSet permissionSet = getRelevantPermissionSet(user.getUser(), targetEntity);
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.Provider;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
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
@@ -51,11 +53,12 @@ public class ConnectionGroupPermissionService extends ModeledObjectPermissionSer
@Override
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();
permissionSet.init(user, targetUser);
permissionSet.init(user, targetEntity, effectiveGroups);
return permissionSet;

View File

@@ -21,9 +21,11 @@ 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.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
@@ -51,11 +53,12 @@ public class ConnectionPermissionService extends ModeledObjectPermissionService
@Override
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();
permissionSet.init(user, targetUser);
permissionSet.init(user, targetEntity, effectiveGroups);
return permissionSet;

View File

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

View File

@@ -24,9 +24,10 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
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.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.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
* permission and target user.
* permission and target entity.
*
* @param targetUser
* The user to whom this permission is granted.
* @param targetEntity
* The entity to whom this permission is granted.
*
* @param permission
* The permission to use to produce the returned model object.
*
* @return
* A model object which is based on the given permission and target
* user.
* entity.
*/
protected abstract ModelType getModelInstance(ModeledUser targetUser,
protected abstract ModelType getModelInstance(
ModeledPermissions<? extends EntityModel> targetEntity,
PermissionType permission);
/**
* Returns a collection of model objects which are based on the given
* permissions and target user.
* permissions and target entity.
*
* @param targetUser
* The user to whom this permission is granted.
* @param targetEntity
* The entity to whom this permission is granted.
*
* @param permissions
* The permissions to use to produce the returned model objects.
*
* @return
* A collection of model objects which are based on the given
* permissions and target user.
* permissions and target entity.
*/
protected Collection<ModelType> getModelInstances(ModeledUser targetUser,
protected Collection<ModelType> getModelInstances(
ModeledPermissions<? extends EntityModel> targetEntity,
Collection<PermissionType> permissions) {
// Create new collection of models by manually converting each permission
Collection<ModelType> models = new ArrayList<ModelType>(permissions.size());
for (PermissionType permission : permissions)
models.add(getModelInstance(targetUser, permission));
models.add(getModelInstance(targetEntity, permission));
return models;
@@ -140,13 +143,14 @@ public abstract class ModeledPermissionService<PermissionSetType extends Permiss
@Override
public Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user,
ModeledUser targetUser) throws GuacamoleException {
ModeledPermissions<? extends EntityModel> targetEntity,
Set<String> effectiveGroups) throws GuacamoleException {
// Retrieve permissions only if allowed
if (canReadPermissions(user, targetUser))
return getPermissionInstances(getPermissionMapper().select(targetUser.getModel()));
if (canReadPermissions(user, targetEntity))
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.");
}

View File

@@ -20,8 +20,8 @@
package org.apache.guacamole.auth.jdbc.permission;
import java.util.Collection;
import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.ibatis.annotations.Param;
import org.apache.guacamole.auth.jdbc.user.UserModel;
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
* 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.
*
* @param user
* The user to retrieve permissions for.
* @param entity
* The entity to retrieve permissions for.
*
* @param type
* The type of permission to return.
@@ -43,20 +43,27 @@ public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissio
* @param identifier
* 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
* 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("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.
*
* @param user
* The user to check permissions of.
* @param entity
* The entity to check permissions of.
*
* @param permissions
* 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
* 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
* A collection containing the subset of identifiers for which at least
* 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("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;
import java.util.Collection;
import java.util.Set;
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.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.ObjectPermissionSet;
@@ -35,14 +37,14 @@ public interface ObjectPermissionService
extends PermissionService<ObjectPermissionSet, ObjectPermission> {
/**
* Retrieves the permission of the given type associated with the given
* user and object, if it exists. If no such permission exists, null is
* Returns whether the permission of the given type and associated with the
* given object has been granted to the given entity.
*
* @param user
* The user retrieving the permission.
*
* @param targetUser
* The user associated with the permission to be retrieved.
* @param targetEntity
* The entity associated with the permission to be retrieved.
*
* @param type
* The type of permission to retrieve.
@@ -50,26 +52,33 @@ public interface ObjectPermissionService
* @param identifier
* 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
* The permission of the given type associated with the given user and
* object, or null if no such permission exists.
* true if permission of the given type and associated with the given
* object has been granted to the given entity, false otherwise.
*
* @throws GuacamoleException
* If an error occurs while retrieving the requested permission.
*/
ObjectPermission retrievePermission(ModeledAuthenticatedUser user,
ModeledUser targetUser, ObjectPermission.Type type,
String identifier) throws GuacamoleException;
boolean hasPermission(ModeledAuthenticatedUser user,
ModeledPermissions<? extends EntityModel> targetEntity,
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.
*
* @param user
* The user checking the permissions.
*
* @param targetUser
* The user to check permissions of.
* @param targetEntity
* The entity to check permissions of.
*
* @param permissions
* 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
* 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
* A collection containing the subset of identifiers for which at least
* one of the specified permissions is granted.
@@ -88,7 +103,9 @@ public interface ObjectPermissionService
* If an error occurs while retrieving permissions.
*/
Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
ModeledUser targetUser, Collection<ObjectPermission.Type> permissions,
Collection<String> identifiers) throws GuacamoleException;
ModeledPermissions<? extends EntityModel> targetEntity,
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;
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
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.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
import org.apache.guacamole.net.auth.permission.ObjectPermission;
/**
* A database implementation of ObjectPermissionSet which uses an injected
* service to query and manipulate the object-level permissions associated with
* a particular user.
* a particular entity.
*/
public abstract class ObjectPermissionSet extends RestrictedObject
implements org.apache.guacamole.net.auth.permission.ObjectPermissionSet {
/**
* The user associated with this permission set. Each of the permissions in
* this permission set is granted to this user.
* The entity associated with this permission set. Each of the permissions
* 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
@@ -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.
*
* @param currentUser
* The user who queried this permission set, and whose permissions
* dictate the access level of all operations performed on this set.
*
* @param user
* The user to whom the permissions in this set are granted.
* @param entity
* 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);
this.user = user;
this.entity = entity;
this.effectiveGroups = effectiveGroups;
}
/**
@@ -78,13 +94,13 @@ public abstract class ObjectPermissionSet extends RestrictedObject
@Override
public Set<ObjectPermission> getPermissions() throws GuacamoleException {
return getObjectPermissionService().retrievePermissions(getCurrentUser(), user);
return getObjectPermissionService().retrievePermissions(getCurrentUser(), entity, effectiveGroups);
}
@Override
public boolean hasPermission(ObjectPermission.Type permission,
String identifier) throws GuacamoleException {
return getObjectPermissionService().retrievePermission(getCurrentUser(), user, permission, identifier) != null;
return getObjectPermissionService().hasPermission(getCurrentUser(), entity, permission, identifier, effectiveGroups);
}
@Override
@@ -102,19 +118,19 @@ public abstract class ObjectPermissionSet extends RestrictedObject
@Override
public Collection<String> getAccessibleObjects(Collection<ObjectPermission.Type> permissions,
Collection<String> identifiers) throws GuacamoleException {
return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), user, permissions, identifiers);
return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), entity, permissions, identifiers, effectiveGroups);
}
@Override
public void addPermissions(Set<ObjectPermission> permissions)
throws GuacamoleException {
getObjectPermissionService().createPermissions(getCurrentUser(), user, permissions);
getObjectPermissionService().createPermissions(getCurrentUser(), entity, permissions);
}
@Override
public void removePermissions(Set<ObjectPermission> permissions)
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;
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;
/**
@@ -32,15 +32,23 @@ import org.apache.ibatis.annotations.Param;
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
* The user to retrieve permissions for.
* @param entity
* 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
* 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

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

View File

@@ -19,16 +19,12 @@
package org.apache.guacamole.auth.jdbc.permission;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
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.GuacamoleSecurityException;
import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
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.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
* permissions of the given user.
* permissions of the given entity.
*
* @param user
* The user who will be retrieving or manipulating permissions through
* the returned permission set.
*
* @param targetUser
* The user to whom the permissions in the returned permission set are
* @param targetEntity
* The entity to whom the permissions in the returned permission 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.
*
* @return
* 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
* If an error occurs while retrieving the permissions of the given
* user, or if permission to retrieve the permissions of the given
* user is denied.
* entity, or if permission to retrieve the permissions of the given
* entity is denied.
*/
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
* The user retrieving the permissions.
*
* @param targetUser
* The user associated with the permissions to be retrieved.
* @param targetEntity
* 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
* The permissions associated with the given user.
* The permissions associated with the given entity.
*
* @throws GuacamoleException
* If an error occurs while retrieving the requested permissions.
*/
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
@@ -96,8 +107,8 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
* @param user
* The user creating the permissions.
*
* @param targetUser
* The user associated with the permissions to be created.
* @param targetEntity
* The entity associated with the permissions to be created.
*
* @param permissions
* 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
* occurs while creating the permissions.
*/
void createPermissions(ModeledAuthenticatedUser user, ModeledUser targetUser,
Collection<PermissionType> permissions) throws GuacamoleException;
void createPermissions(ModeledAuthenticatedUser user,
ModeledPermissions<? extends EntityModel> targetEntity,
Collection<PermissionType> permissions)
throws GuacamoleException;
/**
* Deletes the given permissions. If any permissions do not exist, they
@@ -116,8 +129,8 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
* @param user
* The user deleting the permissions.
*
* @param targetUser
* The user associated with the permissions to be deleted.
* @param targetEntity
* The entity associated with the permissions to be deleted.
*
* @param permissions
* 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
* occurs while deleting the permissions.
*/
void deletePermissions(ModeledAuthenticatedUser user, ModeledUser targetUser,
Collection<PermissionType> permissions) throws GuacamoleException;
void deletePermissions(ModeledAuthenticatedUser user,
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.Provider;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
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
@@ -51,11 +53,12 @@ public class SharingProfilePermissionService extends ModeledObjectPermissionServ
@Override
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();
permissionSet.init(user, targetUser);
permissionSet.init(user, targetEntity, effectiveGroups);
return permissionSet;

View File

@@ -19,7 +19,8 @@
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.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
* 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
* The user to retrieve permissions for.
* @param entity
* The entity to retrieve permissions for.
*
* @param type
* 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
* 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,
@Param("type") SystemPermission.Type type);
SystemPermissionModel selectOne(@Param("entity") EntityModel entity,
@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.Provider;
import java.util.Collection;
import java.util.Set;
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.GuacamoleSecurityException;
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;
/**
@@ -60,14 +62,14 @@ public class SystemPermissionService
}
@Override
protected SystemPermissionModel getModelInstance(final ModeledUser targetUser,
protected SystemPermissionModel getModelInstance(
final ModeledPermissions<? extends EntityModel> targetEntity,
final SystemPermission permission) {
SystemPermissionModel model = new SystemPermissionModel();
// Populate model object with data from user and permission
model.setUserID(targetUser.getModel().getObjectID());
model.setUsername(targetUser.getModel().getIdentifier());
// Populate model object with data from entity and permission
model.setEntityID(targetEntity.getModel().getEntityID());
model.setType(permission.getType());
return model;
@@ -76,23 +78,25 @@ public class SystemPermissionService
@Override
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();
permissionSet.init(user, targetUser);
permissionSet.init(user, targetEntity, effectiveGroups);
return permissionSet;
}
@Override
public void createPermissions(ModeledAuthenticatedUser user, ModeledUser targetUser,
public void createPermissions(ModeledAuthenticatedUser user,
ModeledPermissions<? extends EntityModel> targetEntity,
Collection<SystemPermission> permissions) throws GuacamoleException {
// Only an admin can create system permissions
if (user.getUser().isAdministrator()) {
Collection<SystemPermissionModel> models = getModelInstances(targetUser, permissions);
Collection<SystemPermissionModel> models = getModelInstances(targetEntity, permissions);
systemPermissionMapper.insert(models);
return;
}
@@ -103,17 +107,18 @@ public class SystemPermissionService
}
@Override
public void deletePermissions(ModeledAuthenticatedUser user, ModeledUser targetUser,
public void deletePermissions(ModeledAuthenticatedUser user,
ModeledPermissions<? extends EntityModel> targetEntity,
Collection<SystemPermission> permissions) throws GuacamoleException {
// Only an admin can delete system permissions
if (user.getUser().isAdministrator()) {
// 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.");
Collection<SystemPermissionModel> models = getModelInstances(targetUser, permissions);
Collection<SystemPermissionModel> models = getModelInstances(targetEntity, permissions);
systemPermissionMapper.delete(models);
return;
}
@@ -124,41 +129,42 @@ public class SystemPermissionService
}
/**
* Retrieves the permission of the given type associated with the given
* user, if it exists. If no such permission exists, null is returned.
* Retrieves whether the permission of the given type has been granted to
* the given entity. Permission inheritance through group membership is
* taken into account.
*
* @param user
* The user retrieving the permission.
*
* @param targetUser
* The user associated with the permission to be retrieved.
* @param targetEntity
* The entity associated with the permission to be retrieved.
*
* @param type
* 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
* The permission of the given type associated with the given user, or
* null if no such permission exists.
* true if permission of the given type has been granted to the given
* entity, false otherwise.
*
* @throws GuacamoleException
* If an error occurs while retrieving the requested permission.
*/
public SystemPermission retrievePermission(ModeledAuthenticatedUser user,
ModeledUser targetUser, SystemPermission.Type type) throws GuacamoleException {
public boolean hasPermission(ModeledAuthenticatedUser user,
ModeledPermissions<? extends EntityModel> targetEntity,
SystemPermission.Type type, Set<String> effectiveGroups)
throws GuacamoleException {
// 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
SystemPermissionModel model = getPermissionMapper().selectOne(targetUser.getModel(), type);
if (model == null)
return null;
return getPermissionInstance(model);
}
// User cannot read this user's permissions
// User cannot read this entity's permissions
throw new GuacamoleSecurityException("Permission denied.");
}

View File

@@ -19,28 +19,35 @@
package org.apache.guacamole.auth.jdbc.permission;
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
import com.google.inject.Inject;
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.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
import org.apache.guacamole.net.auth.permission.SystemPermission;
/**
* A database implementation of SystemPermissionSet which uses an injected
* service to query and manipulate the system permissions associated with a
* particular user.
* particular entity.
*/
public class SystemPermissionSet extends RestrictedObject
implements org.apache.guacamole.net.auth.permission.SystemPermissionSet {
/**
* The user associated with this permission set. Each of the permissions in
* this permission set is granted to this user.
* The entity associated with this permission set. Each of the permissions
* 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.
@@ -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.
*
* @param currentUser
* The user who queried this permission set, and whose permissions
* dictate the access level of all operations performed on this set.
*
* @param user
* The user to whom the permissions in this set are granted.
* @param entity
* 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);
this.user = user;
this.entity = entity;
this.effectiveGroups = effectiveGroups;
}
@Override
public Set<SystemPermission> getPermissions() throws GuacamoleException {
return systemPermissionService.retrievePermissions(getCurrentUser(), user);
return systemPermissionService.retrievePermissions(getCurrentUser(), entity, effectiveGroups);
}
@Override
public boolean hasPermission(SystemPermission.Type permission)
throws GuacamoleException {
return systemPermissionService.retrievePermission(getCurrentUser(), user, permission) != null;
return systemPermissionService.hasPermission(getCurrentUser(), entity, permission, effectiveGroups);
}
@Override
@@ -98,13 +114,13 @@ public class SystemPermissionSet extends RestrictedObject
@Override
public void addPermissions(Set<SystemPermission> permissions)
throws GuacamoleException {
systemPermissionService.createPermissions(getCurrentUser(), user, permissions);
systemPermissionService.createPermissions(getCurrentUser(), entity, permissions);
}
@Override
public void removePermissions(Set<SystemPermission> permissions)
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.Provider;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
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
@@ -51,11 +53,12 @@ public class UserPermissionService extends ModeledObjectPermissionService {
@Override
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();
permissionSet.init(user, targetUser);
permissionSet.init(user, targetEntity, effectiveGroups);
return permissionSet;

View File

@@ -20,7 +20,6 @@
package org.apache.guacamole.auth.jdbc.sharing.user;
import java.util.Collections;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticationProvider;
@@ -52,7 +51,8 @@ public class SharedAuthenticatedUser extends RemoteAuthenticatedUser {
* The AuthenticatedUser to copy.
*/
public SharedAuthenticatedUser(AuthenticatedUser authenticatedUser) {
super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials());
super(authenticatedUser.getAuthenticationProvider(),
authenticatedUser.getCredentials(), Collections.<String>emptySet());
this.shareKey = null;
this.identifier = authenticatedUser.getIdentifier();
}
@@ -75,7 +75,7 @@ public class SharedAuthenticatedUser extends RemoteAuthenticatedUser {
*/
public SharedAuthenticatedUser(AuthenticationProvider authenticationProvider,
Credentials credentials, String shareKey) {
super(authenticationProvider, credentials);
super(authenticationProvider, credentials, Collections.<String>emptySet());
this.shareKey = shareKey;
this.identifier = AuthenticatedUser.ANONYMOUS_IDENTIFIER;
}
@@ -102,9 +102,4 @@ public class SharedAuthenticatedUser extends RemoteAuthenticatedUser {
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 {
// 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);
}
@Override
protected ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user)
protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException {
// Return permissions related to sharing profiles
return user.getUser().getSharingProfilePermissions();
return user.getUser().getEffectivePermissions().getSharingProfilePermissions();
}
@Override
protected ObjectPermissionSet getParentPermissionSet(ModeledAuthenticatedUser user)
protected ObjectPermissionSet getParentEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException {
// 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());
// 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
identifiers.clear();

View File

@@ -76,7 +76,7 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser {
*/
public ModeledAuthenticatedUser(AuthenticatedUser authenticatedUser,
AuthenticationProvider modelAuthenticationProvider, ModeledUser user) {
super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials());
super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials(), authenticatedUser.getEffectiveUserGroups());
this.modelAuthenticationProvider = modelAuthenticationProvider;
this.user = user;
super.setAttributes(authenticatedUser.getAttributes());
@@ -99,7 +99,7 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser {
*/
public ModeledAuthenticatedUser(AuthenticationProvider authenticationProvider,
ModeledUser user, Credentials credentials) {
super(authenticationProvider, credentials);
super(authenticationProvider, credentials, user.getEffectiveUserGroups());
this.modelAuthenticationProvider = authenticationProvider;
this.user = user;
}
@@ -170,9 +170,4 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser {
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;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
@@ -33,16 +34,10 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
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.SaltService;
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.UserPermissionService;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
import org.apache.guacamole.form.BooleanField;
import org.apache.guacamole.form.DateField;
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.RelatedObjectSet;
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.LoggerFactory;
/**
* 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.
@@ -187,40 +177,11 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
private SaltService saltService;
/**
* Service for retrieving system permissions.
* Provider for RelatedObjectSets containing the user groups of which this
* user is a member.
*/
@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;
private Provider<UserParentUserGroupSet> parentUserGroupSetProvider;
/**
* Whether attributes which control access restrictions should be exposed
@@ -331,63 +292,6 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
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,
* pulling the values of those attributes from the underlying user model.
@@ -850,12 +754,14 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
@Override
public RelatedObjectSet getUserGroups() throws GuacamoleException {
return new SimpleRelatedObjectSet();
UserParentUserGroupSet parentUserGroupSet = parentUserGroupSetProvider.get();
parentUserGroupSet.init(getCurrentUser(), this);
return parentUserGroupSet;
}
@Override
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.Provider;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import org.apache.guacamole.GuacamoleException;
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.sharingprofile.ModeledSharingProfile;
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.net.auth.ActiveConnection;
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.User;
import org.apache.guacamole.net.auth.UserGroup;
import org.apache.guacamole.net.auth.simple.SimpleDirectory;
/**
* UserContext implementation which is driven by an arbitrary, underlying
@@ -64,6 +64,13 @@ public class ModeledUserContext extends RestrictedObject
@Inject
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
* associated with this context.
@@ -128,6 +135,7 @@ public class ModeledUserContext extends RestrictedObject
// Init directories
userDirectory.init(currentUser);
userGroupDirectory.init(currentUser);
connectionDirectory.init(currentUser);
connectionGroupDirectory.init(currentUser);
sharingProfileDirectory.init(currentUser);
@@ -166,7 +174,7 @@ public class ModeledUserContext extends RestrictedObject
@Override
public Directory<UserGroup> getUserGroupDirectory() throws GuacamoleException {
return new SimpleDirectory<UserGroup>();
return userGroupDirectory;
}
@Override
@@ -224,7 +232,7 @@ public class ModeledUserContext extends RestrictedObject
@Override
public Collection<Form> getUserGroupAttributes() {
return Collections.<Form>emptyList();
return ModeledUserGroup.ATTRIBUTES;
}
@Override

View File

@@ -21,6 +21,8 @@ package org.apache.guacamole.auth.jdbc.user;
import java.util.HashMap;
import java.util.Map;
import java.util.Collections;
import java.util.Set;
import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticationProvider;
import org.apache.guacamole.net.auth.Credentials;
@@ -50,6 +52,12 @@ public abstract class RemoteAuthenticatedUser implements AuthenticatedUser {
*/
private Map<String, String> attributes = new HashMap<String, String>();
/**
* 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;
@Override
public Map<String, String> getAttributes() {
return attributes;
@@ -69,12 +77,17 @@ public abstract class RemoteAuthenticatedUser implements AuthenticatedUser {
*
* @param credentials
* 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,
Credentials credentials) {
Credentials credentials, Set<String> effectiveGroups) {
this.authenticationProvider = authenticationProvider;
this.credentials = credentials;
this.remoteHost = credentials.getRemoteAddress();
this.effectiveGroups = Collections.unmodifiableSet(effectiveGroups);
}
@Override
@@ -92,6 +105,11 @@ public abstract class RemoteAuthenticatedUser implements AuthenticatedUser {
return remoteHost;
}
@Override
public Set<String> getEffectiveUserGroups() {
return effectiveGroups;
}
@Override
public AuthenticationProvider getAuthenticationProvider() {
return authenticationProvider;

View File

@@ -22,12 +22,13 @@ package org.apache.guacamole.auth.jdbc.user;
import java.sql.Date;
import java.sql.Time;
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.
*/
public class UserModel extends ObjectModel {
public class UserModel extends EntityModel {
/**
* The SHA-256 hash of the password and salt.
@@ -124,6 +125,7 @@ public class UserModel extends ObjectModel {
* Creates a new, empty user.
*/
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
* 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
* The results of the search performed with the given parameters.
*/
List<ActivityRecordModel> searchReadable(@Param("user") UserModel user,
@Param("terms") Collection<ActivityRecordSearchTerm> terms,
@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.ActivityRecordSearchTerm;
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.connection.ConnectionRecordModel;
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel;
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.AuthenticatedUser;
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.credentials.CredentialsInfo;
import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
@@ -115,6 +114,12 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
CONFIRM_NEW_PASSWORD
));
/**
* Mapper for creating/deleting entities.
*/
@Inject
private EntityMapper entityMapper;
/**
* Mapper for accessing users.
*/
@@ -211,17 +216,17 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
throws GuacamoleException {
// 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);
}
@Override
protected ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user)
protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException {
// 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)
passwordPolicyService.verifyPassword(object.getIdentifier(), object.getPassword());
// Create base entity object, implicitly populating underlying entity ID
entityMapper.insert(model);
}
@Override
@@ -294,8 +302,7 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
for (ObjectPermission.Type permissionType : IMPLICIT_USER_PERMISSIONS) {
ObjectPermissionModel permissionModel = new ObjectPermissionModel();
permissionModel.setUserID(model.getObjectID());
permissionModel.setUsername(model.getIdentifier());
permissionModel.setEntityID(model.getEntityID());
permissionModel.setType(permissionType);
permissionModel.setObjectIdentifier(model.getIdentifier());
@@ -584,11 +591,10 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
// Otherwise only return explicitly readable history records
else
searchResults = userRecordMapper.searchReadable(user.getUser().getModel(),
requiredContents, sortPredicates, limit);
requiredContents, sortPredicates, limit, user.getEffectiveUserGroups());
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_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;
--
-- 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
-- with corresponding salt. Although the authentication system will always set
@@ -88,9 +107,9 @@ CREATE TABLE `guacamole_connection` (
CREATE TABLE `guacamole_user` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`entity_id` int(11) NOT NULL,
-- Username and optionally-salted password
`username` varchar(128) NOT NULL,
-- Optionally-salted password
`password_hash` binary(32) NOT NULL,
`password_salt` binary(32),
`password_date` datetime NOT NULL,
@@ -117,7 +136,61 @@ CREATE TABLE `guacamole_user` (
`organizational_role` VARCHAR(256),
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;
@@ -207,6 +280,28 @@ CREATE TABLE guacamole_user_attribute (
) 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
-- 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;
--
-- Table of connection permissions. Each connection permission grants a user
-- specific access to a connection.
-- Table of connection permissions. Each connection permission grants a user or
-- user group specific access to a connection.
--
CREATE TABLE `guacamole_connection_permission` (
`user_id` int(11) NOT NULL,
`entity_id` int(11) NOT NULL,
`connection_id` int(11) NOT NULL,
`permission` enum('READ',
'UPDATE',
'DELETE',
'ADMINISTER') NOT NULL,
PRIMARY KEY (`user_id`,`connection_id`,`permission`),
PRIMARY KEY (`entity_id`,`connection_id`,`permission`),
CONSTRAINT `guacamole_connection_permission_ibfk_1`
FOREIGN KEY (`connection_id`)
REFERENCES `guacamole_connection` (`connection_id`) ON DELETE CASCADE,
CONSTRAINT `guacamole_connection_permission_ibfk_2`
FOREIGN KEY (`user_id`)
REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE
CONSTRAINT `guacamole_connection_permission_entity`
FOREIGN KEY (`entity_id`)
REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- 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` (
`user_id` int(11) NOT NULL,
`entity_id` int(11) NOT NULL,
`connection_group_id` int(11) NOT NULL,
`permission` enum('READ',
'UPDATE',
'DELETE',
'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`
FOREIGN KEY (`connection_group_id`)
REFERENCES `guacamole_connection_group` (`connection_group_id`) ON DELETE CASCADE,
CONSTRAINT `guacamole_connection_group_permission_ibfk_2`
FOREIGN KEY (`user_id`)
REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE
CONSTRAINT `guacamole_connection_group_permission_entity`
FOREIGN KEY (`entity_id`)
REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- 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 (
`user_id` integer NOT NULL,
`entity_id` integer NOT NULL,
`sharing_profile_id` integer NOT NULL,
`permission` enum('READ',
'UPDATE',
'DELETE',
'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`
FOREIGN KEY (`sharing_profile_id`)
REFERENCES `guacamole_sharing_profile` (`sharing_profile_id`) ON DELETE CASCADE,
CONSTRAINT `guacamole_sharing_profile_permission_ibfk_2`
FOREIGN KEY (`user_id`)
REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE
CONSTRAINT `guacamole_sharing_profile_permission_entity`
FOREIGN KEY (`entity_id`)
REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of system permissions. Each system permission grants a user a
-- system-level privilege of some kind.
-- Table of system permissions. Each system permission grants a user or user
-- group a system-level privilege of some kind.
--
CREATE TABLE `guacamole_system_permission` (
`user_id` int(11) NOT NULL,
`entity_id` int(11) NOT NULL,
`permission` enum('CREATE_CONNECTION',
'CREATE_CONNECTION_GROUP',
'CREATE_SHARING_PROFILE',
'CREATE_USER',
'CREATE_USER_GROUP',
'ADMINISTER') NOT NULL,
PRIMARY KEY (`user_id`,`permission`),
PRIMARY KEY (`entity_id`,`permission`),
CONSTRAINT `guacamole_system_permission_ibfk_1`
FOREIGN KEY (`user_id`)
REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE
CONSTRAINT `guacamole_system_permission_entity`
FOREIGN KEY (`entity_id`)
REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of user permissions. Each user permission grants a user access to
-- another user (the "affected" user) for a specific type of operation.
-- Table of user permissions. Each user permission grants a user or user group
-- access to another user (the "affected" user) for a specific type of
-- operation.
--
CREATE TABLE `guacamole_user_permission` (
`user_id` int(11) NOT NULL,
`entity_id` int(11) NOT NULL,
`affected_user_id` int(11) NOT NULL,
`permission` enum('READ',
'UPDATE',
'DELETE',
'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`
FOREIGN KEY (`affected_user_id`)
REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE,
CONSTRAINT `guacamole_user_permission_ibfk_2`
FOREIGN KEY (`user_id`)
REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE
CONSTRAINT `guacamole_user_permission_entity`
FOREIGN KEY (`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;

View File

@@ -18,32 +18,36 @@
--
-- Create default user "guacadmin" with password "guacadmin"
INSERT INTO guacamole_user (username, password_hash, password_salt, password_date)
VALUES ('guacadmin',
INSERT INTO guacamole_entity (name, type) VALUES ('guacadmin', 'USER');
INSERT INTO guacamole_user (entity_id, password_hash, password_salt, password_date)
SELECT
entity_id,
x'CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', -- 'guacadmin'
x'FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264',
NOW());
NOW()
FROM guacamole_entity WHERE name = 'guacadmin';
-- Grant this user all system permissions
INSERT INTO guacamole_system_permission
SELECT user_id, permission
INSERT INTO guacamole_system_permission (entity_id, permission)
SELECT entity_id, permission
FROM (
SELECT 'guacadmin' AS username, 'CREATE_CONNECTION' 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_USER' AS permission
UNION SELECT 'guacadmin' AS username, 'CREATE_USER_GROUP' AS permission
UNION SELECT 'guacadmin' AS username, 'ADMINISTER' AS permission
) 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
INSERT INTO guacamole_user_permission
SELECT guacamole_user.user_id, affected.user_id, permission
INSERT INTO guacamole_user_permission (entity_id, affected_user_id, permission)
SELECT guacamole_entity.entity_id, guacamole_user.user_id, permission
FROM (
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, 'ADMINISTER' AS permission
) permissions
JOIN guacamole_user ON permissions.username = guacamole_user.username
JOIN guacamole_user affected ON permissions.affected_username = affected.username;
JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER'
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.
--
--
-- 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
-- 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;
--
-- 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
-- name/value pair associated with a connection. Arbitrary attributes are

View File

@@ -19,11 +19,16 @@
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.auth.jdbc.JDBCEnvironment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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
@@ -36,6 +41,16 @@ public class MySQLEnvironment extends JDBCEnvironment {
*/
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.
*/
@@ -226,4 +241,40 @@ public class MySQLEnvironment extends JDBCEnvironment {
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
FROM guacamole_connection_permission
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'
</select>
@@ -89,7 +93,11 @@
WHERE
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=VARCHAR}</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'
</select>
@@ -165,7 +173,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</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'
GROUP BY guacamole_connection.connection_id;
@@ -177,7 +189,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</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';
SELECT
@@ -191,7 +207,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</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';
</select>

View File

@@ -79,7 +79,10 @@
#{record.sharingProfileIdentifier,jdbcType=VARCHAR},
#{record.sharingProfileName,jdbcType=VARCHAR},
(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.startDate,jdbcType=TIMESTAMP},
#{record.endDate,jdbcType=TIMESTAMP}
@@ -165,13 +168,21 @@
<!-- Restrict to readable connections -->
JOIN guacamole_connection_permission ON
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'
<!-- Restrict to readable users -->
JOIN guacamole_user_permission ON
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'
<!-- Search terms -->
@@ -182,7 +193,10 @@
guacamole_connection_history.user_id IN (
SELECT user_id
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 (

View File

@@ -69,7 +69,11 @@
SELECT connection_group_id
FROM guacamole_connection_group_permission
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'
</select>
@@ -90,7 +94,11 @@
WHERE
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=VARCHAR}</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'
</select>
@@ -161,7 +169,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</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';
SELECT parent_id, guacamole_connection_group.connection_group_id
@@ -172,7 +184,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</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';
SELECT parent_id, guacamole_connection.connection_id
@@ -183,7 +199,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</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';
SELECT
@@ -197,7 +217,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</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';
</select>

View File

@@ -25,24 +25,26 @@
<!-- Result mapper for connection permissions -->
<resultMap id="ConnectionGroupPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<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="connection_group_id" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap>
<!-- Select all permissions for a given user -->
<!-- Select all permissions for a given entity -->
<select id="select" resultMap="ConnectionGroupPermissionResultMap">
SELECT
guacamole_connection_group_permission.user_id,
username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
connection_group_id
FROM guacamole_connection_group_permission
JOIN guacamole_user ON guacamole_connection_group_permission.user_id = guacamole_user.user_id
WHERE guacamole_connection_group_permission.user_id = #{user.objectID,jdbcType=INTEGER}
WHERE
<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>
@@ -50,26 +52,32 @@
<select id="selectOne" resultMap="ConnectionGroupPermissionResultMap">
SELECT
guacamole_connection_group_permission.user_id,
username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
connection_group_id
FROM guacamole_connection_group_permission
JOIN guacamole_user ON guacamole_connection_group_permission.user_id = guacamole_user.user_id
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 connection_group_id = #{identifier,jdbcType=VARCHAR}
</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 DISTINCT connection_group_id
FROM guacamole_connection_group_permission
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
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
@@ -87,10 +95,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
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"
open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER},
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach>
@@ -101,13 +109,13 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT IGNORE INTO guacamole_connection_group_permission (
user_id,
entity_id,
permission,
connection_group_id
)
VALUES
<foreach collection="permissions" item="permission" separator=",">
(#{permission.userID,jdbcType=INTEGER},
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach>

View File

@@ -25,24 +25,26 @@
<!-- Result mapper for connection permissions -->
<resultMap id="ConnectionPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<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="connection_id" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap>
<!-- Select all permissions for a given user -->
<!-- Select all permissions for a given entity -->
<select id="select" resultMap="ConnectionPermissionResultMap">
SELECT
guacamole_connection_permission.user_id,
username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
connection_id
FROM guacamole_connection_permission
JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id
WHERE guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
WHERE
<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>
@@ -50,26 +52,32 @@
<select id="selectOne" resultMap="ConnectionPermissionResultMap">
SELECT
guacamole_connection_permission.user_id,
username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
connection_id
FROM guacamole_connection_permission
JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id
WHERE
guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
<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 connection_id = #{identifier,jdbcType=VARCHAR}
</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 DISTINCT connection_id
FROM guacamole_connection_permission
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
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
@@ -87,10 +95,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
DELETE FROM guacamole_connection_permission
WHERE (user_id, permission, connection_id) IN
WHERE (entity_id, permission, connection_id) IN
<foreach collection="permissions" item="permission"
open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER},
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach>
@@ -101,13 +109,13 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT IGNORE INTO guacamole_connection_permission (
user_id,
entity_id,
permission,
connection_id
)
VALUES
<foreach collection="permissions" item="permission" separator=",">
(#{permission.userID,jdbcType=INTEGER},
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach>

View File

@@ -23,26 +23,28 @@
<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">
<result column="user_id" property="userID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<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="sharing_profile_id" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap>
<!-- Select all permissions for a given user -->
<!-- Select all permissions for a given entity -->
<select id="select" resultMap="SharingProfilePermissionResultMap">
SELECT
guacamole_sharing_profile_permission.user_id,
username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
sharing_profile_id
FROM guacamole_sharing_profile_permission
JOIN guacamole_user ON guacamole_sharing_profile_permission.user_id = guacamole_user.user_id
WHERE guacamole_sharing_profile_permission.user_id = #{user.objectID,jdbcType=INTEGER}
WHERE
<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>
@@ -50,26 +52,32 @@
<select id="selectOne" resultMap="SharingProfilePermissionResultMap">
SELECT
guacamole_sharing_profile_permission.user_id,
username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
sharing_profile_id
FROM guacamole_sharing_profile_permission
JOIN guacamole_user ON guacamole_sharing_profile_permission.user_id = guacamole_user.user_id
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 sharing_profile_id = #{identifier,jdbcType=VARCHAR}
</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 DISTINCT sharing_profile_id
FROM guacamole_sharing_profile_permission
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
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
@@ -87,10 +95,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
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"
open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER},
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach>
@@ -101,13 +109,13 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT IGNORE INTO guacamole_sharing_profile_permission (
user_id,
entity_id,
permission,
sharing_profile_id
)
VALUES
<foreach collection="permissions" item="permission" separator=",">
(#{permission.userID,jdbcType=INTEGER},
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach>

View File

@@ -25,36 +25,40 @@
<!-- Result mapper for system permissions -->
<resultMap id="SystemPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.permission.SystemPermission$Type"/>
</resultMap>
<!-- Select all permissions for a given user -->
<!-- Select all permissions for a given entity -->
<select id="select" resultMap="SystemPermissionResultMap">
SELECT
guacamole_system_permission.user_id,
username,
SELECT DISTINCT
#{entity.entityID} AS entity_id,
permission
FROM guacamole_system_permission
JOIN guacamole_user ON guacamole_system_permission.user_id = guacamole_user.user_id
WHERE guacamole_system_permission.user_id = #{user.objectID,jdbcType=INTEGER}
WHERE
<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 the single permission matching the given criteria -->
<select id="selectOne" resultMap="SystemPermissionResultMap">
SELECT
guacamole_system_permission.user_id,
username,
SELECT DISTINCT
#{entity.entityID} AS entity_id,
permission
FROM guacamole_system_permission
JOIN guacamole_user ON guacamole_system_permission.user_id = guacamole_user.user_id
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}
</select>
@@ -63,10 +67,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
DELETE FROM guacamole_system_permission
WHERE (user_id, permission) IN
WHERE (entity_id, permission) IN
<foreach collection="permissions" item="permission"
open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER},
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR})
</foreach>
@@ -76,12 +80,12 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
INSERT IGNORE INTO guacamole_system_permission (
user_id,
entity_id,
permission
)
VALUES
<foreach collection="permissions" item="permission" separator=",">
(#{permission.userID,jdbcType=INTEGER},
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR})
</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 -->
<resultMap id="UserPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<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_username" property="objectIdentifier" jdbcType="INTEGER"/>
<result column="affected_name" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap>
<!-- Select all permissions for a given user -->
<!-- Select all permissions for a given entity -->
<select id="select" resultMap="UserPermissionResultMap">
SELECT
guacamole_user_permission.user_id,
guacamole_user.username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
affected.username AS affected_username
affected_entity.name AS affected_name
FROM guacamole_user_permission
JOIN guacamole_user ON guacamole_user_permission.user_id = guacamole_user.user_id
JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id
WHERE guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
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
<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>
@@ -51,29 +55,38 @@
<select id="selectOne" resultMap="UserPermissionResultMap">
SELECT
guacamole_user_permission.user_id,
guacamole_user.username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
affected.username AS affected_username
affected_entity.name AS affected_name
FROM guacamole_user_permission
JOIN guacamole_user ON guacamole_user_permission.user_id = guacamole_user.user_id
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
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 affected.username = #{identifier,jdbcType=VARCHAR}
AND affected_entity.name = #{identifier,jdbcType=VARCHAR}
AND affected_entity.type = 'USER'
</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 DISTINCT username
SELECT DISTINCT affected_entity.name
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
guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
AND username IN
<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.name IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
@@ -83,6 +96,7 @@
open="(" separator="," close=")">
#{permission,jdbcType=VARCHAR}
</foreach>
AND affected_entity.type = 'USER'
</select>
@@ -91,15 +105,17 @@
DELETE FROM 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
(guacamole_user_permission.user_id, permission, affected.username) IN
(guacamole_user_permission.entity_id, permission, affected_entity.name) IN
<foreach collection="permissions" item="permission"
open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER},
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach>
AND affected_entity.type = 'USER'
</delete>
@@ -107,19 +123,26 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT IGNORE INTO guacamole_user_permission (
user_id,
entity_id,
permission,
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"
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.objectIdentifier,jdbcType=VARCHAR} AS username
#{permission.objectIdentifier,jdbcType=VARCHAR} AS affected_name
</foreach>
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>

View File

@@ -52,7 +52,11 @@
SELECT sharing_profile_id
FROM guacamole_sharing_profile_permission
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'
</select>
@@ -99,7 +103,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</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';
SELECT
@@ -113,7 +121,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</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';
</select>

View File

@@ -41,8 +41,9 @@
guacamole_user_password_history.password_date
FROM guacamole_user_password_history
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
guacamole_user.username = #{username,jdbcType=VARCHAR}
guacamole_entity.name = #{username,jdbcType=VARCHAR}
ORDER BY
guacamole_user_password_history.password_date DESC
LIMIT #{maxHistorySize}

View File

@@ -28,7 +28,8 @@
<!-- User properties -->
<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_salt" property="passwordSalt" jdbcType="BINARY"/>
<result column="password_date" property="passwordDate" jdbcType="TIMESTAMP"/>
@@ -57,17 +58,24 @@
<!-- Select all usernames -->
<select id="selectIdentifiers" resultType="string">
SELECT username
FROM guacamole_user
SELECT name
FROM guacamole_entity
WHERE guacamole_entity.type = 'USER'
</select>
<!-- Select usernames of all readable users -->
<select id="selectReadableIdentifiers" resultType="string">
SELECT username
SELECT guacamole_entity.name
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
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'
</select>
@@ -77,7 +85,8 @@
SELECT
guacamole_user.user_id,
guacamole_user.username,
guacamole_entity.entity_id,
guacamole_entity.name,
password_hash,
password_salt,
password_date,
@@ -94,13 +103,15 @@
organizational_role,
MAX(start_date) AS last_active
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
WHERE guacamole_user.username IN
WHERE guacamole_entity.name IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
GROUP BY guacamole_user.user_id;
AND guacamole_entity.type = 'USER'
GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
SELECT
guacamole_user_attribute.user_id,
@@ -108,11 +119,13 @@
guacamole_user_attribute.attribute_value
FROM guacamole_user_attribute
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"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>;
</foreach>
AND guacamole_entity.type = 'USER';
</select>
@@ -122,7 +135,8 @@
SELECT
guacamole_user.user_id,
guacamole_user.username,
guacamole_entity.entity_id,
guacamole_entity.name,
password_hash,
password_salt,
password_date,
@@ -139,16 +153,22 @@
organizational_role,
MAX(start_date) AS last_active
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
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"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</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'
GROUP BY guacamole_user.user_id;
GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
SELECT
guacamole_user_attribute.user_id,
@@ -156,13 +176,19 @@
guacamole_user_attribute.attribute_value
FROM guacamole_user_attribute
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
WHERE username IN
WHERE guacamole_entity.name IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</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';
</select>
@@ -173,7 +199,8 @@
SELECT
guacamole_user.user_id,
guacamole_user.username,
guacamole_entity.entity_id,
guacamole_entity.name,
password_hash,
password_salt,
password_date,
@@ -190,10 +217,12 @@
organizational_role,
MAX(start_date) AS last_active
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
WHERE
guacamole_user.username = #{username,jdbcType=VARCHAR}
GROUP BY guacamole_user.user_id;
guacamole_entity.name = #{username,jdbcType=VARCHAR}
AND guacamole_entity.type = 'USER'
GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
SELECT
guacamole_user_attribute.user_id,
@@ -201,14 +230,19 @@
guacamole_user_attribute.attribute_value
FROM guacamole_user_attribute
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>
<!-- Delete single user by username -->
<delete id="delete">
DELETE FROM guacamole_user
WHERE username = #{identifier,jdbcType=VARCHAR}
DELETE FROM guacamole_entity
WHERE
name = #{identifier,jdbcType=VARCHAR}
AND type = 'USER'
</delete>
<!-- Insert single user -->
@@ -216,7 +250,7 @@
parameterType="org.apache.guacamole.auth.jdbc.user.UserModel">
INSERT INTO guacamole_user (
username,
entity_id,
password_hash,
password_salt,
password_date,
@@ -233,7 +267,7 @@
organizational_role
)
VALUES (
#{object.identifier,jdbcType=VARCHAR},
#{object.entityID,jdbcType=VARCHAR},
#{object.passwordHash,jdbcType=BINARY},
#{object.passwordSalt,jdbcType=BINARY},
#{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
FROM guacamole_user_history
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
guacamole_user.username = #{username,jdbcType=VARCHAR}
guacamole_entity.name = #{username,jdbcType=VARCHAR}
ORDER BY
guacamole_user_history.start_date DESC,
guacamole_user_history.end_date DESC
@@ -66,7 +67,10 @@
VALUES (
#{record.remoteHost,jdbcType=VARCHAR},
(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.startDate,jdbcType=TIMESTAMP},
#{record.endDate,jdbcType=TIMESTAMP}
@@ -79,7 +83,10 @@
UPDATE guacamole_user_history
SET remote_host = #{record.remoteHost,jdbcType=VARCHAR},
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},
start_date = #{record.startDate,jdbcType=TIMESTAMP},
end_date = #{record.endDate,jdbcType=TIMESTAMP}
@@ -105,7 +112,10 @@
guacamole_user_history.user_id IN (
SELECT user_id
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">
@@ -146,7 +156,11 @@
<!-- Restrict to readable users -->
JOIN guacamole_user_permission ON
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'
<!-- Search terms -->
@@ -157,7 +171,10 @@
guacamole_user_history.user_id IN (
SELECT user_id
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">

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'
);
--
-- Entity types
--
CREATE TYPE guacamole_entity_type AS ENUM(
'USER',
'USER_GROUP'
);
--
-- Object permission types
--
@@ -46,6 +55,7 @@ CREATE TYPE guacamole_system_permission_type AS ENUM(
'CREATE_CONNECTION_GROUP',
'CREATE_SHARING_PROFILE',
'CREATE_USER',
'CREATE_USER_GROUP',
'ADMINISTER'
);
@@ -131,6 +141,26 @@ CREATE TABLE guacamole_connection (
CREATE INDEX 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
-- with corresponding salt. Although the authentication system will always set
@@ -141,9 +171,9 @@ CREATE INDEX guacamole_connection_parent_id
CREATE TABLE guacamole_user (
user_id serial NOT NULL,
entity_id integer NOT NULL,
-- Username and optionally-salted password
username varchar(128) NOT NULL,
-- Optionally-salted password
password_hash bytea NOT NULL,
password_salt bytea,
password_date timestamptz NOT NULL,
@@ -171,8 +201,62 @@ CREATE TABLE guacamole_user (
PRIMARY KEY (user_id),
CONSTRAINT username
UNIQUE (username)
CONSTRAINT guacamole_user_single_entity
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
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
-- 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);
--
-- Table of connection permissions. Each connection permission grants a user
-- specific access to a connection.
-- Table of connection permissions. Each connection permission grants a user or
-- user group specific access to a connection.
--
CREATE TABLE guacamole_connection_permission (
user_id integer NOT NULL,
entity_id integer NOT NULL,
connection_id integer 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
FOREIGN KEY (connection_id)
REFERENCES guacamole_connection (connection_id) ON DELETE CASCADE,
CONSTRAINT guacamole_connection_permission_ibfk_2
FOREIGN KEY (user_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE
CONSTRAINT guacamole_connection_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_connection_permission_connection_id
ON guacamole_connection_permission(connection_id);
CREATE INDEX guacamole_connection_permission_user_id
ON guacamole_connection_permission(user_id);
CREATE INDEX guacamole_connection_permission_entity_id
ON guacamole_connection_permission(entity_id);
--
-- 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 (
user_id integer NOT NULL,
entity_id integer NOT NULL,
connection_group_id integer 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
FOREIGN KEY (connection_group_id)
REFERENCES guacamole_connection_group (connection_group_id) ON DELETE CASCADE,
CONSTRAINT guacamole_connection_group_permission_ibfk_2
FOREIGN KEY (user_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE
CONSTRAINT guacamole_connection_group_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_connection_group_permission_connection_group_id
ON guacamole_connection_group_permission(connection_group_id);
CREATE INDEX guacamole_connection_group_permission_user_id
ON guacamole_connection_group_permission(user_id);
CREATE INDEX guacamole_connection_group_permission_entity_id
ON guacamole_connection_group_permission(entity_id);
--
-- 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 (
user_id integer NOT NULL,
entity_id integer NOT NULL,
sharing_profile_id integer 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
FOREIGN KEY (sharing_profile_id)
REFERENCES guacamole_sharing_profile (sharing_profile_id) ON DELETE CASCADE,
CONSTRAINT guacamole_sharing_profile_permission_ibfk_2
FOREIGN KEY (user_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE
CONSTRAINT guacamole_sharing_profile_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_sharing_profile_permission_sharing_profile_id
ON guacamole_sharing_profile_permission(sharing_profile_id);
CREATE INDEX guacamole_sharing_profile_permission_user_id
ON guacamole_sharing_profile_permission(user_id);
CREATE INDEX guacamole_sharing_profile_permission_entity_id
ON guacamole_sharing_profile_permission(entity_id);
--
-- Table of system permissions. Each system permission grants a user a
-- system-level privilege of some kind.
-- Table of system permissions. Each system permission grants a user or user
-- group a system-level privilege of some kind.
--
CREATE TABLE guacamole_system_permission (
user_id integer NOT NULL,
entity_id integer 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
FOREIGN KEY (user_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE
CONSTRAINT guacamole_system_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_system_permission_user_id
ON guacamole_system_permission(user_id);
CREATE INDEX guacamole_system_permission_entity_id
ON guacamole_system_permission(entity_id);
--
-- Table of user permissions. Each user permission grants a user access to
-- another user (the "affected" user) for a specific type of operation.
-- Table of user permissions. Each user permission grants a user or user group
-- access to another user (the "affected" user) for a specific type of
-- operation.
--
CREATE TABLE guacamole_user_permission (
user_id integer NOT NULL,
entity_id integer NOT NULL,
affected_user_id integer 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
FOREIGN KEY (affected_user_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE,
CONSTRAINT guacamole_user_permission_ibfk_2
FOREIGN KEY (user_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE
CONSTRAINT guacamole_user_permission_entity
FOREIGN KEY (entity_id)
REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_user_permission_affected_user_id
ON guacamole_user_permission(affected_user_id);
CREATE INDEX guacamole_user_permission_user_id
ON guacamole_user_permission(user_id);
CREATE INDEX guacamole_user_permission_entity_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

View File

@@ -17,36 +17,39 @@
-- under the License.
--
-- Create default user "guacadmin" with password "guacadmin"
INSERT INTO guacamole_user (username, password_hash, password_salt, password_date)
VALUES ('guacadmin',
INSERT INTO guacamole_entity (name, type) VALUES ('guacadmin', 'USER');
INSERT INTO guacamole_user (entity_id, password_hash, password_salt, password_date)
SELECT
entity_id,
decode('CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', 'hex'), -- 'guacadmin'
decode('FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264', 'hex'),
CURRENT_TIMESTAMP);
CURRENT_TIMESTAMP
FROM guacamole_entity WHERE name = 'guacadmin' AND guacamole_entity.type = 'USER';
-- Grant this user all system permissions
INSERT INTO guacamole_system_permission
SELECT user_id, permission::guacamole_system_permission_type
INSERT INTO guacamole_system_permission (entity_id, permission)
SELECT entity_id, permission::guacamole_system_permission_type
FROM (
VALUES
('guacadmin', 'CREATE_CONNECTION'),
('guacadmin', 'CREATE_CONNECTION_GROUP'),
('guacadmin', 'CREATE_SHARING_PROFILE'),
('guacadmin', 'CREATE_USER'),
('guacadmin', 'CREATE_USER_GROUP'),
('guacadmin', 'ADMINISTER')
) 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
INSERT INTO guacamole_user_permission
SELECT guacamole_user.user_id, affected.user_id, permission::guacamole_object_permission_type
INSERT INTO guacamole_user_permission (entity_id, affected_user_id, permission)
SELECT guacamole_entity.entity_id, guacamole_user.user_id, permission::guacamole_object_permission_type
FROM (
VALUES
('guacadmin', 'guacadmin', 'READ'),
('guacadmin', 'guacadmin', 'UPDATE'),
('guacadmin', 'guacadmin', 'ADMINISTER')
) permissions (username, affected_username, permission)
JOIN guacamole_user ON permissions.username = guacamole_user.username
JOIN guacamole_user affected ON permissions.affected_username = affected.username;
JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER'
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.
--
--
-- 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
-- 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
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
-- 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.LoggerFactory;
import org.apache.guacamole.auth.jdbc.security.PasswordPolicy;
import org.apache.ibatis.session.SqlSession;
/**
* A PostgreSQL-specific implementation of JDBCEnvironment provides database
@@ -243,4 +244,9 @@ public class PostgreSQLEnvironment extends JDBCEnvironment {
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
FROM guacamole_connection_permission
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'
</select>
@@ -89,7 +93,11 @@
WHERE
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</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'
</select>
@@ -165,7 +173,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer
</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'
GROUP BY guacamole_connection.connection_id;
@@ -177,7 +189,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer
</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';
SELECT
@@ -191,7 +207,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer
</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';
</select>

View File

@@ -79,7 +79,10 @@
#{record.sharingProfileIdentifier,jdbcType=INTEGER}::integer,
#{record.sharingProfileName,jdbcType=VARCHAR},
(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.startDate,jdbcType=TIMESTAMP},
#{record.endDate,jdbcType=TIMESTAMP}
@@ -163,13 +166,21 @@
<!-- Restrict to readable connections -->
JOIN guacamole_connection_permission ON
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'
<!-- Restrict to readable users -->
JOIN guacamole_user_permission ON
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'
<!-- Search terms -->
@@ -180,7 +191,10 @@
guacamole_connection_history.user_id IN (
SELECT user_id
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 (

View File

@@ -69,7 +69,11 @@
SELECT connection_group_id
FROM guacamole_connection_group_permission
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'
</select>
@@ -90,7 +94,11 @@
WHERE
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</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'
</select>
@@ -161,7 +169,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer
</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';
SELECT parent_id, guacamole_connection_group.connection_group_id
@@ -172,7 +184,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer
</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';
SELECT parent_id, guacamole_connection.connection_id
@@ -183,7 +199,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer
</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';
SELECT
@@ -197,7 +217,11 @@
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer
</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';
</select>

View File

@@ -25,24 +25,26 @@
<!-- Result mapper for connection permissions -->
<resultMap id="ConnectionGroupPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<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="connection_group_id" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap>
<!-- Select all permissions for a given user -->
<!-- Select all permissions for a given entity -->
<select id="select" resultMap="ConnectionGroupPermissionResultMap">
SELECT
guacamole_connection_group_permission.user_id,
username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
connection_group_id
FROM guacamole_connection_group_permission
JOIN guacamole_user ON guacamole_connection_group_permission.user_id = guacamole_user.user_id
WHERE guacamole_connection_group_permission.user_id = #{user.objectID,jdbcType=INTEGER}
WHERE
<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>
@@ -50,26 +52,32 @@
<select id="selectOne" resultMap="ConnectionGroupPermissionResultMap">
SELECT
guacamole_connection_group_permission.user_id,
username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
connection_group_id
FROM guacamole_connection_group_permission
JOIN guacamole_user ON guacamole_connection_group_permission.user_id = guacamole_user.user_id
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 connection_group_id = #{identifier,jdbcType=INTEGER}::integer
</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 DISTINCT connection_group_id
FROM guacamole_connection_group_permission
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
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
@@ -87,10 +95,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
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"
open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER},
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
#{permission.objectIdentifier,jdbcType=INTEGER}::integer)
</foreach>
@@ -101,25 +109,25 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT INTO guacamole_connection_group_permission (
user_id,
entity_id,
permission,
connection_group_id
)
SELECT DISTINCT
permissions.user_id,
permissions.entity_id,
permissions.permission,
permissions.connection_group_id
FROM
<foreach collection="permissions" item="permission"
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.objectIdentifier,jdbcType=INTEGER}::integer AS connection_group_id
</foreach>
AS permissions
WHERE (user_id, permission, connection_group_id) NOT IN (
WHERE (entity_id, permission, connection_group_id) NOT IN (
SELECT
guacamole_connection_group_permission.user_id,
guacamole_connection_group_permission.entity_id,
guacamole_connection_group_permission.permission,
guacamole_connection_group_permission.connection_group_id
FROM guacamole_connection_group_permission

View File

@@ -25,24 +25,26 @@
<!-- Result mapper for connection permissions -->
<resultMap id="ConnectionPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<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="connection_id" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap>
<!-- Select all permissions for a given user -->
<!-- Select all permissions for a given entity -->
<select id="select" resultMap="ConnectionPermissionResultMap">
SELECT
guacamole_connection_permission.user_id,
username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
connection_id
FROM guacamole_connection_permission
JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id
WHERE guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
WHERE
<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>
@@ -50,26 +52,32 @@
<select id="selectOne" resultMap="ConnectionPermissionResultMap">
SELECT
guacamole_connection_permission.user_id,
username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
connection_id
FROM guacamole_connection_permission
JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id
WHERE
guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
<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 connection_id = #{identifier,jdbcType=INTEGER}::integer
</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 DISTINCT connection_id
FROM guacamole_connection_permission
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
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
@@ -87,10 +95,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
DELETE FROM guacamole_connection_permission
WHERE (user_id, permission, connection_id) IN
WHERE (entity_id, permission, connection_id) IN
<foreach collection="permissions" item="permission"
open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER},
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
#{permission.objectIdentifier,jdbcType=INTEGER}::integer)
</foreach>
@@ -101,25 +109,25 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT INTO guacamole_connection_permission (
user_id,
entity_id,
permission,
connection_id
)
SELECT DISTINCT
permissions.user_id,
permissions.entity_id,
permissions.permission,
permissions.connection_id
FROM
<foreach collection="permissions" item="permission"
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.objectIdentifier,jdbcType=INTEGER}::integer AS connection_id
</foreach>
AS permissions
WHERE (user_id, permission, connection_id) NOT IN (
WHERE (entity_id, permission, connection_id) NOT IN (
SELECT
guacamole_connection_permission.user_id,
guacamole_connection_permission.entity_id,
guacamole_connection_permission.permission,
guacamole_connection_permission.connection_id
FROM guacamole_connection_permission

View File

@@ -25,24 +25,26 @@
<!-- Result mapper for sharing profile permissions -->
<resultMap id="SharingProfilePermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<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="sharing_profile_id" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap>
<!-- Select all permissions for a given user -->
<!-- Select all permissions for a given entity -->
<select id="select" resultMap="SharingProfilePermissionResultMap">
SELECT
guacamole_sharing_profile_permission.user_id,
username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
sharing_profile_id
FROM guacamole_sharing_profile_permission
JOIN guacamole_user ON guacamole_sharing_profile_permission.user_id = guacamole_user.user_id
WHERE guacamole_sharing_profile_permission.user_id = #{user.objectID,jdbcType=INTEGER}
WHERE
<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>
@@ -50,26 +52,32 @@
<select id="selectOne" resultMap="SharingProfilePermissionResultMap">
SELECT
guacamole_sharing_profile_permission.user_id,
username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
sharing_profile_id
FROM guacamole_sharing_profile_permission
JOIN guacamole_user ON guacamole_sharing_profile_permission.user_id = guacamole_user.user_id
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 sharing_profile_id = #{identifier,jdbcType=INTEGER}::integer
</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 DISTINCT sharing_profile_id
FROM guacamole_sharing_profile_permission
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
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
@@ -87,10 +95,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
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"
open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER},
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
#{permission.objectIdentifier,jdbcType=INTEGER}::integer)
</foreach>
@@ -101,25 +109,25 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT INTO guacamole_sharing_profile_permission (
user_id,
entity_id,
permission,
sharing_profile_id
)
SELECT DISTINCT
permissions.user_id,
permissions.entity_id,
permissions.permission,
permissions.sharing_profile_id
FROM
<foreach collection="permissions" item="permission"
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.objectIdentifier,jdbcType=INTEGER}::integer AS sharing_profile_id
</foreach>
AS permissions
WHERE (user_id, permission, sharing_profile_id) NOT IN (
WHERE (entity_id, permission, sharing_profile_id) NOT IN (
SELECT
guacamole_sharing_profile_permission.user_id,
guacamole_sharing_profile_permission.entity_id,
guacamole_sharing_profile_permission.permission,
guacamole_sharing_profile_permission.sharing_profile_id
FROM guacamole_sharing_profile_permission

View File

@@ -25,36 +25,40 @@
<!-- Result mapper for system permissions -->
<resultMap id="SystemPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.permission.SystemPermission$Type"/>
</resultMap>
<!-- Select all permissions for a given user -->
<!-- Select all permissions for a given entity -->
<select id="select" resultMap="SystemPermissionResultMap">
SELECT
guacamole_system_permission.user_id,
username,
SELECT DISTINCT
#{entity.entityID} AS entity_id,
permission
FROM guacamole_system_permission
JOIN guacamole_user ON guacamole_system_permission.user_id = guacamole_user.user_id
WHERE guacamole_system_permission.user_id = #{user.objectID,jdbcType=INTEGER}
WHERE
<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 the single permission matching the given criteria -->
<select id="selectOne" resultMap="SystemPermissionResultMap">
SELECT
guacamole_system_permission.user_id,
username,
SELECT DISTINCT
#{entity.entityID} AS entity_id,
permission
FROM guacamole_system_permission
JOIN guacamole_user ON guacamole_system_permission.user_id = guacamole_user.user_id
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
</select>
@@ -63,10 +67,10 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
DELETE FROM guacamole_system_permission
WHERE (user_id, permission) IN
WHERE (entity_id, permission) IN
<foreach collection="permissions" item="permission"
open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER},
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}::guacamole_system_permission_type)
</foreach>
@@ -76,22 +80,22 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
INSERT INTO guacamole_system_permission (
user_id,
entity_id,
permission
)
SELECT DISTINCT
permissions.user_id,
permissions.entity_id,
permissions.permission
FROM
<foreach collection="permissions" item="permission"
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
</foreach>
AS permissions
WHERE (user_id, permission) NOT IN (
WHERE (entity_id, permission) NOT IN (
SELECT
guacamole_system_permission.user_id,
guacamole_system_permission.entity_id,
guacamole_system_permission.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 -->
<resultMap id="UserPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
<result column="user_id" property="userID" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<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_username" property="objectIdentifier" jdbcType="INTEGER"/>
<result column="affected_name" property="objectIdentifier" jdbcType="INTEGER"/>
</resultMap>
<!-- Select all permissions for a given user -->
<!-- Select all permissions for a given entity -->
<select id="select" resultMap="UserPermissionResultMap">
SELECT
guacamole_user_permission.user_id,
guacamole_user.username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
affected.username AS affected_username
affected_entity.name AS affected_name
FROM guacamole_user_permission
JOIN guacamole_user ON guacamole_user_permission.user_id = guacamole_user.user_id
JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id
WHERE guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
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
<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>
@@ -51,38 +55,48 @@
<select id="selectOne" resultMap="UserPermissionResultMap">
SELECT
guacamole_user_permission.user_id,
guacamole_user.username,
#{entity.entityID,jdbcType=INTEGER} AS entity_id,
permission,
affected.username AS affected_username
affected_entity.name AS affected_name
FROM guacamole_user_permission
JOIN guacamole_user ON guacamole_user_permission.user_id = guacamole_user.user_id
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
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 affected.username = #{identifier,jdbcType=INTEGER}
AND affected_entity.name = #{identifier,jdbcType=VARCHAR}
AND affected_entity.type = 'USER'::guacamole_entity_type
</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 DISTINCT username
SELECT DISTINCT affected_entity.name
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
guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
AND username IN
<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.name IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}
#{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'::guacamole_entity_type
</select>
@@ -90,16 +104,18 @@
<delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
DELETE FROM guacamole_user_permission
USING guacamole_user affected
USING guacamole_user affected_user, guacamole_entity affected_entity
WHERE
guacamole_user_permission.affected_user_id = affected.user_id
AND (guacamole_user_permission.user_id, permission, affected.username) IN
guacamole_user_permission.affected_user_id = affected_user.user_id
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"
open="(" separator="," close=")">
(#{permission.userID,jdbcType=INTEGER},
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
#{permission.objectIdentifier,jdbcType=INTEGER})
</foreach>
AND affected_entity.type = 'USER'::guacamole_entity_type
</delete>
@@ -107,26 +123,29 @@
<insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
INSERT INTO guacamole_user_permission (
user_id,
entity_id,
permission,
affected_user_id
)
SELECT DISTINCT
permissions.user_id,
permissions.entity_id,
permissions.permission,
guacamole_user.user_id
affected_user.user_id
FROM
<foreach collection="permissions" item="permission"
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.objectIdentifier,jdbcType=INTEGER} AS username
#{permission.objectIdentifier,jdbcType=VARCHAR}::text AS affected_name
</foreach>
AS permissions
JOIN guacamole_user ON guacamole_user.username = permissions.username
WHERE (permissions.user_id, permissions.permission, guacamole_user.user_id) NOT IN (
JOIN guacamole_entity affected_entity ON
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
guacamole_user_permission.user_id,
guacamole_user_permission.entity_id,
guacamole_user_permission.permission,
guacamole_user_permission.affected_user_id
FROM guacamole_user_permission

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