mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Mark Craig
20.41.2014 54d6d3fed0bf3440b0adcc0ac3f18e3f0d132900
CR-3572 Fix for OPENDJ-1462: Describe how to use SSL correctly

Thanks to Chris Ridd for helpful suggestions as well as his review.
2 files modified
146 ■■■■ changed files
opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/SimpleAuth.java 117 ●●●●● patch | view | raw | blame | history
src/main/docbkx/dev-guide/chap-authenticating.xml 29 ●●●●● patch | view | raw | blame | history
opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/SimpleAuth.java
@@ -21,14 +21,17 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2011-2013 ForgeRock AS
 *      Copyright 2011-2014 ForgeRock AS
 */
package org.forgerock.opendj.examples;
import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ErrorResultException;
@@ -49,8 +52,15 @@
 * <li>use-starttls - (Optional) connect with StartTLS</li>
 * <li>use-ssl - (Optional) connect over SSL</li>
 * </ul>
 * The host, port, bind-dn, and bind-password are required. The use-starttls and
 * use-ssl parameters are optional and mutually exclusive.
 * The host, port, bind-dn, and bind-password arguments are required.
 * The use-starttls and use-ssl arguments are optional and mutually exclusive.
 * <p>
 * If the server certificate is self-signed,
 * or otherwise not trusted out-of-the-box,
 * then set the trust store by using the JSSE system property
 * {@code -Djavax.net.ssl.trustStore=/path/to/opendj/config/keystore}
 * and the trust store password if necessary by using the JSSE system property
 * {@code -Djavax.net.ssl.trustStorePassword=`cat /path/to/opendj/config/keystore.pin`}.
 */
