GUACAMOLE-220: Merge add base extension API support for user groups.

This commit is contained in:
Nick Couchman
2018-04-22 15:45:46 -04:00
35 changed files with 875 additions and 167 deletions

View File

@@ -19,6 +19,8 @@
package org.apache.guacamole.auth.jdbc.sharing.user; 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.auth.jdbc.user.RemoteAuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.AuthenticationProvider;
@@ -100,4 +102,9 @@ public class SharedAuthenticatedUser extends RemoteAuthenticatedUser {
throw new UnsupportedOperationException("Users authenticated via share keys are immutable."); throw new UnsupportedOperationException("Users authenticated via share keys are immutable.");
} }
@Override
public Set<String> getEffectiveUserGroups() {
return Collections.<String>emptySet();
}
} }

View File

@@ -30,10 +30,13 @@ import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionGroup; import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Directory;
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.User;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet; import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
import org.apache.guacamole.net.auth.simple.SimpleObjectPermissionSet; import org.apache.guacamole.net.auth.simple.SimpleObjectPermissionSet;
import org.apache.guacamole.net.auth.simple.SimpleRelatedObjectSet;
import org.apache.guacamole.net.auth.simple.SimpleSystemPermissionSet; import org.apache.guacamole.net.auth.simple.SimpleSystemPermissionSet;
/** /**
@@ -140,6 +143,11 @@ public class SharedUser implements User {
return new SharedObjectPermissionSet(userDirectory.getIdentifiers()); return new SharedObjectPermissionSet(userDirectory.getIdentifiers());
} }
@Override
public ObjectPermissionSet getUserGroupPermissions() throws GuacamoleException {
return new SimpleObjectPermissionSet();
}
@Override @Override
public ObjectPermissionSet getSharingProfilePermissions() throws GuacamoleException { public ObjectPermissionSet getSharingProfilePermissions() throws GuacamoleException {
return new SimpleObjectPermissionSet(); return new SimpleObjectPermissionSet();
@@ -150,4 +158,14 @@ public class SharedUser implements User {
return new SimpleObjectPermissionSet(); return new SimpleObjectPermissionSet();
} }
@Override
public RelatedObjectSet getUserGroups() throws GuacamoleException {
return new SimpleRelatedObjectSet();
}
@Override
public Permissions getEffectivePermissions() throws GuacamoleException {
return this;
}
} }

View File

@@ -169,4 +169,9 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser {
user.setIdentifier(identifier); user.setIdentifier(identifier);
} }
@Override
public Set<String> getEffectiveUserGroups() {
return Collections.<String>emptySet();
}
} }

View File

@@ -52,10 +52,14 @@ import org.apache.guacamole.form.TextField;
import org.apache.guacamole.form.TimeField; import org.apache.guacamole.form.TimeField;
import org.apache.guacamole.form.TimeZoneField; import org.apache.guacamole.form.TimeZoneField;
import org.apache.guacamole.net.auth.ActivityRecord; 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.User;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermission; import org.apache.guacamole.net.auth.permission.SystemPermission;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet; import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
import org.apache.guacamole.net.auth.simple.SimpleObjectPermissionSet;
import org.apache.guacamole.net.auth.simple.SimpleRelatedObjectSet;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -379,6 +383,11 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
return userPermissionService.getPermissionSet(getCurrentUser(), this); return userPermissionService.getPermissionSet(getCurrentUser(), this);
} }
@Override
public ObjectPermissionSet getUserGroupPermissions() throws GuacamoleException {
return new SimpleObjectPermissionSet();
}
/** /**
* Stores all restricted (privileged) attributes within the given Map, * Stores all restricted (privileged) attributes within the given Map,
* pulling the values of those attributes from the underlying user model. * pulling the values of those attributes from the underlying user model.
@@ -839,4 +848,14 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
return userService.retrieveHistory(getCurrentUser(), this); return userService.retrieveHistory(getCurrentUser(), this);
} }
@Override
public RelatedObjectSet getUserGroups() throws GuacamoleException {
return new SimpleRelatedObjectSet();
}
@Override
public Permissions getEffectivePermissions() throws GuacamoleException {
return this;
}
} }

View File

@@ -26,6 +26,7 @@ import org.apache.guacamole.auth.jdbc.connection.ConnectionDirectory;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.RestrictedObject; import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
@@ -46,6 +47,8 @@ import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.SharingProfile; import org.apache.guacamole.net.auth.SharingProfile;
import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.UserGroup;
import org.apache.guacamole.net.auth.simple.SimpleDirectory;
/** /**
* UserContext implementation which is driven by an arbitrary, underlying * UserContext implementation which is driven by an arbitrary, underlying
@@ -161,6 +164,11 @@ public class ModeledUserContext extends RestrictedObject
return userDirectory; return userDirectory;
} }
@Override
public Directory<UserGroup> getUserGroupDirectory() throws GuacamoleException {
return new SimpleDirectory<UserGroup>();
}
@Override @Override
public Directory<Connection> getConnectionDirectory() throws GuacamoleException { public Directory<Connection> getConnectionDirectory() throws GuacamoleException {
return connectionDirectory; return connectionDirectory;
@@ -214,6 +222,11 @@ public class ModeledUserContext extends RestrictedObject
return ModeledUser.ATTRIBUTES; return ModeledUser.ATTRIBUTES;
} }
@Override
public Collection<Form> getUserGroupAttributes() {
return Collections.<Form>emptyList();
}
@Override @Override
public Collection<Form> getConnectionAttributes() { public Collection<Form> getConnectionAttributes() {
return ModeledConnection.ATTRIBUTES; return ModeledConnection.ATTRIBUTES;

View File

@@ -19,6 +19,8 @@
package org.apache.guacamole.net.auth; package org.apache.guacamole.net.auth;
import java.util.Collections;
import java.util.Set;
/** /**
* Basic implementation of an AuthenticatedUser which uses the username to * Basic implementation of an AuthenticatedUser which uses the username to
@@ -29,6 +31,11 @@ public abstract class AbstractAuthenticatedUser extends AbstractIdentifiable
// Prior functionality now resides within AbstractIdentifiable // Prior functionality now resides within AbstractIdentifiable
@Override
public Set<String> getEffectiveUserGroups() {
return Collections.<String>emptySet();
}
@Override @Override
public void invalidate() { public void invalidate() {
// Nothing to invalidate // Nothing to invalidate

View File

@@ -67,6 +67,19 @@ public abstract class AbstractUserContext implements UserContext {
return new SimpleDirectory<User>(self()); return new SimpleDirectory<User>(self());
} }
/**
* {@inheritDoc}
*
* <p>This implementation simply returns an empty {@link Directory}.
* Implementations that wish to expose user groups should override this
* function.
*/
@Override
public Directory<UserGroup> getUserGroupDirectory()
throws GuacamoleException {
return new SimpleDirectory<UserGroup>();
}
/** /**
* {@inheritDoc} * {@inheritDoc}
* *
@@ -181,6 +194,18 @@ public abstract class AbstractUserContext implements UserContext {
return Collections.<Form>emptyList(); return Collections.<Form>emptyList();
} }
/**
* {@inheritDoc}
*
* <p>This implementation simply returns an empty {@link Collection}.
* Implementations that wish to expose custom user group attributes as
* fields within user group edit screens should override this function.
*/
@Override
public Collection<Form> getUserGroupAttributes() {
return Collections.<Form>emptyList();
}
/** /**
* {@inheritDoc} * {@inheritDoc}
* *

View File

@@ -19,6 +19,7 @@
package org.apache.guacamole.net.auth; package org.apache.guacamole.net.auth;
import java.util.Set;
/** /**
* A user of the Guacamole web application who has been authenticated by an * A user of the Guacamole web application who has been authenticated by an
@@ -49,6 +50,24 @@ public interface AuthenticatedUser extends Identifiable {
*/ */
Credentials getCredentials(); Credentials getCredentials();
/**
* Returns a read-only set of the identifiers of all user groups which
* apply to this authenticated user. The exact semantics of what user
* groups apply are up to the implementation, and the user groups within
* this set may be implied, derived dynamically, inherited through multiple
* levels of group membership, etc.
*
* Note that, as with user identifiers, user group identifiers form the
* basis of identity which applies across authentication providers. It is
* expected that any two user groups having the same identifier represent
* the same group, even if defined by different authentication providers.
*
* @return
* A read-only set of the identifiers of all user groups which apply
* to this authenticated user.
*/
Set<String> getEffectiveUserGroups();
/** /**
* Invalidates this authenticated user and their associated token such that * Invalidates this authenticated user and their associated token such that
* they are no longer logged in. This function will be automatically * they are no longer logged in. This function will be automatically

View File

@@ -124,4 +124,20 @@ public class DelegatingUser implements User {
return user.getUserPermissions(); return user.getUserPermissions();
} }
@Override
public ObjectPermissionSet getUserGroupPermissions()
throws GuacamoleException {
return user.getUserGroupPermissions();
}
@Override
public RelatedObjectSet getUserGroups() throws GuacamoleException {
return user.getUserGroups();
}
@Override
public Permissions getEffectivePermissions() throws GuacamoleException {
return user.getEffectivePermissions();
}
} }

View File

@@ -65,6 +65,11 @@ public class DelegatingUserContext implements UserContext {
return userContext.getUserDirectory(); return userContext.getUserDirectory();
} }
@Override
public Directory<UserGroup> getUserGroupDirectory() throws GuacamoleException {
return userContext.getUserGroupDirectory();
}
@Override @Override
public Directory<Connection> getConnectionDirectory() public Directory<Connection> getConnectionDirectory()
throws GuacamoleException { throws GuacamoleException {
@@ -111,6 +116,11 @@ public class DelegatingUserContext implements UserContext {
return userContext.getUserAttributes(); return userContext.getUserAttributes();
} }
@Override
public Collection<Form> getUserGroupAttributes() {
return userContext.getUserGroupAttributes();
}
@Override @Override
public Collection<Form> getConnectionAttributes() { public Collection<Form> getConnectionAttributes() {
return userContext.getConnectionAttributes(); return userContext.getConnectionAttributes();

View File

@@ -0,0 +1,125 @@
/*
* 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.net.auth;
import java.util.Map;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
/**
* UserGroup implementation which simply delegates all function calls to an
* underlying UserGroup.
*/
public class DelegatingUserGroup implements UserGroup {
/**
* The wrapped UserGroup.
*/
private final UserGroup userGroup;
/**
* Wraps the given UserGroup such that all function calls against this
* DelegatingUserGroup will be delegated to it.
*
* @param userGroup
* The UserGroup to wrap.
*/
public DelegatingUserGroup(UserGroup userGroup) {
this.userGroup = userGroup;
}
@Override
public String getIdentifier() {
return userGroup.getIdentifier();
}
@Override
public void setIdentifier(String identifier) {
userGroup.setIdentifier(identifier);
}
@Override
public Map<String, String> getAttributes() {
return userGroup.getAttributes();
}
@Override
public void setAttributes(Map<String, String> attributes) {
userGroup.setAttributes(attributes);
}
@Override
public SystemPermissionSet getSystemPermissions()
throws GuacamoleException {
return userGroup.getSystemPermissions();
}
@Override
public ObjectPermissionSet getConnectionPermissions()
throws GuacamoleException {
return userGroup.getConnectionPermissions();
}
@Override
public ObjectPermissionSet getConnectionGroupPermissions()
throws GuacamoleException {
return userGroup.getConnectionGroupPermissions();
}
@Override
public ObjectPermissionSet getSharingProfilePermissions()
throws GuacamoleException {
return userGroup.getSharingProfilePermissions();
}
@Override
public ObjectPermissionSet getActiveConnectionPermissions()
throws GuacamoleException {
return userGroup.getActiveConnectionPermissions();
}
@Override
public ObjectPermissionSet getUserPermissions() throws GuacamoleException {
return userGroup.getUserPermissions();
}
@Override
public ObjectPermissionSet getUserGroupPermissions()
throws GuacamoleException {
return userGroup.getUserGroupPermissions();
}
@Override
public RelatedObjectSet getUserGroups() throws GuacamoleException {
return userGroup.getUserGroups();
}
@Override
public RelatedObjectSet getMemberUsers() throws GuacamoleException {
return userGroup.getMemberUsers();
}
@Override
public RelatedObjectSet getMemberUserGroups() throws GuacamoleException {
return userGroup.getMemberUserGroups();
}
}

