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

This commit is contained in:
Virtually Nick
2022-01-03 15:31:47 -05:00
parent aa99b4bc8a
commit c2c3428cf0
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.auth.ldap.conf.EncryptionMethod;
import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration;
import org.apache.guacamole.auth.ldap.conf.LDAPSSLProtocol;
import org.apache.guacamole.auth.ldap.conf.MemberAttributeType;
/**
@@ -161,6 +162,11 @@ public class ConnectedLDAPConfiguration implements LDAPConfiguration, AutoClosea
public EncryptionMethod getEncryptionMethod() throws GuacamoleException {
return config.getEncryptionMethod();
}
@Override
public LDAPSSLProtocol getSslProtocol() throws GuacamoleException {
return config.getSslProtocol();
}
@Override
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.auth.ldap.conf.EncryptionMethod;
import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration;
import org.apache.guacamole.auth.ldap.conf.LDAPSSLProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -51,7 +52,8 @@ public class LDAPConnectionService {
/**
* 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. 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
* 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
@@ -66,6 +68,85 @@ public class LDAPConnectionService {
* @param encryptionMethod
* The encryption method that should be used to communicate with the
* 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
* 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,
EncryptionMethod encryptionMethod, 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);
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);
return createLDAPConnection(host, port, encryptionMethod,
LDAPSSLProtocol.TLSv1_3, timeout);
}
/**
@@ -147,6 +195,7 @@ public class LDAPConnectionService {
config.getServerHostname(),
config.getServerPort(),
config.getEncryptionMethod(),
config.getSslProtocol(),
config.getNetworkTimeout());
}
@@ -217,7 +266,7 @@ public class LDAPConnectionService {
port = encryptionMethod.DEFAULT_PORT;
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() {
return EncryptionMethod.NONE;
}
@Override
public LDAPSSLProtocol getSslProtocol() {
return LDAPSSLProtocol.TLSv1_3;
}
@Override
public int getMaxResults() {

View File

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

View File

@@ -116,6 +116,14 @@ public class JacksonLDAPConfiguration implements LDAPConfiguration {
*/
@JsonProperty("encryption-method")
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}.
@@ -365,6 +373,12 @@ public class JacksonLDAPConfiguration implements LDAPConfiguration {
return withDefault(LDAPGuacamoleProperties.LDAP_ENCRYPTION_METHOD,
encryptionMethod, defaultConfig::getEncryptionMethod);
}
@Override
public LDAPSSLProtocol getSslProtocol() throws GuacamoleException {
return withDefault(LDAPGuacamoleProperties.LDAP_SSL_PROTOCOL,
sslProtocol, defaultConfig::getSslProtocol);
}
@Override
public int getMaxResults() throws GuacamoleException {

View File

@@ -183,6 +183,20 @@ public interface LDAPConfiguration {
* If the encryption method cannot be retrieved.
*/
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.

View File

@@ -170,6 +170,14 @@ public class LDAPGuacamoleProperties {
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.

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;
}
}