GUACAMOLE-1488: Merge support for configuring LDAP SSL protocol.

This commit is contained in:
Mike Jumper
2022-12-11 13:11:49 -08:00
committed by GitHub
8 changed files with 228 additions and 37 deletions

View File

@@ -27,6 +27,7 @@ import org.apache.directory.ldap.client.api.LdapNetworkConnection;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.ldap.conf.EncryptionMethod; import org.apache.guacamole.auth.ldap.conf.EncryptionMethod;
import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration; import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration;
import org.apache.guacamole.auth.ldap.conf.LDAPSSLProtocol;
import org.apache.guacamole.auth.ldap.conf.MemberAttributeType; import org.apache.guacamole.auth.ldap.conf.MemberAttributeType;
/** /**
@@ -161,6 +162,11 @@ public class ConnectedLDAPConfiguration implements LDAPConfiguration, AutoClosea
public EncryptionMethod getEncryptionMethod() throws GuacamoleException { public EncryptionMethod getEncryptionMethod() throws GuacamoleException {
return config.getEncryptionMethod(); return config.getEncryptionMethod();
} }
@Override
public LDAPSSLProtocol getSslProtocol() throws GuacamoleException {
return config.getSslProtocol();
}
@Override @Override
public int getMaxResults() throws GuacamoleException { public int getMaxResults() throws GuacamoleException {

View File

@@ -35,6 +35,7 @@ import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.GuacamoleUnsupportedException; import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.auth.ldap.conf.EncryptionMethod; import org.apache.guacamole.auth.ldap.conf.EncryptionMethod;
import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration; import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration;
import org.apache.guacamole.auth.ldap.conf.LDAPSSLProtocol;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -51,7 +52,8 @@ public class LDAPConnectionService {
/** /**
* Creates a new instance of LdapNetworkConnection, configured as required * Creates a new instance of LdapNetworkConnection, configured as required
* to use the given encryption method to communicate with the LDAP server * to use the given encryption method to communicate with the LDAP server
* at the given hostname and port. The returned LdapNetworkConnection is * at the given hostname and port, with the specified encryption method,
* SSL protocol version, and timeout. The returned LdapNetworkConnection is
* configured for use but is not yet connected nor bound to the LDAP * configured for use but is not yet connected nor bound to the LDAP
* server. It will not be bound until a bind operation is explicitly * server. It will not be bound until a bind operation is explicitly
* requested, and will not be connected until it is used in an LDAP * requested, and will not be connected until it is used in an LDAP
@@ -66,6 +68,85 @@ public class LDAPConnectionService {
* @param encryptionMethod * @param encryptionMethod
* The encryption method that should be used to communicate with the * The encryption method that should be used to communicate with the
* LDAP server. * LDAP server.
*
* @param sslProtocol
* The SSL protocol version to use to make a secure LDAP configuration,
* if SSL or STARTTLS is used.
*
* @param timeout
* The maximum number of milliseconds to wait for a response from the
* LDAP server.
*
* @return
* A new instance of LdapNetworkConnection which uses the given
* encryption method to communicate with the LDAP server at the given
* hostname and port.
*
* @throws GuacamoleException
* If the requested encryption method is actually not implemented (a
* bug).
*/
private LdapNetworkConnection createLDAPConnection(String host, int port,
EncryptionMethod encryptionMethod, LDAPSSLProtocol sslProtocol,
int timeout)
throws GuacamoleException {
LdapConnectionConfig config = new LdapConnectionConfig();
config.setLdapHost(host);
config.setLdapPort(port);
config.setTimeout(timeout);
// Map encryption method to proper connection and socket factory
switch (encryptionMethod) {
// Unencrypted LDAP connection
case NONE:
logger.debug("Connection to LDAP server without encryption.");
break;
// LDAP over SSL (LDAPS)
case SSL:
logger.debug("Connecting to LDAP server using SSL/TLS.");
config.setUseSsl(true);
config.setSslProtocol(sslProtocol.toString());
break;
// LDAP + STARTTLS
case STARTTLS:
logger.debug("Connecting to LDAP server using STARTTLS.");
config.setUseTls(true);
config.setSslProtocol(sslProtocol.toString());
break;
// The encryption method, though known, is not actually
// implemented. If encountered, this would be a bug.
default:
throw new GuacamoleUnsupportedException("Unimplemented encryption method: " + encryptionMethod);
}
return new LdapNetworkConnection(config);
}
/**
* Creates a new instance of LdapNetworkConnection, configured as required
* to use the given encryption method to communicate with the LDAP server
* at the given hostname and port with the encryption method and timeout
* specified, as well. The returned LdapNetworkConnection is configured
* for use but is not yet connected nor bound to the LDAP server. It will
* not be bound until a bind operation is explicitly requested, and will
* not be connected until it is used in an LDAP operation (such as a bind).
*
* @param host
* The hostname or IP address of the LDAP server.
*
* @param port
* The TCP port that the LDAP server is listening on.
*
* @param encryptionMethod
* The encryption method that should be used to communicate with the
* LDAP server.
* *
* @param timeout * @param timeout
* The maximum number of milliseconds to wait for a response from the * The maximum number of milliseconds to wait for a response from the
@@ -83,41 +164,8 @@ public class LDAPConnectionService {
private LdapNetworkConnection createLDAPConnection(String host, int port, private LdapNetworkConnection createLDAPConnection(String host, int port,
EncryptionMethod encryptionMethod, int timeout) EncryptionMethod encryptionMethod, int timeout)
throws GuacamoleException { throws GuacamoleException {
return createLDAPConnection(host, port, encryptionMethod,
LdapConnectionConfig config = new LdapConnectionConfig(); LDAPSSLProtocol.TLSv1_3, timeout);
config.setLdapHost(host);
config.setLdapPort(port);
config.setTimeout(timeout);
// Map encryption method to proper connection and socket factory
switch (encryptionMethod) {
// Unencrypted LDAP connection
case NONE:
logger.debug("Connection to LDAP server without encryption.");
break;
// LDAP over SSL (LDAPS)
case SSL:
logger.debug("Connecting to LDAP server using SSL/TLS.");
config.setUseSsl(true);
break;
// LDAP + STARTTLS
case STARTTLS:
logger.debug("Connecting to LDAP server using STARTTLS.");
config.setUseTls(true);
break;
// The encryption method, though known, is not actually
// implemented. If encountered, this would be a bug.
default:
throw new GuacamoleUnsupportedException("Unimplemented encryption method: " + encryptionMethod);
}
return new LdapNetworkConnection(config);
} }
/** /**
@@ -147,6 +195,7 @@ public class LDAPConnectionService {
config.getServerHostname(), config.getServerHostname(),
config.getServerPort(), config.getServerPort(),
config.getEncryptionMethod(), config.getEncryptionMethod(),
config.getSslProtocol(),
config.getNetworkTimeout()); config.getNetworkTimeout());
} }
@@ -217,7 +266,7 @@ public class LDAPConnectionService {
port = encryptionMethod.DEFAULT_PORT; port = encryptionMethod.DEFAULT_PORT;
return createLDAPConnection(host, port, encryptionMethod, return createLDAPConnection(host, port, encryptionMethod,
config.getNetworkTimeout()); config.getSslProtocol(), config.getNetworkTimeout());
} }

View File

@@ -89,6 +89,11 @@ public class DefaultLDAPConfiguration implements LDAPConfiguration {
public EncryptionMethod getEncryptionMethod() { public EncryptionMethod getEncryptionMethod() {
return EncryptionMethod.NONE; return EncryptionMethod.NONE;
} }
@Override
public LDAPSSLProtocol getSslProtocol() {
return LDAPSSLProtocol.TLSv1_3;
}
@Override @Override
public int getMaxResults() { public int getMaxResults() {

View File

@@ -136,6 +136,14 @@ public class EnvironmentLDAPConfiguration implements LDAPConfiguration {
DEFAULT.getEncryptionMethod() DEFAULT.getEncryptionMethod()
); );
} }
@Override
public LDAPSSLProtocol getSslProtocol() throws GuacamoleException {
return environment.getProperty(
LDAPGuacamoleProperties.LDAP_SSL_PROTOCOL,
DEFAULT.getSslProtocol()
);
}
@Override @Override
public int getMaxResults() throws GuacamoleException { public int getMaxResults() throws GuacamoleException {

View File

@@ -116,6 +116,14 @@ public class JacksonLDAPConfiguration implements LDAPConfiguration {
*/ */
@JsonProperty("encryption-method") @JsonProperty("encryption-method")
private String encryptionMethod; private String encryptionMethod;
/**
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_SSL_PROTOCOL}. If
* not set within the YAML, this will be null, and will default to the value
* specified by the LDAP API library.
*/
@JsonProperty("ssl-protocol")
private String sslProtocol;
/** /**
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_MAX_SEARCH_RESULTS}. * The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_MAX_SEARCH_RESULTS}.
@@ -365,6 +373,12 @@ public class JacksonLDAPConfiguration implements LDAPConfiguration {
return withDefault(LDAPGuacamoleProperties.LDAP_ENCRYPTION_METHOD, return withDefault(LDAPGuacamoleProperties.LDAP_ENCRYPTION_METHOD,
encryptionMethod, defaultConfig::getEncryptionMethod); encryptionMethod, defaultConfig::getEncryptionMethod);
} }
@Override
public LDAPSSLProtocol getSslProtocol() throws GuacamoleException {
return withDefault(LDAPGuacamoleProperties.LDAP_SSL_PROTOCOL,
sslProtocol, defaultConfig::getSslProtocol);
}
@Override @Override
public int getMaxResults() throws GuacamoleException { public int getMaxResults() throws GuacamoleException {

View File

@@ -183,6 +183,20 @@ public interface LDAPConfiguration {
* If the encryption method cannot be retrieved. * If the encryption method cannot be retrieved.
*/ */
EncryptionMethod getEncryptionMethod() throws GuacamoleException; EncryptionMethod getEncryptionMethod() throws GuacamoleException;
/**
* Returns the SSL protocol that should be used when making a secure
* connection to the LDAP server. By default the latest available TLS
* version will be used.
*
* @return
* The SSL protocol that should be used when making a secure connection
* to the LDAP server.
*
* @throws GuacamoleException
* If the SSL protocol cannot be retrieved.
*/
LDAPSSLProtocol getSslProtocol() throws GuacamoleException;
/** /**
* Returns maximum number of results a LDAP query can return. * Returns maximum number of results a LDAP query can return.

View File

@@ -170,6 +170,14 @@ public class LDAPGuacamoleProperties {
public String getName() { return "ldap-encryption-method"; } public String getName() { return "ldap-encryption-method"; }
}; };
public static final EnumGuacamoleProperty<LDAPSSLProtocol> LDAP_SSL_PROTOCOL =
new EnumGuacamoleProperty<LDAPSSLProtocol>(LDAPSSLProtocol.class) {
@Override
public String getName() { return "ldap-ssl-protocol"; }
};
/** /**
* The maximum number of results a LDAP query can return. * The maximum number of results a LDAP query can return.

View File

@@ -0,0 +1,87 @@
/*
* 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.conf;
import org.apache.guacamole.properties.EnumGuacamoleProperty.PropertyValue;
/**
* All possible SSL protocols which may be used for secure LDAP connections.
*/
public enum LDAPSSLProtocol {
/**
* Use SSLv3 for secure LDAP connection.
*/
@PropertyValue("SSLv3")
SSLv3("SSLv3"),
/**
* Use original TLS for secure LDAP connection.
*/
@PropertyValue("TLS")
TLS("TLS"),
/**
* Use TLSv1 for secure LDAP connection.
*/
@PropertyValue("TLSv1")
TLSv1("TLSv1"),
/**
* Use TLSv1.1 for secure LDAP connection.
*/
@PropertyValue("TLSv1.1")
TLSv1_1("TLSv1.1"),
/**
* Use TLSv1.2 for secure LDAP connection.
*/
@PropertyValue("TLSv1.2")
TLSv1_2("TLSv1.2"),
/**
* Use TLSv1.3 for secure LDAP connection.
*/
@PropertyValue("TLSv1.3")
TLSv1_3("TLSv1.3");
/**
* The string value of the option to use which is ultimately what the LDAP
* API consumes to set the SSL protocol.
*/
public final String STRING_VALUE;
/**
* Initializes this SSL protocol such that it is associated with the
* given string value.
*
* @param value
* The string value that will be associated with the enum value.
*/
private LDAPSSLProtocol(String value) {
this.STRING_VALUE = value;
}
@Override
public String toString() {
return STRING_VALUE;
}
}