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