diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/AuthenticationProviderService.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/AuthenticationProviderService.java index f56f9e592..486c524bd 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/AuthenticationProviderService.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/AuthenticationProviderService.java @@ -195,10 +195,10 @@ public class AuthenticationProviderService { private ConnectedLDAPConfiguration getLDAPConfiguration(String username, String password) throws GuacamoleException { - // Get relevant LDAP configurations for user - Collection configs = confService.getLDAPConfigurations(username); + // Get all LDAP server configurations + Collection configs = confService.getLDAPConfigurations(); if (configs.isEmpty()) { - logger.info("User \"{}\" does not map to any defined LDAP configurations.", username); + logger.info("Skipping LDAP authentication as no LDAP servers are configured."); return null; } @@ -206,8 +206,18 @@ public class AuthenticationProviderService { // authentication are successful for (LDAPConfiguration config : configs) { + // Attempt connection only if username matches + String translatedUsername = config.appliesTo(username); + if (translatedUsername == null) { + logger.debug("LDAP server \"{}\" does not match username \"{}\".", config.getServerHostname(), username); + continue; + } + + logger.debug("LDAP server \"{}\" matched username \"{}\" as \"{}\".", + config.getServerHostname(), username, translatedUsername); + // Derive DN of user within this LDAP server - Dn bindDn = getUserBindDN(config, username); + Dn bindDn = getUserBindDN(config, translatedUsername); if (bindDn == null || bindDn.isEmpty()) { logger.info("Unable to determine DN of user \"{}\" using LDAP " + "server \"{}\". Proceeding with next server...", diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/ConnectedLDAPConfiguration.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/ConnectedLDAPConfiguration.java index f4a875e6e..997e02376 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/ConnectedLDAPConfiguration.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/ConnectedLDAPConfiguration.java @@ -107,6 +107,11 @@ public class ConnectedLDAPConfiguration implements LDAPConfiguration, AutoClosea connection.close(); } + @Override + public String appliesTo(String username) throws GuacamoleException { + return config.appliesTo(username); + } + @Override public String getServerHostname() throws GuacamoleException { return config.getServerHostname(); diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/ConfigurationService.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/ConfigurationService.java index e8bafcaa6..3ae11c6d2 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/ConfigurationService.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/ConfigurationService.java @@ -61,24 +61,18 @@ public class ConfigurationService { private Environment environment; /** - * Returns the configuration information for the LDAP servers related to - * the user having the given username, if any. If multiple servers are - * returned, each should be tried in order until a successful LDAP - * connection is established. - * - * @param username - * The username of the user whose corresponding LDAP server - * configuration should be retrieved. + * Returns the configuration information for all configured LDAP servers. + * If multiple servers are returned, each should be tried in order until a + * successful LDAP connection is established. * * @return - * The configurations of the LDAP servers related to the user having - * the given username. + * The configurations of all LDAP servers. * * @throws GuacamoleException - * If the configuration information of the LDAP servers related to the - * user having the given username cannot be retrieved due to an error. + * If the configuration information of the LDAP servers cannot be + * retrieved due to an error. */ - public Collection getLDAPConfigurations(String username) throws GuacamoleException { + public Collection getLDAPConfigurations() throws GuacamoleException { // Read configuration from YAML, if available File ldapServers = new File(environment.getGuacamoleHome(), LDAP_SERVERS_YML); diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/EnvironmentLDAPConfiguration.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/EnvironmentLDAPConfiguration.java index 4dca7cde2..37c20c4d1 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/EnvironmentLDAPConfiguration.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/EnvironmentLDAPConfiguration.java @@ -50,6 +50,11 @@ public class EnvironmentLDAPConfiguration implements LDAPConfiguration { this.environment = environment; } + @Override + public String appliesTo(String username) throws GuacamoleException { + return username; + } + @Override public String getServerHostname() throws GuacamoleException { return environment.getProperty( diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/JacksonLDAPConfiguration.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/JacksonLDAPConfiguration.java index 1676d8ac3..467ce6987 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/JacksonLDAPConfiguration.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/JacksonLDAPConfiguration.java @@ -22,6 +22,8 @@ package org.apache.guacamole.auth.ldap.conf; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.Collections; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.directory.api.ldap.model.filter.ExprNode; import org.apache.directory.api.ldap.model.filter.PresenceNode; import org.apache.directory.api.ldap.model.message.AliasDerefMode; @@ -35,6 +37,13 @@ import org.apache.guacamole.GuacamoleServerException; */ public class JacksonLDAPConfiguration implements LDAPConfiguration { + /** + * The regular expressions that match all users that should be routed to + * the LDAP server represented by this configuration. + */ + @JsonProperty("match-usernames") + private List matchUsernames; + /** * The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_HOSTNAME}. If * not set within the YAML, this will be null. @@ -174,7 +183,20 @@ public class JacksonLDAPConfiguration implements LDAPConfiguration { */ @JsonProperty("member-attribute-type") private String memberAttributeType; - + + @Override + public String appliesTo(String username) throws GuacamoleException { + + for (Pattern pattern : matchUsernames) { + Matcher matcher = pattern.matcher(username); + if (matcher.matches()) + return matcher.groupCount() >= 1 ? matcher.group(1) : username; + } + + return null; + + } + @Override public String getServerHostname() { return hostname != null ? hostname : "localhost"; diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPConfiguration.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPConfiguration.java index 5c3315741..ad008380c 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPConfiguration.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPConfiguration.java @@ -31,6 +31,23 @@ import org.apache.guacamole.GuacamoleException; */ public interface LDAPConfiguration { + /** + * Tests whether this LDAPConfiguration applies to the user having the + * given username. If the configuration applies, the username that should + * be used to derive the user's DN is returned. + * + * @param username + * The username to test. + * + * @return + * The username that should be used to derive this user's DN, or null + * if the configuration does not apply. + * + * @throws GuacamoleException + * If an error prevents testing against this configuration. + */ + String appliesTo(String username) throws GuacamoleException; + /** * Returns the hostname or IP address of the LDAP server. By default, this * will be "localhost".