View Javadoc
1   /*
2    * The contents of this file are subject to the terms of the Common Development and
3    * Distribution License (the License). You may not use this file except in compliance with the
4    * License.
5    *
6    * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7    * specific language governing permission and limitations under the License.
8    *
9    * When distributing Covered Software, include this CDDL Header Notice in each file and include
10   * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11   * Header, with the fields enclosed by brackets [] replaced by your own identifying
12   * information: "Portions Copyright [year] [name of copyright owner]".
13   *
14   * Copyright 2011-2015 ForgeRock AS.
15   */
16  
17  package org.forgerock.opendj.examples;
18  
19  import static org.forgerock.opendj.ldap.LDAPConnectionFactory.*;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.security.GeneralSecurityException;
24  
25  import javax.net.ssl.SSLContext;
26  import javax.net.ssl.TrustManager;
27  
28  import org.forgerock.opendj.ldap.Connection;
29  import org.forgerock.opendj.ldap.LdapException;
30  import org.forgerock.opendj.ldap.LDAPConnectionFactory;
31  import org.forgerock.opendj.ldap.ResultCode;
32  import org.forgerock.opendj.ldap.SSLContextBuilder;
33  import org.forgerock.opendj.ldap.TrustManagers;
34  import org.forgerock.util.Options;
35  
36  /**
37   * An example client application which performs simple authentication to a
38   * directory server. This example takes the following command line parameters:
39   * <ul>
40   * <li>host - host name of the directory server</li>
41   * <li>port - port number of the directory server, e.g. 1389, 1636</li>
42   * <li>bind-dn - DN of the user to authenticate</li>
43   * <li>bind-password - Password of the user to authenticate</li>
44   * <li>use-starttls - (Optional) connect with StartTLS</li>
45   * <li>use-ssl - (Optional) connect over SSL</li>
46   * </ul>
47   * The host, port, bind-dn, and bind-password arguments are required.
48   * The use-starttls and use-ssl arguments are optional and mutually exclusive.
49   * <p>
50   * If the server certificate is self-signed,
51   * or otherwise not trusted out-of-the-box,
52   * then set the trust store by using the JSSE system property
53   * {@code -Djavax.net.ssl.trustStore=/path/to/opendj/config/keystore}
54   * and the trust store password if necessary by using the JSSE system property
55   * {@code -Djavax.net.ssl.trustStorePassword=`cat /path/to/opendj/config/keystore.pin`}.
56   */
57  public final class SimpleAuth {
58  
59      /**
60       * Authenticate to the directory either over LDAP, over LDAPS, or using
61       * StartTLS.
62       *
63       * @param args
64       *            The command line arguments
65       */
66      public static void main(final String[] args) {
67          parseArgs(args);
68          // Connect and bind to the server, then close the connection.
69          if (useStartTLS) {
70              connectStartTLS();
71          } else if (useSSL) {
72              connectSSL();
73          } else {
74              connect();
75          }
76      }
77  
78      // --- JCite basic auth ---
79      /**
80       * Authenticate over LDAP.
81       */
82      private static void connect() {
83          final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port);
84          Connection connection = null;
85  
86          try {
87              connection = factory.getConnection();
88              connection.bind(bindDN, bindPassword.toCharArray());
89              System.out.println("Authenticated as " + bindDN + ".");
90          } catch (final LdapException e) {
91              System.err.println(e.getMessage());
92              System.exit(e.getResult().getResultCode().intValue());
93              return;
94          } finally {
95              if (connection != null) {
96                  connection.close();
97              }
98          }
99      }
100     // --- JCite basic auth ---
101 
102     // --- JCite trust options ---
103     /**
104      * For StartTLS and SSL the connection factory needs SSL context options.
105      * In the general case, a trust manager in the SSL context serves
106      * to check server certificates, and a key manager handles client keys
107      * when the server checks certificates from our client.
108      * <p>
109      * This sample expects a directory server
110      * that allows use of Start TLS on the LDAP port.
111      * This sample checks the server certificate,
112      * verifying that the certificate is currently valid,
113      * and that the host name of the server matches that of the certificate,
114      * based on a Java Key Store-format trust store.
115      * This sample does not present a client certificate.
116      *
117      * @param hostname Host name expected in the server certificate
118      * @param truststore Path to trust store file for the trust manager
119      * @param storepass Password for the trust store
120      * @return SSL context options
121      * @throws GeneralSecurityException Could not load the trust store
122      */
123     private static Options getTrustOptions(final String hostname,
124                                            final String truststore,
125                                            final String storepass)
126             throws GeneralSecurityException {
127         Options options = Options.defaultOptions();
128 
129         TrustManager trustManager = null;
130         try {
131             trustManager = TrustManagers.checkValidityDates(
132                     TrustManagers.checkHostName(hostname,
133                             TrustManagers.checkUsingTrustStore(
134                                     truststore, storepass.toCharArray(), null)));
135         } catch (IOException e) {
136             e.printStackTrace();
137             System.exit(1);
138         }
139 
140         if (trustManager != null) {
141             SSLContext sslContext = new SSLContextBuilder()
142                     .setTrustManager(trustManager).getSSLContext();
143             options.set(SSL_CONTEXT, sslContext);
144         }
145 
146         options.set(SSL_USE_STARTTLS, useStartTLS);
147 
148         return options;
149     }
150     // --- JCite trust options ---
151 
152     // --- JCite secure connect ---
153     /**
154      * Perform authentication over a secure connection.
155      */
156     private static void secureConnect() {
157         Connection connection = null;
158 
159         try {
160 
161             final LDAPConnectionFactory factory =
162                     new LDAPConnectionFactory(host, port,
163                             getTrustOptions(host, keystore, storepass));
164             connection = factory.getConnection();
165             connection.bind(bindDN, bindPassword.toCharArray());
166 
167             System.out.println("Authenticated as " + bindDN + ".");
168 
169         } catch (final LdapException e) {
170             System.err.println(e.getMessage());
171             System.exit(e.getResult().getResultCode().intValue());
172             return;
173         } catch (final GeneralSecurityException e) {
174             System.err.println(e.getMessage());
175             System.exit(ResultCode.CLIENT_SIDE_CONNECT_ERROR.intValue());
176         } finally {
177             if (connection != null) {
178                 connection.close();
179             }
180         }
181     }
182     // --- JCite secure connect ---
183 
184     // --- JCite trust all ---
185     /**
186      * For StartTLS and SSL the connection factory needs SSL context options. In
187      * the general case, a trust manager in the SSL context serves to check
188      * server certificates, and a key manager handles client keys when the
189      * server checks certificates from our client.
190      *
191      * OpenDJ directory server lets you install by default with a self-signed
192      * certificate that is not in the system trust store. To simplify this
193      * implementation trusts all server certificates.
194      */
195     private static Options getTrustAllOptions() throws GeneralSecurityException {
196         Options options = Options.defaultOptions();
197         SSLContext sslContext =
198                 new SSLContextBuilder().setTrustManager(TrustManagers.trustAll())
199                         .getSSLContext();
200         options.set(SSL_CONTEXT, sslContext);
201         options.set(SSL_USE_STARTTLS, useStartTLS);
202         return options;
203     }
204     // --- JCite trust all ---
205 
206     // --- JCite trust all connect ---
207     /**
208      * Perform authentication over a secure connection, trusting all server
209      * certificates.
210      */
211     private static void trustAllConnect() {
212         Connection connection = null;
213 
214         try {
215             final LDAPConnectionFactory factory =
216                     new LDAPConnectionFactory(host, port, getTrustAllOptions());
217             connection = factory.getConnection();
218             connection.bind(bindDN, bindPassword.toCharArray());
219             System.out.println("Authenticated as " + bindDN + ".");
220         } catch (final LdapException e) {
221             System.err.println(e.getMessage());
222             System.exit(e.getResult().getResultCode().intValue());
223             return;
224         } catch (final GeneralSecurityException e) {
225             System.err.println(e.getMessage());
226             System.exit(ResultCode.CLIENT_SIDE_CONNECT_ERROR.intValue());
227         } finally {
228             if (connection != null) {
229                 connection.close();
230             }
231         }
232     }
233     // --- JCite trust all connect ---
234 
235     /**
236      * Authenticate using StartTLS.
237      */
238     private static void connectStartTLS() {
239         secureConnect();
240         // trustAllConnect();
241     }
242 
243     /**
244      * Authenticate over LDAPS.
245      */
246     private static void connectSSL() {
247         secureConnect();
248         // trustAllConnect();
249     }
250 
251     private static String host;
252     private static int port;
253     private static String bindDN;
254     private static String bindPassword;
255     private static boolean useStartTLS;
256     private static boolean useSSL;
257     private static String keystore;
258     private static String storepass;
259 
260     /**
261      * Parse command line arguments.
262      *
263      * @param args
264      *            host port bind-dn bind-password [ use-starttls | use-ssl ]
265      */
266     private static void parseArgs(String[] args) {
267         if (args.length < 4 || args.length > 5) {
268             giveUp();
269         }
270 
271         host = args[0];
272         port = Integer.parseInt(args[1]);
273         bindDN = args[2];
274         bindPassword = args[3];
275 
276         if (args.length == 5) {
277             if ("use-starttls".equals(args[4].toLowerCase())) {
278                 useStartTLS = true;
279                 useSSL = false;
280             } else if ("use-ssl".equals(args[4].toLowerCase())) {
281                 useStartTLS = false;
282                 useSSL = true;
283             } else {
284                 giveUp();
285             }
286         }
287 
288         keystore = System.getProperty("javax.net.ssl.trustStore");
289         storepass = System.getProperty("javax.net.ssl.trustStorePassword");
290         if (keystore == null) { // Try to use Java's cacerts trust store.
291             keystore = System.getProperty("java.home") + File.separator
292                     + "lib" + File.separator
293                     + "security" + File.separator
294                     + "cacerts";
295             storepass = "changeit"; // Default password
296         }
297     }
298 
299     private static void giveUp() {
300         printUsage();
301         System.exit(1);
302     }
303 
304     private static void printUsage() {
305         System.err.println("Usage: host port bind-dn bind-password [ use-starttls | use-ssl ]");
306         System.err.println("\thost, port, bind-dn, and bind-password arguments are required.");
307         System.err.println("\tuse-starttls and use-ssl are optional and mutually exclusive.");
308         System.err.println("\tOptionally set javax.net.ssl.trustStore and javax.net.ssl.trustStorePassword.");
309     }
310 
311     private SimpleAuth() {
312         // Not used.
313     }
314 }