Skip to content

Commit

Permalink
GUACAMOLE-577: Add support for Proxy Configuration to Connections sto…
Browse files Browse the repository at this point in the history
…red in LDAP.
  • Loading branch information
necouchman committed Aug 30, 2024
1 parent 2799df6 commit 6fab0f5
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 20 deletions.
27 changes: 21 additions & 6 deletions extensions/guacamole-auth-ldap/schema/guacConfigGroup.ldif
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,24 @@
dn: cn=guacConfigGroup,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: guacConfigGroup
olcAttributeTypes: {0}( 1.3.6.1.4.1.38971.1.1.1 NAME 'guacConfigProtocol' SYNTAX 1.3.6.1.4.1.1466
.115.121.1.15 )
olcAttributeTypes: {1}( 1.3.6.1.4.1.38971.1.1.2 NAME 'guacConfigParameter' SYNTAX 1.3.6.1.4.1.146
6.115.121.1.15 )
olcObjectClasses: {0}( 1.3.6.1.4.1.38971.1.2.1 NAME 'guacConfigGroup' DESC 'Guacamole config
uration group' SUP groupOfNames MUST guacConfigProtocol MAY guacConfigParameter )

olcAttributeTypes: ( 1.3.6.1.4.1.38971.1.1.1 NAME 'guacConfigProtocol'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcAttributeTypes: ( 1.3.6.1.4.1.38971.1.1.2 NAME 'guacConfigParameter'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcAttributeTypes: ( 1.3.6.1.4.1.38971.1.1.3 NAME 'guacConfigProxyHostname'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcAttributeTypes: ( 1.3.6.1.4.1.38971.1.1.4 NAME 'guacConfigProxyPort'
SINGLE-VALUE
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
olcAttributeTypes: ( 1.3.6.1.4.1.38971.1.1.5 NAME 'guacConfigProxyEncryption'
SINGLE-VALUE
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcObjectClasses: ( 1.3.6.1.4.1.38971.1.2.1 NAME 'guacConfigGroup'
DESC 'Guacamole configuration group'
SUP groupOfNames
MUST guacConfigProtocol
MAY ( guacConfigParameter $
guacConfigProxyHostname $
guacConfigProxyPort $
guacConfigProxyEncryption ) )
20 changes: 17 additions & 3 deletions extensions/guacamole-auth-ldap/schema/guacConfigGroup.schema
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,28 @@
#

attributetype ( 1.3.6.1.4.1.38971.1.1.1 NAME 'guacConfigProtocol'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

attributetype ( 1.3.6.1.4.1.38971.1.1.2 NAME 'guacConfigParameter'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

attributetype ( 1.3.6.1.4.1.38971.1.1.3 NAME 'guacConfigProxyHostname'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

attributetype ( 1.3.6.1.4.1.38971.1.1.4 NAME 'guacConfigProxyPort'
SINGLE-VALUE
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )

attributetype ( 1.3.6.1.4.1.38971.1.1.5 NAME 'guacConfigProxyEncryption'
SINGLE-VALUE
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )

objectClass ( 1.3.6.1.4.1.38971.1.2.1 NAME 'guacConfigGroup'
DESC 'Guacamole configuration group'
SUP groupOfNames
MUST guacConfigProtocol
MAY guacConfigParameter )
MAY ( guacConfigParameter $
guacConfigProxyHostname $
guacConfigProxyPort $
guacConfigProxyEncryption ) )

Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@
import org.apache.guacamole.auth.ldap.ObjectQueryService;
import org.apache.guacamole.auth.ldap.group.UserGroupService;
import org.apache.guacamole.auth.ldap.user.LDAPAuthenticatedUser;
import org.apache.guacamole.environment.LocalEnvironment;
import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration;
import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration.EncryptionMethod;
import org.apache.guacamole.net.auth.TokenInjectingConnection;
import org.apache.guacamole.net.auth.simple.SimpleConnection;
import org.apache.guacamole.protocol.GuacamoleConfiguration;
Expand All @@ -59,6 +63,33 @@ public class ConnectionService {
* Logger for this class.
*/
private static final Logger logger = LoggerFactory.getLogger(ConnectionService.class);

/**
* The name of the LDAP attribute that stores connection configuration
* parameters for Guacamole.
*/
public static final String LDAP_ATTRIBUTE_PARAMETER = "guacConfigParameter";

/**
* The name of the LDAP attribute that stores the protocol for a Guacamole
* connection.
*/
public static final String LDAP_ATTRIBUTE_PROTOCOL = "guacConfigProtocol";

/**
* The name of the LDAP attribute that stores guacd proxy hostname.
*/
public static final String LDAP_ATTRIBUTE_PROXY_HOSTNAME = "guacConfigProxyHostname";

/**
* The name of the LDAP attribute that stores guacd proxy port.
*/
public static final String LDAP_ATTRIBUTE_PROXY_PORT = "guacConfigProxyPort";

/**
* The name of the LDAP attribute that stores guacd proxy hostname.
*/
public static final String LDAP_ATTRIBUTE_PROXY_ENCRYPTION = "guacConfigProxyEncryption";

/**
* Service for executing LDAP queries.
Expand Down Expand Up @@ -192,11 +223,21 @@ public Map<String, Connection> getConnections(LDAPAuthenticatedUser user)
config.setProtocol(protocol.getString());
}
catch (LdapInvalidAttributeValueException e) {
logger.error("Invalid value of the protocol entry: {}",
e.getMessage());
logger.error("Invalid value of the protocol entry: {}", e.getMessage());
logger.debug("LDAP exception when getting protocol value.", e);
return null;
}

// Get proxy configuration, if any
GuacamoleProxyConfiguration proxyConfig;
try {
proxyConfig = getProxyConfiguration(entry);
}
catch (GuacamoleException e) {
logger.error("Failed to retrieve proxy configuration.", e.getMessage());
logger.debug("Guacamole Exception when retrieving proxy configuration.", e);
return null;
}

// Get parameters, if any
Attribute parameterAttribute = entry.get(LDAP_ATTRIBUTE_NAME_PARAMETER);
Expand All @@ -209,10 +250,8 @@ public Map<String, Connection> getConnections(LDAPAuthenticatedUser user)
parameter = parameterAttribute.getString();
}
catch (LdapInvalidAttributeValueException e) {
logger.warn("Parameter value not valid for {}: {}",
cnName, e.getMessage());
logger.debug("LDAP exception when getting parameter value.",
e);
logger.warn("Parameter value not valid for {}: {}", cnName, e.getMessage());
logger.debug("LDAP exception when getting parameter value.", e);
return null;
}
parameterAttribute.remove(parameter);
Expand All @@ -234,7 +273,7 @@ public Map<String, Connection> getConnections(LDAPAuthenticatedUser user)
}

// Store connection using cn for both identifier and name
Connection connection = new SimpleConnection(cnName, cnName, config, true);
Connection connection = new SimpleConnection(cnName, cnName, proxyConfig, config, true);
connection.setParentIdentifier(LDAPAuthenticationProvider.ROOT_CONNECTION_GROUP);

// Inject LDAP-specific tokens only if LDAP handled user
Expand Down Expand Up @@ -301,5 +340,64 @@ private ExprNode getConnectionSearchFilter(LDAPAuthenticatedUser user)

return searchFilter;
}

/**
* Given an LDAP entry that stores a GuacamoleConfiguration, generate a
* GuacamoleProxyConfiguration that tells the client how to connect to guacd.
* If the proxy configuration values are not found in the LDAP entry the
* defaults from the environment are used. If errors occur while trying to
* ready or parse values from the LDAP entry a GuacamoleException is thrown.
*
* @param connectionEntry
* The LDAP entry that should be checked for proxy configuration values.
*
* @return
* The GuacamoleProxyConfiguration that contains information on how
* to contact guacd for the given Guacamole connection configuration.
*
* @throws GuacamoleException
* If errors occur trying to parse LDAP values from the entry.
*/
private GuacamoleProxyConfiguration getProxyConfiguration(Entry connectionEntry)
throws GuacamoleException {

try {

// Get default proxy configuration values
GuacamoleProxyConfiguration proxyConfig = LocalEnvironment.getInstance().getDefaultGuacamoleProxyConfiguration();
String proxyHostname = proxyConfig.getHostname();
int proxyPort = proxyConfig.getPort();
EncryptionMethod proxyEncryption = proxyConfig.getEncryptionMethod();

// Get the proxy hostname
Attribute proxyHostAttr = connectionEntry.get(LDAP_ATTRIBUTE_PROXY_HOSTNAME);
if (proxyHostAttr != null && proxyHostAttr.size() > 0)
proxyHostname = proxyHostAttr.getString();

// Get the proxy port
Attribute proxyPortAttr = connectionEntry.get(LDAP_ATTRIBUTE_PROXY_PORT);
if (proxyPortAttr != null && proxyPortAttr.size() > 0)
proxyPort = Integer.parseInt(proxyPortAttr.getString());

// Get the proxy encryption method
Attribute proxyEncryptionAttr = connectionEntry.get(LDAP_ATTRIBUTE_PROXY_ENCRYPTION);
if (proxyEncryptionAttr != null && proxyEncryptionAttr.size() > 0) {
try {
proxyEncryption = EncryptionMethod.valueOf(proxyEncryptionAttr.getString());
}
catch (IllegalArgumentException e) {
throw new GuacamoleServerException("Unknown encryption method specified, value must be either \"NONE\" or \"SSL\".", e);
}
}

// Return a new proxy configuration
return new GuacamoleProxyConfiguration(proxyHostname, proxyPort, proxyEncryption);
}
catch (LdapInvalidAttributeValueException e) {
logger.error("Invalid value in proxy configuration: {}", e.getMessage());
logger.debug("LDAP exception fetching proxy attribute value.", e);
throw new GuacamoleServerException("Invalid LDAP value in proxy configuration.", e);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import java.util.Map;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.environment.LocalEnvironment;
import org.apache.guacamole.net.GuacamoleSocket;
import org.apache.guacamole.net.GuacamoleTunnel;
Expand Down Expand Up @@ -53,6 +52,11 @@ public class SimpleConnection extends AbstractConnection {
* Backing configuration, containing all sensitive information.
*/
private GuacamoleConfiguration fullConfig;

/**
* The proxy configuration describing how to connect to guacd.
*/
private GuacamoleProxyConfiguration proxyConfig;

/**
* Whether parameter tokens in the underlying GuacamoleConfiguration should
Expand Down Expand Up @@ -158,6 +162,39 @@ public SimpleConnection(String name, String identifier,
this.interpretTokens = interpretTokens;

}

/**
* Creates a new SimpleConnection having the given identifier,
* GuacamoleConfiguration, and GuacamoleProxyConfiguration. 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 proxyConfig
* The Guacamole proxy configuration describing how the connection to
* guacd should be established, or null if the default settings will be
* used.
*
* @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,
GuacamoleProxyConfiguration proxyConfig,
GuacamoleConfiguration config, boolean interpretTokens) {

this(name, identifier, config, interpretTokens);
this.proxyConfig = proxyConfig;

}

/**
* Returns the GuacamoleConfiguration describing how to connect to this
Expand Down Expand Up @@ -201,9 +238,9 @@ public void setAttributes(Map<String, String> attributes) {
public GuacamoleTunnel connect(GuacamoleClientInformation info)
throws GuacamoleException {

// Retrieve proxy configuration from environment
Environment environment = LocalEnvironment.getInstance();
GuacamoleProxyConfiguration proxyConfig = environment.getDefaultGuacamoleProxyConfiguration();
// Retrieve proxy configuration from environment if we don't have one
if (proxyConfig == null)
proxyConfig = LocalEnvironment.getInstance().getDefaultGuacamoleProxyConfiguration();

// Get guacd connection parameters
String hostname = proxyConfig.getHostname();
Expand Down

0 comments on commit 6fab0f5

Please sign in to comment.