mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
GUACAMOLE-936: Clean up referral logic and logging. Ensure associated LDAP connections are always closed.
This commit is contained in:
@@ -40,8 +40,6 @@ import org.apache.guacamole.GuacamoleServerException;
|
||||
import org.apache.guacamole.GuacamoleUnsupportedException;
|
||||
import org.apache.guacamole.auth.ldap.conf.ConfigurationService;
|
||||
import org.apache.guacamole.auth.ldap.conf.EncryptionMethod;
|
||||
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
|
||||
import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -123,7 +121,8 @@ public class LDAPConnectionService {
|
||||
* bound.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while binding to the LDAP server.
|
||||
* If the configuration details relevant to binding to the LDAP server
|
||||
* cannot be read.
|
||||
*/
|
||||
public LdapNetworkConnection bindAs(Dn userDN, String password)
|
||||
throws GuacamoleException {
|
||||
@@ -165,46 +164,49 @@ public class LDAPConnectionService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new LdapNetworkConnection object for following a referral
|
||||
* with the given LdapUrl, and copy the username and password
|
||||
* from the original connection.
|
||||
* Establishes a new network connection to the LDAP server indicated by the
|
||||
* given LDAP referral URL. The credentials used to bind with the referred
|
||||
* LDAP server will be the same as those used to bind with the original
|
||||
* connection.
|
||||
*
|
||||
* @param referralUrl
|
||||
* The LDAP URL to follow.
|
||||
* @param ldapConnection
|
||||
* The LDAP connection that bind credentials should be copied from.
|
||||
*
|
||||
* @param ldapConfig
|
||||
* The connection configuration to use to retrieve username and
|
||||
* password.
|
||||
*
|
||||
* @param hop
|
||||
* The current hop number of this referral - once the configured
|
||||
* limit is reached, this method will throw an exception.
|
||||
* @param url
|
||||
* The URL of the referred LDAP server to which a new network
|
||||
* connection should be established.
|
||||
*
|
||||
* @return
|
||||
* A LdapNetworkConnection object that points at the location
|
||||
* specified in the referralUrl.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs parsing out the LdapUrl object or the
|
||||
* maximum number of referral hops is reached.
|
||||
* A LdapNetworkConnection representing a network connection to the
|
||||
* LDAP server specified in the URL, or null if the specified URL is
|
||||
* invalid.
|
||||
*/
|
||||
public LdapNetworkConnection getReferralConnection(LdapUrl referralUrl,
|
||||
LdapConnectionConfig ldapConfig, int hop)
|
||||
throws GuacamoleException {
|
||||
|
||||
if (hop >= confService.getMaxReferralHops())
|
||||
throw new GuacamoleServerException("Maximum number of referrals reached.");
|
||||
public LdapNetworkConnection getReferralConnection(
|
||||
LdapNetworkConnection ldapConnection, String url) {
|
||||
|
||||
LdapConnectionConfig ldapConfig = ldapConnection.getConfig();
|
||||
LdapConnectionConfig referralConfig = new LdapConnectionConfig();
|
||||
|
||||
// Copy bind name and password from original config
|
||||
referralConfig.setName(ldapConfig.getName());
|
||||
referralConfig.setCredentials(ldapConfig.getCredentials());
|
||||
|
||||
LdapUrl referralUrl;
|
||||
try {
|
||||
referralUrl = new LdapUrl(url);
|
||||
}
|
||||
catch (LdapException e) {
|
||||
logger.debug("Referral URL \"{}\" is invalid.", url, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Look for host - if not there, bail out.
|
||||
String host = referralUrl.getHost();
|
||||
if (host == null || host.isEmpty())
|
||||
throw new GuacamoleServerException("Referral URL contains no host.");
|
||||
if (host == null || host.isEmpty()) {
|
||||
logger.debug("Referral URL \"{}\" is invalid as it contains "
|
||||
+ "no hostname.", url );
|
||||
return null;
|
||||
}
|
||||
|
||||
referralConfig.setLdapHost(host);
|
||||
|
||||
|
@@ -23,6 +23,7 @@ import com.google.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -38,7 +39,6 @@ import org.apache.directory.api.ldap.model.filter.EqualityNode;
|
||||
import org.apache.directory.api.ldap.model.filter.ExprNode;
|
||||
import org.apache.directory.api.ldap.model.filter.OrNode;
|
||||
import org.apache.directory.api.ldap.model.filter.PresenceNode;
|
||||
import org.apache.directory.api.ldap.model.message.Referral;
|
||||
import org.apache.directory.api.ldap.model.message.SearchRequest;
|
||||
import org.apache.directory.api.ldap.model.name.Dn;
|
||||
import org.apache.directory.api.ldap.model.url.LdapUrl;
|
||||
@@ -46,6 +46,8 @@ import org.apache.directory.ldap.client.api.LdapConnectionConfig;
|
||||
import org.apache.directory.ldap.client.api.LdapNetworkConnection;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleServerException;
|
||||
import org.apache.guacamole.auth.ldap.conf.ConfigurationService;
|
||||
import org.apache.guacamole.auth.ldap.conf.LDAPGuacamoleProperties;
|
||||
import org.apache.guacamole.net.auth.Identifiable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -70,6 +72,12 @@ public class ObjectQueryService {
|
||||
@Inject
|
||||
private LDAPConnectionService ldapService;
|
||||
|
||||
/**
|
||||
* Service for retrieving LDAP server configuration information.
|
||||
*/
|
||||
@Inject
|
||||
private ConfigurationService confService;
|
||||
|
||||
/**
|
||||
* Returns the identifier of the object represented by the given LDAP
|
||||
* entry. Multiple attributes may be declared as containing the identifier
|
||||
@@ -204,13 +212,21 @@ public class ObjectQueryService {
|
||||
public List<Entry> search(LdapNetworkConnection ldapConnection,
|
||||
Dn baseDN, ExprNode query, int searchHop) throws GuacamoleException {
|
||||
|
||||
// Refuse to follow referrals if limit has been reached
|
||||
int maxHops = confService.getMaxReferralHops();
|
||||
if (searchHop >= maxHops) {
|
||||
logger.debug("Refusing to follow further referrals as the maximum "
|
||||
+ "number of referral hops ({}) has been reached. LDAP "
|
||||
+ "search results may be incomplete. If further referrals "
|
||||
+ "should be followed, consider setting the \"{}\" "
|
||||
+ "property to a larger value.", maxHops, LDAPGuacamoleProperties.LDAP_MAX_REFERRAL_HOPS.getName());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
logger.debug("Searching \"{}\" for objects matching \"{}\".", baseDN, query);
|
||||
|
||||
LdapConnectionConfig ldapConnectionConfig = ldapConnection.getConfig();
|
||||
|
||||
// Search within subtree of given base DN
|
||||
SearchRequest request = ldapService.getSearchRequest(baseDN,
|
||||
query);
|
||||
SearchRequest request = ldapService.getSearchRequest(baseDN, query);
|
||||
|
||||
// Produce list of all entries in the search result, automatically
|
||||
// following referrals if configured to do so
|
||||
@@ -219,22 +235,48 @@ public class ObjectQueryService {
|
||||
try (SearchCursor results = ldapConnection.search(request)) {
|
||||
while (results.next()) {
|
||||
|
||||
if (results.isEntry()) {
|
||||
// Add entry directly if no referral is involved
|
||||
if (results.isEntry())
|
||||
entries.add(results.getEntry());
|
||||
}
|
||||
else if (results.isReferral() && request.isFollowReferrals()) {
|
||||
|
||||
Referral referral = results.getReferral();
|
||||
for (String url : referral.getLdapUrls()) {
|
||||
LdapNetworkConnection referralConnection =
|
||||
ldapService.getReferralConnection(
|
||||
new LdapUrl(url),
|
||||
ldapConnectionConfig, searchHop++
|
||||
);
|
||||
entries.addAll(search(referralConnection, baseDN, query,
|
||||
searchHop));
|
||||
// If a referral must be followed to obtain further results,
|
||||
// retrieval of those results depends on whether such referral
|
||||
// following is enabled
|
||||
else if (results.isReferral()) {
|
||||
|
||||
// Follow received referrals only if configured to do so
|
||||
if (request.isFollowReferrals()) {
|
||||
for (String url : results.getReferral().getLdapUrls()) {
|
||||
|
||||
// Connect to referred LDAP server to retrieve further results, ensuring the network
|
||||
// connection is always closed when it will no longer be used
|
||||
try (LdapNetworkConnection referralConnection = ldapService.getReferralConnection(ldapConnection, url)) {
|
||||
if (referralConnection != null) {
|
||||
logger.debug("Following referral to \"{}\"...", url);
|
||||
entries.addAll(search(referralConnection, baseDN, query, searchHop + 1));
|
||||
}
|
||||
else
|
||||
logger.debug("Could not follow referral to "
|
||||
+ "\"{}\" as the URL is invalid.", url);
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
logger.warn("Referral to \"{}\" could not be followed: {}", url, e.getMessage());
|
||||
logger.debug("Failed to follow LDAP referral.", e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Log if referrals may be applicable but they aren't being
|
||||
// followed
|
||||
else
|
||||
logger.debug("Referrals to one or more other LDAP "
|
||||
+ "servers were received but are being "
|
||||
+ "ignored because following of referrals is "
|
||||
+ "not enabled. If referrals must be "
|
||||
+ "followed, consider setting the \"{}\" "
|
||||
+ "property to \"true\".", LDAPGuacamoleProperties.LDAP_FOLLOW_REFERRALS.getName());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -244,7 +286,7 @@ public class ObjectQueryService {
|
||||
}
|
||||
catch (CursorException | IOException | LdapException e) {
|
||||
throw new GuacamoleServerException("Unable to query list of "
|
||||
+ "objects from LDAP directory.", e);
|
||||
+ "objects from LDAP directory: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user