From ef7ef3580c171a858061966edecb6ce6885e5ba4 Mon Sep 17 00:00:00 2001
From: Mark Craig <mark.craig@forgerock.com>
Date: Tue, 20 May 2014 14:41:00 +0000
Subject: [PATCH] CR-3572 Fix for OPENDJ-1462: Describe how to use SSL correctly
---
opendj-sdk/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/SimpleAuth.java | 117 +++++++++++++++++++++++++++++++++++++-
opendj-sdk/src/main/docbkx/dev-guide/chap-authenticating.xml | 29 +++++----
2 files changed, 128 insertions(+), 18 deletions(-)
diff --git a/opendj-sdk/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/SimpleAuth.java b/opendj-sdk/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/SimpleAuth.java
index cf74ab1..82bd6df 100644
--- a/opendj-sdk/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/SimpleAuth.java
+++ b/opendj-sdk/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() {
diff --git a/opendj-sdk/src/main/docbkx/dev-guide/chap-authenticating.xml b/opendj-sdk/src/main/docbkx/dev-guide/chap-authenticating.xml
index 7d555f3..a50223d 100644
--- a/opendj-sdk/src/main/docbkx/dev-guide/chap-authenticating.xml
+++ b/opendj-sdk/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"
--
Gitblit v1.10.0