001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2011-2014 ForgeRock AS 025 */ 026 027package org.forgerock.opendj.examples; 028 029import java.io.File; 030import java.io.IOException; 031import java.security.GeneralSecurityException; 032 033import javax.net.ssl.SSLContext; 034import javax.net.ssl.TrustManager; 035 036import org.forgerock.opendj.ldap.Connection; 037import org.forgerock.opendj.ldap.LdapException; 038import org.forgerock.opendj.ldap.LDAPConnectionFactory; 039import org.forgerock.opendj.ldap.LDAPOptions; 040import org.forgerock.opendj.ldap.ResultCode; 041import org.forgerock.opendj.ldap.SSLContextBuilder; 042import org.forgerock.opendj.ldap.TrustManagers; 043 044/** 045 * An example client application which performs simple authentication to a 046 * directory server. This example takes the following command line parameters: 047 * <ul> 048 * <li>host - host name of the directory server</li> 049 * <li>port - port number of the directory server, e.g. 1389, 1636</li> 050 * <li>bind-dn - DN of the user to authenticate</li> 051 * <li>bind-password - Password of the user to authenticate</li> 052 * <li>use-starttls - (Optional) connect with StartTLS</li> 053 * <li>use-ssl - (Optional) connect over SSL</li> 054 * </ul> 055 * The host, port, bind-dn, and bind-password arguments are required. 056 * The use-starttls and use-ssl arguments are optional and mutually exclusive. 057 * <p> 058 * If the server certificate is self-signed, 059 * or otherwise not trusted out-of-the-box, 060 * then set the trust store by using the JSSE system property 061 * {@code -Djavax.net.ssl.trustStore=/path/to/opendj/config/keystore} 062 * and the trust store password if necessary by using the JSSE system property 063 * {@code -Djavax.net.ssl.trustStorePassword=`cat /path/to/opendj/config/keystore.pin`}. 064 */ 065public final class SimpleAuth { 066 067 /** 068 * Authenticate to the directory either over LDAP, over LDAPS, or using 069 * StartTLS. 070 * 071 * @param args 072 * The command line arguments 073 */ 074 public static void main(final String[] args) { 075 parseArgs(args); 076 // Connect and bind to the server, then close the connection. 077 if (useStartTLS) { 078 connectStartTLS(); 079 } else if (useSSL) { 080 connectSSL(); 081 } else { 082 connect(); 083 } 084 } 085 086 // --- JCite basic auth --- 087 /** 088 * Authenticate over LDAP. 089 */ 090 private static void connect() { 091 final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); 092 Connection connection = null; 093 094 try { 095 connection = factory.getConnection(); 096 connection.bind(bindDN, bindPassword.toCharArray()); 097 System.out.println("Authenticated as " + bindDN + "."); 098 } catch (final LdapException e) { 099 System.err.println(e.getMessage()); 100 System.exit(e.getResult().getResultCode().intValue()); 101 return; 102 } finally { 103 if (connection != null) { 104 connection.close(); 105 } 106 } 107 } 108 // --- JCite basic auth --- 109 110 // --- JCite trust options --- 111 /** 112 * For StartTLS and SSL the connection factory needs SSL context options. 113 * In the general case, a trust manager in the SSL context serves 114 * to check server certificates, and a key manager handles client keys 115 * when the server checks certificates from our client. 116 * <p> 117 * This sample expects a directory server 118 * that allows use of Start TLS on the LDAP port. 119 * This sample checks the server certificate, 120 * verifying that the certificate is currently valid, 121 * and that the host name of the server matches that of the certificate, 122 * based on a Java Key Store-format trust store. 123 * This sample does not present a client certificate. 124 * 125 * @param hostname Host name expected in the server certificate 126 * @param truststore Path to trust store file for the trust manager 127 * @param storepass Password for the trust store 128 * @return SSL context options 129 * @throws GeneralSecurityException Could not load the trust store 130 */ 131 private static LDAPOptions getTrustOptions(final String hostname, 132 final String truststore, 133 final String storepass) 134 throws GeneralSecurityException { 135 LDAPOptions lo = new LDAPOptions(); 136 137 TrustManager trustManager = null; 138 try { 139 trustManager = TrustManagers.checkValidityDates( 140 TrustManagers.checkHostName(hostname, 141 TrustManagers.checkUsingTrustStore( 142 truststore, storepass.toCharArray(), null))); 143 } catch (IOException e) { 144 e.printStackTrace(); 145 System.exit(1); 146 } 147 148 if (trustManager != null) { 149 SSLContext sslContext = new SSLContextBuilder() 150 .setTrustManager(trustManager).getSSLContext(); 151 lo.setSSLContext(sslContext); 152 } 153 154 lo.setUseStartTLS(useStartTLS); 155 156 return lo; 157 } 158 // --- JCite trust options --- 159 160 // --- JCite secure connect --- 161 /** 162 * Perform authentication over a secure connection. 163 */ 164 private static void secureConnect() { 165 Connection connection = null; 166 167 try { 168 169 final LDAPConnectionFactory factory = 170 new LDAPConnectionFactory(host, port, 171 getTrustOptions(host, keystore, storepass)); 172 connection = factory.getConnection(); 173 connection.bind(bindDN, bindPassword.toCharArray()); 174 175 System.out.println("Authenticated as " + bindDN + "."); 176 177 } catch (final LdapException e) { 178 System.err.println(e.getMessage()); 179 System.exit(e.getResult().getResultCode().intValue()); 180 return; 181 } catch (final GeneralSecurityException e) { 182 System.err.println(e.getMessage()); 183 System.exit(ResultCode.CLIENT_SIDE_CONNECT_ERROR.intValue()); 184 } finally { 185 if (connection != null) { 186 connection.close(); 187 } 188 } 189 } 190 // --- JCite secure connect --- 191 192 // --- JCite trust all --- 193 /** 194 * For StartTLS and SSL the connection factory needs SSL context options. In 195 * the general case, a trust manager in the SSL context serves to check 196 * server certificates, and a key manager handles client keys when the 197 * server checks certificates from our client. 198 * 199 * OpenDJ directory server lets you install by default with a self-signed 200 * certificate that is not in the system trust store. To simplify this 201 * implementation trusts all server certificates. 202 */ 203 private static LDAPOptions getTrustAllOptions() throws GeneralSecurityException { 204 LDAPOptions lo = new LDAPOptions(); 205 SSLContext sslContext = 206 new SSLContextBuilder().setTrustManager(TrustManagers.trustAll()) 207 .getSSLContext(); 208 lo.setSSLContext(sslContext); 209 lo.setUseStartTLS(useStartTLS); 210 return lo; 211 } 212 // --- JCite trust all --- 213 214 // --- JCite trust all connect --- 215 /** 216 * Perform authentication over a secure connection, trusting all server 217 * certificates. 218 */ 219 private static void trustAllConnect() { 220 Connection connection = null; 221 222 try { 223 final LDAPConnectionFactory factory = 224 new LDAPConnectionFactory(host, port, getTrustAllOptions()); 225 connection = factory.getConnection(); 226 connection.bind(bindDN, bindPassword.toCharArray()); 227 System.out.println("Authenticated as " + bindDN + "."); 228 } catch (final LdapException e) { 229 System.err.println(e.getMessage()); 230 System.exit(e.getResult().getResultCode().intValue()); 231 return; 232 } catch (final GeneralSecurityException e) { 233 System.err.println(e.getMessage()); 234 System.exit(ResultCode.CLIENT_SIDE_CONNECT_ERROR.intValue()); 235 } finally { 236 if (connection != null) { 237 connection.close(); 238 } 239 } 240 } 241 // --- JCite trust all connect --- 242 243 /** 244 * Authenticate using StartTLS. 245 */ 246 private static void connectStartTLS() { 247 secureConnect(); 248 // trustAllConnect(); 249 } 250 251 /** 252 * Authenticate over LDAPS. 253 */ 254 private static void connectSSL() { 255 secureConnect(); 256 // trustAllConnect(); 257 } 258 259 private static String host; 260 private static int port; 261 private static String bindDN; 262 private static String bindPassword; 263 private static boolean useStartTLS; 264 private static boolean useSSL; 265 private static String keystore; 266 private static String storepass; 267 268 /** 269 * Parse command line arguments. 270 * 271 * @param args 272 * host port bind-dn bind-password [ use-starttls | use-ssl ] 273 */ 274 private static void parseArgs(String[] args) { 275 if (args.length < 4 || args.length > 5) { 276 giveUp(); 277 } 278 279 host = args[0]; 280 port = Integer.parseInt(args[1]); 281 bindDN = args[2]; 282 bindPassword = args[3]; 283 284 if (args.length == 5) { 285 if ("use-starttls".equals(args[4].toLowerCase())) { 286 useStartTLS = true; 287 useSSL = false; 288 } else if ("use-ssl".equals(args[4].toLowerCase())) { 289 useStartTLS = false; 290 useSSL = true; 291 } else { 292 giveUp(); 293 } 294 } 295 296 keystore = System.getProperty("javax.net.ssl.trustStore"); 297 storepass = System.getProperty("javax.net.ssl.trustStorePassword"); 298 if (keystore == null) { // Try to use Java's cacerts trust store. 299 keystore = System.getProperty("java.home") + File.separator 300 + "lib" + File.separator 301 + "security" + File.separator 302 + "cacerts"; 303 storepass = "changeit"; // Default password 304 } 305 } 306 307 private static void giveUp() { 308 printUsage(); 309 System.exit(1); 310 } 311 312 private static void printUsage() { 313 System.err.println("Usage: host port bind-dn bind-password [ use-starttls | use-ssl ]"); 314 System.err.println("\thost, port, bind-dn, and bind-password arguments are required."); 315 System.err.println("\tuse-starttls and use-ssl are optional and mutually exclusive."); 316 System.err.println("\tOptionally set javax.net.ssl.trustStore and javax.net.ssl.trustStorePassword."); 317 } 318 319 private SimpleAuth() { 320 // Not used. 321 } 322}