GUACAMOLE-957: Choose LDAP configurations based on usernames.

This commit is contained in:
Michael Jumper
2021-10-21 00:30:47 -07:00
parent 49a4a6c7a0
commit 91a057cad9
6 changed files with 71 additions and 18 deletions

View File

@@ -195,10 +195,10 @@ public class AuthenticationProviderService {
private ConnectedLDAPConfiguration getLDAPConfiguration(String username,
String password) throws GuacamoleException {
// Get relevant LDAP configurations for user
Collection<? extends LDAPConfiguration> configs = confService.getLDAPConfigurations(username);
// Get all LDAP server configurations
Collection<? extends LDAPConfiguration> 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...",

View File

@@ -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();

View File

@@ -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<? extends LDAPConfiguration> getLDAPConfigurations(String username) throws GuacamoleException {
public Collection<? extends LDAPConfiguration> getLDAPConfigurations() throws GuacamoleException {
// Read configuration from YAML, if available
File ldapServers = new File(environment.getGuacamoleHome(), LDAP_SERVERS_YML);

View File

@@ -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(

View File

@@ -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<Pattern> matchUsernames;
/**
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_HOSTNAME}. If
* not set within the YAML, this will be null.
@@ -175,6 +184,19 @@ 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";

View File

@@ -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".