GUACAMOLE-524: Merge update connect() API changes for backward compatibility with 1.0.0.

This commit is contained in:
Virtually Nick
2019-01-22 22:20:24 -05:00
committed by GitHub
9 changed files with 425 additions and 32 deletions

View File

@@ -107,7 +107,7 @@ public class QuickConnectDirectory extends SimpleDirectory<Connection> {
String name = QCParser.getName(config); String name = QCParser.getName(config);
// Create a new connection and set the parent identifier. // Create a new connection and set the parent identifier.
Connection connection = new SimpleConnection(name, newConnectionId, config); Connection connection = new SimpleConnection(name, newConnectionId, config, true);
connection.setParentIdentifier(QuickConnectUserContext.ROOT_IDENTIFIER); connection.setParentIdentifier(QuickConnectUserContext.ROOT_IDENTIFIER);
// Place the object in this directory. // Place the object in this directory.

View File

@@ -19,6 +19,7 @@
package org.apache.guacamole.net.auth; package org.apache.guacamole.net.auth;
import java.util.Collections;
import java.util.Map; import java.util.Map;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.GuacamoleTunnel; import org.apache.guacamole.net.GuacamoleTunnel;
@@ -29,6 +30,46 @@ import org.apache.guacamole.protocol.GuacamoleClientInformation;
*/ */
public interface Connectable { public interface Connectable {
/*
* IMPORTANT:
* ----------
* The web application (guacamole) defines its own version of this
* interface containing defaults which allow backwards compatibility with
* 1.0.0. Any changes to this interface MUST be properly reflected in that
* copy of the interface such that they are binary compatible.
*/
/**
* Establishes a connection to guacd using the information associated with
* this object. The connection will be provided the given client
* information.
*
* @deprecated
* This function has been deprecated in favor of
* {@link #connect(org.apache.guacamole.protocol.GuacamoleClientInformation, java.util.Map)},
* which allows for connection parameter tokens to be injected and
* applied by cooperating extensions, replacing the functionality
* previously provided through the {@link org.apache.guacamole.token.StandardTokens}
* class. It continues to be defined on this interface for
* compatibility. <strong>New implementations should instead implement
* {@link #connect(org.apache.guacamole.protocol.GuacamoleClientInformation, java.util.Map)}.</strong>
*
* @param info
* Information associated with the connecting client.
*
* @return
* A fully-established GuacamoleTunnel.
*
* @throws GuacamoleException
* If an error occurs while connecting to guacd, or if permission to
* connect is denied.
*/
@Deprecated
default GuacamoleTunnel connect(GuacamoleClientInformation info)
throws GuacamoleException {
return this.connect(info, Collections.emptyMap());
}
/** /**
* Establishes a connection to guacd using the information associated with * Establishes a connection to guacd using the information associated with
* this object. The connection will be provided the given client * this object. The connection will be provided the given client

View File

@@ -19,6 +19,7 @@
package org.apache.guacamole.net.auth; package org.apache.guacamole.net.auth;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -39,6 +40,24 @@ public class DelegatingConnection implements Connection {
*/ */
private final Connection connection; private final Connection connection;
/**
* The tokens which should apply strictly to the next call to
* {@link #connect(org.apache.guacamole.protocol.GuacamoleClientInformation)}.
* This storage is intended as a temporary bridge allowing the old version
* of connect() to be overridden while still resulting in the same behavior
* as older versions of DelegatingConnection. <strong>This storage should be
* removed once support for the old, deprecated connect() is removed.</strong>
*/
private final ThreadLocal<Map<String, String>> currentTokens =
new ThreadLocal<Map<String, String>>() {
@Override
protected Map<String, String> initialValue() {
return Collections.emptyMap();
}
};
/** /**
* Wraps the given Connection such that all function calls against this * Wraps the given Connection such that all function calls against this
* DelegatingConnection will be delegated to it. * DelegatingConnection will be delegated to it.
@@ -127,10 +146,27 @@ public class DelegatingConnection implements Connection {
return connection.getSharingProfileIdentifiers(); return connection.getSharingProfileIdentifiers();
} }
@Override
@Deprecated
public GuacamoleTunnel connect(GuacamoleClientInformation info)
throws GuacamoleException {
return connection.connect(info, currentTokens.get());
}
@Override @Override
public GuacamoleTunnel connect(GuacamoleClientInformation info, public GuacamoleTunnel connect(GuacamoleClientInformation info,
Map<String, String> tokens) throws GuacamoleException { Map<String, String> tokens) throws GuacamoleException {
return connection.connect(info, tokens);
// Make received tokens available within the legacy connect() strictly
// in context of the current connect() call
try {
currentTokens.set(tokens);
return connect(info);
}
finally {
currentTokens.remove();
}
} }
@Override @Override

View File

@@ -19,6 +19,7 @@
package org.apache.guacamole.net.auth; package org.apache.guacamole.net.auth;
import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
@@ -36,6 +37,25 @@ public class DelegatingConnectionGroup implements ConnectionGroup {
*/ */
private final ConnectionGroup connectionGroup; private final ConnectionGroup connectionGroup;
/**
* The tokens which should apply strictly to the next call to
* {@link #connect(org.apache.guacamole.protocol.GuacamoleClientInformation)}.
* This storage is intended as a temporary bridge allowing the old version
* of connect() to be overridden while still resulting in the same behavior
* as older versions of DelegatingConnectionGroup. <strong>This storage
* should be removed once support for the old, deprecated connect() is
* removed.</strong>
*/
private final ThreadLocal<Map<String, String>> currentTokens =
new ThreadLocal<Map<String, String>>() {
@Override
protected Map<String, String> initialValue() {
return Collections.emptyMap();
}
};
/** /**
* Wraps the given ConnectionGroup such that all function calls against this * Wraps the given ConnectionGroup such that all function calls against this
* DelegatingConnectionGroup will be delegated to it. * DelegatingConnectionGroup will be delegated to it.
@@ -118,10 +138,27 @@ public class DelegatingConnectionGroup implements ConnectionGroup {
connectionGroup.setAttributes(attributes); connectionGroup.setAttributes(attributes);
} }
@Override
@Deprecated
public GuacamoleTunnel connect(GuacamoleClientInformation info)
throws GuacamoleException {
return connectionGroup.connect(info, currentTokens.get());
}
@Override @Override
public GuacamoleTunnel connect(GuacamoleClientInformation info, public GuacamoleTunnel connect(GuacamoleClientInformation info,
Map<String, String> tokens) throws GuacamoleException { Map<String, String> tokens) throws GuacamoleException {
return connectionGroup.connect(info, tokens);
// Make received tokens available within the legacy connect() strictly
// in context of the current connect() call
try {
currentTokens.set(tokens);
return connect(info);
}
finally {
currentTokens.remove();
}
} }
@Override @Override

View File

@@ -167,7 +167,7 @@ public abstract class SimpleAuthenticationProvider
return null; return null;
// Return user context restricted to authorized configs // Return user context restricted to authorized configs
return new SimpleUserContext(this, authenticatedUser.getIdentifier(), configs); return new SimpleUserContext(this, authenticatedUser.getIdentifier(), configs, true);
} }

View File

@@ -41,10 +41,10 @@ import org.apache.guacamole.protocol.GuacamoleConfiguration;
import org.apache.guacamole.token.TokenFilter; import org.apache.guacamole.token.TokenFilter;
/** /**
* An extremely basic Connection implementation. The underlying connection to * A Connection implementation which establishes the underlying connection to
* guacd is established using the configuration information provided in * guacd using the configuration information provided in guacamole.properties.
* guacamole.properties. Parameter tokens provided to connect() are * Parameter tokens provided to connect() are automatically applied if
* automatically applied. Tracking of active connections and connection history * explicitly requested. Tracking of active connections and connection history
* is not provided. * is not provided.
*/ */
public class SimpleConnection extends AbstractConnection { public class SimpleConnection extends AbstractConnection {
@@ -52,38 +52,135 @@ public class SimpleConnection extends AbstractConnection {
/** /**
* Backing configuration, containing all sensitive information. * Backing configuration, containing all sensitive information.
*/ */
private GuacamoleConfiguration config; private GuacamoleConfiguration fullConfig;
/** /**
* Creates a completely uninitialized SimpleConnection. * Whether parameter tokens in the underlying GuacamoleConfiguration should
* be automatically applied upon connecting. If false, parameter tokens
* will not be interpreted at all.
*/
private final boolean interpretTokens;
/**
* The tokens which should apply strictly to the next call to
* {@link #connect(org.apache.guacamole.protocol.GuacamoleClientInformation)}.
* This storage is intended as a temporary bridge allowing the old version
* of connect() to be overridden while still resulting in the same behavior
* as older versions of SimpleConnection. <strong>This storage should be
* removed once support for the old, deprecated connect() is removed.</strong>
*/
private final ThreadLocal<Map<String, String>> currentTokens =
new ThreadLocal<Map<String, String>>() {
@Override
protected Map<String, String> initialValue() {
return Collections.emptyMap();
}
};
/**
* Creates a completely uninitialized SimpleConnection. The name,
* identifier, and configuration of this SimpleConnection must eventually
* be set before the SimpleConnection may be used. Parameter tokens within
* the GuacamoleConfiguration eventually supplied with
* {@link #setConfiguration(org.apache.guacamole.protocol.GuacamoleConfiguration)}
* will not be interpreted.
*/ */
public SimpleConnection() { public SimpleConnection() {
this(false);
}
/**
* Creates a completely uninitialized SimpleConnection. The name,
* identifier, and configuration of this SimpleConnection must eventually
* be set before the SimpleConnection may be used. Parameter tokens within
* the GuacamoleConfiguration eventually supplied with
* {@link #setConfiguration(org.apache.guacamole.protocol.GuacamoleConfiguration)}
* will not be interpreted unless explicitly requested.
*
* @param interpretTokens
* Whether parameter tokens in the underlying GuacamoleConfiguration
* should be automatically applied upon connecting. If false, parameter
* tokens will not be interpreted at all.
*/
public SimpleConnection(boolean interpretTokens) {
this.interpretTokens = interpretTokens;
} }
/** /**
* Creates a new SimpleConnection having the given identifier and * Creates a new SimpleConnection having the given identifier and
* GuacamoleConfiguration. * GuacamoleConfiguration. Parameter tokens within the
* GuacamoleConfiguration will not be interpreted unless explicitly
* requested.
* *
* @param name The name to associate with this connection. * @param name
* @param identifier The identifier to associate with this connection. * The name to associate with this connection.
* @param config The configuration describing how to connect to this *
* connection. * @param identifier
* The identifier to associate with this connection.
*
* @param config
* The configuration describing how to connect to this connection.
*/ */
public SimpleConnection(String name, String identifier, public SimpleConnection(String name, String identifier,
GuacamoleConfiguration config) { GuacamoleConfiguration config) {
this(name, identifier, config, false);
}
// Set name /**
setName(name); * Creates a new SimpleConnection having the given identifier and
* GuacamoleConfiguration. Parameter tokens will be interpreted if
* explicitly requested.
*
* @param name
* The name to associate with this connection.
*
* @param identifier
* The identifier to associate with this connection.
*
* @param config
* The configuration describing how to connect to this connection.
*
* @param interpretTokens
* Whether parameter tokens in the underlying GuacamoleConfiguration
* should be automatically applied upon connecting. If false, parameter
* tokens will not be interpreted at all.
*/
public SimpleConnection(String name, String identifier,
GuacamoleConfiguration config, boolean interpretTokens) {
// Set identifier super.setName(name);
setIdentifier(identifier); super.setIdentifier(identifier);
super.setConfiguration(config);
// Set config this.fullConfig = config;
setConfiguration(config); this.interpretTokens = interpretTokens;
this.config = config;
} }
/**
* Returns the GuacamoleConfiguration describing how to connect to this
* connection. Unlike {@link #getConfiguration()}, which is allowed to omit
* or tokenize information, the GuacamoleConfiguration returned by this
* function will always be the full configuration to be used to establish
* the connection, as provided when this SimpleConnection was created or via
* {@link #setConfiguration(org.apache.guacamole.protocol.GuacamoleConfiguration)}.
*
* @return
* The full GuacamoleConfiguration describing how to connect to this
* connection, without any information omitted or tokenized.
*/
protected GuacamoleConfiguration getFullConfiguration() {
return fullConfig;
}
@Override
public void setConfiguration(GuacamoleConfiguration config) {
super.setConfiguration(config);
this.fullConfig = config;
}
@Override @Override
public int getActiveConnections() { public int getActiveConnections() {
return 0; return 0;
@@ -100,8 +197,9 @@ public class SimpleConnection extends AbstractConnection {
} }
@Override @Override
public GuacamoleTunnel connect(GuacamoleClientInformation info, @Deprecated
Map<String, String> tokens) throws GuacamoleException { public GuacamoleTunnel connect(GuacamoleClientInformation info)
throws GuacamoleException {
// Retrieve proxy configuration from environment // Retrieve proxy configuration from environment
Environment environment = new LocalEnvironment(); Environment environment = new LocalEnvironment();
@@ -112,8 +210,8 @@ public class SimpleConnection extends AbstractConnection {
int port = proxyConfig.getPort(); int port = proxyConfig.getPort();
// Apply tokens to config parameters // Apply tokens to config parameters
GuacamoleConfiguration filteredConfig = new GuacamoleConfiguration(config); GuacamoleConfiguration filteredConfig = new GuacamoleConfiguration(getFullConfiguration());
new TokenFilter(tokens).filterValues(filteredConfig.getParameters()); new TokenFilter(currentTokens.get()).filterValues(filteredConfig.getParameters());
GuacamoleSocket socket; GuacamoleSocket socket;
@@ -146,6 +244,41 @@ public class SimpleConnection extends AbstractConnection {
} }
/**
* {@inheritDoc}
*
* <p>This implementation will connect using the GuacamoleConfiguration
* returned by {@link #getFullConfiguration()}, honoring the
* "guacd-hostname", "guacd-port", and "guacd-ssl" properties set within
* guacamole.properties. Parameter tokens will be taken into account if
* the SimpleConnection was explicitly requested to do so when created.
*
* <p>Implementations requiring more complex behavior should consider using
* the {@link AbstractConnection} base class or implementing
* {@link org.apache.guacamole.net.auth.Connection} directly.
*/
@Override
public GuacamoleTunnel connect(GuacamoleClientInformation info,
Map<String, String> tokens) throws GuacamoleException {
// Make received tokens available within the legacy connect() strictly
// in context of the current connect() call
try {
// Automatically filter configurations only if explicitly
// configured to do so
if (interpretTokens)
currentTokens.set(tokens);
return connect(info);
}
finally {
currentTokens.remove();
}
}
@Override @Override
public Date getLastActive() { public Date getLastActive() {
return null; return null;

View File

@@ -109,9 +109,16 @@ public class SimpleConnectionGroup extends AbstractConnectionGroup {
} }
@Override @Override
public GuacamoleTunnel connect(GuacamoleClientInformation info, @Deprecated
Map<String, String> tokens) throws GuacamoleException { public GuacamoleTunnel connect(GuacamoleClientInformation info)
throws GuacamoleException {
throw new GuacamoleSecurityException("Permission denied."); throw new GuacamoleSecurityException("Permission denied.");
} }
@Override
public GuacamoleTunnel connect(GuacamoleClientInformation info,
Map<String, String> tokens) throws GuacamoleException {
return connect(info);
}
} }

View File

@@ -59,7 +59,8 @@ public class SimpleUserContext extends AbstractUserContext {
* Creates a new SimpleUserContext which provides access to only those * Creates a new SimpleUserContext which provides access to only those
* configurations within the given Map. The username is set to the * configurations within the given Map. The username is set to the
* ANONYMOUS_IDENTIFIER defined by AuthenticatedUser, effectively declaring * ANONYMOUS_IDENTIFIER defined by AuthenticatedUser, effectively declaring
* the current user as anonymous. * the current user as anonymous. Parameter tokens within the given
* GuacamoleConfigurations will not be interpreted.
* *
* @param authProvider * @param authProvider
* The AuthenticationProvider creating this UserContext. * The AuthenticationProvider creating this UserContext.
@@ -76,6 +77,8 @@ public class SimpleUserContext extends AbstractUserContext {
/** /**
* Creates a new SimpleUserContext for the user with the given username * Creates a new SimpleUserContext for the user with the given username
* which provides access to only those configurations within the given Map. * which provides access to only those configurations within the given Map.
* Parameter tokens within the given GuacamoleConfigurations will not be
* interpreted.
* *
* @param authProvider * @param authProvider
* The AuthenticationProvider creating this UserContext. * The AuthenticationProvider creating this UserContext.
@@ -89,6 +92,33 @@ public class SimpleUserContext extends AbstractUserContext {
*/ */
public SimpleUserContext(AuthenticationProvider authProvider, public SimpleUserContext(AuthenticationProvider authProvider,
String username, Map<String, GuacamoleConfiguration> configs) { String username, Map<String, GuacamoleConfiguration> configs) {
this(authProvider, username, configs, false);
}
/**
* Creates a new SimpleUserContext for the user with the given username
* which provides access to only those configurations within the given Map.
* Parameter tokens within the given GuacamoleConfigurations will be
* interpreted if explicitly requested.
*
* @param authProvider
* The AuthenticationProvider creating this UserContext.
*
* @param username
* The username of the user associated with this UserContext.
*
* @param configs
* A Map of all configurations for which the user associated with
* this UserContext has read access.
*
* @param interpretTokens
* Whether parameter tokens in the underlying GuacamoleConfigurations
* should be automatically applied upon connecting. If false, parameter
* tokens will not be interpreted at all.
*/
public SimpleUserContext(AuthenticationProvider authProvider,
String username, Map<String, GuacamoleConfiguration> configs,
boolean interpretTokens) {
// Produce map of connections from given configs // Produce map of connections from given configs
Map<String, Connection> connections = new ConcurrentHashMap<String, Connection>(configs.size()); Map<String, Connection> connections = new ConcurrentHashMap<String, Connection>(configs.size());
@@ -99,7 +129,7 @@ public class SimpleUserContext extends AbstractUserContext {
GuacamoleConfiguration config = configEntry.getValue(); GuacamoleConfiguration config = configEntry.getValue();
// Add as simple connection // Add as simple connection
Connection connection = new SimpleConnection(identifier, identifier, config); Connection connection = new SimpleConnection(identifier, identifier, config, interpretTokens);
connection.setParentIdentifier(DEFAULT_ROOT_CONNECTION_GROUP); connection.setParentIdentifier(DEFAULT_ROOT_CONNECTION_GROUP);
connections.put(identifier, connection); connections.put(identifier, connection);

View File

@@ -0,0 +1,109 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.net.auth;
import java.util.Collections;
import java.util.Map;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.GuacamoleTunnel;
import org.apache.guacamole.protocol.GuacamoleClientInformation;
/**
* Internal, ABI-compatible version of the Connectable interface from
* guacamole-ext which defines fallback defaults for older versions of the API.
* As this interface will take precedence in the servlet container's
* classloader over the definition from guacamole-ext, this allows backwards
* compatibility with the 1.0.0 API while keeping the actual API definition
* within guacamole-ext strict.
*
* <p>For this to work, this interface definition <strong>MUST</strong> be 100%
* ABI-compatible with the Connectable interface defined by guacamole-ext in
* 1.0.0 and onward.
*/
public interface Connectable {
/**
* Establishes a connection to guacd using the information associated with
* this object. The connection will be provided the given client
* information.
*
* <p>This definition is the legacy connect() definition from 1.0.0 and
* older. It is redefined here for the sake of ABI compatibility with
* 1.0.0 but is deprecated within guacamole-ext.
*
* @deprecated
* This definition exists solely for binary compatibility. It should
* never be used by new code. New implementations should instead use
* the current version of connect() as defined by guacamole-ext.
*
* @param info
* Information associated with the connecting client.
*
* @return
* A fully-established GuacamoleTunnel.
*
* @throws GuacamoleException
* If an error occurs while connecting to guacd, or if permission to
* connect is denied.
*/
@Deprecated
default GuacamoleTunnel connect(GuacamoleClientInformation info)
throws GuacamoleException {
// Pass through usages of the old API to the new API
return this.connect(info, Collections.emptyMap());
}
/**
* {@inheritDoc}
*
* <p>This definition is the current version of connect() as defined by
* guacamole-ext.
*
* <p>A default implementation which invokes the old, deprecated
* {@link #connect(org.apache.guacamole.protocol.GuacamoleClientInformation)}
* is provided solely for compatibility with extensions which implement only
* the old version of this function. This default implementation is useful
* only for extensions relying on the older API and will be removed when
* support for that version of the API is removed.
*
* @see
* The definition of getActiveConnections() in the current version of
* the Connectable interface, as defined by guacamole-ext.
*/
default GuacamoleTunnel connect(GuacamoleClientInformation info,
Map<String, String> tokens) throws GuacamoleException {
// Allow old implementations of Connectable to continue to work
return this.connect(info);
}
/**
* {@inheritDoc}
*
* @see
* The definition of getActiveConnections() in the current version of
* the Connectable interface, as defined by guacamole-ext.
*/
int getActiveConnections();
}