diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java index 8dcf6f59a..e2f3c1523 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java @@ -499,6 +499,10 @@ public class ConnectionService extends ModeledChildDirectoryObjectService tokens) throws GuacamoleException { // Connect only if READ permission is granted if (hasObjectPermission(user, connection.getIdentifier(), ObjectPermission.Type.READ)) - return tunnelService.getGuacamoleTunnel(user, connection, info); + return tunnelService.getGuacamoleTunnel(user, connection, info, tokens); // The user does not have permission to connect throw new GuacamoleSecurityException("Permission denied."); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnection.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnection.java index 660212cdc..b49262668 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnection.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnection.java @@ -259,8 +259,9 @@ public class ModeledConnection extends ModeledChildDirectoryObject tokens) throws GuacamoleException { + return connectionService.connect(getCurrentUser(), this, info, tokens); } @Override diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java index 01119b92e..3e9ec72a8 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java @@ -21,6 +21,7 @@ package org.apache.guacamole.auth.jdbc.connectiongroup; import com.google.inject.Inject; import com.google.inject.Provider; +import java.util.Map; import java.util.Set; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper; @@ -243,6 +244,10 @@ public class ConnectionGroupService extends ModeledChildDirectoryObjectService tokens) throws GuacamoleException { // Connect only if READ permission is granted if (hasObjectPermission(user, connectionGroup.getIdentifier(), ObjectPermission.Type.READ)) - return tunnelService.getGuacamoleTunnel(user, connectionGroup, info); + return tunnelService.getGuacamoleTunnel(user, connectionGroup, info, tokens); // The user does not have permission to connect throw new GuacamoleSecurityException("Permission denied."); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ModeledConnectionGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ModeledConnectionGroup.java index 3aac52d59..bcf457af0 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ModeledConnectionGroup.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ModeledConnectionGroup.java @@ -135,9 +135,9 @@ public class ModeledConnectionGroup extends ModeledChildDirectoryObject tokens) throws GuacamoleException { + return connectionGroupService.connect(getCurrentUser(), this, info, tokens); } @Override diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/RootConnectionGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/RootConnectionGroup.java index d2e555132..08b32fd8f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/RootConnectionGroup.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/RootConnectionGroup.java @@ -122,8 +122,8 @@ public class RootConnectionGroup extends RestrictedObject } @Override - public GuacamoleTunnel connect(GuacamoleClientInformation info) - throws GuacamoleException { + public GuacamoleTunnel connect(GuacamoleClientInformation info, + Map tokens) throws GuacamoleException { throw new GuacamoleSecurityException("Permission denied."); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnection.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnection.java index 5483d0267..cf0083167 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnection.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnection.java @@ -131,9 +131,9 @@ public class SharedConnection implements Connection { } @Override - public GuacamoleTunnel connect(GuacamoleClientInformation info) - throws GuacamoleException { - return tunnelService.getGuacamoleTunnel(user, definition, info); + public GuacamoleTunnel connect(GuacamoleClientInformation info, + Map tokens) throws GuacamoleException { + return tunnelService.getGuacamoleTunnel(user, definition, info, tokens); } @Override diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connectiongroup/SharedRootConnectionGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connectiongroup/SharedRootConnectionGroup.java index 71b997c25..33d9ca7e3 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connectiongroup/SharedRootConnectionGroup.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connectiongroup/SharedRootConnectionGroup.java @@ -98,8 +98,8 @@ public class SharedRootConnectionGroup implements ConnectionGroup { } @Override - public GuacamoleTunnel connect(GuacamoleClientInformation info) - throws GuacamoleException { + public GuacamoleTunnel connect(GuacamoleClientInformation info, + Map tokens) throws GuacamoleException { throw new GuacamoleSecurityException("Permission denied."); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java index 5f7fc1ba3..20ac29995 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java @@ -52,7 +52,6 @@ import org.apache.guacamole.net.auth.ConnectionGroup; import org.apache.guacamole.protocol.ConfiguredGuacamoleSocket; import org.apache.guacamole.protocol.GuacamoleClientInformation; import org.apache.guacamole.protocol.GuacamoleConfiguration; -import org.apache.guacamole.token.StandardTokens; import org.apache.guacamole.token.TokenFilter; import org.mybatis.guice.transactional.Transactional; import org.apache.guacamole.auth.jdbc.connection.ConnectionParameterMapper; @@ -233,13 +232,6 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS for (ConnectionParameterModel parameter : parameters) config.setParameter(parameter.getName(), parameter.getValue()); - // Build token filter containing credential tokens - TokenFilter tokenFilter = new TokenFilter(); - StandardTokens.addStandardTokens(tokenFilter, user); - - // Filter the configuration - tokenFilter.filterValues(config.getParameters()); - return config; } @@ -279,13 +271,6 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS for (SharingProfileParameterModel parameter : parameters) config.setParameter(parameter.getName(), parameter.getValue()); - // Build token filter containing credential tokens - TokenFilter tokenFilter = new TokenFilter(); - StandardTokens.addStandardTokens(tokenFilter, user); - - // Filter the configuration - tokenFilter.filterValues(config.getParameters()); - return config; } @@ -454,6 +439,10 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS * Information describing the Guacamole client connecting to the given * connection. * + * @param tokens + * A Map containing the token names and corresponding values to be + * applied as parameter tokens when establishing the connection. + * * @param interceptErrors * Whether errors from the upstream remote desktop should be * intercepted and rethrown as GuacamoleUpstreamExceptions. @@ -467,7 +456,8 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS * while connection configuration information is being retrieved. */ private GuacamoleTunnel assignGuacamoleTunnel(ActiveConnectionRecord activeConnection, - GuacamoleClientInformation info, boolean interceptErrors) throws GuacamoleException { + GuacamoleClientInformation info, Map tokens, + boolean interceptErrors) throws GuacamoleException { // Record new active connection Runnable cleanupTask = new ConnectionCleanupTask(activeConnection); @@ -504,6 +494,13 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS } + // Build token filter containing credential tokens + TokenFilter tokenFilter = new TokenFilter(); + tokenFilter.setTokens(tokens); + + // Filter the configuration + tokenFilter.filterValues(config.getParameters()); + // Obtain socket which will automatically run the cleanup task ConfiguredGuacamoleSocket socket = new ConfiguredGuacamoleSocket( getUnconfiguredGuacamoleSocket(connection.getGuacamoleProxyConfiguration(), @@ -651,8 +648,8 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS @Override @Transactional public GuacamoleTunnel getGuacamoleTunnel(final ModeledAuthenticatedUser user, - final ModeledConnection connection, GuacamoleClientInformation info) - throws GuacamoleException { + final ModeledConnection connection, GuacamoleClientInformation info, + Map tokens) throws GuacamoleException { // Acquire access to single connection, ignoring the failover-only flag acquire(user, Collections.singletonList(connection), true); @@ -660,7 +657,7 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS // Connect only if the connection was successfully acquired ActiveConnectionRecord connectionRecord = activeConnectionRecordProvider.get(); connectionRecord.init(user, connection); - return assignGuacamoleTunnel(connectionRecord, info, false); + return assignGuacamoleTunnel(connectionRecord, info, tokens, false); } @@ -673,7 +670,8 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS @Transactional public GuacamoleTunnel getGuacamoleTunnel(ModeledAuthenticatedUser user, ModeledConnectionGroup connectionGroup, - GuacamoleClientInformation info) throws GuacamoleException { + GuacamoleClientInformation info, Map tokens) + throws GuacamoleException { // Track failures in upstream (remote desktop) connections boolean upstreamHasFailed = false; @@ -706,7 +704,8 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS // Connect to acquired child ActiveConnectionRecord connectionRecord = activeConnectionRecordProvider.get(); connectionRecord.init(user, connectionGroup, connection); - GuacamoleTunnel tunnel = assignGuacamoleTunnel(connectionRecord, info, connections.size() > 1); + GuacamoleTunnel tunnel = assignGuacamoleTunnel(connectionRecord, + info, tokens, connections.size() > 1); // If session affinity is enabled, prefer this connection going forward if (connectionGroup.isSessionAffinityEnabled()) @@ -755,7 +754,7 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS @Transactional public GuacamoleTunnel getGuacamoleTunnel(RemoteAuthenticatedUser user, SharedConnectionDefinition definition, - GuacamoleClientInformation info) + GuacamoleClientInformation info, Map tokens) throws GuacamoleException { // Create a connection record which describes the shared connection @@ -764,7 +763,7 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS definition.getSharingProfile()); // Connect to shared connection described by the created record - GuacamoleTunnel tunnel = assignGuacamoleTunnel(connectionRecord, info, false); + GuacamoleTunnel tunnel = assignGuacamoleTunnel(connectionRecord, info, tokens, false); // Register tunnel, such that it is closed when the // SharedConnectionDefinition is invalidated diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/GuacamoleTunnelService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/GuacamoleTunnelService.java index 34d929340..bad521951 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/GuacamoleTunnelService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/GuacamoleTunnelService.java @@ -20,6 +20,7 @@ package org.apache.guacamole.auth.jdbc.tunnel; import java.util.Collection; +import java.util.Map; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.connection.ModeledConnection; import org.apache.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; @@ -73,6 +74,10 @@ public interface GuacamoleTunnelService { * Information describing the Guacamole client connecting to the given * connection. * + * @param tokens + * A Map containing the token names and corresponding values to be + * applied as parameter tokens when establishing the connection. + * * @return * A new GuacamoleTunnel which is configured and connected to the given * connection. @@ -82,8 +87,8 @@ public interface GuacamoleTunnelService { * rules. */ GuacamoleTunnel getGuacamoleTunnel(ModeledAuthenticatedUser user, - ModeledConnection connection, GuacamoleClientInformation info) - throws GuacamoleException; + ModeledConnection connection, GuacamoleClientInformation info, + Map tokens) throws GuacamoleException; /** * Returns a collection containing connection records representing all @@ -117,6 +122,10 @@ public interface GuacamoleTunnelService { * Information describing the Guacamole client connecting to the given * connection group. * + * @param tokens + * A Map containing the token names and corresponding values to be + * applied as parameter tokens when establishing the connection. + * * @return * A new GuacamoleTunnel which is configured and connected to the given * connection group. @@ -127,7 +136,7 @@ public interface GuacamoleTunnelService { */ GuacamoleTunnel getGuacamoleTunnel(ModeledAuthenticatedUser user, ModeledConnectionGroup connectionGroup, - GuacamoleClientInformation info) + GuacamoleClientInformation info, Map tokens) throws GuacamoleException; /** @@ -163,6 +172,10 @@ public interface GuacamoleTunnelService { * Information describing the Guacamole client connecting to the given * connection. * + * @param tokens + * A Map containing the token names and corresponding values to be + * applied as parameter tokens when establishing the connection. + * * @return * A new GuacamoleTunnel which is configured and connected to the given * active connection. @@ -173,7 +186,7 @@ public interface GuacamoleTunnelService { */ GuacamoleTunnel getGuacamoleTunnel(RemoteAuthenticatedUser user, SharedConnectionDefinition definition, - GuacamoleClientInformation info) + GuacamoleClientInformation info, Map tokens) throws GuacamoleException; } diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java index 984e77211..18e3b9ceb 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java @@ -39,8 +39,6 @@ import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.simple.SimpleConnection; import org.apache.guacamole.protocol.GuacamoleConfiguration; -import org.apache.guacamole.token.StandardTokens; -import org.apache.guacamole.token.TokenFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -122,10 +120,6 @@ public class ConnectionService { confService.getLDAPSearchConstraints() ); - // Build token filter containing credential tokens - TokenFilter tokenFilter = new TokenFilter(); - StandardTokens.addStandardTokens(tokenFilter, user); - // Produce connections for each readable configuration Map connections = new HashMap(); while (results.hasMore()) { @@ -180,9 +174,6 @@ public class ConnectionService { } - // Filter the configuration, substituting all defined tokens - tokenFilter.filterValues(config.getParameters()); - // Store connection using cn for both identifier and name String name = cn.getStringValue(); Connection connection = new SimpleConnection(name, name, config); diff --git a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectionGroup.java b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectionGroup.java index cbce37976..dbb693467 100644 --- a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectionGroup.java +++ b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectionGroup.java @@ -108,8 +108,8 @@ public class QuickConnectionGroup extends AbstractConnectionGroup { } @Override - public GuacamoleTunnel connect(GuacamoleClientInformation info) - throws GuacamoleException { + public GuacamoleTunnel connect(GuacamoleClientInformation info, + Map tokens) throws GuacamoleException { // This group does not support connections throw new GuacamoleSecurityException("Permission denied."); } diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Connectable.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Connectable.java index 7face9264..39b12f98f 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Connectable.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Connectable.java @@ -19,6 +19,7 @@ package org.apache.guacamole.net.auth; +import java.util.Map; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.net.GuacamoleTunnel; import org.apache.guacamole.protocol.GuacamoleClientInformation; @@ -31,11 +32,21 @@ public interface Connectable { /** * Establishes a connection to guacd using the information associated with * this object. The connection will be provided the given client - * information. + * information. Implementations which support parameter tokens should + * apply the given tokens when configuring the connection, such as with a + * {@link org.apache.guacamole.token.TokenFilter}. + * + * @see Parameter Tokens * * @param info * Information associated with the connecting client. * + * @param tokens + * A Map containing the token names and corresponding values to be + * applied as parameter tokens when establishing the connection. If the + * implementation does not support parameter tokens, this Map may be + * ignored. + * * @return * A fully-established GuacamoleTunnel. * @@ -43,8 +54,8 @@ public interface Connectable { * If an error occurs while connecting to guacd, or if permission to * connect is denied. */ - public GuacamoleTunnel connect(GuacamoleClientInformation info) - throws GuacamoleException; + public GuacamoleTunnel connect(GuacamoleClientInformation info, + Map tokens) throws GuacamoleException; /** * Returns the number of active connections associated with this object. diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/DelegatingConnection.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/DelegatingConnection.java index fa1ab7849..b80e8683a 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/DelegatingConnection.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/DelegatingConnection.java @@ -128,9 +128,9 @@ public class DelegatingConnection implements Connection { } @Override - public GuacamoleTunnel connect(GuacamoleClientInformation info) - throws GuacamoleException { - return connection.connect(info); + public GuacamoleTunnel connect(GuacamoleClientInformation info, + Map tokens) throws GuacamoleException { + return connection.connect(info, tokens); } @Override diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/DelegatingConnectionGroup.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/DelegatingConnectionGroup.java index db647d617..1d958bdb2 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/DelegatingConnectionGroup.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/DelegatingConnectionGroup.java @@ -119,8 +119,9 @@ public class DelegatingConnectionGroup implements ConnectionGroup { } @Override - public GuacamoleTunnel connect(GuacamoleClientInformation info) throws GuacamoleException { - return connectionGroup.connect(info); + public GuacamoleTunnel connect(GuacamoleClientInformation info, + Map tokens) throws GuacamoleException { + return connectionGroup.connect(info, tokens); } @Override diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleAuthenticationProvider.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleAuthenticationProvider.java index 7b1e3e7f0..6d08d99ac 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleAuthenticationProvider.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleAuthenticationProvider.java @@ -31,8 +31,6 @@ import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.Credentials; import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.protocol.GuacamoleConfiguration; -import org.apache.guacamole.token.StandardTokens; -import org.apache.guacamole.token.TokenFilter; /** * Provides means of retrieving a set of named GuacamoleConfigurations for a @@ -140,84 +138,13 @@ public abstract class SimpleAuthenticationProvider } - /** - * Given an arbitrary credentials object, returns a Map containing all - * configurations authorized by those credentials, filtering those - * configurations using a TokenFilter and the standard credential tokens - * (like ${GUAC_USERNAME} and ${GUAC_PASSWORD}). The keys of this Map - * are Strings which uniquely identify each configuration. - * - * @param credentials - * The credentials to use to retrieve authorized configurations. - * - * @return - * A Map of all configurations authorized by the given credentials, or - * null if the credentials given are not authorized. - * - * @throws GuacamoleException - * If an error occurs while retrieving configurations. - */ - private Map - getFilteredAuthorizedConfigurations(Credentials credentials) - throws GuacamoleException { - - // Get configurations - Map configs = - getAuthorizedConfigurations(credentials); - - // Return as unauthorized if not authorized to retrieve configs - if (configs == null) - return null; - - // Build credential TokenFilter - TokenFilter tokenFilter = new TokenFilter(); - StandardTokens.addStandardTokens(tokenFilter, credentials); - - // Filter each configuration - for (GuacamoleConfiguration config : configs.values()) - tokenFilter.filterValues(config.getParameters()); - - return configs; - - } - - /** - * Given a user who has already been authenticated, returns a Map - * containing all configurations for which that user is authorized, - * filtering those configurations using a TokenFilter and the standard - * credential tokens (like ${GUAC_USERNAME} and ${GUAC_PASSWORD}). The keys - * of this Map are Strings which uniquely identify each configuration. - * - * @param authenticatedUser - * The user whose authorized configurations are to be retrieved. - * - * @return - * A Map of all configurations authorized for use by the given user, or - * null if the user is not authorized to use any configurations. - * - * @throws GuacamoleException - * If an error occurs while retrieving configurations. - */ - private Map - getFilteredAuthorizedConfigurations(AuthenticatedUser authenticatedUser) - throws GuacamoleException { - - // Pull cached configurations, if any - if (authenticatedUser instanceof SimpleAuthenticatedUser && authenticatedUser.getAuthenticationProvider() == this) - return ((SimpleAuthenticatedUser) authenticatedUser).getAuthorizedConfigurations(); - - // Otherwise, pull using credentials - return getFilteredAuthorizedConfigurations(authenticatedUser.getCredentials()); - - } - @Override public AuthenticatedUser authenticateUser(final Credentials credentials) throws GuacamoleException { // Get configurations Map configs = - getFilteredAuthorizedConfigurations(credentials); + getAuthorizedConfigurations(credentials); // Return as unauthorized if not authorized to retrieve configs if (configs == null) @@ -233,7 +160,7 @@ public abstract class SimpleAuthenticationProvider // Get configurations Map configs = - getFilteredAuthorizedConfigurations(authenticatedUser); + getAuthorizedConfigurations(authenticatedUser.getCredentials()); // Return as unauthorized if not authorized to retrieve configs if (configs == null) diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnection.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnection.java index 85783a0a4..f9da240c4 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnection.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnection.java @@ -38,9 +38,14 @@ import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration; import org.apache.guacamole.protocol.ConfiguredGuacamoleSocket; import org.apache.guacamole.protocol.GuacamoleClientInformation; import org.apache.guacamole.protocol.GuacamoleConfiguration; +import org.apache.guacamole.token.TokenFilter; /** - * An extremely basic Connection implementation. + * An extremely basic Connection implementation. The underlying connection to + * guacd is established using the configuration information provided in + * guacamole.properties. Parameter tokens provided to connect() are + * automatically applied. Tracking of active connections and connection history + * is not provided. */ public class SimpleConnection extends AbstractConnection { @@ -95,8 +100,8 @@ public class SimpleConnection extends AbstractConnection { } @Override - public GuacamoleTunnel connect(GuacamoleClientInformation info) - throws GuacamoleException { + public GuacamoleTunnel connect(GuacamoleClientInformation info, + Map tokens) throws GuacamoleException { // Retrieve proxy configuration from environment Environment environment = new LocalEnvironment(); @@ -106,6 +111,11 @@ public class SimpleConnection extends AbstractConnection { String hostname = proxyConfig.getHostname(); int port = proxyConfig.getPort(); + // Apply tokens to config parameters + GuacamoleConfiguration filteredConfig = new GuacamoleConfiguration(config); + TokenFilter tokenFilter = new TokenFilter(); + tokenFilter.filterValues(config.getParameters()); + GuacamoleSocket socket; // Determine socket type based on required encryption method @@ -115,7 +125,7 @@ public class SimpleConnection extends AbstractConnection { case SSL: socket = new ConfiguredGuacamoleSocket( new SSLGuacamoleSocket(hostname, port), - config, info + filteredConfig, info ); break; @@ -123,7 +133,7 @@ public class SimpleConnection extends AbstractConnection { case NONE: socket = new ConfiguredGuacamoleSocket( new InetGuacamoleSocket(hostname, port), - config, info + filteredConfig, info ); break; diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnectionGroup.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnectionGroup.java index 3a7df28c2..a077eb312 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnectionGroup.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnectionGroup.java @@ -109,8 +109,8 @@ public class SimpleConnectionGroup extends AbstractConnectionGroup { } @Override - public GuacamoleTunnel connect(GuacamoleClientInformation info) - throws GuacamoleException { + public GuacamoleTunnel connect(GuacamoleClientInformation info, + Map tokens) throws GuacamoleException { throw new GuacamoleSecurityException("Permission denied."); } diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/token/StandardTokens.java b/guacamole-ext/src/main/java/org/apache/guacamole/token/StandardTokens.java index 8faca158f..22a042e0c 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/token/StandardTokens.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/token/StandardTokens.java @@ -29,7 +29,12 @@ import org.apache.guacamole.net.auth.Credentials; /** * Utility class which provides access to standardized token names, as well as * facilities for generating those tokens from common objects. + * + * @deprecated Standard tokens are now supplied by default to the connect() + * functions of connections and connection groups. Manually generating the + * standard tokens is not necessary. */ +@Deprecated public class StandardTokens { /** diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connection/APIConnectionWrapper.java b/guacamole/src/main/java/org/apache/guacamole/rest/connection/APIConnectionWrapper.java index 3a987e544..704db2397 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/connection/APIConnectionWrapper.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/connection/APIConnectionWrapper.java @@ -128,7 +128,8 @@ public class APIConnectionWrapper implements Connection { } @Override - public GuacamoleTunnel connect(GuacamoleClientInformation info) throws GuacamoleException { + public GuacamoleTunnel connect(GuacamoleClientInformation info, + Map tokens) throws GuacamoleException { throw new UnsupportedOperationException("Operation not supported."); } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/APIConnectionGroupWrapper.java b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/APIConnectionGroupWrapper.java index 625b009d6..552b7871b 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/APIConnectionGroupWrapper.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/APIConnectionGroupWrapper.java @@ -112,7 +112,8 @@ public class APIConnectionGroupWrapper implements ConnectionGroup { } @Override - public GuacamoleTunnel connect(GuacamoleClientInformation info) throws GuacamoleException { + public GuacamoleTunnel connect(GuacamoleClientInformation info, + Map tokens) throws GuacamoleException { throw new UnsupportedOperationException("Operation not supported."); } diff --git a/guacamole/src/main/java/org/apache/guacamole/tunnel/StandardTokenMap.java b/guacamole/src/main/java/org/apache/guacamole/tunnel/StandardTokenMap.java new file mode 100644 index 000000000..1d357d21b --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/tunnel/StandardTokenMap.java @@ -0,0 +1,139 @@ +/* + * 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 java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import org.apache.guacamole.net.auth.AuthenticatedUser; +import org.apache.guacamole.net.auth.Credentials; + +/** + * Map which is automatically populated with the name/value pairs of all + * standardized tokens available for a particular AuthenticatedUser. + */ +public class StandardTokenMap extends HashMap { + + /** + * The name of the token containing the user's username. + */ + public static final String USERNAME_TOKEN = "GUAC_USERNAME"; + + /** + * The name of the token containing the user's password. + */ + public static final String PASSWORD_TOKEN = "GUAC_PASSWORD"; + + /** + * The name of the token containing the hostname/address of the machine the + * user authenticated from. + */ + public static final String CLIENT_HOSTNAME_TOKEN = "GUAC_CLIENT_HOSTNAME"; + + /** + * The name of the token containing the IP address of the machine the user + * authenticated from. + */ + public static final String CLIENT_ADDRESS_TOKEN = "GUAC_CLIENT_ADDRESS"; + + /** + * The name of the token containing the current date (server-local time). + */ + public static final String DATE_TOKEN = "GUAC_DATE"; + + /** + * The name of the token containing the current time (server-local time). + */ + public static final String TIME_TOKEN = "GUAC_TIME"; + + /** + * The date format that should be used for the date token. This format must + * be compatible with Java's SimpleDateFormat. + */ + private static final String DATE_FORMAT = "yyyyMMdd"; + + /** + * The date format that should be used for the time token. This format must + * be compatible with Java's SimpleDateFormat. + */ + private static final String TIME_FORMAT = "HHmmss"; + + /** + * The prefix of the arbitrary attribute tokens. + */ + public static final String ATTR_TOKEN_PREFIX = "GUAC_ATTR_"; + + /** + * Creates a new StandardTokenMap which is pre-populated with the + * name/value pairs of all standardized tokens available for the given + * AuthenticatedUser. + * + * @param authenticatedUser + * The AuthenticatedUser to generate standard tokens for. + */ + public StandardTokenMap(AuthenticatedUser authenticatedUser) { + + // Add date/time tokens (server-local time) + Date currentTime = new Date(); + put(DATE_TOKEN, new SimpleDateFormat(DATE_FORMAT).format(currentTime)); + put(TIME_TOKEN, new SimpleDateFormat(TIME_FORMAT).format(currentTime)); + + Credentials credentials = authenticatedUser.getCredentials(); + Map attributes = authenticatedUser.getAttributes(); + + // Add username token + String username = credentials.getUsername(); + if (username != null) + put(USERNAME_TOKEN, username); + + // Default to the authenticated user's username for the GUAC_USERNAME + // token + else + put(USERNAME_TOKEN, authenticatedUser.getIdentifier()); + + // Add password token + String password = credentials.getPassword(); + if (password != null) + put(PASSWORD_TOKEN, password); + + // Add client hostname token + String hostname = credentials.getRemoteHostname(); + if (hostname != null) + put(CLIENT_HOSTNAME_TOKEN, hostname); + + // Add client address token + String address = credentials.getRemoteAddress(); + if (address != null) + put(CLIENT_ADDRESS_TOKEN, address); + + // Add tokens for all attributes on the AuthenticatedUser + if (attributes != null) { + for (Map.Entry entry : attributes.entrySet()) { + String key = entry.getKey().toString(); + String tokenName = ATTR_TOKEN_PREFIX + key.toUpperCase(); + String tokenValue = entry.getValue().toString(); + put(tokenName, tokenValue); + } + } + + } + +} 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 e023a706f..1479d8243 100644 --- a/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java +++ b/guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java @@ -22,6 +22,7 @@ package org.apache.guacamole.tunnel; import com.google.inject.Inject; 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.GuacamoleSession; @@ -187,6 +188,10 @@ public class TunnelRequestService { * @param info * Information describing the connected Guacamole client. * + * @param tokens + * A Map containing the token names and corresponding values to be + * applied as parameter tokens when establishing the connection. + * * @return * A new tunnel, connected as required by the request. * @@ -195,7 +200,7 @@ public class TunnelRequestService { */ protected GuacamoleTunnel createConnectedTunnel(UserContext context, final TunnelRequest.Type type, String id, - GuacamoleClientInformation info) + GuacamoleClientInformation info, Map tokens) throws GuacamoleException { // Create connected tunnel from identifier @@ -216,7 +221,7 @@ public class TunnelRequestService { } // Connect tunnel - tunnel = connection.connect(info); + tunnel = connection.connect(info, tokens); logger.info("User \"{}\" connected to connection \"{}\".", context.self().getIdentifier(), id); break; } @@ -235,7 +240,7 @@ public class TunnelRequestService { } // Connect tunnel - tunnel = group.connect(info); + tunnel = group.connect(info, tokens); logger.info("User \"{}\" connected to group \"{}\".", context.self().getIdentifier(), id); break; } @@ -385,16 +390,17 @@ public class TunnelRequestService { GuacamoleClientInformation info = getClientInformation(request); GuacamoleSession session = authenticationService.getGuacamoleSession(authToken); + AuthenticatedUser authenticatedUser = session.getAuthenticatedUser(); UserContext userContext = session.getUserContext(authProviderIdentifier); try { // Create connected tunnel using provided connection ID and client information - GuacamoleTunnel tunnel = createConnectedTunnel(userContext, type, id, info); + GuacamoleTunnel tunnel = createConnectedTunnel(userContext, type, + id, info, new StandardTokenMap(authenticatedUser)); // Notify listeners to allow connection to be vetoed - fireTunnelConnectEvent(session.getAuthenticatedUser(), - session.getAuthenticatedUser().getCredentials(), tunnel); + fireTunnelConnectEvent(authenticatedUser, authenticatedUser.getCredentials(), tunnel); // Associate tunnel with session return createAssociatedTunnel(tunnel, authToken, session, userContext, type, id);