public final class SimpleAuth {
@@ -97,6 +107,88 @@
    }
    // --- JCite basic auth ---
    // --- JCite trust options ---
    /**
     * For StartTLS and SSL the connection factory needs SSL context options.
     * In the general case, a trust manager in the SSL context serves
     * to check server certificates, and a key manager handles client keys
     * when the server checks certificates from our client.
     * <p>
     * This sample expects a directory server
     * that allows use of Start TLS on the LDAP port.
     * This sample checks the server certificate,
     * verifying that the certificate is currently valid,
     * and that the host name of the server matches that of the certificate,
     * based on a Java Key Store-format trust store.
     * This sample does not present a client certificate.
     *
     * @param hostname Host name expected in the server certificate
     * @param truststore Path to trust store file for the trust manager
     * @param storepass Password for the trust store
     * @return SSL context options
     * @throws GeneralSecurityException Could not load the trust store
     */
    private static LDAPOptions getTrustOptions(final String hostname,
                                               final String truststore,
                                               final String storepass)
            throws GeneralSecurityException {
        LDAPOptions lo = new LDAPOptions();
        TrustManager trustManager = null;
        try {
            trustManager = TrustManagers.checkValidityDates(
                    TrustManagers.checkHostName(hostname,
                            TrustManagers.checkUsingTrustStore(
                                    truststore, storepass.toCharArray(), null)));
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
        if (trustManager != null) {
            SSLContext sslContext = new SSLContextBuilder()
                    .setTrustManager(trustManager).getSSLContext();
            lo.setSSLContext(sslContext);
        }
        lo.setUseStartTLS(useStartTLS);
        return lo;
    }
    // --- JCite trust options ---
    // --- JCite secure connect ---
    /**
     * Perform authentication over a secure connection.
     */
    private static void secureConnect() {
        Connection connection = null;
        try {
            final LDAPConnectionFactory factory =
                    new LDAPConnectionFactory(host, port,
                            getTrustOptions(host, keystore, storepass));
            connection = factory.getConnection();
            connection.bind(bindDN, bindPassword.toCharArray());
            System.out.println("Authenticated as " + bindDN + ".");
        } catch (final ErrorResultException e) {
            System.err.println(e.getMessage());
            System.exit(e.getResult().getResultCode().intValue());
            return;
        } catch (final GeneralSecurityException e) {
            System.err.println(e.getMessage());
            System.exit(ResultCode.CLIENT_SIDE_CONNECT_ERROR.intValue());
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }
    // --- JCite secure connect ---
    // --- JCite trust all ---
    /**
     * For StartTLS and SSL the connection factory needs SSL context options. In
@@ -152,14 +244,16 @@
     * Authenticate using StartTLS.
     */
    private static void connectStartTLS() {
        trustAllConnect();
        secureConnect();
        // trustAllConnect();
    }
    /**
     * Authenticate over LDAPS.
     */
    private static void connectSSL() {
        trustAllConnect();
        secureConnect();
        // trustAllConnect();
    }
    private static String host;
@@ -168,6 +262,8 @@
    private static String bindPassword;
    private static boolean useStartTLS = false;
    private static boolean useSSL = false;
    private static String keystore;
    private static String storepass;
    /**
     * Parse command line arguments.
@@ -196,6 +292,16 @@
                giveUp();
            }
        }
        keystore = System.getProperty("javax.net.ssl.trustStore");
        storepass = System.getProperty("javax.net.ssl.trustStorePassword");
        if (keystore == null) { // Try to use Java's cacerts trust store.
            keystore = System.getProperty("java.home") + File.separator
                    + "lib" + File.separator
                    + "security" + File.separator
                    + "cacerts";
            storepass = "changeit"; // Default password
        }
    }
    private static void giveUp() {
@@ -207,6 +313,7 @@
        System.err.println("Usage: host port bind-dn bind-password [ use-starttls | use-ssl ]");
        System.err.println("\thost, port, bind-dn, and bind-password arguments are required.");
        System.err.println("\tuse-starttls and use-ssl are optional and mutually exclusive.");
        System.err.println("\tOptionally set javax.net.ssl.trustStore and javax.net.ssl.trustStorePassword.");
    }
    private SimpleAuth() {
src/main/docbkx/dev-guide/chap-authenticating.xml
@@ -104,28 +104,31 @@
  factory in order to set an SSL context, and set whether to use Start TLS.
  The SSL context lets you set a trust manager to check server certificates,
  and also set a key manager to provide keys when the server needs to check
  your client certificates. In the simplest, not-so-secure case, you can
  set up a trust manager that trusts all certificates.</para>
  your client certificates.</para>
  
  <para>The following example is an excerpt from the OpenDJ LDAP SDK example,
  <filename>SimpleAuth.java</filename>.</para>
  
  <programlisting language="java"
  >[jcp:org.forgerock.opendj.examples.SimpleAuth:--- JCite trust all ---]</programlisting>
  >[jcp:org.forgerock.opendj.examples.SimpleAuth:--- JCite trust options ---]</programlisting>
  
  <para>A more secure and extensive SSL context would include a trust manager
  using a trust store and trust manager methods to check server certificates.
  If you also want to be able to authenticate to the server using your client
  certificate, you would need a key manager.</para>
  <para>
   This implementation relies on a Java Key Store format trust store,
   and trust manager methods to check server certificates.
   If you also want to be able to authenticate to the server
   using your client certificate, then you would need a key manager, too.
  </para>
  
  <para>The authentication over SSL or using Start TLS in the trust-all case is
  much like simple authentication over LDAP without connection-level security.
  The primary differences are that you pass the <literal>LDAPOptions</literal>
  to the LDAP connection factory, and that you handle the potential security
  exception involved in setting up the SSL context.</para>
  <para>
   The authentication over SSL or using Start TLS is
   much like simple authentication over LDAP without connection-level security.
   The primary differences are that you pass the <literal>LDAPOptions</literal>
   to the LDAP connection factory, and that you handle the potential security
   exception involved in setting up the SSL context.
  </para>
  
  <programlisting language="java"
  >[jcp:org.forgerock.opendj.examples.SimpleAuth:--- JCite trust all connect ---]</programlisting>
  >[jcp:org.forgerock.opendj.examples.SimpleAuth:--- JCite secure connect ---]</programlisting>
  <para>For a complete example in context, see <link
  xlink:href="http://opendj.forgerock.org/opendj-ldap-sdk-examples/xref/org/forgerock/opendj/examples/SimpleAuth.html"