GUACAMOLE-1224: Add CRUD-type events for Directory modifications.

This commit is contained in:
Michael Jumper
2022-09-20 17:07:17 -07:00
parent 0af17df712
commit 417587259f
27 changed files with 1022 additions and 176 deletions

View File

@@ -34,6 +34,104 @@ import org.apache.guacamole.GuacamoleException;
*/ */
public interface Directory<ObjectType extends Identifiable> { public interface Directory<ObjectType extends Identifiable> {
/**
* 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<? extends Identifiable> 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<? extends Identifiable> 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<? extends Identifiable> 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<? extends Identifiable> 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 * Returns the object having the given identifier. Note that changes to
* the object returned will not necessarily affect the object stored within * the object returned will not necessarily affect the object stored within

View File

@@ -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 <ObjectType>
* The type of object stored within the {@link Directory}.
*/
public interface DirectoryEvent<ObjectType extends Identifiable>
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();
}

View File

@@ -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 <ObjectType>
* The type of object stored within the {@link Directory}.
*/
public interface DirectoryFailureEvent<ObjectType extends Identifiable>
extends DirectoryEvent<ObjectType>, FailureEvent {
}

View File

@@ -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 <ObjectType>
* The type of object stored within the {@link Directory}.
*/
public interface DirectorySuccessEvent<ObjectType extends Identifiable>
extends DirectoryEvent<ObjectType> {
}

View File

@@ -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<Class<? extends Identifiable>> getDirectoryTypes() {
Set<Class<? extends Identifiable>> 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<? extends Identifiable>) 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<Class<? extends Identifiable>> 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<? extends Identifiable> 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()));
}
}
}

View File

@@ -26,6 +26,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.ActiveConnection; 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.Directory;
import org.apache.guacamole.net.auth.Permissions; import org.apache.guacamole.net.auth.Permissions;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
@@ -48,6 +49,9 @@ public class ActiveConnectionDirectoryResource
* operations and subresources available for the given ActiveConnection * operations and subresources available for the given ActiveConnection
* Directory. * Directory.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param userContext * @param userContext
* The UserContext associated with the given Directory. * The UserContext associated with the given Directory.
* *
@@ -63,11 +67,13 @@ public class ActiveConnectionDirectoryResource
* representing ActiveConnections. * representing ActiveConnections.
*/ */
@AssistedInject @AssistedInject
public ActiveConnectionDirectoryResource(@Assisted UserContext userContext, public ActiveConnectionDirectoryResource(
@Assisted AuthenticatedUser authenticatedUser,
@Assisted UserContext userContext,
@Assisted Directory<ActiveConnection> directory, @Assisted Directory<ActiveConnection> directory,
DirectoryObjectTranslator<ActiveConnection, APIActiveConnection> translator, DirectoryObjectTranslator<ActiveConnection, APIActiveConnection> translator,
DirectoryObjectResourceFactory<ActiveConnection, APIActiveConnection> resourceFactory) { DirectoryObjectResourceFactory<ActiveConnection, APIActiveConnection> resourceFactory) {
super(userContext, directory, translator, resourceFactory); super(authenticatedUser, userContext, ActiveConnection.class, directory, translator, resourceFactory);
} }
@Override @Override

View File

