Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GUACAMOLE-220: Add base extension API support for user groups. #274

Merged
merged 7 commits into from
Apr 22, 2018

Conversation

mike-jumper
Copy link
Contributor

This change adds the base classes necessary for exposing user groups via extensions, and for declaring the permissions which apply to a user but are not necessarily directly granted to that user.

Overall, this involves:

  • A new UserGroup interface, as well as the usual DelegatingUserGroup, and Directory<UserGroup> on UserContext.
  • A new base interface, Permissions, which User and UserGroup share, defining the interface common to any object which can be granted permissions.
  • A new getEffectivePermissions() function on User which returns a Permissions that represents all permissions which apply to the user, even if those permissions are inherited through some arbitrary means (such as user groups). The traditional getUserPermissions(), getConnectionPermissions(), etc. directly on the User return permission sets which describe permissions which are directly granted only.
  • A new getEffectiveUserGroups() function on AuthenticatedUser which allows implementations to expose the identity of a user's group memberships in addition to the user's own identity. This forms the means by which membership in groups can be shared across extensions (for example, LDAP group membership can affect a user in MySQL so long as an identical MySQL group exists, even if that user does not exist in MySQL).
  • A new RelatedObjectSet interface, similar to PermissionSet, which abstracts batch add/remove operations on a group of objects sharing some arbitrary relation, such as the member users of a user group, the parent user groups of a user, etc. This allows relations between specific objects to be established or removed without affecting the existence of those objects (as Directory would require) nor necessarily other relations to those objects.

The user groups themselves are exposed via a Directory<UserGroup> at the UserContext level, like all other objects. A new ObjectPermissionSet for user group permissions is exposed within Permissions. User membership within groups, group membership within groups, the set of groups containing a particular user, and the set of groups containing a particular group can all be maintained through the various getters returning RelatedObjectSet instances.

Other than (1) updating the REST services and JavaScript to use effective permissions rather than directly-granted permissions and (2) any stubs necessary to allow the database auth to continue working, no changes outside the API are made here.

Assuming these changes move forward, I will open further pull requests for the REST API changes, interface changes, and finally database auth changes.

Copy link
Contributor

@necouchman necouchman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took a first pass at it. Looks really good to me - just minor questions/comments.

* @throws GuacamoleException
* If an error occurs while retrieving the user groups.
*/
RelatedObjectSet getMemberUserGroups() throws GuacamoleException;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason that getUserGroups() and getMemberUserGroups() are both necessary? Based on the stubs and descriptions, here, they look identical? I see that they're both implemented in DelegatingUserGroup, but they have identical implementations, there, and getMemberUserGroups() does not appear to be used anywhere outside of there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getUserGroups() returns the user groups of which the current group is a member, while getMemberUserGroups() returns the user groups which are members of the current group.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, in that case, the comments above the code need to be updated. The comment above getUserGroups() says:

Returns a set of all readable user groups that are members of this user group.

and the comment above getMemberUserGroups() starts with:

Returns a set of all readable user groups that are members of this user group.

Also, the @return comment seems to be identical for both of them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK - this should now be corrected.

* A read-only implementation of RelatedObjectSet which uses a backing Set
* of identifiers to determine which objects are present.
*/
public class SimpleRelatedObjectSet implements RelatedObjectSet {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think there's any value to implementing a AbstractRelatedObjectSet class like you've done for several of the other Simple classes, that implements a bunch of these default behaviors? Perhaps not initially useful for the JDBC extension, but is it something that would be helpful as other extensions implement the RelatedObjectSet class without having to rely on the behavior of SimpleRelatedObjectSet?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In principle, yes, but I'm not sure what that would be. There are only two functions that are effectively unimplemented by SimpleRelatedObjectSet:

  1. addObjects()
  2. removeObjects()

both of which make changes to the RelatedObjectSet in a way that would be implementation dependent. It does make sense to provide default behaviors, but I don't think there are any sensible default behaviors we can provide here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense.

User self = userContext.self();
Permissions effective = self.getEffectivePermissions();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the ConnectionGroupTree class you did:

Permissions effective = userContext.self().getEffectivePermissions();

eliminating the need for the existence of the self object. Any reason not to do the same, here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope. Sounds fine to me. I'll make the change.

@@ -143,13 +144,14 @@ public DirectoryResource(UserContext userContext, Directory<InternalType> direct

// An admin user has access to all objects
User self = userContext.self();
SystemPermissionSet systemPermissions = self.getSystemPermissions();
Permissions effective = self.getEffectivePermissions();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same note as above - any reason not to do

Permissions effective = userContext.self().getEffectivePermissions()

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope. No reason. Will do.

User self = userContext.self();
Permissions effective = self.getEffectivePermissions();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with previous places, guessing these two lines could be collapsed...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, I agree.

Copy link
Contributor

@necouchman necouchman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few more style/grammar nitpicks.

@@ -19,6 +19,9 @@

package org.apache.guacamole.net.auth;

import java.util.Collections;
import java.util.Set;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra line added, here - seems like most files have a single space between import and class documentation.

* 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing period at the end of this sentence.

* Returns all user 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 implied,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"may be implied"

@mike-jumper
Copy link
Contributor Author

OK, I believe I've addressed the issues above, with the exception of adding a AbstractRelatedObjectSet (as I am unable to define a set of default behaviors that is not already provided by SimpleRelatedObjectSet).

@necouchman
Copy link
Contributor

Cool - will try to review one last time tonight and get it merged.

Copy link
Contributor

@necouchman necouchman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, about to merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants