From 1c7242b80064b2255eb91f52c46b21845a60f2b0 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 10 Aug 2019 18:03:53 -0700 Subject: [PATCH] GUACAMOLE-360: Refactor TunnelRequestService to handle any Connectable supported by TunnelRequestType. --- .../guacamole/tunnel/TunnelRequest.java | 51 +------ .../tunnel/TunnelRequestService.java | 91 +++--------- .../guacamole/tunnel/TunnelRequestType.java | 140 ++++++++++++++++++ 3 files changed, 161 insertions(+), 121 deletions(-) create mode 100644 guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestType.java diff --git a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java index 74e3b4dcf..fe58e18d4 100644 --- a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java +++ b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequest.java @@ -21,8 +21,6 @@ package org.apache.guacamole.tunnel; import java.util.List; import org.apache.guacamole.GuacamoleClientException; -import org.apache.guacamole.GuacamoleClientException; -import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException; /** @@ -101,40 +99,6 @@ public abstract class TunnelRequest { */ public static final String TIMEZONE_PARAMETER = "GUAC_TIMEZONE"; - /** - * All supported object types that can be used as the destination of a - * tunnel. - */ - public static enum Type { - - /** - * A Guacamole connection. - */ - CONNECTION("c"), - - /** - * A Guacamole connection group. - */ - CONNECTION_GROUP("g"); - - /** - * The parameter value which denotes a destination object of this type. - */ - final String PARAMETER_VALUE; - - /** - * Defines a Type having the given corresponding parameter value. - * - * @param value - * The parameter value which denotes a destination object of this - * type. - */ - Type(String value) { - PARAMETER_VALUE = value; - } - - }; - /** * Returns the value of the parameter having the given name. * @@ -257,18 +221,11 @@ public abstract class TunnelRequest { * If the type was not present in the request, or if the type requested * is in the wrong format. */ - public Type getType() throws GuacamoleException { + public TunnelRequestType getType() throws GuacamoleException { - String type = getRequiredParameter(TYPE_PARAMETER); - - // For each possible object type - for (Type possibleType : Type.values()) { - - // Match against defined parameter value - if (type.equals(possibleType.PARAMETER_VALUE)) - return possibleType; - - } + TunnelRequestType type = TunnelRequestType.parseType(getRequiredParameter(TYPE_PARAMETER)); + if (type != null) + return type; throw new GuacamoleClientException("Illegal identifier - unknown type."); diff --git a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java index 598a4e57b..fa56b1932 100644 --- a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java +++ b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java @@ -24,15 +24,13 @@ import com.google.inject.Singleton; import java.util.List; import java.util.Map; import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.GuacamoleSecurityException; +import org.apache.guacamole.GuacamoleResourceNotFoundException; import org.apache.guacamole.GuacamoleSession; import org.apache.guacamole.GuacamoleUnauthorizedException; import org.apache.guacamole.net.GuacamoleTunnel; 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.Connectable; import org.apache.guacamole.net.auth.Credentials; -import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.event.TunnelCloseEvent; import org.apache.guacamole.net.event.TunnelConnectEvent; @@ -204,58 +202,20 @@ public class TunnelRequestService { * If an error occurs while creating the tunnel. */ protected GuacamoleTunnel createConnectedTunnel(UserContext context, - final TunnelRequest.Type type, String id, + final TunnelRequestType type, String id, GuacamoleClientInformation info, Map tokens) throws GuacamoleException { - // Create connected tunnel from identifier - GuacamoleTunnel tunnel = null; - switch (type) { - - // Connection identifiers - case CONNECTION: { - - // Get connection directory - Directory directory = context.getConnectionDirectory(); - - // Get authorized connection - Connection connection = directory.get(id); - if (connection == null) { - logger.info("Connection \"{}\" does not exist for user \"{}\".", id, context.self().getIdentifier()); - throw new GuacamoleSecurityException("Requested connection is not authorized."); - } - - // Connect tunnel - tunnel = connection.connect(info, tokens); - logger.info("User \"{}\" connected to connection \"{}\".", context.self().getIdentifier(), id); - break; - } - - // Connection group identifiers - case CONNECTION_GROUP: { - - // Get connection group directory - Directory directory = context.getConnectionGroupDirectory(); - - // Get authorized connection group - ConnectionGroup group = directory.get(id); - if (group == null) { - logger.info("Connection group \"{}\" does not exist for user \"{}\".", id, context.self().getIdentifier()); - throw new GuacamoleSecurityException("Requested connection group is not authorized."); - } - - // Connect tunnel - tunnel = group.connect(info, tokens); - logger.info("User \"{}\" connected to group \"{}\".", context.self().getIdentifier(), id); - break; - } - - // Type is guaranteed to be one of the above - default: - assert(false); - - } + // Retrieve requested destination object + Connectable connectable = type.getConnectable(context, id); + if (connectable == null) + throw new GuacamoleResourceNotFoundException("Requested tunnel " + + "destination does not exist."); + // Connect tunnel to destination + GuacamoleTunnel tunnel = connectable.connect(info, tokens); + logger.info("User \"{}\" connected to {} \"{}\".", + context.self().getIdentifier(), type.NAME, id); return tunnel; } @@ -297,7 +257,7 @@ public class TunnelRequestService { */ protected GuacamoleTunnel createAssociatedTunnel(final GuacamoleTunnel tunnel, final String authToken, final GuacamoleSession session, - final UserContext context, final TunnelRequest.Type type, + final UserContext context, final TunnelRequestType type, final String id) throws GuacamoleException { // Monitor tunnel closure and data @@ -320,26 +280,9 @@ public class TunnelRequestService { long connectionEndTime = System.currentTimeMillis(); long duration = connectionEndTime - connectionStartTime; - // Log closure - switch (type) { - - // Connection identifiers - case CONNECTION: - logger.info("User \"{}\" disconnected from connection \"{}\". Duration: {} milliseconds", - session.getAuthenticatedUser().getIdentifier(), id, duration); - break; - - // Connection group identifiers - case CONNECTION_GROUP: - logger.info("User \"{}\" disconnected from connection group \"{}\". Duration: {} milliseconds", - session.getAuthenticatedUser().getIdentifier(), id, duration); - break; - - // Type is guaranteed to be one of the above - default: - assert(false); - - } + logger.info("User \"{}\" disconnected from {} \"{}\". Duration: {} milliseconds", + session.getAuthenticatedUser().getIdentifier(), + type.NAME, id, duration); try { @@ -390,7 +333,7 @@ public class TunnelRequestService { // Parse request parameters String authToken = request.getAuthenticationToken(); String id = request.getIdentifier(); - TunnelRequest.Type type = request.getType(); + TunnelRequestType type = request.getType(); String authProviderIdentifier = request.getAuthenticationProviderIdentifier(); GuacamoleClientInformation info = getClientInformation(request); diff --git a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestType.java b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestType.java new file mode 100644 index 000000000..654527a5a --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestType.java @@ -0,0 +1,140 @@ +/* + * 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.tunnel; + +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.Connectable; +import org.apache.guacamole.net.auth.Connection; +import org.apache.guacamole.net.auth.ConnectionGroup; +import org.apache.guacamole.net.auth.UserContext; + +/** + * All supported object types that can be used as the destination of a tunnel. + * + * @see TunnelRequest#TYPE_PARAMETER + * @see TunnelRequest#getType() + */ +public enum TunnelRequestType { + + /** + * A Guacamole connection. + */ + CONNECTION("c", "connection") { + + @Override + public Connection getConnectable(UserContext userContext, + String identifier) throws GuacamoleException { + return userContext.getConnectionDirectory().get(identifier); + } + + }, + + /** + * A Guacamole connection group. + */ + CONNECTION_GROUP("g", "connection group") { + + @Override + public ConnectionGroup getConnectable(UserContext userContext, + String identifier) throws GuacamoleException { + return userContext.getConnectionGroupDirectory().get(identifier); + } + + }; + + /** + * The parameter value which denotes a destination object of this type + * within a tunnel request. + * + * @see TunnelRequest#TYPE_PARAMETER + * @see TunnelRequest#getType() + */ + public final String PARAMETER_VALUE; + + /** + * A human-readable, descriptive name of the type of destination object. + */ + public final String NAME; + + /** + * Defines a tunnel request type having the given corresponding parameter + * value and human-readable name. + * + * @param value + * The parameter value which denotes a destination object of this + * type. + * + * @param name + * A human-readable, descriptive name of the type of destination + * object. + */ + private TunnelRequestType(String value, String name) { + PARAMETER_VALUE = value; + NAME = name; + } + + /** + * Retrieves the object having the given identifier from the given + * UserContext, where the type of object retrieved is the type of object + * represented by this tunnel request type. + * + * @param userContext + * The UserContext to retrieve the object from. + * + * @param identifier + * The identifier of the object to retrieve. + * + * @return + * The object having the given identifier, or null if no such object + * exists. + * + * @throws GuacamoleException + * If an error occurs retrieving the requested object, or if permission + * to retrieve the object is denied. + */ + public abstract Connectable getConnectable(UserContext userContext, + String identifier) throws GuacamoleException; + + /** + * Parses the given tunnel request type string, returning the + * TunnelRequestType which matches that string, as declared by + * {@link #PARAMETER_VALUE}. If no such type exists, null is returned. + * + * @param type + * The type string to parse. + * + * @return + * The TunnelRequestType which specifies the given string as its + * {@link #PARAMETER_VALUE}, or null if no such type exists. + */ + public static TunnelRequestType parseType(String type) { + + // Locate type with given parameter value + for (TunnelRequestType possibleType : values()) { + if (type.equals(possibleType.PARAMETER_VALUE)) + return possibleType; + } + + // No such type + return null; + + } + +}