@@ -30,6 +30,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.ActiveConnection; 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.Connection;
import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
@@ -47,17 +48,6 @@ import org.apache.guacamole.rest.directory.DirectoryResourceFactory;
public class ActiveConnectionResource public class ActiveConnectionResource
extends DirectoryObjectResource<ActiveConnection, APIActiveConnection> { extends DirectoryObjectResource<ActiveConnection, APIActiveConnection> {
/**
* 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 * A factory which can be used to create instances of resources representing
* Connection. * Connection.
@@ -70,6 +60,9 @@ public class ActiveConnectionResource
* Creates a new ActiveConnectionResource which exposes the operations and * Creates a new ActiveConnectionResource which exposes the operations and
* subresources available for the given ActiveConnection. * subresources available for the given ActiveConnection.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param userContext * @param userContext
* The UserContext associated with the given Directory. * The UserContext associated with the given Directory.
* *
@@ -85,13 +78,12 @@ public class ActiveConnectionResource
* ActiveConnections. * ActiveConnections.
*/ */
@AssistedInject @AssistedInject
public ActiveConnectionResource(@Assisted UserContext userContext, public ActiveConnectionResource(@Assisted AuthenticatedUser authenticatedUser,
@Assisted UserContext userContext,
@Assisted Directory<ActiveConnection> directory, @Assisted Directory<ActiveConnection> directory,
@Assisted ActiveConnection activeConnection, @Assisted ActiveConnection activeConnection,
DirectoryObjectTranslator<ActiveConnection, APIActiveConnection> translator) { DirectoryObjectTranslator<ActiveConnection, APIActiveConnection> translator) {
super(userContext, directory, activeConnection, translator); super(authenticatedUser, userContext, ActiveConnection.class, directory, activeConnection, translator);
this.userContext = userContext;
this.activeConnection = activeConnection;
} }
/** /**
@@ -109,9 +101,12 @@ public class ActiveConnectionResource
public DirectoryObjectResource<Connection, APIConnection> getConnection() public DirectoryObjectResource<Connection, APIConnection> getConnection()
throws GuacamoleException { throws GuacamoleException {
UserContext userContext = getUserContext();
ActiveConnection activeConnection = getInternalObject();
// Return the underlying connection as a resource // Return the underlying connection as a resource
return connectionDirectoryResourceFactory return connectionDirectoryResourceFactory
.create(userContext, userContext.getConnectionDirectory()) .create(getAuthenticatedUser(), userContext, userContext.getConnectionDirectory())
.getObjectResource(activeConnection.getConnectionIdentifier()); .getObjectResource(activeConnection.getConnectionIdentifier());
} }
@@ -137,7 +132,7 @@ public class ActiveConnectionResource
throws GuacamoleException { throws GuacamoleException {
// Generate and return sharing credentials for the active connection // Generate and return sharing credentials for the active connection
return new APIUserCredentials(activeConnection.getSharingCredentials(sharingProfileIdentifier)); return new APIUserCredentials(getInternalObject().getSharingCredentials(sharingProfileIdentifier));
} }

View File

@@ -25,6 +25,7 @@ import javax.ws.rs.Consumes;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; 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.Connection;
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.Permissions;
@@ -47,6 +48,9 @@ public class ConnectionDirectoryResource
* Creates a new ConnectionDirectoryResource which exposes the operations * Creates a new ConnectionDirectoryResource which exposes the operations
* and subresources available for the given Connection Directory. * and subresources available for the given Connection Directory.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param userContext * @param userContext
* The UserContext associated with the given Directory. * The UserContext associated with the given Directory.
* *
@@ -62,11 +66,11 @@ public class ConnectionDirectoryResource
* representing Connections. * representing Connections.
*/ */
@AssistedInject @AssistedInject
public ConnectionDirectoryResource(@Assisted UserContext userContext, public ConnectionDirectoryResource(@Assisted AuthenticatedUser authenticatedUser,
@Assisted Directory<Connection> directory, @Assisted UserContext userContext, @Assisted Directory<Connection> directory,
DirectoryObjectTranslator<Connection, APIConnection> translator, DirectoryObjectTranslator<Connection, APIConnection> translator,
DirectoryObjectResourceFactory<Connection, APIConnection> resourceFactory) { DirectoryObjectResourceFactory<Connection, APIConnection> resourceFactory) {
super(userContext, directory, translator, resourceFactory); super(authenticatedUser, userContext, Connection.class, directory, translator, resourceFactory);
} }
@Override @Override

View File

@@ -32,6 +32,7 @@ import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.GuacamoleUnsupportedException; import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.net.auth.ActivityRecordSet; 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.Connection;
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.Permissions;
@@ -66,17 +67,6 @@ public class ConnectionResource extends DirectoryObjectResource<Connection, APIC
*/ */
private static final Logger logger = LoggerFactory.getLogger(ConnectionResource.class); private static final Logger logger = LoggerFactory.getLogger(ConnectionResource.class);
/**
* The UserContext associated with the Directory which contains the
* Connection exposed by this resource.
*/
private final UserContext userContext;
/**
* The Connection object represented by this ConnectionResource.
*/
private final Connection connection;
/** /**
* A factory which can be used to create instances of resources representing * A factory which can be used to create instances of resources representing
* SharingProfiles. * SharingProfiles.
@@ -89,6 +79,9 @@ public class ConnectionResource extends DirectoryObjectResource<Connection, APIC
* Creates a new ConnectionResource which exposes the operations and * Creates a new ConnectionResource which exposes the operations and
* subresources available for the given Connection. * subresources available for the given Connection.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param userContext * @param userContext
* The UserContext associated with the given Directory. * The UserContext associated with the given Directory.
* *
@@ -103,13 +96,12 @@ public class ConnectionResource extends DirectoryObjectResource<Connection, APIC
* object given. * object given.
*/ */
@AssistedInject @AssistedInject
public ConnectionResource(@Assisted UserContext userContext, public ConnectionResource(@Assisted AuthenticatedUser authenticatedUser,
@Assisted UserContext userContext,
@Assisted Directory<Connection> directory, @Assisted Directory<Connection> directory,
@Assisted Connection connection, @Assisted Connection connection,
DirectoryObjectTranslator<Connection, APIConnection> translator) { DirectoryObjectTranslator<Connection, APIConnection> translator) {
super(userContext, directory, connection, translator); super(authenticatedUser, userContext, Connection.class, directory, connection, translator);
this.userContext = userContext;
this.connection = connection;
} }
/** /**
@@ -126,8 +118,10 @@ public class ConnectionResource extends DirectoryObjectResource<Connection, APIC
public Map<String, String> getConnectionParameters() public Map<String, String> getConnectionParameters()
throws GuacamoleException { throws GuacamoleException {
Connection connection = getInternalObject();
// Pull effective permissions // Pull effective permissions
Permissions effective = userContext.self().getEffectivePermissions(); Permissions effective = getUserContext().self().getEffectivePermissions();
// Retrieve permission sets // Retrieve permission sets
SystemPermissionSet systemPermissions = effective.getSystemPermissions(); SystemPermissionSet systemPermissions = effective.getSystemPermissions();
@@ -162,6 +156,8 @@ public class ConnectionResource extends DirectoryObjectResource<Connection, APIC
public ConnectionHistoryResource getConnectionHistory() public ConnectionHistoryResource getConnectionHistory()
throws GuacamoleException { throws GuacamoleException {
Connection connection = getInternalObject();
// Try the current getConnectionHistory() method, first, for connection history. // Try the current getConnectionHistory() method, first, for connection history.
try { try {
return new ConnectionHistoryResource(connection.getConnectionHistory() return new ConnectionHistoryResource(connection.getConnectionHistory()
@@ -201,6 +197,9 @@ public class ConnectionResource extends DirectoryObjectResource<Connection, APIC
public DirectoryResource<SharingProfile, APISharingProfile> public DirectoryResource<SharingProfile, APISharingProfile>
getSharingProfileDirectoryResource() throws GuacamoleException { getSharingProfileDirectoryResource() throws GuacamoleException {
UserContext userContext = getUserContext();
Connection connection = getInternalObject();
// Produce subset of all SharingProfiles, containing only those which // Produce subset of all SharingProfiles, containing only those which
// are associated with this connection // are associated with this connection
Directory<SharingProfile> sharingProfiles = new DirectoryView<>( Directory<SharingProfile> sharingProfiles = new DirectoryView<>(
@@ -209,7 +208,7 @@ public class ConnectionResource extends DirectoryObjectResource<Connection, APIC
); );
// Return a new resource which provides access to only those SharingProfiles // Return a new resource which provides access to only those SharingProfiles
return sharingProfileDirectoryResourceFactory.create(userContext, sharingProfiles); return sharingProfileDirectoryResourceFactory.create(getAuthenticatedUser(), userContext, sharingProfiles);
} }

View File

@@ -25,6 +25,7 @@ import javax.ws.rs.Consumes;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; 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.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.Permissions;
@@ -44,28 +45,14 @@ import org.apache.guacamole.rest.directory.DirectoryResource;
public class ConnectionGroupDirectoryResource public class ConnectionGroupDirectoryResource
extends DirectoryResource<ConnectionGroup, APIConnectionGroup> { extends DirectoryResource<ConnectionGroup, APIConnectionGroup> {
/**
* 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<ConnectionGroup> directory;
/**
* A factory which can be used to create instances of resources representing
* ConnectionGroups.
*/
private final DirectoryObjectResourceFactory<ConnectionGroup, APIConnectionGroup> resourceFactory;
/** /**
* Creates a new ConnectionGroupDirectoryResource which exposes the * Creates a new ConnectionGroupDirectoryResource which exposes the
* operations and subresources available for the given ConnectionGroup * operations and subresources available for the given ConnectionGroup
* Directory. * Directory.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param userContext * @param userContext
* The UserContext associated with the given Directory. * The UserContext associated with the given Directory.
* *
@@ -81,23 +68,24 @@ public class ConnectionGroupDirectoryResource
* representing ConnectionGroups. * representing ConnectionGroups.
*/ */
@AssistedInject @AssistedInject
public ConnectionGroupDirectoryResource(@Assisted UserContext userContext, public ConnectionGroupDirectoryResource(
@Assisted AuthenticatedUser authenticatedUser,
@Assisted UserContext userContext,
@Assisted Directory<ConnectionGroup> directory, @Assisted Directory<ConnectionGroup> directory,
DirectoryObjectTranslator<ConnectionGroup, APIConnectionGroup> translator, DirectoryObjectTranslator<ConnectionGroup, APIConnectionGroup> translator,
DirectoryObjectResourceFactory<ConnectionGroup, APIConnectionGroup> resourceFactory) { DirectoryObjectResourceFactory<ConnectionGroup, APIConnectionGroup> resourceFactory) {
super(userContext, directory, translator, resourceFactory); super(authenticatedUser, userContext, ConnectionGroup.class, directory, translator, resourceFactory);
this.userContext = userContext;
this.directory = directory;
this.resourceFactory = resourceFactory;
} }
@Override @Override
public DirectoryObjectResource<ConnectionGroup, APIConnectionGroup> public DirectoryObjectResource<ConnectionGroup, APIConnectionGroup>
getObjectResource(String identifier) throws GuacamoleException { getObjectResource(String identifier) throws GuacamoleException {
UserContext userContext = getUserContext();
// Use root group if identifier is the standard root identifier // Use root group if identifier is the standard root identifier
if (identifier != null && identifier.equals(APIConnectionGroup.ROOT_IDENTIFIER)) if (identifier != null && identifier.equals(APIConnectionGroup.ROOT_IDENTIFIER))
return resourceFactory.create(userContext, directory, return getResourceFactory().create(getAuthenticatedUser(), userContext, getDirectory(),
userContext.getRootConnectionGroup()); userContext.getRootConnectionGroup());
return super.getObjectResource(identifier); return super.getObjectResource(identifier);

View File

@@ -29,6 +29,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; 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.ConnectionGroup;
import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
@@ -45,21 +46,13 @@ import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
public class ConnectionGroupResource public class ConnectionGroupResource
extends DirectoryObjectResource<ConnectionGroup, APIConnectionGroup> { extends DirectoryObjectResource<ConnectionGroup, APIConnectionGroup> {
/**
* 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 * Creates a new ConnectionGroupResource which exposes the operations and
* subresources available for the given ConnectionGroup. * subresources available for the given ConnectionGroup.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param userContext * @param userContext
* The UserContext associated with the given Directory. * The UserContext associated with the given Directory.
* *
@@ -75,13 +68,13 @@ public class ConnectionGroupResource
* object given. * object given.
*/ */
@AssistedInject @AssistedInject
public ConnectionGroupResource(@Assisted UserContext userContext, public ConnectionGroupResource(
@Assisted AuthenticatedUser authenticatedUser,
@Assisted UserContext userContext,
@Assisted Directory<ConnectionGroup> directory, @Assisted Directory<ConnectionGroup> directory,
@Assisted ConnectionGroup connectionGroup, @Assisted ConnectionGroup connectionGroup,
DirectoryObjectTranslator<ConnectionGroup, APIConnectionGroup> translator) { DirectoryObjectTranslator<ConnectionGroup, APIConnectionGroup> translator) {
super(userContext, directory, connectionGroup, translator); super(authenticatedUser, userContext, ConnectionGroup.class, directory, connectionGroup, translator);
this.userContext = userContext;
this.connectionGroup = connectionGroup;
} }
/** /**
@@ -107,8 +100,8 @@ public class ConnectionGroupResource
throws GuacamoleException { throws GuacamoleException {
// Retrieve the requested tree, filtering by the given permissions // Retrieve the requested tree, filtering by the given permissions
ConnectionGroupTree tree = new ConnectionGroupTree(userContext, ConnectionGroupTree tree = new ConnectionGroupTree(getUserContext(),
connectionGroup, permissions); getInternalObject(), permissions);
// Return tree as a connection group // Return tree as a connection group
return tree.getRootAPIConnectionGroup(); return tree.getRootAPIConnectionGroup();

View File

@@ -19,6 +19,7 @@
package org.apache.guacamole.rest.directory; package org.apache.guacamole.rest.directory;
import javax.inject.Inject;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
import javax.ws.rs.GET; import javax.ws.rs.GET;
@@ -27,9 +28,15 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleClientException; import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException; 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.Directory;
import org.apache.guacamole.net.auth.Identifiable; import org.apache.guacamole.net.auth.Identifiable;
import org.apache.guacamole.net.auth.UserContext; 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 * 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) @Consumes(MediaType.APPLICATION_JSON)
public abstract class DirectoryObjectResource<InternalType extends Identifiable, ExternalType> { public abstract class DirectoryObjectResource<InternalType extends Identifiable, ExternalType> {
/**
* The user that is accessing this resource.
*/
private final AuthenticatedUser authenticatedUser;
/** /**
* The UserContext associated with the Directory containing the object * The UserContext associated with the Directory containing the object
* represented by this DirectoryObjectResource. * represented by this DirectoryObjectResource.
*/ */
private final UserContext userContext; private final UserContext userContext;
/**
* The type of object represented by this DirectoryObjectResource.
*/
private final Class<InternalType> internalType;
/** /**
* The Directory which contains the object represented by this * The Directory which contains the object represented by this
* DirectoryObjectResource. * DirectoryObjectResource.
@@ -74,13 +91,26 @@ public abstract class DirectoryObjectResource<InternalType extends Identifiable,
*/ */
private final DirectoryObjectTranslator<InternalType, ExternalType> translator; private final DirectoryObjectTranslator<InternalType, ExternalType> translator;
/**
* Service for dispatching events to registered listeners.
*/
@Inject
private ListenerService listenerService;
/** /**
* Creates a new DirectoryObjectResource which exposes the operations * Creates a new DirectoryObjectResource which exposes the operations
* available for the given object. * available for the given object.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param userContext * @param userContext
* The UserContext associated with the given Directory. * The UserContext associated with the given Directory.
* *
* @param internalType
* The type of object that this DirectoryObjectResource should
* represent.
*
* @param directory * @param directory
* The Directory which contains the given object. * The Directory which contains the given object.
* *
@@ -91,15 +121,162 @@ public abstract class DirectoryObjectResource<InternalType extends Identifiable,
* A DirectoryObjectTranslator implementation which handles the type of * A DirectoryObjectTranslator implementation which handles the type of
* object given. * object given.
*/ */
public DirectoryObjectResource(UserContext userContext, public DirectoryObjectResource(AuthenticatedUser authenticatedUser,
UserContext userContext, Class<InternalType> internalType,
Directory<InternalType> directory, InternalType object, Directory<InternalType> directory, InternalType object,
DirectoryObjectTranslator<InternalType, ExternalType> translator) { DirectoryObjectTranslator<InternalType, ExternalType> translator) {
this.authenticatedUser = authenticatedUser;
this.userContext = userContext; this.userContext = userContext;
this.directory = directory; this.directory = directory;
this.internalType = internalType;
this.object = object; this.object = object;
this.translator = translator; 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<InternalType>() {
@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<InternalType>() {
@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<InternalType> 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 * Returns the object represented by this DirectoryObjectResource, in a
* format intended for interchange. * format intended for interchange.
@@ -138,7 +315,15 @@ public abstract class DirectoryObjectResource<InternalType extends Identifiable,
// Perform update // Perform update
translator.applyExternalChanges(object, modifiedObject); translator.applyExternalChanges(object, modifiedObject);
directory.update(object);
try {
directory.update(object);
fireDirectorySuccessEvent(DirectoryEvent.Operation.UPDATE);
}
catch (GuacamoleException | RuntimeException | Error e) {
fireDirectoryFailureEvent(DirectoryEvent.Operation.UPDATE, e);
throw e;
}
} }
@@ -150,7 +335,14 @@ public abstract class DirectoryObjectResource<InternalType extends Identifiable,
*/ */
@DELETE @DELETE
public void deleteObject() throws GuacamoleException { public void deleteObject() throws GuacamoleException {
directory.remove(object.getIdentifier()); try {
directory.remove(object.getIdentifier());
fireDirectorySuccessEvent(DirectoryEvent.Operation.REMOVE);
}
catch (GuacamoleException | RuntimeException | Error e) {
fireDirectoryFailureEvent(DirectoryEvent.Operation.REMOVE, e);
throw e;
}
} }
} }

View File

@@ -19,6 +19,7 @@
package org.apache.guacamole.rest.directory; 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.Directory;
import org.apache.guacamole.net.auth.Identifiable; import org.apache.guacamole.net.auth.Identifiable;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
@@ -41,6 +42,9 @@ public interface DirectoryObjectResourceFactory<InternalType extends Identifiabl
/** /**
* Creates a new DirectoryObjectResource which exposes the given object. * Creates a new DirectoryObjectResource which exposes the given object.
* *
* @param authenticatedUser
* The user that is accessing the resource.
*
* @param userContext * @param userContext
* The UserContext which contains the given Directory. * The UserContext which contains the given Directory.
* *
@@ -55,7 +59,7 @@ public interface DirectoryObjectResourceFactory<InternalType extends Identifiabl
* A new DirectoryObjectResource which exposes the given object. * A new DirectoryObjectResource which exposes the given object.
*/ */
DirectoryObjectResource<InternalType, ExternalType> DirectoryObjectResource<InternalType, ExternalType>
create(UserContext userContext, Directory<InternalType> directory, create(AuthenticatedUser authenticatedUser, UserContext userContext,
InternalType object); Directory<InternalType> directory, InternalType object);
} }

View File

@@ -23,6 +23,7 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.inject.Inject;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.PATCH; import javax.ws.rs.PATCH;
@@ -36,6 +37,8 @@ import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleResourceNotFoundException; import org.apache.guacamole.GuacamoleResourceNotFoundException;
import org.apache.guacamole.GuacamoleUnsupportedException; 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.Directory;
import org.apache.guacamole.net.auth.Identifiable; import org.apache.guacamole.net.auth.Identifiable;
import org.apache.guacamole.net.auth.Permissions; 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.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.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.APIPatch;
import org.apache.guacamole.rest.event.ListenerService;
/** /**
* A REST resource which abstracts the operations available on all Guacamole * 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) @Consumes(MediaType.APPLICATION_JSON)
public abstract class DirectoryResource<InternalType extends Identifiable, ExternalType> { public abstract class DirectoryResource<InternalType extends Identifiable, ExternalType> {
/**
* The user that is accessing this resource.
*/
private final AuthenticatedUser authenticatedUser;
/** /**
* The UserContext associated with the Directory being exposed by this * The UserContext associated with the Directory being exposed by this
* DirectoryResource. * DirectoryResource.
*/ */
private final UserContext userContext; private final UserContext userContext;
/**
* The type of object contained within the Directory exposed by this
* DirectoryResource.
*/
private final Class<InternalType> internalType;
/** /**
* The Directory being exposed by this DirectoryResource. * The Directory being exposed by this DirectoryResource.
*/ */
@@ -92,13 +110,25 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
*/ */
private final DirectoryObjectResourceFactory<InternalType, ExternalType> resourceFactory; private final DirectoryObjectResourceFactory<InternalType, ExternalType> resourceFactory;
/**
* Service for dispatching events to registered listeners.
*/
@Inject
private ListenerService listenerService;
/** /**
* Creates a new DirectoryResource which exposes the operations available * Creates a new DirectoryResource which exposes the operations available
* for the given Directory. * for the given Directory.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param userContext * @param userContext
* The UserContext associated with the given Directory. * The UserContext associated with the given Directory.
* *
* @param internalType
* The type of object contained within the given Directory.
*
* @param directory * @param directory
* The Directory being exposed by this DirectoryResource. * The Directory being exposed by this DirectoryResource.
* *
@@ -110,11 +140,15 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
* A factory which can be used to create instances of resources * A factory which can be used to create instances of resources
* representing individual objects contained within the given Directory. * representing individual objects contained within the given Directory.
*/ */
public DirectoryResource(UserContext userContext, Directory<InternalType> directory, public DirectoryResource(AuthenticatedUser authenticatedUser,
UserContext userContext, Class<InternalType> internalType,
Directory<InternalType> directory,
DirectoryObjectTranslator<InternalType, ExternalType> translator, DirectoryObjectTranslator<InternalType, ExternalType> translator,
DirectoryObjectResourceFactory<InternalType, ExternalType> resourceFactory) { DirectoryObjectResourceFactory<InternalType, ExternalType> resourceFactory) {
this.authenticatedUser = authenticatedUser;
this.userContext = userContext; this.userContext = userContext;
this.directory = directory; this.directory = directory;
this.internalType = internalType;
this.translator = translator; this.translator = translator;
this.resourceFactory = resourceFactory; this.resourceFactory = resourceFactory;
} }
@@ -139,6 +173,174 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
protected abstract ObjectPermissionSet getObjectPermissions( protected abstract ObjectPermissionSet getObjectPermissions(
Permissions permissions) throws GuacamoleException; Permissions permissions) throws GuacamoleException;
/**
* Notifies all registered listeners that the given operation has succeeded
* against the object having the given identifier within the Directory
* represented by this resource.
*
* @param operation
* The operation that was performed.
*
* @param identifier
* The identifier of the object affected by the operation.
*
* @param object
* The specific object affected by the operation, if available. If not
* available, this may be null.
*
* @throws GuacamoleException
* If a listener throws a GuacamoleException from its event handler.
*/
protected void fireDirectorySuccessEvent(DirectoryEvent.Operation operation,
String identifier, InternalType object)
throws GuacamoleException {
listenerService.handleEvent(new DirectorySuccessEvent<InternalType>() {
@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<InternalType>() {
@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<InternalType> 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<InternalType, ExternalType> getResourceFactory() {
return resourceFactory;
}
/** /**
* Returns a map of all objects available within this DirectoryResource, * Returns a map of all objects available within this DirectoryResource,
* filtering the returned map by the given permission, if specified. * filtering the returned map by the given permission, if specified.
@@ -213,7 +415,15 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
throw new GuacamoleClientException("Patch paths must start with \"/\"."); throw new GuacamoleClientException("Patch paths must start with \"/\".");
// Remove specified object // Remove specified object
directory.remove(path.substring(1)); String identifier = path.substring(1);
try {
directory.remove(identifier);
fireDirectorySuccessEvent(DirectoryEvent.Operation.REMOVE, identifier, null);
}
catch (GuacamoleException | RuntimeException | Error e) {
fireDirectoryFailureEvent(DirectoryEvent.Operation.REMOVE, identifier, null, e);
throw e;
}
} }
@@ -244,11 +454,18 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
// Filter/sanitize object contents // Filter/sanitize object contents
translator.filterExternalObject(userContext, object); translator.filterExternalObject(userContext, object);
InternalType internal = translator.toInternalObject(object);
// Create the new object within the directory // Create the new object within the directory
directory.add(translator.toInternalObject(object)); try {
directory.add(internal);
return object; fireDirectorySuccessEvent(DirectoryEvent.Operation.ADD, internal.getIdentifier(), internal);
return object;
}
catch (GuacamoleException | RuntimeException | Error e) {
fireDirectoryFailureEvent(DirectoryEvent.Operation.ADD, internal.getIdentifier(), internal, e);
throw e;
}
} }
@@ -272,12 +489,21 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
throws GuacamoleException { throws GuacamoleException {
// Retrieve the object having the given identifier // Retrieve the object having the given identifier
InternalType object = directory.get(identifier); InternalType object;
if (object == null) try {
throw new GuacamoleResourceNotFoundException("Not found: \"" + identifier + "\""); object = directory.get(identifier);
if (object == null)
throw new GuacamoleResourceNotFoundException("Not found: \"" + identifier + "\"");
}
catch (GuacamoleException | RuntimeException | Error e) {
fireDirectoryFailureEvent(DirectoryEvent.Operation.GET, identifier, null, e);
throw e;
}
// Return a resource which provides access to the retrieved object // Return a resource which provides access to the retrieved object
return resourceFactory.create(userContext, directory, object); DirectoryObjectResource<InternalType, ExternalType> resource = resourceFactory.create(authenticatedUser, userContext, directory, object);
fireDirectorySuccessEvent(DirectoryEvent.Operation.GET, identifier, object);
return resource;
} }

View File

@@ -19,6 +19,7 @@
package org.apache.guacamole.rest.directory; 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.Directory;
import org.apache.guacamole.net.auth.Identifiable; import org.apache.guacamole.net.auth.Identifiable;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
@@ -41,6 +42,9 @@ public interface DirectoryResourceFactory<InternalType extends Identifiable, Ext
/** /**
* Creates a new DirectoryResource which exposes the given Directory. * Creates a new DirectoryResource which exposes the given Directory.
* *
* @param authenticatedUser
* The user that is accessing the resource.
*
* @param userContext * @param userContext
* The UserContext from which the given Directory was obtained. * The UserContext from which the given Directory was obtained.
* *
@@ -52,6 +56,7 @@ public interface DirectoryResourceFactory<InternalType extends Identifiable, Ext
* A new DirectoryResource which exposes the given Directory. * A new DirectoryResource which exposes the given Directory.
*/ */
DirectoryResource<InternalType, ExternalType> DirectoryResource<InternalType, ExternalType>
create(UserContext userContext, Directory<InternalType> directory); create(AuthenticatedUser authenticatedUser, UserContext userContext,
Directory<InternalType> directory);
} }

View File

@@ -116,7 +116,7 @@ public class SessionResource {
UserContext userContext = session.getUserContext(authProviderIdentifier); UserContext userContext = session.getUserContext(authProviderIdentifier);
// Return a resource exposing the retrieved UserContext // Return a resource exposing the retrieved UserContext
return userContextResourceFactory.create(userContext); return userContextResourceFactory.create(session.getAuthenticatedUser(), userContext);
} }

View File

@@ -30,6 +30,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.ActiveConnection; 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.Connection;
import org.apache.guacamole.net.auth.ConnectionGroup; import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.net.auth.SharingProfile; import org.apache.guacamole.net.auth.SharingProfile;
@@ -59,6 +60,11 @@ public class UserContextResource {
*/ */
private final UserContext userContext; private final UserContext userContext;
/**
* The user that is accessing this resource.
*/
private final AuthenticatedUser authenticatedUser;
/** /**
* Factory for creating DirectoryObjectResources which expose a given User. * 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 * Creates a new UserContextResource which exposes the data within the
* given UserContext. * given UserContext.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param userContext * @param userContext
* The UserContext which should be exposed through this * The UserContext which should be exposed through this
* UserContextResource. * UserContextResource.
*/ */
@AssistedInject @AssistedInject
public UserContextResource(@Assisted UserContext userContext) { public UserContextResource(@Assisted AuthenticatedUser authenticatedUser,
@Assisted UserContext userContext) {
this.authenticatedUser = authenticatedUser;
this.userContext = userContext; this.userContext = userContext;
} }
@@ -140,7 +151,7 @@ public class UserContextResource {
@Path("self") @Path("self")
public DirectoryObjectResource<User, APIUser> getSelfResource() public DirectoryObjectResource<User, APIUser> getSelfResource()
throws GuacamoleException { throws GuacamoleException {
return userResourceFactory.create(userContext, return userResourceFactory.create(authenticatedUser, userContext,
userContext.getUserDirectory(), userContext.self()); userContext.getUserDirectory(), userContext.self());
} }
@@ -158,8 +169,8 @@ public class UserContextResource {
@Path("activeConnections") @Path("activeConnections")
public DirectoryResource<ActiveConnection, APIActiveConnection> public DirectoryResource<ActiveConnection, APIActiveConnection>
getActiveConnectionDirectoryResource() throws GuacamoleException { getActiveConnectionDirectoryResource() throws GuacamoleException {
return activeConnectionDirectoryResourceFactory.create(userContext, return activeConnectionDirectoryResourceFactory.create(authenticatedUser,
userContext.getActiveConnectionDirectory()); userContext, userContext.getActiveConnectionDirectory());
} }
/** /**
@@ -176,8 +187,8 @@ public class UserContextResource {
@Path("connections") @Path("connections")
public DirectoryResource<Connection, APIConnection> getConnectionDirectoryResource() public DirectoryResource<Connection, APIConnection> getConnectionDirectoryResource()
throws GuacamoleException { throws GuacamoleException {
return connectionDirectoryResourceFactory.create(userContext, return connectionDirectoryResourceFactory.create(authenticatedUser,
userContext.getConnectionDirectory()); userContext, userContext.getConnectionDirectory());
} }
/** /**
@@ -194,8 +205,8 @@ public class UserContextResource {
@Path("connectionGroups") @Path("connectionGroups")
public DirectoryResource<ConnectionGroup, APIConnectionGroup> getConnectionGroupDirectoryResource() public DirectoryResource<ConnectionGroup, APIConnectionGroup> getConnectionGroupDirectoryResource()
throws GuacamoleException { throws GuacamoleException {
return connectionGroupDirectoryResourceFactory.create(userContext, return connectionGroupDirectoryResourceFactory.create(authenticatedUser,
userContext.getConnectionGroupDirectory()); userContext, userContext.getConnectionGroupDirectory());
} }
/** /**
@@ -212,8 +223,8 @@ public class UserContextResource {
@Path("sharingProfiles") @Path("sharingProfiles")
public DirectoryResource<SharingProfile, APISharingProfile> public DirectoryResource<SharingProfile, APISharingProfile>
getSharingProfileDirectoryResource() throws GuacamoleException { getSharingProfileDirectoryResource() throws GuacamoleException {
return sharingProfileDirectoryResourceFactory.create(userContext, return sharingProfileDirectoryResourceFactory.create(authenticatedUser,
userContext.getSharingProfileDirectory()); userContext, userContext.getSharingProfileDirectory());
} }
/** /**
@@ -230,8 +241,8 @@ public class UserContextResource {
@Path("users") @Path("users")
public DirectoryResource<User, APIUser> getUserDirectoryResource() public DirectoryResource<User, APIUser> getUserDirectoryResource()
throws GuacamoleException { throws GuacamoleException {
return userDirectoryResourceFactory.create(userContext, return userDirectoryResourceFactory.create(authenticatedUser,
userContext.getUserDirectory()); userContext, userContext.getUserDirectory());
} }
/** /**
@@ -248,8 +259,8 @@ public class UserContextResource {
@Path("userGroups") @Path("userGroups")
public DirectoryResource<UserGroup, APIUserGroup> getUserGroupDirectoryResource() public DirectoryResource<UserGroup, APIUserGroup> getUserGroupDirectoryResource()
throws GuacamoleException { throws GuacamoleException {
return userGroupDirectoryResourceFactory.create(userContext, return userGroupDirectoryResourceFactory.create(authenticatedUser,
userContext.getUserGroupDirectory()); userContext, userContext.getUserGroupDirectory());
} }
/** /**

View File

@@ -19,6 +19,7 @@
package org.apache.guacamole.rest.session; package org.apache.guacamole.rest.session;
import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
/** /**
@@ -31,6 +32,9 @@ public interface UserContextResourceFactory {
* Creates a new UserContextResource which exposes the contents of the * Creates a new UserContextResource which exposes the contents of the
* given UserContext. * given UserContext.
* *
* @param authenticatedUser
* The user that is accessing the resource.
*
* @param userContext * @param userContext
* The UserContext whose contents should be exposed. * The UserContext whose contents should be exposed.
* *
@@ -38,6 +42,7 @@ public interface UserContextResourceFactory {
* A new UserContextResource which exposes the contents of the given * A new UserContextResource which exposes the contents of the given
* UserContext. * UserContext.
*/ */
UserContextResource create(UserContext userContext); UserContextResource create(AuthenticatedUser authenticatedUser,
UserContext userContext);
} }

View File

@@ -25,6 +25,7 @@ import javax.ws.rs.Consumes;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; 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.Directory;
import org.apache.guacamole.net.auth.Permissions; import org.apache.guacamole.net.auth.Permissions;
import org.apache.guacamole.net.auth.SharingProfile; import org.apache.guacamole.net.auth.SharingProfile;
@@ -48,6 +49,9 @@ public class SharingProfileDirectoryResource
* operations and subresources available for the given SharingProfile * operations and subresources available for the given SharingProfile
* Directory. * Directory.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param userContext * @param userContext
* The UserContext associated with the given Directory. * The UserContext associated with the given Directory.
* *
@@ -63,11 +67,13 @@ public class SharingProfileDirectoryResource
* representing SharingProfiles. * representing SharingProfiles.
*/ */
@AssistedInject @AssistedInject
public SharingProfileDirectoryResource(@Assisted UserContext userContext, public SharingProfileDirectoryResource(
@Assisted AuthenticatedUser authenticatedUser,
@Assisted UserContext userContext,
@Assisted Directory<SharingProfile> directory, @Assisted Directory<SharingProfile> directory,
DirectoryObjectTranslator<SharingProfile, APISharingProfile> translator, DirectoryObjectTranslator<SharingProfile, APISharingProfile> translator,
DirectoryObjectResourceFactory<SharingProfile, APISharingProfile> resourceFactory) { DirectoryObjectResourceFactory<SharingProfile, APISharingProfile> resourceFactory) {
super(userContext, directory, translator, resourceFactory); super(authenticatedUser, userContext, SharingProfile.class, directory, translator, resourceFactory);
} }
@Override @Override

View File

@@ -29,6 +29,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; 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.AuthenticatedUser;
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.Permissions;
import org.apache.guacamole.net.auth.SharingProfile; import org.apache.guacamole.net.auth.SharingProfile;
@@ -49,21 +50,13 @@ import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
public class SharingProfileResource public class SharingProfileResource
extends DirectoryObjectResource<SharingProfile, APISharingProfile> { extends DirectoryObjectResource<SharingProfile, APISharingProfile> {
/**
* 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 * Creates a new SharingProfileResource which exposes the operations and
* subresources available for the given SharingProfile. * subresources available for the given SharingProfile.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param userContext * @param userContext
* The UserContext associated with the given Directory. * The UserContext associated with the given Directory.
* *
@@ -78,13 +71,12 @@ public class SharingProfileResource
* object given. * object given.
*/ */
@AssistedInject @AssistedInject
public SharingProfileResource(@Assisted UserContext userContext, public SharingProfileResource(@Assisted AuthenticatedUser authenticatedUser,
@Assisted UserContext userContext,
@Assisted Directory<SharingProfile> directory, @Assisted Directory<SharingProfile> directory,
@Assisted SharingProfile sharingProfile, @Assisted SharingProfile sharingProfile,
DirectoryObjectTranslator<SharingProfile, APISharingProfile> translator) { DirectoryObjectTranslator<SharingProfile, APISharingProfile> translator) {
super(userContext, directory, sharingProfile, translator); super(authenticatedUser, userContext, SharingProfile.class, directory, sharingProfile, translator);
this.userContext = userContext;
this.sharingProfile = sharingProfile;
} }
/** /**
@@ -103,8 +95,10 @@ public class SharingProfileResource
public Map<String, String> getParameters() public Map<String, String> getParameters()
throws GuacamoleException { throws GuacamoleException {
SharingProfile sharingProfile = getInternalObject();
// Pull effective permissions // Pull effective permissions
Permissions effective = userContext.self().getEffectivePermissions(); Permissions effective = getUserContext().self().getEffectivePermissions();
// Retrieve permission sets // Retrieve permission sets
SystemPermissionSet systemPermissions = effective.getSystemPermissions(); SystemPermissionSet systemPermissions = effective.getSystemPermissions();

View File

@@ -105,7 +105,7 @@ public class TunnelCollectionResource {
throw new GuacamoleResourceNotFoundException("No such tunnel."); throw new GuacamoleResourceNotFoundException("No such tunnel.");
// Return corresponding tunnel resource // Return corresponding tunnel resource
return tunnelResourceFactory.create(tunnel); return tunnelResourceFactory.create(session.getAuthenticatedUser(), tunnel);
} }

View File

@@ -34,6 +34,7 @@ import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleResourceNotFoundException; import org.apache.guacamole.GuacamoleResourceNotFoundException;
import org.apache.guacamole.environment.Environment; import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.net.auth.ActiveConnection; 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.net.auth.UserContext;
import org.apache.guacamole.protocols.ProtocolInfo; import org.apache.guacamole.protocols.ProtocolInfo;
import org.apache.guacamole.rest.activeconnection.APIActiveConnection; 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; 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. * The tunnel that this TunnelResource represents.
*/ */
@@ -78,11 +84,16 @@ public class TunnelResource {
* Creates a new TunnelResource which exposes the operations and * Creates a new TunnelResource which exposes the operations and
* subresources available for the given tunnel. * subresources available for the given tunnel.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param tunnel * @param tunnel
* The tunnel that this TunnelResource should represent. * The tunnel that this TunnelResource should represent.
*/ */
@AssistedInject @AssistedInject
public TunnelResource(@Assisted UserTunnel tunnel) { public TunnelResource(@Assisted AuthenticatedUser authenticatedUser,
@Assisted UserTunnel tunnel) {
this.authenticatedUser = authenticatedUser;
this.tunnel = tunnel; this.tunnel = tunnel;
} }
@@ -110,7 +121,7 @@ public class TunnelResource {
throw new GuacamoleResourceNotFoundException("No readable active connection for tunnel."); throw new GuacamoleResourceNotFoundException("No readable active connection for tunnel.");
// Return the associated ActiveConnection as a resource // Return the associated ActiveConnection as a resource
return activeConnectionResourceFactory.create(userContext, return activeConnectionResourceFactory.create(authenticatedUser, userContext,
userContext.getActiveConnectionDirectory(), activeConnection); userContext.getActiveConnectionDirectory(), activeConnection);
} }

View File

@@ -19,6 +19,7 @@
package org.apache.guacamole.rest.tunnel; package org.apache.guacamole.rest.tunnel;
import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.tunnel.UserTunnel; import org.apache.guacamole.tunnel.UserTunnel;
/** /**
@@ -31,12 +32,15 @@ public interface TunnelResourceFactory {
* Creates a new TunnelResource which exposes the contents of the * Creates a new TunnelResource which exposes the contents of the
* given tunnel. * given tunnel.
* *
* @param authenticatedUser
* The user that is accessing the resource.
*
* @param tunnel * @param tunnel
* The tunnel whose contents should be exposed. * The tunnel whose contents should be exposed.
* *
* @return * @return
* A new TunnelResource which exposes the contents of the given tunnel. * A new TunnelResource which exposes the contents of the given tunnel.
*/ */
TunnelResource create(UserTunnel tunnel); TunnelResource create(AuthenticatedUser authenticatedUser, UserTunnel tunnel);
} }

View File

@@ -25,6 +25,7 @@ import javax.ws.rs.Consumes;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; 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.User;
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.Permissions;
@@ -46,6 +47,9 @@ public class UserDirectoryResource extends DirectoryResource<User, APIUser> {
* Creates a new UserDirectoryResource which exposes the operations and * Creates a new UserDirectoryResource which exposes the operations and
* subresources available for the given User Directory. * subresources available for the given User Directory.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param userContext * @param userContext
* The UserContext associated with the given Directory. * The UserContext associated with the given Directory.
* *
@@ -61,11 +65,12 @@ public class UserDirectoryResource extends DirectoryResource<User, APIUser> {
* representing Users. * representing Users.
*/ */
@AssistedInject @AssistedInject
public UserDirectoryResource(@Assisted UserContext userContext, public UserDirectoryResource(@Assisted AuthenticatedUser authenticatedUser,
@Assisted UserContext userContext,
@Assisted Directory<User> directory, @Assisted Directory<User> directory,
DirectoryObjectTranslator<User, APIUser> translator, DirectoryObjectTranslator<User, APIUser> translator,
DirectoryObjectResourceFactory<User, APIUser> resourceFactory) { DirectoryObjectResourceFactory<User, APIUser> resourceFactory) {
super(userContext, directory, translator, resourceFactory); super(authenticatedUser, userContext, User.class, directory, translator, resourceFactory);
} }
@Override @Override

View File

@@ -33,6 +33,7 @@ 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.GuacamoleUnsupportedException; 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.AuthenticationProvider;
import org.apache.guacamole.net.auth.Credentials; import org.apache.guacamole.net.auth.Credentials;
import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.User;
@@ -63,27 +64,13 @@ public class UserResource
*/ */
private static final Logger logger = LoggerFactory.getLogger(UserResource.class); 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<User> directory;
/**
* The User object represented by this UserResource.
*/
private final User user;
/** /**
* Creates a new UserResource which exposes the operations and subresources * Creates a new UserResource which exposes the operations and subresources
* available for the given User. * available for the given User.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param userContext * @param userContext
* The UserContext associated with the given Directory. * The UserContext associated with the given Directory.
* *
@@ -97,14 +84,12 @@ public class UserResource
* A DirectoryObjectTranslator implementation which handles Users. * A DirectoryObjectTranslator implementation which handles Users.
*/ */
@AssistedInject @AssistedInject
public UserResource(@Assisted UserContext userContext, public UserResource(@Assisted AuthenticatedUser authenticatedUser,
@Assisted UserContext userContext,
@Assisted Directory<User> directory, @Assisted Directory<User> directory,
@Assisted User user, @Assisted User user,
DirectoryObjectTranslator<User, APIUser> translator) { DirectoryObjectTranslator<User, APIUser> translator) {
super(userContext, directory, user, translator); super(authenticatedUser, userContext, User.class, directory, user, translator);
this.userContext = userContext;
this.directory = directory;
this.user = user;
} }
/** /**
@@ -122,6 +107,8 @@ public class UserResource
public UserHistoryResource getUserHistory() public UserHistoryResource getUserHistory()
throws GuacamoleException { throws GuacamoleException {
User user = getInternalObject();
// First try to retrieve history using the current getUserHistory() method. // First try to retrieve history using the current getUserHistory() method.
try { try {
return new UserHistoryResource(user.getUserHistory()); return new UserHistoryResource(user.getUserHistory());
@@ -147,7 +134,7 @@ public class UserResource
public void updateObject(APIUser modifiedObject) throws GuacamoleException { public void updateObject(APIUser modifiedObject) throws GuacamoleException {
// A user may not use this endpoint to update their password // A user may not use this endpoint to update their password
User currentUser = userContext.self(); User currentUser = getUserContext().self();
if ( if (
currentUser.getIdentifier().equals(modifiedObject.getUsername()) currentUser.getIdentifier().equals(modifiedObject.getUsername())
&& modifiedObject.getPassword() != null) { && modifiedObject.getPassword() != null) {
@@ -178,13 +165,15 @@ public class UserResource
public void updatePassword(APIUserPasswordUpdate userPasswordUpdate, public void updatePassword(APIUserPasswordUpdate userPasswordUpdate,
@Context HttpServletRequest request) throws GuacamoleException { @Context HttpServletRequest request) throws GuacamoleException {
User user = getInternalObject();
// Build credentials // Build credentials
Credentials credentials = new Credentials(user.getIdentifier(), Credentials credentials = new Credentials(user.getIdentifier(),
userPasswordUpdate.getOldPassword(), request); userPasswordUpdate.getOldPassword(), request);
// Verify that the old password was correct // Verify that the old password was correct
try { try {
AuthenticationProvider authProvider = userContext.getAuthenticationProvider(); AuthenticationProvider authProvider = getUserContext().getAuthenticationProvider();
if (authProvider.authenticateUser(credentials) == null) if (authProvider.authenticateUser(credentials) == null)
throw new GuacamoleSecurityException("Permission denied."); throw new GuacamoleSecurityException("Permission denied.");
} }
@@ -196,7 +185,7 @@ public class UserResource
// Set password to the newly provided one // Set password to the newly provided one
user.setPassword(userPasswordUpdate.getNewPassword()); user.setPassword(userPasswordUpdate.getNewPassword());
directory.update(user); getDirectory().update(user);
} }
@@ -211,7 +200,7 @@ public class UserResource
*/ */
@Path("permissions") @Path("permissions")
public PermissionSetResource getPermissions() { public PermissionSetResource getPermissions() {
return new PermissionSetResource(user); return new PermissionSetResource(getInternalObject());
} }
/** /**
@@ -228,7 +217,7 @@ public class UserResource
@GET @GET
@Path("effectivePermissions") @Path("effectivePermissions")
public APIPermissionSet getEffectivePermissions() throws GuacamoleException { public APIPermissionSet getEffectivePermissions() throws GuacamoleException {
return new APIPermissionSet(user.getEffectivePermissions()); return new APIPermissionSet(getInternalObject().getEffectivePermissions());
} }
/** /**
@@ -245,7 +234,7 @@ public class UserResource
*/ */
@Path("userGroups") @Path("userGroups")
public RelatedObjectSetResource getUserGroups() throws GuacamoleException { public RelatedObjectSetResource getUserGroups() throws GuacamoleException {
return new RelatedObjectSetResource(user.getUserGroups()); return new RelatedObjectSetResource(getInternalObject().getUserGroups());
} }
} }

View File

@@ -25,6 +25,7 @@ import javax.ws.rs.Consumes;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; 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.UserGroup;
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.Permissions;
@@ -46,6 +47,9 @@ public class UserGroupDirectoryResource extends DirectoryResource<UserGroup, API
* Creates a new UserGroupDirectoryResource which exposes the operations * Creates a new UserGroupDirectoryResource which exposes the operations
* and subresources available for the given UserGroup Directory. * and subresources available for the given UserGroup Directory.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param userContext * @param userContext
* The UserContext associated with the given Directory. * The UserContext associated with the given Directory.
* *
@@ -61,11 +65,13 @@ public class UserGroupDirectoryResource extends DirectoryResource<UserGroup, API
* representing UserGroups. * representing UserGroups.
*/ */
@AssistedInject @AssistedInject
public UserGroupDirectoryResource(@Assisted UserContext userContext, public UserGroupDirectoryResource(
@Assisted AuthenticatedUser authenticatedUser,
@Assisted UserContext userContext,
@Assisted Directory<UserGroup> directory, @Assisted Directory<UserGroup> directory,
DirectoryObjectTranslator<UserGroup, APIUserGroup> translator, DirectoryObjectTranslator<UserGroup, APIUserGroup> translator,
DirectoryObjectResourceFactory<UserGroup, APIUserGroup> resourceFactory) { DirectoryObjectResourceFactory<UserGroup, APIUserGroup> resourceFactory) {
super(userContext, directory, translator, resourceFactory); super(authenticatedUser, userContext, UserGroup.class, directory, translator, resourceFactory);
} }
@Override @Override

View File

@@ -26,6 +26,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; 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.UserGroup;
import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
@@ -43,15 +44,13 @@ import org.apache.guacamole.rest.permission.PermissionSetResource;
public class UserGroupResource public class UserGroupResource
extends DirectoryObjectResource<UserGroup, APIUserGroup> { extends DirectoryObjectResource<UserGroup, APIUserGroup> {
/**
* The UserGroup object represented by this UserGroupResource.
*/
private final UserGroup userGroup;
/** /**
* Creates a new UserGroupResource which exposes the operations and * Creates a new UserGroupResource which exposes the operations and
* subresources available for the given UserGroup. * subresources available for the given UserGroup.
* *
* @param authenticatedUser
* The user that is accessing this resource.
*
* @param userContext * @param userContext
* The UserContext associated with the given Directory. * The UserContext associated with the given Directory.
* *
@@ -65,12 +64,12 @@ public class UserGroupResource
* A DirectoryObjectTranslator implementation which handles Users. * A DirectoryObjectTranslator implementation which handles Users.
*/ */
@AssistedInject @AssistedInject
public UserGroupResource(@Assisted UserContext userContext, public UserGroupResource(@Assisted AuthenticatedUser authenticatedUser,
@Assisted UserContext userContext,
@Assisted Directory<UserGroup> directory, @Assisted Directory<UserGroup> directory,
@Assisted UserGroup userGroup, @Assisted UserGroup userGroup,
DirectoryObjectTranslator<UserGroup, APIUserGroup> translator) { DirectoryObjectTranslator<UserGroup, APIUserGroup> translator) {
super(userContext, directory, userGroup, translator); super(authenticatedUser, userContext, UserGroup.class, directory, userGroup, translator);
this.userGroup = userGroup;
} }
/** /**
@@ -87,7 +86,7 @@ public class UserGroupResource
*/ */
@Path("userGroups") @Path("userGroups")
public RelatedObjectSetResource getUserGroups() throws GuacamoleException { public RelatedObjectSetResource getUserGroups() throws GuacamoleException {
return new RelatedObjectSetResource(userGroup.getUserGroups()); return new RelatedObjectSetResource(getInternalObject().getUserGroups());
} }
/** /**
@@ -104,7 +103,7 @@ public class UserGroupResource
*/ */
@Path("memberUsers") @Path("memberUsers")
public RelatedObjectSetResource getMemberUsers() throws GuacamoleException { public RelatedObjectSetResource getMemberUsers() throws GuacamoleException {
return new RelatedObjectSetResource(userGroup.getMemberUsers()); return new RelatedObjectSetResource(getInternalObject().getMemberUsers());
} }
/** /**
@@ -121,7 +120,7 @@ public class UserGroupResource
*/ */
@Path("memberUserGroups") @Path("memberUserGroups")
public RelatedObjectSetResource getMemberUserGroups() throws GuacamoleException { public RelatedObjectSetResource getMemberUserGroups() throws GuacamoleException {
return new RelatedObjectSetResource(userGroup.getMemberUserGroups()); return new RelatedObjectSetResource(getInternalObject().getMemberUserGroups());
} }
/** /**
@@ -135,7 +134,7 @@ public class UserGroupResource
*/ */
@Path("permissions") @Path("permissions")
public PermissionSetResource getPermissions() { public PermissionSetResource getPermissions() {
return new PermissionSetResource(userGroup); return new PermissionSetResource(getInternalObject());
} }
} }