mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
GUACAMOLE-243: Implement LDAP referral handling in Guacamole LDAP extension.
This commit is contained in:
committed by
Nick Couchman
parent
b8abcd6755
commit
d98cdd2917
@@ -251,6 +251,24 @@ public class ConfigurationService {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the boolean value for whether the connection should
|
||||
* follow referrals or not. By default, it will not.
|
||||
*
|
||||
* @return
|
||||
* The boolean value of whether to follow referrals
|
||||
* as configured in guacamole.properties
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If guacamole.properties cannot be parsed.
|
||||
*/
|
||||
public boolean getFollowReferrals() throws GuacamoleException {
|
||||
return environment.getProperty(
|
||||
LDAPGuacamoleProperties.LDAP_FOLLOW_REFERRALS,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of LDAPSearchConstraints to apply globally
|
||||
* to all LDAP searches.
|
||||
@@ -272,6 +290,23 @@ public class ConfigurationService {
|
||||
return constraints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of referral hops to follow.
|
||||
*
|
||||
* @return
|
||||
* The maximum number of referral hops to follow
|
||||
* as configured in guacamole.properties
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If guacamole.properties cannot be parsed.
|
||||
*/
|
||||
public int getMaxReferralHops() throws GuacamoleException {
|
||||
return environment.getProperty(
|
||||
LDAPGuacamoleProperties.LDAP_MAX_REFERRAL_HOPS,
|
||||
5
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the search filter that should be used when querying the
|
||||
* LDAP server for Guacamole users. If no filter is specified,
|
||||
@@ -281,7 +316,6 @@ public class ConfigurationService {
|
||||
* The search filter that should be used when querying the
|
||||
* LDAP server for users that are valid in Guacamole, or
|
||||
* "(objectClass=*)" if not specified.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If guacamole.properties cannot be parsed.
|
||||
*/
|
||||
@@ -292,4 +326,52 @@ public class ConfigurationService {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the authentication method to use during referral following.
|
||||
*
|
||||
* @return
|
||||
* The authentication method to use during referral following
|
||||
* as configured in guacamole.properties or as derived from
|
||||
* other configuration options.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If guacamole.properties cannot be parsed.
|
||||
*/
|
||||
public String getReferralAuthentication() throws GuacamoleException {
|
||||
String confMethod = environment.getProperty(
|
||||
LDAPGuacamoleProperties.LDAP_REFERRAL_AUTHENTICATION
|
||||
);
|
||||
|
||||
if (confMethod == null)
|
||||
|
||||
if (getSearchBindDN() != null && getSearchBindPassword() != null)
|
||||
return "bind";
|
||||
|
||||
else
|
||||
return "anonymous";
|
||||
|
||||
else if (confMethod.equals("bind") && (getSearchBindDN() == null || getSearchBindPassword() == null))
|
||||
throw new GuacamoleException("Referral is set to bind with credentials, but credentials are not configured.");
|
||||
|
||||
return confMethod;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of seconds to wait for LDAP operations
|
||||
*
|
||||
* @return
|
||||
* The maximum number of seconds to wait for LDAP operations
|
||||
* as configured in guacamole.properties
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If guacamole.properties cannot be parsed.
|
||||
*/
|
||||
public int getOperationTimeout() throws GuacamoleException {
|
||||
return environment.getProperty(
|
||||
LDAPGuacamoleProperties.LDAP_OPERATION_TIMEOUT,
|
||||
30
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -21,12 +21,14 @@ package org.apache.guacamole.auth.ldap;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.novell.ldap.LDAPConnection;
|
||||
import com.novell.ldap.LDAPConstraints;
|
||||
import com.novell.ldap.LDAPException;
|
||||
import com.novell.ldap.LDAPJSSESecureSocketFactory;
|
||||
import com.novell.ldap.LDAPJSSEStartTLSFactory;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleUnsupportedException;
|
||||
import org.apache.guacamole.auth.ldap.ReferralAuthHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -111,6 +113,26 @@ public class LDAPConnectionService {
|
||||
// Obtain appropriately-configured LDAPConnection instance
|
||||
LDAPConnection ldapConnection = createLDAPConnection();
|
||||
|
||||
// Configure LDAP connection constraints
|
||||
LDAPConstraints ldapConstraints = ldapConnection.getConstraints();
|
||||
if (ldapConstraints == null)
|
||||
ldapConstraints = new LDAPConstraints();
|
||||
|
||||
// Set whether or not we follow referrals, and max hops
|
||||
ldapConstraints.setReferralFollowing(confService.getFollowReferrals());
|
||||
String refAuthMethod = confService.getReferralAuthentication();
|
||||
|
||||
if (refAuthMethod != null && refAuthMethod.equals("bind"))
|
||||
ldapConstraints.setReferralHandler(new ReferralAuthHandler(userDN, password));
|
||||
|
||||
ldapConstraints.setHopLimit(confService.getMaxReferralHops());
|
||||
|
||||
// Set timelimit to wait for LDAP operations, converting to ms
|
||||
ldapConstraints.setTimeLimit(confService.getOperationTimeout() * 1000);
|
||||
|
||||
// Apply the constraints to the connection
|
||||
ldapConnection.setConstraints(ldapConstraints);
|
||||
|
||||
try {
|
||||
|
||||
// Connect to LDAP server
|
||||
|
@@ -19,6 +19,7 @@
|
||||
|
||||
package org.apache.guacamole.auth.ldap;
|
||||
|
||||
import org.apache.guacamole.properties.BooleanGuacamoleProperty;
|
||||
import org.apache.guacamole.properties.IntegerGuacamoleProperty;
|
||||
import org.apache.guacamole.properties.StringGuacamoleProperty;
|
||||
|
||||
@@ -174,4 +175,44 @@ public class LDAPGuacamoleProperties {
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether or not we should follow referrals
|
||||
*/
|
||||
public static final BooleanGuacamoleProperty LDAP_FOLLOW_REFERRALS = new BooleanGuacamoleProperty() {
|
||||
|
||||
@Override
|
||||
public String getName() { return "ldap-follow-referrals"; }
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Maximum number of referral hops to follow
|
||||
*/
|
||||
public static final IntegerGuacamoleProperty LDAP_MAX_REFERRAL_HOPS = new IntegerGuacamoleProperty() {
|
||||
|
||||
@Override
|
||||
public String getName() { return "ldap-max-referral-hops"; }
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Authentication method to use to follow referrals
|
||||
*/
|
||||
public static final StringGuacamoleProperty LDAP_REFERRAL_AUTHENTICATION = new StringGuacamoleProperty() {
|
||||
|
||||
@Override
|
||||
public String getName() { return "ldap-referral-authentication"; }
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Number of seconds to wait for LDAP operations to complete
|
||||
*/
|
||||
public static final IntegerGuacamoleProperty LDAP_OPERATION_TIMEOUT = new IntegerGuacamoleProperty() {
|
||||
|
||||
@Override
|
||||
public String getName() { return "ldap-operation-timeout"; }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.auth.ldap;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.novell.ldap.LDAPAuthHandler;
|
||||
import com.novell.ldap.LDAPAuthProvider;
|
||||
import com.novell.ldap.LDAPConnection;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ReferralAuthHandler implements LDAPAuthHandler {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private final Logger logger = LoggerFactory.getLogger(ReferralAuthHandler.class);
|
||||
|
||||
/**
|
||||
* The LDAPAuthProvider object that will be set and returned to the referral handler.
|
||||
*/
|
||||
private final LDAPAuthProvider ldapAuth;
|
||||
|
||||
/**
|
||||
* Service for retrieving LDAP server configuration information.
|
||||
*/
|
||||
@Inject
|
||||
private ConfigurationService confService;
|
||||
|
||||
|
||||
public ReferralAuthHandler() throws GuacamoleException {
|
||||
String binddn = confService.getSearchBindDN();
|
||||
String password = confService.getSearchBindPassword();
|
||||
byte[] passwordBytes;
|
||||
try {
|
||||
|
||||
// Convert password into corresponding byte array
|
||||
if (password != null)
|
||||
passwordBytes = password.getBytes("UTF-8");
|
||||
else
|
||||
passwordBytes = null;
|
||||
|
||||
}
|
||||
catch (UnsupportedEncodingException e) {
|
||||
logger.error("Unexpected lack of support for UTF-8: {}", e.getMessage());
|
||||
logger.debug("Support for UTF-8 (as required by Java spec) not found.", e);
|
||||
throw new GuacamoleException("Could not set password due to missing support for UTF-8 encoding.");
|
||||
}
|
||||
|
||||
ldapAuth = new LDAPAuthProvider(binddn, passwordBytes);
|
||||
|
||||
}
|
||||
|
||||
public ReferralAuthHandler(String dn, String password) throws GuacamoleException {
|
||||
byte[] passwordBytes;
|
||||
try {
|
||||
|
||||
// Convert password into corresponding byte array
|
||||
if (password != null)
|
||||
passwordBytes = password.getBytes("UTF-8");
|
||||
else
|
||||
passwordBytes = null;
|
||||
|
||||
}
|
||||
catch (UnsupportedEncodingException e) {
|
||||
logger.error("Unexpected lack of support for UTF-8: {}", e.getMessage());
|
||||
logger.debug("Support for UTF-8 (as required by Java spec) not found.", e);
|
||||
throw new GuacamoleException("Could not set password due to missing UTF-8 support.");
|
||||
}
|
||||
ldapAuth = new LDAPAuthProvider(dn, passwordBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LDAPAuthProvider getAuthProvider(String host, int port) {
|
||||
return ldapAuth;
|
||||
}
|
||||
|
||||
}
|
@@ -24,6 +24,7 @@ import com.novell.ldap.LDAPAttribute;
|
||||
import com.novell.ldap.LDAPConnection;
|
||||
import com.novell.ldap.LDAPEntry;
|
||||
import com.novell.ldap.LDAPException;
|
||||
import com.novell.ldap.LDAPReferralException;
|
||||
import com.novell.ldap.LDAPSearchResults;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -107,19 +108,35 @@ public class UserService {
|
||||
// Read all visible users
|
||||
while (results.hasMore()) {
|
||||
|
||||
LDAPEntry entry = results.next();
|
||||
try {
|
||||
|
||||
LDAPEntry entry = results.next();
|
||||
|
||||
// Get username from record
|
||||
LDAPAttribute username = entry.getAttribute(usernameAttribute);
|
||||
if (username == null) {
|
||||
logger.warn("Queried user is missing the username attribute \"{}\".", usernameAttribute);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Store user using their username as the identifier
|
||||
String identifier = username.getStringValue();
|
||||
if (users.put(identifier, new SimpleUser(identifier)) != null)
|
||||
logger.warn("Possibly ambiguous user account: \"{}\".", identifier);
|
||||
|
||||
// Get username from record
|
||||
LDAPAttribute username = entry.getAttribute(usernameAttribute);
|
||||
if (username == null) {
|
||||
logger.warn("Queried user is missing the username attribute \"{}\".", usernameAttribute);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Store user using their username as the identifier
|
||||
String identifier = username.getStringValue();
|
||||
if (users.put(identifier, new SimpleUser(identifier)) != null)
|
||||
logger.warn("Possibly ambiguous user account: \"{}\".", identifier);
|
||||
catch (LDAPReferralException e) {
|
||||
if (confService.getFollowReferrals()) {
|
||||
logger.error("Could not follow referral.", e.getMessage());
|
||||
logger.debug("Error encountered trying to follow referral.", e);
|
||||
throw new GuacamoleException("Could not follow LDAP referral.");
|
||||
}
|
||||
else {
|
||||
logger.warn("Encountered a referral, but not following it.", e.getMessage());
|
||||
logger.debug("Got a referral, but not configured to follow it.", e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user