View File

@@ -0,0 +1,129 @@
/*
* 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.net.auth;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
/**
* An object which may be granted permissions to access/manipulate various
* other objects or aspects of the system. The permissions granted are exposed
* through subclasses of PermissionSet, and may be mutable depending on the
* access level of the current user.
*/
public interface Permissions {
/**
* Returns all permissions given to this object regarding currently-active
* connections.
*
* @return
* An ObjectPermissionSet of all active connection permissions granted
* to this object.
*
* @throws GuacamoleException
* If an error occurs while retrieving permissions, or if reading all
* permissions is not allowed.
*/
ObjectPermissionSet getActiveConnectionPermissions()
throws GuacamoleException;
/**
* Returns all connection group permissions given to this object.
*
* @return
* An ObjectPermissionSet of all connection group permissions granted
* to this object.
*
* @throws GuacamoleException
* If an error occurs while retrieving permissions, or if reading all
* permissions is not allowed.
*/
ObjectPermissionSet getConnectionGroupPermissions()
throws GuacamoleException;
/**
* Returns all connection permissions given to this object.
*
* @return
* An ObjectPermissionSet of all connection permissions granted to this
* object.
*
* @throws GuacamoleException
* If an error occurs while retrieving permissions, or if reading all
* permissions is not allowed.
*/
ObjectPermissionSet getConnectionPermissions() throws GuacamoleException;
/**
* Returns all sharing profile permissions given to this object.
*
* @return
* An ObjectPermissionSet of all sharing profile permissions granted to
* this object.
*
* @throws GuacamoleException
* If an error occurs while retrieving permissions, or if reading all
* permissions is not allowed.
*/
ObjectPermissionSet getSharingProfilePermissions()
throws GuacamoleException;
/**
* Returns all system-level permissions given to this object.
*
* @return
* A SystemPermissionSet of all system-level permissions granted to
* this object.
*
* @throws GuacamoleException
* If an error occurs while retrieving permissions, or if reading all
* permissions is not allowed.
*/
SystemPermissionSet getSystemPermissions() throws GuacamoleException;
/**
* Returns all user permissions given to this object.
*
* @return
* An ObjectPermissionSet of all user permissions granted to this
* object.
*
* @throws GuacamoleException
* If an error occurs while retrieving permissions, or if reading all
* permissions is not allowed.
*/
ObjectPermissionSet getUserPermissions() throws GuacamoleException;
/**
* Returns all user group permissions given to this object.
*
* @return
* An ObjectPermissionSet of all user group permissions granted to this
* object.
*
* @throws GuacamoleException
* If an error occurs while retrieving permissions, or if reading all
* permissions is not allowed.
*/
ObjectPermissionSet getUserGroupPermissions() throws GuacamoleException;
}

