From 38fc88aa89f1eb893ce43acf49179e4b2b1228c7 Mon Sep 17 00:00:00 2001
From: Mark Craig <mark.craig@forgerock.com>
Date: Tue, 22 Nov 2011 16:16:03 +0000
Subject: [PATCH] Example showing SASL PLAIN authentication
---
opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/saslauth/package-info.java | 32 +++++
opendj3/src/main/docbkx/dev-guide/chap-authenticating.xml | 62 ++++++++++
opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/saslauth/Main.java | 210 +++++++++++++++++++++++++++++++++++
3 files changed, 303 insertions(+), 1 deletions(-)
diff --git a/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/saslauth/Main.java b/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/saslauth/Main.java
new file mode 100644
index 0000000..f7b2dd4
--- /dev/null
+++ b/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/saslauth/Main.java
@@ -0,0 +1,210 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opendj3/legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2011 ForgeRock AS
+ */
+
+/**
+ * An example client application which performs SASL authentication to a
+ * directory server, displays a result, and closes the connection.
+ *
+ * Set up StartTLS before using this example.
+ */
+package org.forgerock.opendj.examples.saslauth;
+
+import java.security.GeneralSecurityException;
+
+import javax.net.ssl.SSLContext;
+
+import org.forgerock.opendj.ldap.Connection;
+import org.forgerock.opendj.ldap.ErrorResultException;
+import org.forgerock.opendj.ldap.LDAPConnectionFactory;
+import org.forgerock.opendj.ldap.LDAPOptions;
+import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.SSLContextBuilder;
+import org.forgerock.opendj.ldap.TrustManagers;
+import org.forgerock.opendj.ldap.requests.PlainSASLBindRequest;
+import org.forgerock.opendj.ldap.requests.Requests;
+
+
+
+/**
+ * An example client application which performs SASL PLAIN authentication to a
+ * directory server over LDAP with StartTLS. This example takes the following
+ * command line parameters:
+ * <ul>
+ * <li>host - host name of the directory server</li>
+ * <li>port - port number of the directory server for StartTLS, e.g. 1389</li>
+ * <li>authzid - (Optional) Authorization identity</li>
+ * <li>authcid - Authentication identity</li>
+ * <li>passwd - Password of the user to authenticate</li>
+ * </ul>
+ * The host, port, authcid, and passwd are required.
+ * SASL PLAIN is described in <a href="http://www.ietf.org/rfc/rfc4616.txt">RFC
+ * 4616</a>.
+ * <p>
+ * The authzid and authcid are prefixed as described in <a
+ * href="http://tools.ietf.org/html/rfc4513#section-5.2.1.8">RFC 4513, section
+ * 5.2.1.8</a>, with "dn:" if you pass in a distinguished name, or with "u:" if
+ * you pass in a user ID.
+ * <p>
+ * By default, OpenDJ is set up for SASL PLAIN to use the Exact Match Identity
+ * Mapper to find entries by searching uid values for the user ID. In other
+ * words, the following examples are equivalent.
+ * <pre>
+ * dn:uid=bjensen,ou=people,dc=example,dc=com
+ * u:bjensen
+ * </pre>
+ */
+public final class Main
+{
+ /**
+ * Authenticate to the directory using SASL PLAIN.
+ * @param args The command line arguments
+ */
+ public static void main(String[] args)
+ {
+ parseArgs(args);
+ Connection connection = null;
+
+ try
+ {
+ final LDAPConnectionFactory factory =
+ new LDAPConnectionFactory(host, port, getTrustAllOptions());
+ connection = factory.getConnection();
+ PlainSASLBindRequest request = Requests.newPlainSASLBindRequest(
+ authcid, passwd.toCharArray());
+ if (authzid != null) request.setAuthorizationID(authzid);
+ connection.bind(request);
+ System.out.println("Authenticated as " + authcid + ".");
+ }
+ catch (final ErrorResultException e)
+ {
+ System.err.println(e.getMessage());
+ System.exit(e.getResult().getResultCode().intValue());
+ return;
+ }
+ catch (final InterruptedException e)
+ {
+ System.err.println(e.getMessage());
+ System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.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();
+ }
+ }
+
+
+
+ /**
+ * For StartTLS 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.
+ *
+ * OpenDJ directory server lets you install by default with a self-signed
+ * certificate that is not in the system trust store. To simplify this
+ * implementation trusts all server certificates.
+ */
+ private static LDAPOptions getTrustAllOptions()
+ throws GeneralSecurityException
+ {
+ LDAPOptions lo = new LDAPOptions();
+ SSLContext sslContext = new SSLContextBuilder()
+ .setTrustManager(TrustManagers.trustAll()).getSSLContext();
+ lo.setSSLContext(sslContext);
+ lo.setUseStartTLS(true);
+ return lo;
+ }
+
+
+
+ private static String host;
+ private static int port;
+ private static String authzid;
+ private static String authcid;
+ private static String passwd;
+
+
+
+ /**
+ * Parse command line arguments.
+ * @param args host port [authzid] authcid passwd
+ */
+ private static void parseArgs(String[] args)
+ {
+ if (args.length < 4 || args.length > 5) giveUp();
+
+ host = args[0];
+ port = Integer.parseInt(args[1]);
+
+ if (args.length == 5)
+ {
+ authzid = args[2];
+ authcid = args[3];
+ passwd = args[4];
+ }
+ else
+ {
+ authzid = null;
+ authcid = args[2];
+ passwd = args[3];
+ }
+ }
+
+
+
+ private static void giveUp()
+ {
+ printUsage();
+ System.exit(1);
+ }
+
+
+
+ private static void printUsage()
+ {
+ System.err.println(
+ "Usage: host port [authzid] authcid passwd");
+ System.err.println(
+ "\tThe port must be able to handle LDAP with StartTLS.");
+ System.err.println(
+ "\tSee http://www.ietf.org/rfc/rfc4616.txt for more on SASL PLAIN.");
+ }
+
+
+
+ private Main()
+ {
+ // Not used.
+ }
+}
diff --git a/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/saslauth/package-info.java b/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/saslauth/package-info.java
new file mode 100644
index 0000000..31ab1aa
--- /dev/null
+++ b/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/saslauth/package-info.java
@@ -0,0 +1,32 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opendj3/legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opendj3/legal-notices/CDDLv1_0.txt. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2011 ForgeRock AS
+ */
+
+/**
+ * An example client application which performs SASL authentication to a
+ * directory server, displays a result, and closes the connection.
+ */
+package org.forgerock.opendj.examples.saslauth;
diff --git a/opendj3/src/main/docbkx/dev-guide/chap-authenticating.xml b/opendj3/src/main/docbkx/dev-guide/chap-authenticating.xml
index a2660f8..a57e9f6 100644
--- a/opendj3/src/main/docbkx/dev-guide/chap-authenticating.xml
+++ b/opendj3/src/main/docbkx/dev-guide/chap-authenticating.xml
@@ -190,6 +190,66 @@
<section xml:id="sasl-auth">
<title>SASL Authentication</title>
- <para>TODO</para>
+ <para>Simple Authentication and Security Layer (SASL) provides a way to
+ use other mechanisms for authentication such as Kerberos or Digest
+ authentication, or even to define your own authentication mechanism. The
+ directory server likely advertises supported SASL mechanisms in the root
+ DSE. The follow example shows how to search OpenDJ for supported SASL
+ mechanisms.</para>
+
+ <screen>$ ldapsearch
+ --port 1389
+ --bindDN "cn=Directory Manager"
+ --bindPassword password
+ --baseDN ""
+ --searchScope base
+ "(objectclass=*)" supportedSASLMechanisms
+dn:
+supportedSASLMechanisms: PLAIN
+supportedSASLMechanisms: EXTERNAL
+supportedSASLMechanisms: DIGEST-MD5
+supportedSASLMechanisms: CRAM-MD5</screen>
+
+ <para>Notice that neither the Kerberos (GSSAPI SASL) nor the Anonymous
+ mechanism is enabled by default, though OpenDJ implements both.</para>
+
+ <para>In order to use a SASL mechanism to bind, your program must set up
+ a <literal>SASLBindRequest</literal> and pass that to the
+ <literal>bind()</literal> method of the <literal>Connection</literal>.</para>
+
+ <para>This section shows an example using the SASL PLAIN mechanism, which
+ takes either a DN or a user ID to authenticate, with an optional DN or user
+ ID as the authorization ID that identifies the user who performs operations.
+ The SASL PLAIN mechanism itself does not secure the connection, so the
+ example uses StartTLS. The example is provided with the OpenDJ LDAP SDK
+ examples in
+ <filename>org.forgerock.opendj.examples.saslauth.Main.java</filename>.
+ The following excerpt shows the core of the bind process.</para>
+
+ <programlisting language="java">try
+{
+ final LDAPConnectionFactory factory =
+ new LDAPConnectionFactory(host, port, getTrustAllOptions());
+ connection = factory.getConnection();
+ PlainSASLBindRequest request = Requests.newPlainSASLBindRequest(
+ authcid, passwd.toCharArray());
+ if (authzid != null) request.setAuthorizationID(authzid);
+ connection.bind(request);
+ System.out.println("Authenticated as " + authcid + ".");
+}</programlisting>
+
+ <para>The implementation for <literal>getTrustAllOptions()</literal>, the
+ same as in the example above, sets up Start TLS. When you run this example
+ with both authorization and authentication IDs, <literal>authzid</literal>
+ and <literal>authcid</literal>, set to <literal>u:bjensen</literal> and
+ password <literal>hifalutin</literal>, the bind is successful, and the
+ program reaches the final line of the <literal>try</literal> block.</para>
+
+ <screen>Authenticated as u:bjensen.</screen>
+
+ <para>Behind the scenes, OpenDJ has the SASL PLAIN mechanism configured by
+ default to use the Exact Match Identity Mapper to look up user IDs as
+ <literal>uid</literal> values. If you use another directory server, you might
+ have to configure how it maps user IDs to user entries.</para>
</section>
</chapter>
\ No newline at end of file
--
Gitblit v1.10.0