GUACAMOLE-220: Map and query user group tables.

This commit is contained in:
Michael Jumper
2018-04-08 00:08:36 -07:00
parent 69f58c8ca3
commit c5c2984151
13 changed files with 1127 additions and 9 deletions

View File

@@ -65,6 +65,9 @@ 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;
@@ -79,6 +82,10 @@ 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.UserGroupService;
import org.mybatis.guice.MyBatisModule;
import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider;
@@ -128,6 +135,8 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
addMapperClass(SharingProfileMapper.class);
addMapperClass(SharingProfileParameterMapper.class);
addMapperClass(SharingProfilePermissionMapper.class);
addMapperClass(UserGroupMapper.class);
addMapperClass(UserGroupPermissionMapper.class);
addMapperClass(UserMapper.class);
addMapperClass(UserPermissionMapper.class);
addMapperClass(UserRecordMapper.class);
@@ -146,12 +155,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
@@ -172,6 +184,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

@@ -28,13 +28,13 @@ import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissio
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;
import org.apache.guacamole.net.auth.simple.SimpleObjectPermissionSet;
/**
* An implementation of the base Permissions interface which is common to both
@@ -88,6 +88,12 @@ public abstract class ModeledPermissions<ModelType extends EntityModel>
@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.
@@ -171,8 +177,8 @@ public abstract class ModeledPermissions<ModelType extends EntityModel>
@Override
public ObjectPermissionSet getUserGroupPermissions() throws GuacamoleException {
// FIXME: STUB
return new SimpleObjectPermissionSet();
return userGroupPermissionService.getPermissionSet(getCurrentUser(),
this, Collections.<String>emptySet());
}
/**
@@ -256,8 +262,7 @@ public abstract class ModeledPermissions<ModelType extends EntityModel>
@Override
public ObjectPermissionSet getUserGroupPermissions()
throws GuacamoleException {
// FIXME: STUB
return new SimpleObjectPermissionSet();
return userGroupPermissionService.getPermissionSet(getCurrentUser(), ModeledPermissions.this, effectiveGroups);
}
};

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

@@ -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

@@ -0,0 +1,191 @@
/*
* 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.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;
import org.apache.guacamole.net.auth.simple.SimpleRelatedObjectSet;
/**
* 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
)));
/**
* Service for managing user groups.
*/
@Inject
private UserGroupService userGroupService;
/**
* 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;
}
/**
* Creates a new, empty ModeledUserGroup.
*/
public ModeledUserGroup() {
}
/**
* 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 {
return new SimpleRelatedObjectSet();
}
@Override
public RelatedObjectSet getMemberUsers() throws GuacamoleException {
return new SimpleRelatedObjectSet();
}
@Override
public RelatedObjectSet getMemberUserGroups() throws GuacamoleException {
return new SimpleRelatedObjectSet();
}
}

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,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,189 @@
/*
* 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.Collection;
import java.util.Collections;
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
Collection<UserGroupModel> existing = userGroupMapper.select(Collections.singleton(model.getIdentifier()));
if (!existing.isEmpty())
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);
// Username must not be blank
if (model.getIdentifier() == null || model.getIdentifier().trim().isEmpty())
throw new GuacamoleClientException("The group name must not be blank.");
// Check whether such a group is already present
UserGroupModel existing = userGroupMapper.selectOne(model.getIdentifier());
if (existing != null) {
// Do not rename to existing user group
if (!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

@@ -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

@@ -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'::guacamole_entity_type
</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'::guacamole_entity_type
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'::guacamole_entity_type;
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'::guacamole_entity_type;
</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'::guacamole_entity_type
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'::guacamole_entity_type
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'::guacamole_entity_type;
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'::guacamole_entity_type
</select>
<!-- Delete single group by name -->
<delete id="delete">
DELETE FROM guacamole_entity
WHERE
name = #{identifier,jdbcType=VARCHAR}
AND type = 'USER_GROUP'::guacamole_entity_type
</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>