View File

@@ -0,0 +1,78 @@
/*
* 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.net.auth;
import java.util.Set;
import org.apache.guacamole.GuacamoleException;
/**
* An arbitrary set of existing objects sharing some common relation. Unlike a
* Directory, which provides for maintaining the entire lifecycle of its
* objects, a RelatedObjectSet only maintains the relation between its
* containing object and the objects within the set. Adding/removing an object
* from a RelatedObjectSet affects only the status of the specific relationship
* represented by the RelatedObjectSet, not the existence of the objects
* themselves.
*/
public interface RelatedObjectSet {
/**
* Returns a Set which contains the identifiers of all objects contained
* within this RelatedObjectSet.
*
* @return
* A Set which contains the identifiers of all objects contained
* within this RelatedObjectSet.
*
* @throws GuacamoleException
* If an error occurs while retrieving the objects within the set, or
* if objects cannot be retrieved due to lack of permissions to do so.
*/
Set<String> getObjects() throws GuacamoleException;
/**
* Adds the objects having the given identifiers, if not already present.
* If a specified object is already present, no operation is performed
* regarding that object.
*
* @param identifiers
* The identifiers of all objects being added.
*
* @throws GuacamoleException
* If an error occurs while adding the objects, or if permission to add
* objects is denied.
*/
void addObjects(Set<String> identifiers) throws GuacamoleException;
/**
* Removes each of the objects having the specified identifiers, if
* present. If a specified object is not present, no operation is performed
* regarding that object.
*
* @param identifiers
* The identifiers of all objects being removed.
*
* @throws GuacamoleException
* If an error occurs while removing the objects, or if permission to
* remove objects is denied.
*/
void removeObjects(Set<String> identifiers) throws GuacamoleException;
}

View File

@@ -22,14 +22,11 @@ package org.apache.guacamole.net.auth;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
/** /**
* A user of the Guacamole web application. * A user of the Guacamole web application.
*/ */
public interface User extends Identifiable, Attributes { public interface User extends Identifiable, Attributes, Permissions {
/** /**
* All standard attribute names with semantics defined by the Guacamole web * All standard attribute names with semantics defined by the Guacamole web
@@ -109,85 +106,33 @@ public interface User extends Identifiable, Attributes {
List<? extends ActivityRecord> getHistory() throws GuacamoleException; List<? extends ActivityRecord> getHistory() throws GuacamoleException;
/** /**
* Returns all system-level permissions given to this user. * Returns a set of all readable user groups of which this user is a member.
* If permission is granted for the current user to modify the membership of
* this user, then the returned set will be mutable, and any such
* modifications should be made through changes to the returned set.
* *
* @return * @return
* A SystemPermissionSet of all system-level permissions granted to * The set of all readable user groups of which this user is a member.
* this user.
* *
* @throws GuacamoleException * @throws GuacamoleException
* If an error occurs while retrieving permissions, or if reading all * If an error occurs while retrieving the user groups.
* permissions is not allowed.
*/ */
SystemPermissionSet getSystemPermissions() throws GuacamoleException; RelatedObjectSet getUserGroups() throws GuacamoleException;
/** /**
* Returns all connection permissions given to this user. * Returns a read-only view of all permissions granted to this user. The
* exact semantics of what permissions are granted are up to the
* implementation, and the permissions within this view may be implied,
* derived dynamically, inherited through multiple levels of group
* membership, etc.
* *
* @return * @return
* An ObjectPermissionSet of all connection permissions granted to this * A read-only view of the permissions which are granted to this user.
* user.
* *
* @throws GuacamoleException * @throws GuacamoleException
* If an error occurs while retrieving permissions, or if reading all * If an error occurs while retrieving permissions, or if reading all
* permissions is not allowed. * permissions is not allowed.
*/ */
ObjectPermissionSet getConnectionPermissions() Permissions getEffectivePermissions() throws GuacamoleException;
throws GuacamoleException;
/**
* Returns all connection group permissions given to this user.
*
* @return
* An ObjectPermissionSet of all connection group permissions granted
* to this user.
*
* @throws GuacamoleException
* If an error occurs while retrieving permissions, or if reading all
* permissions is not allowed.
*/
ObjectPermissionSet getConnectionGroupPermissions()
throws GuacamoleException;
/**
* Returns all sharing profile permissions given to this user.
*
* @return
* An ObjectPermissionSet of all sharing profile permissions granted to
* this user.
*
* @throws GuacamoleException
* If an error occurs while retrieving permissions, or if reading all
* permissions is not allowed.
*/
ObjectPermissionSet getSharingProfilePermissions()
throws GuacamoleException;
/**
* Returns all permissions given to this user regarding currently-active
* connections.
*
* @return
* An ObjectPermissionSet of all active connection permissions granted
* to this user.
*
* @throws GuacamoleException
* If an error occurs while retrieving permissions, or if reading all
* permissions is not allowed.
*/
ObjectPermissionSet getActiveConnectionPermissions()
throws GuacamoleException;
/**
* Returns all user permissions given to this user.
*
* @return
* An ObjectPermissionSet of all user permissions granted to this user.
*
* @throws GuacamoleException
* If an error occurs while retrieving permissions, or if reading all
* permissions is not allowed.
*/
ObjectPermissionSet getUserPermissions() throws GuacamoleException;
} }

