From e50b79850923484252c328b421a4100968601407 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Fri, 05 Jul 2013 12:40:13 +0000
Subject: [PATCH] Fix OPENDJ-1033: The Rest2LDAP servlet does not support SSL

---
 opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LDAP.java |   72 ++++++++++++++++++++++++++++++++++--
 1 files changed, 68 insertions(+), 4 deletions(-)

diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LDAP.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LDAP.java
index 7c97bcd..b9cbbe1 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LDAP.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LDAP.java
@@ -21,6 +21,8 @@
 import static org.forgerock.opendj.rest2ldap.ReadOnUpdatePolicy.CONTROLS;
 import static org.forgerock.opendj.rest2ldap.Utils.ensureNotNull;
 
+import java.io.IOException;
+import java.security.GeneralSecurityException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedHashMap;
@@ -52,13 +54,16 @@
 import org.forgerock.opendj.ldap.FailoverLoadBalancingAlgorithm;
 import org.forgerock.opendj.ldap.Filter;
 import org.forgerock.opendj.ldap.LDAPConnectionFactory;
+import org.forgerock.opendj.ldap.LDAPOptions;
 import org.forgerock.opendj.ldap.LinkedAttribute;
 import org.forgerock.opendj.ldap.MultipleEntriesFoundException;
 import org.forgerock.opendj.ldap.RDN;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.RoundRobinLoadBalancingAlgorithm;
+import org.forgerock.opendj.ldap.SSLContextBuilder;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.forgerock.opendj.ldap.TimeoutResultException;
+import org.forgerock.opendj.ldap.TrustManagers;
 import org.forgerock.opendj.ldap.requests.BindRequest;
 import org.forgerock.opendj.ldap.requests.Requests;
 import org.forgerock.opendj.ldap.requests.SearchRequest;
@@ -70,6 +75,23 @@
  * collections.
  */
 public final class Rest2LDAP {
+
+    /**
+     * Indicates whether or not LDAP client connections should use SSL or
+     * StartTLS.
+     */
+    private enum ConnectionSecurity {
+        NONE, SSL, STARTTLS
+    }
+
+    /**
+     * Specifies the mechanism which should be used for trusting certificates
+     * presented by the LDAP server.
+     */
+    private enum TrustManagerType {
+        TRUSTALL, JVM, FILE
+    }
+
     /**
      * A builder for incrementally constructing LDAP resource collections.
      */
@@ -965,6 +987,48 @@
             bindRequest = null;
         }
 
+        // Parse SSL/StartTLS parameters.
+        final ConnectionSecurity connectionSecurity =
+                configuration.get("connectionSecurity").defaultTo(ConnectionSecurity.NONE).asEnum(
+                        ConnectionSecurity.class);
+        final LDAPOptions options = new LDAPOptions();
+        if (connectionSecurity != ConnectionSecurity.NONE) {
+            try {
+                // Configure SSL.
+                final SSLContextBuilder builder = new SSLContextBuilder();
+
+                // Parse trust store configuration.
+                final TrustManagerType trustManagerType =
+                        configuration.get("trustManager").defaultTo(TrustManagerType.TRUSTALL)
+                                .asEnum(TrustManagerType.class);
+                switch (trustManagerType) {
+                case TRUSTALL:
+                    builder.setTrustManager(TrustManagers.trustAll());
+                    break;
+                case JVM:
+                    // Do nothing: JVM trust manager is the default.
+                    break;
+                case FILE:
+                    final String fileName =
+                            configuration.get("fileBasedTrustManagerFile").required().asString();
+                    final String password =
+                            configuration.get("fileBasedTrustManagerPassword").asString();
+                    final String type = configuration.get("fileBasedTrustManagerType").asString();
+                    builder.setTrustManager(TrustManagers.checkUsingTrustStore(fileName,
+                            password != null ? password.toCharArray() : null, type));
+                    break;
+                }
+                options.setSSLContext(builder.getSSLContext());
+                options.setUseStartTLS(connectionSecurity == ConnectionSecurity.STARTTLS);
+            } catch (GeneralSecurityException e) {
+                // Rethrow as unchecked exception.
+                throw new IllegalArgumentException(e);
+            } catch (IOException e) {
+                // Rethrow as unchecked exception.
+                throw new IllegalArgumentException(e);
+            }
+        }
+
         // Parse primary data center.
         final JsonValue primaryLDAPServers = configuration.get("primaryLDAPServers");
         if (!primaryLDAPServers.isList() || primaryLDAPServers.size() == 0) {
@@ -972,7 +1036,7 @@
         }
         final ConnectionFactory primary =
                 parseLDAPServers(primaryLDAPServers, bindRequest, connectionPoolSize,
-                        heartBeatIntervalSeconds);
+                        heartBeatIntervalSeconds, options);
 
         // Parse secondary data center(s).
         final JsonValue secondaryLDAPServers = configuration.get("secondaryLDAPServers");
@@ -981,7 +1045,7 @@
             if (secondaryLDAPServers.size() > 0) {
                 secondary =
                         parseLDAPServers(secondaryLDAPServers, bindRequest, connectionPoolSize,
-                                heartBeatIntervalSeconds);
+                                heartBeatIntervalSeconds, options);
             } else {
                 secondary = null;
             }
@@ -1029,12 +1093,12 @@
 
     private static ConnectionFactory parseLDAPServers(final JsonValue config,
             final BindRequest bindRequest, final int connectionPoolSize,
-            final int heartBeatIntervalSeconds) {
+            final int heartBeatIntervalSeconds, final LDAPOptions options) {
         final List<ConnectionFactory> servers = new ArrayList<ConnectionFactory>(config.size());
         for (final JsonValue server : config) {
             final String host = server.get("hostname").required().asString();
             final int port = server.get("port").required().asInteger();
-            ConnectionFactory factory = new LDAPConnectionFactory(host, port);
+            ConnectionFactory factory = new LDAPConnectionFactory(host, port, options);
             if (bindRequest != null) {
                 factory = Connections.newAuthenticatedConnectionFactory(factory, bindRequest);
             }

--
Gitblit v1.10.0