From 417587259f427db04624b731d7536ee048b3856a Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 20 Sep 2022 17:07:17 -0700 Subject: [PATCH] GUACAMOLE-1224: Add CRUD-type events for Directory modifications. --- .../apache/guacamole/net/auth/Directory.java | 98 +++++++ .../guacamole/net/event/DirectoryEvent.java | 111 ++++++++ .../net/event/DirectoryFailureEvent.java | 36 +++ .../net/event/DirectorySuccessEvent.java | 35 +++ .../guacamole/net/auth/DirectoryTest.java | 124 +++++++++ .../ActiveConnectionDirectoryResource.java | 10 +- .../ActiveConnectionResource.java | 29 +-- .../ConnectionDirectoryResource.java | 10 +- .../rest/connection/ConnectionResource.java | 33 ++- .../ConnectionGroupDirectoryResource.java | 34 +-- .../ConnectionGroupResource.java | 27 +- .../directory/DirectoryObjectResource.java | 198 +++++++++++++- .../DirectoryObjectResourceFactory.java | 8 +- .../rest/directory/DirectoryResource.java | 244 +++++++++++++++++- .../directory/DirectoryResourceFactory.java | 7 +- .../rest/session/SessionResource.java | 2 +- .../rest/session/UserContextResource.java | 39 ++- .../session/UserContextResourceFactory.java | 7 +- .../SharingProfileDirectoryResource.java | 10 +- .../SharingProfileResource.java | 26 +- .../rest/tunnel/TunnelCollectionResource.java | 2 +- .../guacamole/rest/tunnel/TunnelResource.java | 15 +- .../rest/tunnel/TunnelResourceFactory.java | 6 +- .../rest/user/UserDirectoryResource.java | 9 +- .../guacamole/rest/user/UserResource.java | 45 ++-- .../usergroup/UserGroupDirectoryResource.java | 10 +- .../rest/usergroup/UserGroupResource.java | 23 +- 27 files changed, 1022 insertions(+), 176 deletions(-) create mode 100644 guacamole-ext/src/main/java/org/apache/guacamole/net/event/DirectoryEvent.java create mode 100644 guacamole-ext/src/main/java/org/apache/guacamole/net/event/DirectoryFailureEvent.java create mode 100644 guacamole-ext/src/main/java/org/apache/guacamole/net/event/DirectorySuccessEvent.java create mode 100644 guacamole-ext/src/test/java/org/apache/guacamole/net/auth/DirectoryTest.java diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Directory.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Directory.java index 287145fc0..ba1e1522d 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Directory.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Directory.java @@ -34,6 +34,104 @@ import org.apache.guacamole.GuacamoleException; */ public interface Directory { + /** + * All Directory types that may be found on the {@link UserContext} + * interface. + */ + public enum Type { + + /** + * The type of a Directory that contains {@link ActiveConnection} + * objects. + */ + ACTIVE_CONNECTION(ActiveConnection.class), + + /** + * The type of a Directory that contains {@link Connection} + * objects. + */ + CONNECTION(Connection.class), + + /** + * The type of a Directory that contains {@link ConnectionGroup} + * objects. + */ + CONNECTION_GROUP(ConnectionGroup.class), + + /** + * The type of a Directory that contains {@link SharingProfile} + * objects. + */ + SHARING_PROFILE(SharingProfile.class), + + /** + * The type of a Directory that contains {@link User} objects. + */ + USER(User.class), + + /** + * The type of a Directory that contains {@link UserGroup} + * objects. + */ + USER_GROUP(UserGroup.class); + + /** + * The base class of the type of object stored within the type of + * Directory represented by this Directory.Type. + */ + private final Class objectType; + + /** + * Creates a new Directory.Type representing the type of a Directory + * that contains only subclasses of the given class. + * + * @param objectType + * The base class of the type of object stored within the type of + * Directory represented by this Directory.Type. + */ + private Type(Class objectType) { + this.objectType = objectType; + } + + /** + * Returns the base class of the type of object stored within a + * {@link Directory} of this type. + * + * @return + * The base class of the type of object stored within a + * {@link Directory} of this type. + */ + public Class getObjectType() { + return objectType; + } + + /** + * Returns the Directory.Type representing the type of a Directory that + * could contain an object having the given class. The class may be a + * subclass of the overall base class of the objects stored within the + * Directory. + * + * @param objectType + * The class to determine the Directory.Type of. + * + * @return + * The Directory.Type representing the type of a Directory that + * could contain an object having the given class, or null if there + * is no such Directory available via the UserContext interface. + */ + public static Type of(Class objectType) { + + for (Type type : Type.values()) { + if (type.getObjectType().isAssignableFrom(objectType)) + return type; + } + + return null; + + } + + } + /** * Returns the object having the given identifier. Note that changes to * the object returned will not necessarily affect the object stored within diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/DirectoryEvent.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/DirectoryEvent.java new file mode 100644 index 000000000..2ff74bf94 --- /dev/null +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/DirectoryEvent.java @@ -0,0 +1,111 @@ +/* + * 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.event; + +import org.apache.guacamole.net.auth.Directory; +import org.apache.guacamole.net.auth.Identifiable; + +/** + * Abstract basis for events which involve a modification made to the objects + * within a {@link Directory}. + * + * @param + * The type of object stored within the {@link Directory}. + */ +public interface DirectoryEvent + extends AuthenticationProviderEvent, UserEvent { + + /** + * The types of directory operations that may be represented by a + * DirectoryEvent. + */ + public enum Operation { + + /** + * An object was added to the {@link Directory}. The object added can + * be accessed with {@link #getObject()}, and its identifier may be + * obtained from {@link #getObjectIdentifier()}. + */ + ADD, + + /** + * An object was retrieved from a {@link Directory}. The object + * retrieved can be accessed with {@link #getObject()}, and its + * identifier may be obtained from {@link #getObjectIdentifier()}. + */ + GET, + + /** + * An existing object within a {@link Directory} was modified. The + * modified object can be accessed with {@link #getObject()}, and its + * identifier may be obtained from {@link #getObjectIdentifier()}. + */ + UPDATE, + + /** + * An existing object within a {@link Directory} was deleted/removed. + * The identifier of the object that was deleted may be obtained from + * {@link #getObjectIdentifier()}. The full object that was deleted + * will be made available via {@link #getObject()} if possible, but + * this is not guaranteed for deletions. + */ + REMOVE + + } + + /** + * Returns the type of objects stored within the {@link Directory} + * affected by the operation. + * + * @return + * The type of objects stored within the {@link Directory}. + */ + Directory.Type getDirectoryType(); + + /** + * Returns the operation that was performed/attempted. + * + * @return + * The operation that was performed or attempted. + */ + Operation getOperation(); + + /** + * Returns the identifier of the object affected by the operation. If the + * object was just created, this will be the identifier of the new object. + * + * @return + * The identifier of the object affected by the operation. + */ + String getObjectIdentifier(); + + /** + * Returns the object affected by the operation, if available. For + * deletions, there is no guarantee that the affected object will be + * available within this event. If the object is not available, null is + * returned. + * + * @return + * The object affected by the operation performed, or null if that + * object is not available in the context of this event. + */ + ObjectType getObject(); + +} diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/DirectoryFailureEvent.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/DirectoryFailureEvent.java new file mode 100644 index 000000000..a9ec474d1 --- /dev/null +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/DirectoryFailureEvent.java @@ -0,0 +1,36 @@ +/* + * 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.event; + +import org.apache.guacamole.net.auth.Directory; +import org.apache.guacamole.net.auth.Identifiable; + +/** + * Event that is dispatched whenever a REST API request to create/modify/delete + * an object within a {@link Directory} fails. The specific failure is made + * available via {@link #getFailure()}. + * + * @param + * The type of object stored within the {@link Directory}. + */ +public interface DirectoryFailureEvent + extends DirectoryEvent, FailureEvent { + +} diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/event/DirectorySuccessEvent.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/DirectorySuccessEvent.java new file mode 100644 index 000000000..691cee7f7 --- /dev/null +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/event/DirectorySuccessEvent.java @@ -0,0 +1,35 @@ +/* + * 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.event; + +import org.apache.guacamole.net.auth.Directory; +import org.apache.guacamole.net.auth.Identifiable; + +/** + * Event that is dispatched whenever a REST API request to create/modify/delete + * an object within a {@link Directory} succeeds. + * + * @param + * The type of object stored within the {@link Directory}. + */ +public interface DirectorySuccessEvent + extends DirectoryEvent { + +} diff --git a/guacamole-ext/src/test/java/org/apache/guacamole/net/auth/DirectoryTest.java b/guacamole-ext/src/test/java/org/apache/guacamole/net/auth/DirectoryTest.java new file mode 100644 index 000000000..04623aa58 --- /dev/null +++ b/guacamole-ext/src/test/java/org/apache/guacamole/net/auth/DirectoryTest.java @@ -0,0 +1,124 @@ +/* + * 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.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import org.junit.Assert; +import org.junit.Test; + +/** + * Test that verifies the functionality provided by the Directory interface. + */ +public class DirectoryTest { + + /** + * Returns a Collection of all classes that have associated Directories + * available via the UserContext interface. The classes are retrieved + * using reflection by enumerating the type parameters of the return types + * of all functions that return a Directory. + * + * @return + * A Collection of all classes that have associated Directories + * available via the UserContext interface. + */ + @SuppressWarnings("unchecked") // Verified via calls to isAssignableFrom() + private Collection> getDirectoryTypes() { + + Set> types = new HashSet<>(); + + Method[] methods = UserContext.class.getMethods(); + for (Method method : methods) { + + if (!Directory.class.isAssignableFrom(method.getReturnType())) + continue; + + Type retType = method.getGenericReturnType(); + Assert.assertTrue("UserContext functions that return directories " + + "must have proper type parameters for the returned " + + "directory.", retType instanceof ParameterizedType); + + Type[] typeArgs = ((ParameterizedType) retType).getActualTypeArguments(); + Assert.assertEquals("UserContext functions that return directories " + + "must properly declare exactly one type argument for " + + "those directories.", 1, typeArgs.length); + + Class directoryType = (Class) typeArgs[0]; + Assert.assertTrue("Directories returned by UserContext functions " + + "must contain subclasses of Identifiable.", + Identifiable.class.isAssignableFrom(directoryType)); + + types.add((Class) directoryType); + + } + + return Collections.unmodifiableSet(types); + + } + + /** + * Verifies that Directory.Type covers the types of all directories exposed + * by the UserContext interface. + */ + @Test + public void testTypeCoverage() { + + Collection> types = getDirectoryTypes(); + + Assert.assertEquals("Directory.Type must provide exactly one value " + + "for each type of directory provideed by the UserContext " + + "interface.", types.size(), Directory.Type.values().length); + + for (Class type : types) { + + Directory.Type dirType = Directory.Type.of(type); + Assert.assertNotNull("of() must provide mappings for all directory " + + "types defined on the UserContext interface.", dirType); + + Assert.assertEquals("getObjectType() must return the same base " + + "superclass used by UserContext for all directory " + + "types defined on the UserContext interface.", type, + dirType.getObjectType()); + + } + + } + + /** + * Verifies that each type declared by Directory.Type exposes an + * associated class via getObjectType() which then maps back to the same + * type via Directory.Type.of(). + */ + @Test + public void testTypeIdentity() { + for (Directory.Type dirType : Directory.Type.values()) { + Assert.assertEquals("For all defined directory types, " + + "Directory.Type.of(theType.getObjectType()) must " + + "correctly map back to theType.", dirType, + Directory.Type.of(dirType.getObjectType())); + } + } + +} diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionDirectoryResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionDirectoryResource.java index 5296565ab..88319f01c 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionDirectoryResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionDirectoryResource.java @@ -26,6 +26,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.net.auth.ActiveConnection; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Permissions; import org.apache.guacamole.net.auth.UserContext; @@ -48,6 +49,9 @@ public class ActiveConnectionDirectoryResource * operations and subresources available for the given ActiveConnection * Directory. * + * @param authenticatedUser + * The user that is accessing this resource. + * * @param userContext * The UserContext associated with the given Directory. * @@ -63,11 +67,13 @@ public class ActiveConnectionDirectoryResource * representing ActiveConnections. */ @AssistedInject - public ActiveConnectionDirectoryResource(@Assisted UserContext userContext, + public ActiveConnectionDirectoryResource( + @Assisted AuthenticatedUser authenticatedUser, + @Assisted UserContext userContext, @Assisted Directory directory, DirectoryObjectTranslator translator, DirectoryObjectResourceFactory resourceFactory) { - super(userContext, directory, translator, resourceFactory); + super(authenticatedUser, userContext, ActiveConnection.class, directory, translator, resourceFactory); } @Override diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionResource.java index 514daa124..59afe18d1 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionResource.java @@ -30,6 +30,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.net.auth.ActiveConnection; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.UserContext; @@ -47,17 +48,6 @@ import org.apache.guacamole.rest.directory.DirectoryResourceFactory; public class ActiveConnectionResource extends DirectoryObjectResource { - /** - * The UserContext associated with the Directory which contains the - * Connection exposed by this resource. - */ - private final UserContext userContext; - - /** - * The ActiveConnection exposed by this ActiveConnectionResource. - */ - private final ActiveConnection activeConnection; - /** * A factory which can be used to create instances of resources representing * Connection. @@ -70,6 +60,9 @@ public class ActiveConnectionResource * Creates a new ActiveConnectionResource which exposes the operations and * subresources available for the given ActiveConnection. * + * @param authenticatedUser + * The user that is accessing this resource. + * * @param userContext * The UserContext associated with the given Directory. * @@ -85,13 +78,12 @@ public class ActiveConnectionResource * ActiveConnections. */ @AssistedInject - public ActiveConnectionResource(@Assisted UserContext userContext, + public ActiveConnectionResource(@Assisted AuthenticatedUser authenticatedUser, + @Assisted UserContext userContext, @Assisted Directory directory, @Assisted ActiveConnection activeConnection, DirectoryObjectTranslator translator) { - super(userContext, directory, activeConnection, translator); - this.userContext = userContext; - this.activeConnection = activeConnection; + super(authenticatedUser, userContext, ActiveConnection.class, directory, activeConnection, translator); } /** @@ -109,9 +101,12 @@ public class ActiveConnectionResource public DirectoryObjectResource getConnection() throws GuacamoleException { + UserContext userContext = getUserContext(); + ActiveConnection activeConnection = getInternalObject(); + // Return the underlying connection as a resource return connectionDirectoryResourceFactory - .create(userContext, userContext.getConnectionDirectory()) + .create(getAuthenticatedUser(), userContext, userContext.getConnectionDirectory()) .getObjectResource(activeConnection.getConnectionIdentifier()); } @@ -137,7 +132,7 @@ public class ActiveConnectionResource throws GuacamoleException { // Generate and return sharing credentials for the active connection - return new APIUserCredentials(activeConnection.getSharingCredentials(sharingProfileIdentifier)); + return new APIUserCredentials(getInternalObject().getSharingCredentials(sharingProfileIdentifier)); } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionDirectoryResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionDirectoryResource.java index 88408a796..612e05502 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionDirectoryResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionDirectoryResource.java @@ -25,6 +25,7 @@ import javax.ws.rs.Consumes; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Permissions; @@ -47,6 +48,9 @@ public class ConnectionDirectoryResource * Creates a new ConnectionDirectoryResource which exposes the operations * and subresources available for the given Connection Directory. * + * @param authenticatedUser + * The user that is accessing this resource. + * * @param userContext * The UserContext associated with the given Directory. * @@ -62,11 +66,11 @@ public class ConnectionDirectoryResource * representing Connections. */ @AssistedInject - public ConnectionDirectoryResource(@Assisted UserContext userContext, - @Assisted Directory directory, + public ConnectionDirectoryResource(@Assisted AuthenticatedUser authenticatedUser, + @Assisted UserContext userContext, @Assisted Directory directory, DirectoryObjectTranslator translator, DirectoryObjectResourceFactory resourceFactory) { - super(userContext, directory, translator, resourceFactory); + super(authenticatedUser, userContext, Connection.class, directory, translator, resourceFactory); } @Override diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionResource.java index 15586e187..484543ba2 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionResource.java @@ -32,6 +32,7 @@ import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleUnsupportedException; import org.apache.guacamole.net.auth.ActivityRecordSet; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Permissions; @@ -65,17 +66,6 @@ public class ConnectionResource extends DirectoryObjectResource directory, @Assisted Connection connection, DirectoryObjectTranslator translator) { - super(userContext, directory, connection, translator); - this.userContext = userContext; - this.connection = connection; + super(authenticatedUser, userContext, Connection.class, directory, connection, translator); } /** @@ -126,8 +118,10 @@ public class ConnectionResource extends DirectoryObjectResource getConnectionParameters() throws GuacamoleException { + Connection connection = getInternalObject(); + // Pull effective permissions - Permissions effective = userContext.self().getEffectivePermissions(); + Permissions effective = getUserContext().self().getEffectivePermissions(); // Retrieve permission sets SystemPermissionSet systemPermissions = effective.getSystemPermissions(); @@ -162,6 +156,8 @@ public class ConnectionResource extends DirectoryObjectResource getSharingProfileDirectoryResource() throws GuacamoleException { + UserContext userContext = getUserContext(); + Connection connection = getInternalObject(); + // Produce subset of all SharingProfiles, containing only those which // are associated with this connection Directory sharingProfiles = new DirectoryView<>( @@ -209,7 +208,7 @@ public class ConnectionResource extends DirectoryObjectResource { - /** - * The UserContext associated with the Directory which contains the - * ConnectionGroup exposed by this resource. - */ - private final UserContext userContext; - - /** - * The Directory exposed by this resource. - */ - private final Directory directory; - - /** - * A factory which can be used to create instances of resources representing - * ConnectionGroups. - */ - private final DirectoryObjectResourceFactory resourceFactory; - /** * Creates a new ConnectionGroupDirectoryResource which exposes the * operations and subresources available for the given ConnectionGroup * Directory. * + * @param authenticatedUser + * The user that is accessing this resource. + * * @param userContext * The UserContext associated with the given Directory. * @@ -81,23 +68,24 @@ public class ConnectionGroupDirectoryResource * representing ConnectionGroups. */ @AssistedInject - public ConnectionGroupDirectoryResource(@Assisted UserContext userContext, + public ConnectionGroupDirectoryResource( + @Assisted AuthenticatedUser authenticatedUser, + @Assisted UserContext userContext, @Assisted Directory directory, DirectoryObjectTranslator translator, DirectoryObjectResourceFactory resourceFactory) { - super(userContext, directory, translator, resourceFactory); - this.userContext = userContext; - this.directory = directory; - this.resourceFactory = resourceFactory; + super(authenticatedUser, userContext, ConnectionGroup.class, directory, translator, resourceFactory); } @Override public DirectoryObjectResource getObjectResource(String identifier) throws GuacamoleException { + UserContext userContext = getUserContext(); + // Use root group if identifier is the standard root identifier if (identifier != null && identifier.equals(APIConnectionGroup.ROOT_IDENTIFIER)) - return resourceFactory.create(userContext, directory, + return getResourceFactory().create(getAuthenticatedUser(), userContext, getDirectory(), userContext.getRootConnectionGroup()); return super.getObjectResource(identifier); diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupResource.java index f91b8ebb9..22f41b0cf 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupResource.java @@ -29,6 +29,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.ConnectionGroup; import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.UserContext; @@ -45,21 +46,13 @@ import org.apache.guacamole.rest.directory.DirectoryObjectTranslator; public class ConnectionGroupResource extends DirectoryObjectResource { - /** - * The UserContext associated with the Directory which contains the - * ConnectionGroup exposed by this resource. - */ - private final UserContext userContext; - - /** - * The ConnectionGroup object represented by this ConnectionGroupResource. - */ - private final ConnectionGroup connectionGroup; - /** * Creates a new ConnectionGroupResource which exposes the operations and * subresources available for the given ConnectionGroup. * + * @param authenticatedUser + * The user that is accessing this resource. + * * @param userContext * The UserContext associated with the given Directory. * @@ -75,13 +68,13 @@ public class ConnectionGroupResource * object given. */ @AssistedInject - public ConnectionGroupResource(@Assisted UserContext userContext, + public ConnectionGroupResource( + @Assisted AuthenticatedUser authenticatedUser, + @Assisted UserContext userContext, @Assisted Directory directory, @Assisted ConnectionGroup connectionGroup, DirectoryObjectTranslator translator) { - super(userContext, directory, connectionGroup, translator); - this.userContext = userContext; - this.connectionGroup = connectionGroup; + super(authenticatedUser, userContext, ConnectionGroup.class, directory, connectionGroup, translator); } /** @@ -107,8 +100,8 @@ public class ConnectionGroupResource throws GuacamoleException { // Retrieve the requested tree, filtering by the given permissions - ConnectionGroupTree tree = new ConnectionGroupTree(userContext, - connectionGroup, permissions); + ConnectionGroupTree tree = new ConnectionGroupTree(getUserContext(), + getInternalObject(), permissions); // Return tree as a connection group return tree.getRootAPIConnectionGroup(); diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryObjectResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryObjectResource.java index 7b354a226..8ed36fec0 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryObjectResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryObjectResource.java @@ -19,6 +19,7 @@ package org.apache.guacamole.rest.directory; +import javax.inject.Inject; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; @@ -27,9 +28,15 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.apache.guacamole.GuacamoleClientException; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.AuthenticatedUser; +import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Identifiable; import org.apache.guacamole.net.auth.UserContext; +import org.apache.guacamole.net.event.DirectoryEvent; +import org.apache.guacamole.net.event.DirectoryFailureEvent; +import org.apache.guacamole.net.event.DirectorySuccessEvent; +import org.apache.guacamole.rest.event.ListenerService; /** * A REST resource which abstracts the operations available on an existing @@ -51,12 +58,22 @@ import org.apache.guacamole.net.auth.UserContext; @Consumes(MediaType.APPLICATION_JSON) public abstract class DirectoryObjectResource { + /** + * The user that is accessing this resource. + */ + private final AuthenticatedUser authenticatedUser; + /** * The UserContext associated with the Directory containing the object * represented by this DirectoryObjectResource. */ private final UserContext userContext; + /** + * The type of object represented by this DirectoryObjectResource. + */ + private final Class internalType; + /** * The Directory which contains the object represented by this * DirectoryObjectResource. @@ -74,13 +91,26 @@ public abstract class DirectoryObjectResource translator; + /** + * Service for dispatching events to registered listeners. + */ + @Inject + private ListenerService listenerService; + /** * Creates a new DirectoryObjectResource which exposes the operations * available for the given object. * + * @param authenticatedUser + * The user that is accessing this resource. + * * @param userContext * The UserContext associated with the given Directory. * + * @param internalType + * The type of object that this DirectoryObjectResource should + * represent. + * * @param directory * The Directory which contains the given object. * @@ -91,15 +121,162 @@ public abstract class DirectoryObjectResource internalType, Directory directory, InternalType object, DirectoryObjectTranslator translator) { + this.authenticatedUser = authenticatedUser; this.userContext = userContext; this.directory = directory; + this.internalType = internalType; this.object = object; this.translator = translator; } + /** + * Notifies all registered listeners that the given operation has succeeded + * against the object represented by this resource. + * + * @param operation + * The operation that was performed. + * + * @throws GuacamoleException + * If a listener throws a GuacamoleException from its event handler. + */ + protected void fireDirectorySuccessEvent(DirectoryEvent.Operation operation) + throws GuacamoleException { + listenerService.handleEvent(new DirectorySuccessEvent() { + + @Override + public Directory.Type getDirectoryType() { + return Directory.Type.of(internalType); + } + + @Override + public DirectoryEvent.Operation getOperation() { + return operation; + } + + @Override + public String getObjectIdentifier() { + return object.getIdentifier(); + } + + @Override + public InternalType getObject() { + return object; + } + + @Override + public AuthenticatedUser getAuthenticatedUser() { + return authenticatedUser; + } + + @Override + public AuthenticationProvider getAuthenticationProvider() { + return userContext.getAuthenticationProvider(); + } + + }); + } + + /** + * Notifies all registered listeners that the given operation has failed + * against the object represented by this resource. + * + * @param operation + * The operation that failed. + * + * @param failure + * The failure that occurred. + * + * @throws GuacamoleException + * If a listener throws a GuacamoleException from its event handler. + */ + protected void fireDirectoryFailureEvent(DirectoryEvent.Operation operation, + Throwable failure) throws GuacamoleException { + listenerService.handleEvent(new DirectoryFailureEvent() { + + @Override + public Directory.Type getDirectoryType() { + return Directory.Type.of(internalType); + } + + @Override + public DirectoryEvent.Operation getOperation() { + return operation; + } + + @Override + public String getObjectIdentifier() { + return object.getIdentifier(); + } + + @Override + public InternalType getObject() { + return object; + } + + @Override + public AuthenticatedUser getAuthenticatedUser() { + return authenticatedUser; + } + + @Override + public AuthenticationProvider getAuthenticationProvider() { + return userContext.getAuthenticationProvider(); + } + + @Override + public Throwable getFailure() { + return failure; + } + + }); + } + + /** + * Returns the user accessing this resource. + * + * @return + * The user accessing this resource. + */ + protected AuthenticatedUser getAuthenticatedUser() { + return authenticatedUser; + } + + /** + * Returns the UserContext providing the Directory that contains the object + * exposed by this resource. + * + * @return + * The UserContext providing the Directory that contains the object + * exposed by this resource. + */ + protected UserContext getUserContext() { + return userContext; + } + + /** + * Returns the Directory containing the object exposed by this resource. + * + * @return + * The Directory containing the object exposed by this resource. + */ + protected Directory getDirectory() { + return directory; + } + + /** + * Returns the object exposed by this resource. + * + * @return + * The object exposed by this resource. + */ + protected InternalType getInternalObject() { + return object; + } + /** * Returns the object represented by this DirectoryObjectResource, in a * format intended for interchange. @@ -138,7 +315,15 @@ public abstract class DirectoryObjectResource - create(UserContext userContext, Directory directory, - InternalType object); + create(AuthenticatedUser authenticatedUser, UserContext userContext, + Directory directory, InternalType object); } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResource.java index e9b4b225b..50d428528 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResource.java @@ -23,6 +23,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.inject.Inject; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.PATCH; @@ -36,6 +37,8 @@ import org.apache.guacamole.GuacamoleClientException; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleResourceNotFoundException; import org.apache.guacamole.GuacamoleUnsupportedException; +import org.apache.guacamole.net.auth.AuthenticatedUser; +import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Identifiable; import org.apache.guacamole.net.auth.Permissions; @@ -44,7 +47,11 @@ 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; +import org.apache.guacamole.net.event.DirectoryEvent; +import org.apache.guacamole.net.event.DirectoryFailureEvent; +import org.apache.guacamole.net.event.DirectorySuccessEvent; import org.apache.guacamole.rest.APIPatch; +import org.apache.guacamole.rest.event.ListenerService; /** * A REST resource which abstracts the operations available on all Guacamole @@ -68,12 +75,23 @@ import org.apache.guacamole.rest.APIPatch; @Consumes(MediaType.APPLICATION_JSON) public abstract class DirectoryResource { + /** + * The user that is accessing this resource. + */ + private final AuthenticatedUser authenticatedUser; + /** * The UserContext associated with the Directory being exposed by this * DirectoryResource. */ private final UserContext userContext; + /** + * The type of object contained within the Directory exposed by this + * DirectoryResource. + */ + private final Class internalType; + /** * The Directory being exposed by this DirectoryResource. */ @@ -92,13 +110,25 @@ public abstract class DirectoryResource resourceFactory; + /** + * Service for dispatching events to registered listeners. + */ + @Inject + private ListenerService listenerService; + /** * Creates a new DirectoryResource which exposes the operations available * for the given Directory. * + * @param authenticatedUser + * The user that is accessing this resource. + * * @param userContext * The UserContext associated with the given Directory. * + * @param internalType + * The type of object contained within the given Directory. + * * @param directory * The Directory being exposed by this DirectoryResource. * @@ -110,11 +140,15 @@ public abstract class DirectoryResource directory, + public DirectoryResource(AuthenticatedUser authenticatedUser, + UserContext userContext, Class internalType, + Directory directory, DirectoryObjectTranslator translator, DirectoryObjectResourceFactory resourceFactory) { + this.authenticatedUser = authenticatedUser; this.userContext = userContext; this.directory = directory; + this.internalType = internalType; this.translator = translator; this.resourceFactory = resourceFactory; } @@ -139,6 +173,174 @@ public abstract class DirectoryResource() { + + @Override + public Directory.Type getDirectoryType() { + return Directory.Type.of(internalType); + } + + @Override + public DirectoryEvent.Operation getOperation() { + return operation; + } + + @Override + public String getObjectIdentifier() { + return identifier; + } + + @Override + public InternalType getObject() { + return object; + } + + @Override + public AuthenticatedUser getAuthenticatedUser() { + return authenticatedUser; + } + + @Override + public AuthenticationProvider getAuthenticationProvider() { + return userContext.getAuthenticationProvider(); + } + + }); + } + + /** + * Notifies all registered listeners that the given operation has failed + * against the object having the given identifier within the Directory + * represented by this resource. + * + * @param operation + * The operation that failed. + * + * @param identifier + * The identifier of the object that would have been affected by the + * operation had it succeeded. + * + * @param object + * The specific object would have been affected by the operation, if + * available, had it succeeded, including any changes that were + * intended to be applied to the object. If not available, this may be + * null. + * + * @param failure + * The failure that occurred. + * + * @throws GuacamoleException + * If a listener throws a GuacamoleException from its event handler. + */ + protected void fireDirectoryFailureEvent(DirectoryEvent.Operation operation, + String identifier, InternalType object, Throwable failure) + throws GuacamoleException { + listenerService.handleEvent(new DirectoryFailureEvent() { + + @Override + public Directory.Type getDirectoryType() { + return Directory.Type.of(internalType); + } + + @Override + public DirectoryEvent.Operation getOperation() { + return operation; + } + + @Override + public String getObjectIdentifier() { + return identifier; + } + + @Override + public InternalType getObject() { + return object; + } + + @Override + public AuthenticatedUser getAuthenticatedUser() { + return authenticatedUser; + } + + @Override + public AuthenticationProvider getAuthenticationProvider() { + return userContext.getAuthenticationProvider(); + } + + @Override + public Throwable getFailure() { + return failure; + } + + }); + } + + /** + * Returns the user accessing this resource. + * + * @return + * The user accessing this resource. + */ + protected AuthenticatedUser getAuthenticatedUser() { + return authenticatedUser; + } + + /** + * Returns the UserContext providing the Directory exposed by this + * resource. + * + * @return + * The UserContext providing the Directory exposed by this resource. + */ + protected UserContext getUserContext() { + return userContext; + } + + /** + * Returns the Directory exposed by this resource. + * + * @return + * The Directory exposed by this resource. + */ + protected Directory getDirectory() { + return directory; + } + + /** + * Returns a factory that can be used to create instances of resources + * representing individual objects contained within the Directory exposed + * by this resource. + * + * @return + * A factory that can be used to create instances of resources + * representing individual objects contained within the Directory + * exposed by this resource. + */ + public DirectoryObjectResourceFactory getResourceFactory() { + return resourceFactory; + } + /** * Returns a map of all objects available within this DirectoryResource, * filtering the returned map by the given permission, if specified. @@ -213,7 +415,15 @@ public abstract class DirectoryResource resource = resourceFactory.create(authenticatedUser, userContext, directory, object); + fireDirectorySuccessEvent(DirectoryEvent.Operation.GET, identifier, object); + return resource; } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResourceFactory.java b/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResourceFactory.java index 357777a6f..c28294bae 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResourceFactory.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResourceFactory.java @@ -19,6 +19,7 @@ package org.apache.guacamole.rest.directory; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Identifiable; import org.apache.guacamole.net.auth.UserContext; @@ -41,6 +42,9 @@ public interface DirectoryResourceFactory - create(UserContext userContext, Directory directory); + create(AuthenticatedUser authenticatedUser, UserContext userContext, + Directory directory); } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/session/SessionResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/session/SessionResource.java index 0c334b068..6116c3785 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/session/SessionResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/session/SessionResource.java @@ -116,7 +116,7 @@ public class SessionResource { UserContext userContext = session.getUserContext(authProviderIdentifier); // Return a resource exposing the retrieved UserContext - return userContextResourceFactory.create(userContext); + return userContextResourceFactory.create(session.getAuthenticatedUser(), userContext); } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResource.java index cbb04d172..b696259c3 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResource.java @@ -30,6 +30,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.net.auth.ActiveConnection; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.ConnectionGroup; import org.apache.guacamole.net.auth.SharingProfile; @@ -59,6 +60,11 @@ public class UserContextResource { */ private final UserContext userContext; + /** + * The user that is accessing this resource. + */ + private final AuthenticatedUser authenticatedUser; + /** * Factory for creating DirectoryObjectResources which expose a given User. */ @@ -115,12 +121,17 @@ public class UserContextResource { * Creates a new UserContextResource which exposes the data within the * given UserContext. * + * @param authenticatedUser + * The user that is accessing this resource. + * * @param userContext * The UserContext which should be exposed through this * UserContextResource. */ @AssistedInject - public UserContextResource(@Assisted UserContext userContext) { + public UserContextResource(@Assisted AuthenticatedUser authenticatedUser, + @Assisted UserContext userContext) { + this.authenticatedUser = authenticatedUser; this.userContext = userContext; } @@ -140,7 +151,7 @@ public class UserContextResource { @Path("self") public DirectoryObjectResource getSelfResource() throws GuacamoleException { - return userResourceFactory.create(userContext, + return userResourceFactory.create(authenticatedUser, userContext, userContext.getUserDirectory(), userContext.self()); } @@ -158,8 +169,8 @@ public class UserContextResource { @Path("activeConnections") public DirectoryResource getActiveConnectionDirectoryResource() throws GuacamoleException { - return activeConnectionDirectoryResourceFactory.create(userContext, - userContext.getActiveConnectionDirectory()); + return activeConnectionDirectoryResourceFactory.create(authenticatedUser, + userContext, userContext.getActiveConnectionDirectory()); } /** @@ -176,8 +187,8 @@ public class UserContextResource { @Path("connections") public DirectoryResource getConnectionDirectoryResource() throws GuacamoleException { - return connectionDirectoryResourceFactory.create(userContext, - userContext.getConnectionDirectory()); + return connectionDirectoryResourceFactory.create(authenticatedUser, + userContext, userContext.getConnectionDirectory()); } /** @@ -194,8 +205,8 @@ public class UserContextResource { @Path("connectionGroups") public DirectoryResource getConnectionGroupDirectoryResource() throws GuacamoleException { - return connectionGroupDirectoryResourceFactory.create(userContext, - userContext.getConnectionGroupDirectory()); + return connectionGroupDirectoryResourceFactory.create(authenticatedUser, + userContext, userContext.getConnectionGroupDirectory()); } /** @@ -212,8 +223,8 @@ public class UserContextResource { @Path("sharingProfiles") public DirectoryResource getSharingProfileDirectoryResource() throws GuacamoleException { - return sharingProfileDirectoryResourceFactory.create(userContext, - userContext.getSharingProfileDirectory()); + return sharingProfileDirectoryResourceFactory.create(authenticatedUser, + userContext, userContext.getSharingProfileDirectory()); } /** @@ -230,8 +241,8 @@ public class UserContextResource { @Path("users") public DirectoryResource getUserDirectoryResource() throws GuacamoleException { - return userDirectoryResourceFactory.create(userContext, - userContext.getUserDirectory()); + return userDirectoryResourceFactory.create(authenticatedUser, + userContext, userContext.getUserDirectory()); } /** @@ -248,8 +259,8 @@ public class UserContextResource { @Path("userGroups") public DirectoryResource getUserGroupDirectoryResource() throws GuacamoleException { - return userGroupDirectoryResourceFactory.create(userContext, - userContext.getUserGroupDirectory()); + return userGroupDirectoryResourceFactory.create(authenticatedUser, + userContext, userContext.getUserGroupDirectory()); } /** diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResourceFactory.java b/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResourceFactory.java index 5eea3edf5..c969a6311 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResourceFactory.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResourceFactory.java @@ -19,6 +19,7 @@ package org.apache.guacamole.rest.session; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.UserContext; /** @@ -31,6 +32,9 @@ public interface UserContextResourceFactory { * Creates a new UserContextResource which exposes the contents of the * given UserContext. * + * @param authenticatedUser + * The user that is accessing the resource. + * * @param userContext * The UserContext whose contents should be exposed. * @@ -38,6 +42,7 @@ public interface UserContextResourceFactory { * A new UserContextResource which exposes the contents of the given * UserContext. */ - UserContextResource create(UserContext userContext); + UserContextResource create(AuthenticatedUser authenticatedUser, + UserContext userContext); } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/sharingprofile/SharingProfileDirectoryResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/sharingprofile/SharingProfileDirectoryResource.java index ab24ef381..16ae29509 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/sharingprofile/SharingProfileDirectoryResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/sharingprofile/SharingProfileDirectoryResource.java @@ -25,6 +25,7 @@ import javax.ws.rs.Consumes; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Permissions; import org.apache.guacamole.net.auth.SharingProfile; @@ -48,6 +49,9 @@ public class SharingProfileDirectoryResource * operations and subresources available for the given SharingProfile * Directory. * + * @param authenticatedUser + * The user that is accessing this resource. + * * @param userContext * The UserContext associated with the given Directory. * @@ -63,11 +67,13 @@ public class SharingProfileDirectoryResource * representing SharingProfiles. */ @AssistedInject - public SharingProfileDirectoryResource(@Assisted UserContext userContext, + public SharingProfileDirectoryResource( + @Assisted AuthenticatedUser authenticatedUser, + @Assisted UserContext userContext, @Assisted Directory directory, DirectoryObjectTranslator translator, DirectoryObjectResourceFactory resourceFactory) { - super(userContext, directory, translator, resourceFactory); + super(authenticatedUser, userContext, SharingProfile.class, directory, translator, resourceFactory); } @Override diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/sharingprofile/SharingProfileResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/sharingprofile/SharingProfileResource.java index 4797ade7f..46daac9b3 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/sharingprofile/SharingProfileResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/sharingprofile/SharingProfileResource.java @@ -29,6 +29,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleSecurityException; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Permissions; import org.apache.guacamole.net.auth.SharingProfile; @@ -49,21 +50,13 @@ import org.apache.guacamole.rest.directory.DirectoryObjectTranslator; public class SharingProfileResource extends DirectoryObjectResource { - /** - * The UserContext associated with the Directory which contains the - * SharingProfile exposed by this resource. - */ - private final UserContext userContext; - - /** - * The SharingProfile object represented by this SharingProfileResource. - */ - private final SharingProfile sharingProfile; - /** * Creates a new SharingProfileResource which exposes the operations and * subresources available for the given SharingProfile. * + * @param authenticatedUser + * The user that is accessing this resource. + * * @param userContext * The UserContext associated with the given Directory. * @@ -78,13 +71,12 @@ public class SharingProfileResource * object given. */ @AssistedInject - public SharingProfileResource(@Assisted UserContext userContext, + public SharingProfileResource(@Assisted AuthenticatedUser authenticatedUser, + @Assisted UserContext userContext, @Assisted Directory directory, @Assisted SharingProfile sharingProfile, DirectoryObjectTranslator translator) { - super(userContext, directory, sharingProfile, translator); - this.userContext = userContext; - this.sharingProfile = sharingProfile; + super(authenticatedUser, userContext, SharingProfile.class, directory, sharingProfile, translator); } /** @@ -103,8 +95,10 @@ public class SharingProfileResource public Map getParameters() throws GuacamoleException { + SharingProfile sharingProfile = getInternalObject(); + // Pull effective permissions - Permissions effective = userContext.self().getEffectivePermissions(); + Permissions effective = getUserContext().self().getEffectivePermissions(); // Retrieve permission sets SystemPermissionSet systemPermissions = effective.getSystemPermissions(); diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/tunnel/TunnelCollectionResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/tunnel/TunnelCollectionResource.java index abd7b422d..770469c7e 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/tunnel/TunnelCollectionResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/tunnel/TunnelCollectionResource.java @@ -105,7 +105,7 @@ public class TunnelCollectionResource { throw new GuacamoleResourceNotFoundException("No such tunnel."); // Return corresponding tunnel resource - return tunnelResourceFactory.create(tunnel); + return tunnelResourceFactory.create(session.getAuthenticatedUser(), tunnel); } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/tunnel/TunnelResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/tunnel/TunnelResource.java index 7c0ec7eef..7107ab277 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/tunnel/TunnelResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/tunnel/TunnelResource.java @@ -34,6 +34,7 @@ import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleResourceNotFoundException; import org.apache.guacamole.environment.Environment; import org.apache.guacamole.net.auth.ActiveConnection; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.protocols.ProtocolInfo; import org.apache.guacamole.rest.activeconnection.APIActiveConnection; @@ -55,6 +56,11 @@ public class TunnelResource { */ private static final String DEFAULT_MEDIA_TYPE = MediaType.APPLICATION_OCTET_STREAM; + /** + * The user that is accessing this resource. + */ + private final AuthenticatedUser authenticatedUser; + /** * The tunnel that this TunnelResource represents. */ @@ -78,11 +84,16 @@ public class TunnelResource { * Creates a new TunnelResource which exposes the operations and * subresources available for the given tunnel. * + * @param authenticatedUser + * The user that is accessing this resource. + * * @param tunnel * The tunnel that this TunnelResource should represent. */ @AssistedInject - public TunnelResource(@Assisted UserTunnel tunnel) { + public TunnelResource(@Assisted AuthenticatedUser authenticatedUser, + @Assisted UserTunnel tunnel) { + this.authenticatedUser = authenticatedUser; this.tunnel = tunnel; } @@ -110,7 +121,7 @@ public class TunnelResource { throw new GuacamoleResourceNotFoundException("No readable active connection for tunnel."); // Return the associated ActiveConnection as a resource - return activeConnectionResourceFactory.create(userContext, + return activeConnectionResourceFactory.create(authenticatedUser, userContext, userContext.getActiveConnectionDirectory(), activeConnection); } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/tunnel/TunnelResourceFactory.java b/guacamole/src/main/java/org/apache/guacamole/rest/tunnel/TunnelResourceFactory.java index 2deacf88a..9efdf9c68 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/tunnel/TunnelResourceFactory.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/tunnel/TunnelResourceFactory.java @@ -19,6 +19,7 @@ package org.apache.guacamole.rest.tunnel; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.tunnel.UserTunnel; /** @@ -31,12 +32,15 @@ public interface TunnelResourceFactory { * Creates a new TunnelResource which exposes the contents of the * given tunnel. * + * @param authenticatedUser + * The user that is accessing the resource. + * * @param tunnel * The tunnel whose contents should be exposed. * * @return * A new TunnelResource which exposes the contents of the given tunnel. */ - TunnelResource create(UserTunnel tunnel); + TunnelResource create(AuthenticatedUser authenticatedUser, UserTunnel tunnel); } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/user/UserDirectoryResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/user/UserDirectoryResource.java index f93016fe9..0918ca82f 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/user/UserDirectoryResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/user/UserDirectoryResource.java @@ -25,6 +25,7 @@ import javax.ws.rs.Consumes; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Permissions; @@ -46,6 +47,9 @@ public class UserDirectoryResource extends DirectoryResource { * Creates a new UserDirectoryResource which exposes the operations and * subresources available for the given User Directory. * + * @param authenticatedUser + * The user that is accessing this resource. + * * @param userContext * The UserContext associated with the given Directory. * @@ -61,11 +65,12 @@ public class UserDirectoryResource extends DirectoryResource { * representing Users. */ @AssistedInject - public UserDirectoryResource(@Assisted UserContext userContext, + public UserDirectoryResource(@Assisted AuthenticatedUser authenticatedUser, + @Assisted UserContext userContext, @Assisted Directory directory, DirectoryObjectTranslator translator, DirectoryObjectResourceFactory resourceFactory) { - super(userContext, directory, translator, resourceFactory); + super(authenticatedUser, userContext, User.class, directory, translator, resourceFactory); } @Override diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/user/UserResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/user/UserResource.java index aa8a3ec7e..9b79fbb48 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/user/UserResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/user/UserResource.java @@ -33,6 +33,7 @@ import javax.ws.rs.core.MediaType; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleUnsupportedException; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.Credentials; import org.apache.guacamole.net.auth.User; @@ -63,27 +64,13 @@ public class UserResource */ private static final Logger logger = LoggerFactory.getLogger(UserResource.class); - /** - * The UserContext associated with the Directory which contains the User - * exposed by this resource. - */ - private final UserContext userContext; - - /** - * The Directory which contains the User object represented by this - * UserResource. - */ - private final Directory directory; - - /** - * The User object represented by this UserResource. - */ - private final User user; - /** * Creates a new UserResource which exposes the operations and subresources * available for the given User. * + * @param authenticatedUser + * The user that is accessing this resource. + * * @param userContext * The UserContext associated with the given Directory. * @@ -97,14 +84,12 @@ public class UserResource * A DirectoryObjectTranslator implementation which handles Users. */ @AssistedInject - public UserResource(@Assisted UserContext userContext, + public UserResource(@Assisted AuthenticatedUser authenticatedUser, + @Assisted UserContext userContext, @Assisted Directory directory, @Assisted User user, DirectoryObjectTranslator translator) { - super(userContext, directory, user, translator); - this.userContext = userContext; - this.directory = directory; - this.user = user; + super(authenticatedUser, userContext, User.class, directory, user, translator); } /** @@ -122,6 +107,8 @@ public class UserResource public UserHistoryResource getUserHistory() throws GuacamoleException { + User user = getInternalObject(); + // First try to retrieve history using the current getUserHistory() method. try { return new UserHistoryResource(user.getUserHistory()); @@ -147,7 +134,7 @@ public class UserResource public void updateObject(APIUser modifiedObject) throws GuacamoleException { // A user may not use this endpoint to update their password - User currentUser = userContext.self(); + User currentUser = getUserContext().self(); if ( currentUser.getIdentifier().equals(modifiedObject.getUsername()) && modifiedObject.getPassword() != null) { @@ -178,13 +165,15 @@ public class UserResource public void updatePassword(APIUserPasswordUpdate userPasswordUpdate, @Context HttpServletRequest request) throws GuacamoleException { + User user = getInternalObject(); + // Build credentials Credentials credentials = new Credentials(user.getIdentifier(), userPasswordUpdate.getOldPassword(), request); // Verify that the old password was correct try { - AuthenticationProvider authProvider = userContext.getAuthenticationProvider(); + AuthenticationProvider authProvider = getUserContext().getAuthenticationProvider(); if (authProvider.authenticateUser(credentials) == null) throw new GuacamoleSecurityException("Permission denied."); } @@ -196,7 +185,7 @@ public class UserResource // Set password to the newly provided one user.setPassword(userPasswordUpdate.getNewPassword()); - directory.update(user); + getDirectory().update(user); } @@ -211,7 +200,7 @@ public class UserResource */ @Path("permissions") public PermissionSetResource getPermissions() { - return new PermissionSetResource(user); + return new PermissionSetResource(getInternalObject()); } /** @@ -228,7 +217,7 @@ public class UserResource @GET @Path("effectivePermissions") public APIPermissionSet getEffectivePermissions() throws GuacamoleException { - return new APIPermissionSet(user.getEffectivePermissions()); + return new APIPermissionSet(getInternalObject().getEffectivePermissions()); } /** @@ -245,7 +234,7 @@ public class UserResource */ @Path("userGroups") public RelatedObjectSetResource getUserGroups() throws GuacamoleException { - return new RelatedObjectSetResource(user.getUserGroups()); + return new RelatedObjectSetResource(getInternalObject().getUserGroups()); } } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/usergroup/UserGroupDirectoryResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/usergroup/UserGroupDirectoryResource.java index fc4d48be3..44327a29c 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/usergroup/UserGroupDirectoryResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/usergroup/UserGroupDirectoryResource.java @@ -25,6 +25,7 @@ import javax.ws.rs.Consumes; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.UserGroup; import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Permissions; @@ -46,6 +47,9 @@ public class UserGroupDirectoryResource extends DirectoryResource directory, DirectoryObjectTranslator translator, DirectoryObjectResourceFactory resourceFactory) { - super(userContext, directory, translator, resourceFactory); + super(authenticatedUser, userContext, UserGroup.class, directory, translator, resourceFactory); } @Override diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/usergroup/UserGroupResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/usergroup/UserGroupResource.java index 350b59fed..6994484d9 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/usergroup/UserGroupResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/usergroup/UserGroupResource.java @@ -26,6 +26,7 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.UserGroup; import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.UserContext; @@ -43,15 +44,13 @@ import org.apache.guacamole.rest.permission.PermissionSetResource; public class UserGroupResource extends DirectoryObjectResource { - /** - * The UserGroup object represented by this UserGroupResource. - */ - private final UserGroup userGroup; - /** * Creates a new UserGroupResource which exposes the operations and * subresources available for the given UserGroup. * + * @param authenticatedUser + * The user that is accessing this resource. + * * @param userContext * The UserContext associated with the given Directory. * @@ -65,12 +64,12 @@ public class UserGroupResource * A DirectoryObjectTranslator implementation which handles Users. */ @AssistedInject - public UserGroupResource(@Assisted UserContext userContext, + public UserGroupResource(@Assisted AuthenticatedUser authenticatedUser, + @Assisted UserContext userContext, @Assisted Directory directory, @Assisted UserGroup userGroup, DirectoryObjectTranslator translator) { - super(userContext, directory, userGroup, translator); - this.userGroup = userGroup; + super(authenticatedUser, userContext, UserGroup.class, directory, userGroup, translator); } /** @@ -87,7 +86,7 @@ public class UserGroupResource */ @Path("userGroups") public RelatedObjectSetResource getUserGroups() throws GuacamoleException { - return new RelatedObjectSetResource(userGroup.getUserGroups()); + return new RelatedObjectSetResource(getInternalObject().getUserGroups()); } /** @@ -104,7 +103,7 @@ public class UserGroupResource */ @Path("memberUsers") public RelatedObjectSetResource getMemberUsers() throws GuacamoleException { - return new RelatedObjectSetResource(userGroup.getMemberUsers()); + return new RelatedObjectSetResource(getInternalObject().getMemberUsers()); } /** @@ -121,7 +120,7 @@ public class UserGroupResource */ @Path("memberUserGroups") public RelatedObjectSetResource getMemberUserGroups() throws GuacamoleException { - return new RelatedObjectSetResource(userGroup.getMemberUserGroups()); + return new RelatedObjectSetResource(getInternalObject().getMemberUserGroups()); } /** @@ -135,7 +134,7 @@ public class UserGroupResource */ @Path("permissions") public PermissionSetResource getPermissions() { - return new PermissionSetResource(userGroup); + return new PermissionSetResource(getInternalObject()); } }