View File

@@ -84,6 +84,20 @@ public interface UserContext {
*/ */
Directory<User> getUserDirectory() throws GuacamoleException; Directory<User> getUserDirectory() throws GuacamoleException;
/**
* Retrieves a Directory which can be used to view and manipulate user
* groups, but only as allowed by the permissions given to the user of this
* UserContext.
*
* @return
* A Directory whose operations are bound by the restrictions
* of this UserContext.
*
* @throws GuacamoleException
* If an error occurs while creating the Directory.
*/
Directory<UserGroup> getUserGroupDirectory() throws GuacamoleException;
/** /**
* Retrieves a Directory which can be used to view and manipulate * Retrieves a Directory which can be used to view and manipulate
* connections and their configurations, but only as allowed by the * connections and their configurations, but only as allowed by the
@@ -197,6 +211,17 @@ public interface UserContext {
*/ */
Collection<Form> getUserAttributes(); Collection<Form> getUserAttributes();
/**
* Retrieves a collection of all attributes applicable to user groups. This
* collection will contain only those attributes which the current user has
* general permission to view or modify. If there are no such attributes,
* this collection will be empty.
*
* @return
* A collection of all attributes applicable to user groups.
*/
Collection<Form> getUserGroupAttributes();
/** /**
* Retrieves a collection of all attributes applicable to connections. This * Retrieves a collection of all attributes applicable to connections. This
* collection will contain only those attributes which the current user has * collection will contain only those attributes which the current user has

View File

@@ -0,0 +1,77 @@
/*
* 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.net.auth;
import org.apache.guacamole.GuacamoleException;
/**
* A user group of the Guacamole web application. Each user group may contain
* any number of Guacamole users and other user groups, and defines the
* permissions implicitly granted to its members.
*/
public interface UserGroup extends Identifiable, Attributes, Permissions {
/**
* Returns a set of all readable user groups of which this user group is a
* member. If permission is granted for the current user to modify the
* membership of this user group, then the returned set will be mutable,
* and any such modifications should be made through changes to the
* returned set.
*
* @return
* The set of all readable user groups of which this user group is a
* member.
*
* @throws GuacamoleException
* If an error occurs while retrieving the user groups.
*/
RelatedObjectSet getUserGroups() throws GuacamoleException;
/**
* Returns a set of all readable users that are members of this user group.
* If permission is granted for the current user to modify the members of
* this group, then the returned set will be mutable, and any such
* modifications should be made through changes to the returned set.
*
* @return
* The set all readable users that are members of this user group,
* which may be mutable.
*
* @throws GuacamoleException
* If an error occurs while retrieving the users.
*/
RelatedObjectSet getMemberUsers() throws GuacamoleException;
/**
* Returns a set of all readable user groups that are members of this user
* group. If permission is granted for the current user to modify the
* members of this group, then the returned set will be mutable, and any
* such modifications should be made through changes to the returned set.
*
* @return
* The set of all readable user groups that are members of this user
* group, which may be mutable.
*
* @throws GuacamoleException
* If an error occurs while retrieving the user groups.
*/
RelatedObjectSet getMemberUserGroups() throws GuacamoleException;
}

View File

@@ -19,7 +19,9 @@
package org.apache.guacamole.net.auth.simple; package org.apache.guacamole.net.auth.simple;
import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.AbstractAuthenticatedUser; import org.apache.guacamole.net.auth.AbstractAuthenticatedUser;
@@ -131,6 +133,11 @@ public abstract class SimpleAuthenticationProvider
return credentials; return credentials;
} }
@Override
public Set<String> getEffectiveUserGroups() {
return Collections.<String>emptySet();
}
} }
/** /**

View File

@@ -0,0 +1,88 @@
/*
* 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.net.auth.simple;
import java.util.Collections;
import java.util.Set;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.net.auth.RelatedObjectSet;
/**
* A read-only implementation of RelatedObjectSet which uses a backing Set
* of identifiers to determine which objects are present.
*/
public class SimpleRelatedObjectSet implements RelatedObjectSet {
/**
* A set containing the identifiers of all objects currently present.
*/
private Set<String> identifiers = Collections.<String>emptySet();
/**
* Creates a new empty SimpleObjectPermissionSet.
*/
public SimpleRelatedObjectSet() {
}
/**
* Creates a new SimpleRelatedObjectSet which contains the objects having
* the identifiers within the given Set. The given Set backs the contents
* of the new SimpleRelatedObjectSet. While the SimpleRelatedObjectSet is
* read-only, any changes to the underlying Set will be reflected in the
* SimpleRelatedObjectSet.
*
* @param identifiers
* The Set containing the identifiers of all objects which should be
* present within the new SimpleRelatedObjectSet.
*/
public SimpleRelatedObjectSet(Set<String> identifiers) {
this.identifiers = identifiers;
}
/**
* Replaces the Set of object identifiers which backs this
* SimpleRelatedObjectSet. Future function calls on this
* SimpleRelatedObjectSet will instead use the provided Set.
*
* @param identifiers
* The Set containing the identifiers of all objects which should be
* present within this SimpleRelatedObjectSet.
*/
protected void setObjects(Set<String> identifiers) {
this.identifiers = identifiers;
}
@Override
public Set<String> getObjects() {
return identifiers;
}
@Override
public void addObjects(Set<String> identifiers) throws GuacamoleException {
throw new GuacamoleSecurityException("Permission denied.");
}
@Override
public void removeObjects(Set<String> identifiers) throws GuacamoleException {
throw new GuacamoleSecurityException("Permission denied.");
}
}

View File

@@ -29,6 +29,8 @@ import java.util.Set;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.AbstractUser; import org.apache.guacamole.net.auth.AbstractUser;
import org.apache.guacamole.net.auth.ActivityRecord; 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.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet; import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
@@ -200,6 +202,12 @@ public class SimpleUser extends AbstractUser {
return new SimpleObjectPermissionSet(userPermissions); return new SimpleObjectPermissionSet(userPermissions);
} }
@Override
public ObjectPermissionSet getUserGroupPermissions()
throws GuacamoleException {
return new SimpleObjectPermissionSet();
}
@Override @Override
public ObjectPermissionSet getActiveConnectionPermissions() public ObjectPermissionSet getActiveConnectionPermissions()
throws GuacamoleException { throws GuacamoleException {
@@ -211,4 +219,14 @@ public class SimpleUser extends AbstractUser {
return new SimpleObjectPermissionSet(); return new SimpleObjectPermissionSet();
} }
@Override
public RelatedObjectSet getUserGroups() throws GuacamoleException {
return new SimpleRelatedObjectSet();
}
@Override
public Permissions getEffectivePermissions() throws GuacamoleException {
return this;
}
} }

View File

@@ -35,9 +35,9 @@ import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionRecord; import org.apache.guacamole.net.auth.ConnectionRecord;
import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.Permissions;
import org.apache.guacamole.rest.directory.DirectoryView; import org.apache.guacamole.rest.directory.DirectoryView;
import org.apache.guacamole.net.auth.SharingProfile; import org.apache.guacamole.net.auth.SharingProfile;
import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
@@ -119,11 +119,12 @@ public class ConnectionResource extends DirectoryObjectResource<Connection, APIC
public Map<String, String> getConnectionParameters() public Map<String, String> getConnectionParameters()
throws GuacamoleException { throws GuacamoleException {
User self = userContext.self(); // Pull effective permissions
Permissions effective = userContext.self().getEffectivePermissions();
// Retrieve permission sets // Retrieve permission sets
SystemPermissionSet systemPermissions = self.getSystemPermissions(); SystemPermissionSet systemPermissions = effective.getSystemPermissions();
ObjectPermissionSet connectionPermissions = self.getConnectionPermissions(); ObjectPermissionSet connectionPermissions = effective.getConnectionPermissions();
// Deny access if adminstrative or update permission is missing // Deny access if adminstrative or update permission is missing
String identifier = connection.getIdentifier(); String identifier = connection.getIdentifier();

View File

@@ -29,8 +29,8 @@ import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionGroup; import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.Permissions;
import org.apache.guacamole.net.auth.SharingProfile; import org.apache.guacamole.net.auth.SharingProfile;
import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
@@ -356,9 +356,9 @@ public class ConnectionGroupTree {
retrievedGroups.put(root.getIdentifier(), this.rootAPIGroup); retrievedGroups.put(root.getIdentifier(), this.rootAPIGroup);
// Store user's current permissions // Store user's current permissions
User self = userContext.self(); Permissions effective = userContext.self().getEffectivePermissions();
this.connectionPermissions = self.getConnectionPermissions(); this.connectionPermissions = effective.getConnectionPermissions();
this.sharingProfilePermissions = self.getSharingProfilePermissions(); this.sharingProfilePermissions = effective.getSharingProfilePermissions();
// Store required directories // Store required directories
this.connectionDirectory = userContext.getConnectionDirectory(); this.connectionDirectory = userContext.getConnectionDirectory();

View File

@@ -37,7 +37,7 @@ import org.apache.guacamole.GuacamoleResourceNotFoundException;
import org.apache.guacamole.GuacamoleUnsupportedException; import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.Identifiable; import org.apache.guacamole.net.auth.Identifiable;
import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.Permissions;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
@@ -142,14 +142,14 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
throws GuacamoleException { throws GuacamoleException {
// An admin user has access to all objects // An admin user has access to all objects
User self = userContext.self(); Permissions effective = userContext.self().getEffectivePermissions();
SystemPermissionSet systemPermissions = self.getSystemPermissions(); SystemPermissionSet systemPermissions = effective.getSystemPermissions();
boolean isAdmin = systemPermissions.hasPermission(SystemPermission.Type.ADMINISTER); boolean isAdmin = systemPermissions.hasPermission(SystemPermission.Type.ADMINISTER);
// Filter objects, if requested // Filter objects, if requested
Collection<String> identifiers = directory.getIdentifiers(); Collection<String> identifiers = directory.getIdentifiers();
if (!isAdmin && permissions != null && !permissions.isEmpty()) { if (!isAdmin && permissions != null && !permissions.isEmpty()) {
ObjectPermissionSet objectPermissions = self.getUserPermissions(); ObjectPermissionSet objectPermissions = effective.getUserPermissions();
identifiers = objectPermissions.getAccessibleObjects(permissions, identifiers); identifiers = objectPermissions.getAccessibleObjects(permissions, identifiers);
} }

View File

@@ -24,20 +24,20 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.Permissions;
import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermission; import org.apache.guacamole.net.auth.permission.SystemPermission;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet; import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
/** /**
* The set of permissions which are granted to a specific user, organized by * The set of permissions which are granted to a specific user or user group,
* object type and, if applicable, identifier. This object can be constructed * organized by object type and, if applicable, identifier. This object can be
* with arbitrary permissions present, or manipulated after creation through * constructed with arbitrary permissions present, or manipulated after creation
* the manipulation or replacement of its collections of permissions, but is * through the manipulation or replacement of its collections of permissions,
* otherwise not intended for internal use as a data structure for permissions. * but is otherwise not intended for internal use as a data structure for
* Its primary purpose is as a hierarchical format for exchanging granted * permissions. Its primary purpose is as a hierarchical format for exchanging
* permissions with REST clients. * granted permissions with REST clients.
*/ */
public class APIPermissionSet { public class APIPermissionSet {
@@ -146,24 +146,23 @@ public class APIPermissionSet {
/** /**
* Creates a new permission set containing all permissions currently * Creates a new permission set containing all permissions currently
* granted to the given user. * granted within the given Permissions object.
* *
* @param user * @param permissions
* The user whose permissions should be stored within this permission * The permissions that should be stored within this permission set.
* set.
* *
* @throws GuacamoleException * @throws GuacamoleException
* If an error occurs while retrieving the user's permissions. * If an error occurs while retrieving the permissions.
*/ */
public APIPermissionSet(User user) throws GuacamoleException { public APIPermissionSet(Permissions permissions) throws GuacamoleException {
// Add all permissions from the provided user // Add all permissions from the provided user
addSystemPermissions(systemPermissions, user.getSystemPermissions()); addSystemPermissions(systemPermissions, permissions.getSystemPermissions());
addObjectPermissions(connectionPermissions, user.getConnectionPermissions()); addObjectPermissions(connectionPermissions, permissions.getConnectionPermissions());
addObjectPermissions(connectionGroupPermissions, user.getConnectionGroupPermissions()); addObjectPermissions(connectionGroupPermissions, permissions.getConnectionGroupPermissions());
addObjectPermissions(sharingProfilePermissions, user.getSharingProfilePermissions()); addObjectPermissions(sharingProfilePermissions, permissions.getSharingProfilePermissions());
addObjectPermissions(activeConnectionPermissions, user.getActiveConnectionPermissions()); addObjectPermissions(activeConnectionPermissions, permissions.getActiveConnectionPermissions());
addObjectPermissions(userPermissions, user.getUserPermissions()); addObjectPermissions(userPermissions, permissions.getUserPermissions());
} }
@@ -229,7 +228,7 @@ public class APIPermissionSet {
/** /**
* Returns a map of user IDs to the set of permissions granted for that * Returns a map of user IDs to the set of permissions granted for that
* user. If no permissions are granted to a particular user, its ID will * user. If no permissions are granted for a particular user, its ID will
* not be present as a key in the map. This map is mutable, and changes to * not be present as a key in the map. This map is mutable, and changes to
* to this map will affect the permission set directly. * to this map will affect the permission set directly.
* *

View File

@@ -30,8 +30,8 @@ import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.Permissions;
import org.apache.guacamole.net.auth.SharingProfile; import org.apache.guacamole.net.auth.SharingProfile;
import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
@@ -103,11 +103,12 @@ public class SharingProfileResource
public Map<String, String> getParameters() public Map<String, String> getParameters()
throws GuacamoleException { throws GuacamoleException {
User self = userContext.self(); // Pull effective permissions
Permissions effective = userContext.self().getEffectivePermissions();
// Retrieve permission sets // Retrieve permission sets
SystemPermissionSet systemPermissions = self.getSystemPermissions(); SystemPermissionSet systemPermissions = effective.getSystemPermissions();
ObjectPermissionSet sharingProfilePermissions = self.getSharingProfilePermissions(); ObjectPermissionSet sharingProfilePermissions = effective.getSharingProfilePermissions();
// Deny access if adminstrative or update permission is missing // Deny access if adminstrative or update permission is missing
String identifier = sharingProfile.getIdentifier(); String identifier = sharingProfile.getIdentifier();

View File

@@ -26,6 +26,8 @@ import java.util.Map;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException; import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.net.auth.ActivityRecord; 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.User;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet; import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
@@ -110,12 +112,28 @@ public class APIUserWrapper implements User {
throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access."); throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access.");
} }
@Override
public ObjectPermissionSet getUserGroupPermissions()
throws GuacamoleException {
throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access.");
}
@Override @Override
public ObjectPermissionSet getActiveConnectionPermissions() public ObjectPermissionSet getActiveConnectionPermissions()
throws GuacamoleException { throws GuacamoleException {
throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access."); throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access.");
} }
@Override
public Permissions getEffectivePermissions() throws GuacamoleException {
throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access.");
}
@Override
public RelatedObjectSet getUserGroups() throws GuacamoleException {
throw new GuacamoleUnsupportedException("APIUserWrapper does not provide group access.");
}
@Override @Override
public Date getLastActive() { public Date getLastActive() {
return null; return null;

View File

@@ -43,6 +43,7 @@ import org.apache.guacamole.net.auth.credentials.GuacamoleCredentialsException;
import org.apache.guacamole.rest.directory.DirectoryObjectResource; import org.apache.guacamole.rest.directory.DirectoryObjectResource;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator; import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
import org.apache.guacamole.rest.history.APIActivityRecord; import org.apache.guacamole.rest.history.APIActivityRecord;
import org.apache.guacamole.rest.permission.APIPermissionSet;
import org.apache.guacamole.rest.permission.PermissionSetResource; import org.apache.guacamole.rest.permission.PermissionSetResource;
/** /**
@@ -181,7 +182,8 @@ public class UserResource
/** /**
* Returns a resource which abstracts operations available on the overall * Returns a resource which abstracts operations available on the overall
* permissions granted to the User represented by this UserResource. * permissions granted directly to the User represented by this
* UserResource.
* *
* @return * @return
* A resource which representing the permissions granted to the User * A resource which representing the permissions granted to the User
@@ -192,4 +194,21 @@ public class UserResource
return new PermissionSetResource(user); return new PermissionSetResource(user);
} }
/**
* Returns a read-only view of the permissions effectively granted to this
* user, including permissions which may be inherited or implied.
*
* @return
* A read-only view of the permissions effectively granted to this
* user.
*
* @throws GuacamoleException
* If the effective permissions for this user cannot be retrieved.
*/
@GET
@Path("effectivePermissions")
public APIPermissionSet getEffectivePermissions() throws GuacamoleException {
return new APIPermissionSet(user.getEffectivePermissions());
}
} }

View File

@@ -199,7 +199,7 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i
}); });
// Query the user's permissions for the current connection // Query the user's permissions for the current connection
permissionService.getPermissions($scope.selectedDataSource, authenticationService.getCurrentUsername()) permissionService.getEffectivePermissions($scope.selectedDataSource, authenticationService.getCurrentUsername())
.success(function permissionsReceived(permissions) { .success(function permissionsReceived(permissions) {
$scope.permissions = permissions; $scope.permissions = permissions;

View File

@@ -134,7 +134,7 @@ angular.module('manage').controller('manageConnectionGroupController', ['$scope'
}); });
// Query the user's permissions for the current connection group // Query the user's permissions for the current connection group
permissionService.getPermissions($scope.selectedDataSource, authenticationService.getCurrentUsername()) permissionService.getEffectivePermissions($scope.selectedDataSource, authenticationService.getCurrentUsername())
.success(function permissionsReceived(permissions) { .success(function permissionsReceived(permissions) {
$scope.permissions = permissions; $scope.permissions = permissions;

View File

@@ -175,7 +175,7 @@ angular.module('manage').controller('manageSharingProfileController', ['$scope',
}); });
// Query the user's permissions for the current sharing profile // Query the user's permissions for the current sharing profile
permissionService.getPermissions($scope.selectedDataSource, authenticationService.getCurrentUsername()) permissionService.getEffectivePermissions($scope.selectedDataSource, authenticationService.getCurrentUsername())
.success(function permissionsReceived(permissions) { .success(function permissionsReceived(permissions) {
$scope.permissions = permissions; $scope.permissions = permissions;

View File

@@ -680,7 +680,7 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
// Query the user's permissions for the current user // Query the user's permissions for the current user
dataSourceService.apply( dataSourceService.apply(
permissionService.getPermissions, permissionService.getEffectivePermissions,
dataSources, dataSources,
currentUsername currentUsername
) )

View File

@@ -329,7 +329,7 @@ angular.module('navigation').factory('userPageService', ['$injector',
// Retrieve current permissions // Retrieve current permissions
dataSourceService.apply( dataSourceService.apply(
permissionService.getPermissions, permissionService.getEffectivePermissions,
authenticationService.getAvailableDataSources(), authenticationService.getAvailableDataSources(),
authenticationService.getCurrentUsername() authenticationService.getCurrentUsername()
) )
@@ -422,7 +422,7 @@ angular.module('navigation').factory('userPageService', ['$injector',
// Retrieve current permissions // Retrieve current permissions
dataSourceService.apply( dataSourceService.apply(
permissionService.getPermissions, permissionService.getEffectivePermissions,
authenticationService.getAvailableDataSources(), authenticationService.getAvailableDataSources(),
authenticationService.getCurrentUsername() authenticationService.getCurrentUsername()
) )

View File

@@ -36,7 +36,10 @@ angular.module('rest').factory('permissionService', ['$injector',
/** /**
* Returns the URL for the REST resource most appropriate for accessing * Returns the URL for the REST resource most appropriate for accessing
* the permissions of the user having the given username. * the effective permissions of the user having the given username.
* Effective permissions differ from the permissions returned via
* getPermissions() in that permissions which are not directly granted to
* the user are included.
* *
* It is important to note that a particular data source can authenticate * It is important to note that a particular data source can authenticate
* and provide permissions for a user, even if that user does not exist * and provide permissions for a user, even if that user does not exist
@@ -56,7 +59,7 @@ angular.module('rest').factory('permissionService', ['$injector',
* The URL for the REST resource representing the user having the given * The URL for the REST resource representing the user having the given
* username. * username.
*/ */
var getPermissionsResourceURL = function getPermissionsResourceURL(dataSource, username) { var getEffectivePermissionsResourceURL = function getEffectivePermissionsResourceURL(dataSource, username) {
// Create base URL for data source // Create base URL for data source
var base = 'api/session/data/' + encodeURIComponent(dataSource); var base = 'api/session/data/' + encodeURIComponent(dataSource);
@@ -65,18 +68,20 @@ angular.module('rest').factory('permissionService', ['$injector',
// user actually existing (they may not). Access their permissions via // user actually existing (they may not). Access their permissions via
// "self" rather than the collection of defined users. // "self" rather than the collection of defined users.
if (username === authenticationService.getCurrentUsername()) if (username === authenticationService.getCurrentUsername())
return base + '/self/permissions'; return base + '/self/effectivePermissions';
// Otherwise, the user must exist for their permissions to be // Otherwise, the user must exist for their permissions to be
// accessible. Use the collection of defined users. // accessible. Use the collection of defined users.
return base + '/users/' + encodeURIComponent(username) + '/permissions'; return base + '/users/' + encodeURIComponent(username) + '/effectivePermissions';
}; };
/** /**
* Makes a request to the REST API to get the list of permissions for a * Makes a request to the REST API to get the list of effective permissions
* given user, returning a promise that provides an array of * for a given user, returning a promise that provides an array of
* @link{Permission} objects if successful. * @link{Permission} objects if successful. Effective permissions differ
* from the permissions returned via getPermissions() in that permissions
* which are not directly granted to the user are included.
* *
* @param {String} dataSource * @param {String} dataSource
* The unique identifier of the data source containing the user whose * The unique identifier of the data source containing the user whose
@@ -90,7 +95,7 @@ angular.module('rest').factory('permissionService', ['$injector',
* A promise which will resolve with a @link{PermissionSet} upon * A promise which will resolve with a @link{PermissionSet} upon
* success. * success.
*/ */
service.getPermissions = function getPermissions(dataSource, userID) { service.getEffectivePermissions = function getEffectivePermissions(dataSource, userID) {
// Build HTTP parameters set // Build HTTP parameters set
var httpParameters = { var httpParameters = {
@@ -101,58 +106,89 @@ angular.module('rest').factory('permissionService', ['$injector',
return $http({ return $http({
cache : cacheService.users, cache : cacheService.users,
method : 'GET', method : 'GET',
url : getPermissionsResourceURL(dataSource, userID), url : getEffectivePermissionsResourceURL(dataSource, userID),
params : httpParameters params : httpParameters
}); });
}; };
/** /**
* Makes a request to the REST API to add permissions for a given user, * Returns the URL for the REST resource most appropriate for accessing
* returning a promise that can be used for processing the results of the * the permissions of the user having the given identifier. The permissions
* call. * retrieved differ from effective permissions (those returned by
* getEffectivePermissions()) in that only permissions which are directly
* granted to the user are included.
*
* It is important to note that a particular data source can authenticate
* and provide permissions for a user, even if that user does not exist
* within that data source (and thus cannot be found beneath
* "api/session/data/{dataSource}/users")
* *
* @param {String} dataSource * @param {String} dataSource
* The unique identifier of the data source containing the user whose * The unique identifier of the data source containing the user whose
* permissions should be modified. This identifier corresponds to an * permissions should be retrieved. This identifier corresponds to an
* AuthenticationProvider within the Guacamole web application. * AuthenticationProvider within the Guacamole web application.
* *
* @param {String} userID * @param {String} identifier
* The ID of the user to modify the permissions of. * The identifier of the user for which the URL of the proper REST
* resource should be derived.
* *
* @param {PermissionSet} permissions * @returns {String}
* The set of permissions to add. * The URL for the REST resource representing the user having the given
* * identifier.
* @returns {Promise}
* A promise for the HTTP call which will succeed if and only if the
* add operation is successful.
*/ */
service.addPermissions = function addPermissions(dataSource, userID, permissions) { var getPermissionsResourceURL = function getPermissionsResourceURL(dataSource, identifier) {
return service.patchPermissions(dataSource, userID, permissions, null);
// Create base URL for data source
var base = 'api/session/data/' + encodeURIComponent(dataSource);
// If the username is that of the current user, do not rely on the
// user actually existing (they may not). Access their permissions via
// "self" rather than the collection of defined users.
if (identifier === authenticationService.getCurrentUsername())
return base + '/self/permissions';
// Otherwise, the user must exist for their permissions to be
// accessible. Use the collection of defined users.
return base + '/users/' + encodeURIComponent(identifier) + '/permissions';
}; };
/** /**
* Makes a request to the REST API to remove permissions for a given user, * Makes a request to the REST API to get the list of permissions for a
* returning a promise that can be used for processing the results of the * given user, returning a promise that provides an array of
* call. * @link{Permission} objects if successful. The permissions retrieved
* differ from effective permissions (those returned by
* getEffectivePermissions()) in that only permissions which are directly
* granted to the user included.
* *
* @param {String} dataSource * @param {String} dataSource
* The unique identifier of the data source containing the user whose * The unique identifier of the data source containing the user whose
* permissions should be modified. This identifier corresponds to an * permissions should be retrieved. This identifier corresponds to an
* AuthenticationProvider within the Guacamole web application. * AuthenticationProvider within the Guacamole web application.
* *
* @param {String} userID * @param {String} identifier
* The ID of the user to modify the permissions of. * The identifier of the user to retrieve the permissions for.
* *
* @param {PermissionSet} permissions * @returns {Promise.<PermissionSet>}
* The set of permissions to remove. * A promise which will resolve with a @link{PermissionSet} upon
* * success.
* @returns {Promise}
* A promise for the HTTP call which will succeed if and only if the
* remove operation is successful.
*/ */
service.removePermissions = function removePermissions(dataSource, userID, permissions) { service.getPermissions = function getPermissions(dataSource, identifier) {
return service.patchPermissions(dataSource, userID, null, permissions);
// Build HTTP parameters set
var httpParameters = {
token : authenticationService.getCurrentToken()
};
// Retrieve user permissions
return $http({
cache : cacheService.users,
method : 'GET',
url : getPermissionsResourceURL(dataSource, identifier),
params : httpParameters
});
}; };
/** /**
@@ -240,15 +276,17 @@ angular.module('rest').factory('permissionService', ['$injector',
/** /**
* Makes a request to the REST API to modify the permissions for a given * Makes a request to the REST API to modify the permissions for a given
* user, returning a promise that can be used for processing the results of * user, returning a promise that can be used for processing the results of
* the call. * the call. This request affects only the permissions directly granted to
* the user, and may not affect permissions inherited through other means
* (effective permissions).
* *
* @param {String} dataSource * @param {String} dataSource
* The unique identifier of the data source containing the user whose * The unique identifier of the data source containing the user whose
* permissions should be modified. This identifier corresponds to an * permissions should be modified. This identifier corresponds to an
* AuthenticationProvider within the Guacamole web application. * AuthenticationProvider within the Guacamole web application.
* *
* @param {String} userID * @param {String} identifier
* The ID of the user to modify the permissions of. * The identifier of the user to modify the permissions of.
* *
* @param {PermissionSet} [permissionsToAdd] * @param {PermissionSet} [permissionsToAdd]
* The set of permissions to add, if any. * The set of permissions to add, if any.
@@ -260,7 +298,8 @@ angular.module('rest').factory('permissionService', ['$injector',
* A promise for the HTTP call which will succeed if and only if the * A promise for the HTTP call which will succeed if and only if the
* patch operation is successful. * patch operation is successful.
*/ */
service.patchPermissions = function patchPermissions(dataSource, userID, permissionsToAdd, permissionsToRemove) { service.patchPermissions = function patchPermissions(dataSource, identifier,
permissionsToAdd, permissionsToRemove) {
var permissionPatch = []; var permissionPatch = [];
@@ -278,7 +317,7 @@ angular.module('rest').factory('permissionService', ['$injector',
// Patch user permissions // Patch user permissions
return $http({ return $http({
method : 'PATCH', method : 'PATCH',
url : getPermissionsResourceURL(dataSource, userID), url : getPermissionsResourceURL(dataSource, identifier),
params : httpParameters, params : httpParameters,
data : permissionPatch data : permissionPatch
}) })

View File

@@ -404,7 +404,7 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
}; };
// Retrieve current permissions // Retrieve current permissions
permissionService.getPermissions($scope.dataSource, currentUsername) permissionService.getEffectivePermissions($scope.dataSource, currentUsername)
.success(function permissionsRetrieved(permissions) { .success(function permissionsRetrieved(permissions) {
// Store retrieved permissions // Store retrieved permissions

View File

@@ -185,7 +185,7 @@ angular.module('settings').directive('guacSettingsPreferences', [function guacSe
}); });
// Retrieve current permissions // Retrieve current permissions
permissionService.getPermissions(dataSource, username) permissionService.getEffectivePermissions(dataSource, username)
.success(function permissionsRetrieved(permissions) { .success(function permissionsRetrieved(permissions) {
// Add action for changing password if permission is granted // Add action for changing password if permission is granted

View File

@@ -232,7 +232,7 @@ angular.module('settings').directive('guacSettingsUsers', [function guacSettings
// Retrieve current permissions // Retrieve current permissions
dataSourceService.apply( dataSourceService.apply(
permissionService.getPermissions, permissionService.getEffectivePermissions,
dataSources, dataSources,
currentUsername currentUsername
) )