001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2011-2015 ForgeRock AS. 015 */ 016 017package org.forgerock.opendj.examples; 018 019import static org.forgerock.opendj.ldap.LDAPConnectionFactory.*; 020 021import java.io.File; 022import java.io.IOException; 023import java.security.GeneralSecurityException; 024 025import javax.net.ssl.SSLContext; 026import javax.net.ssl.TrustManager; 027 028import org.forgerock.opendj.ldap.Connection; 029import org.forgerock.opendj.ldap.LdapException; 030import org.forgerock.opendj.ldap.LDAPConnectionFactory; 031import org.forgerock.opendj.ldap.ResultCode; 032import org.forgerock.opendj.ldap.SSLContextBuilder; 033import org.forgerock.opendj.ldap.TrustManagers; 034import org.forgerock.util.Options; 035 036/** 037 * An example client application which performs simple authentication to a 038 * directory server. This example takes the following command line parameters: 039 * <ul> 040 * <li>host - host name of the directory server</li> 041 * <li>port - port number of the directory server, e.g. 1389, 1636</li> 042 * <li>bind-dn - DN of the user to authenticate</li> 043 * <li>bind-password - Password of the user to authenticate</li> 044 * <li>use-starttls - (Optional) connect with StartTLS</li> 045 * <li>use-ssl - (Optional) connect over SSL</li> 046 * </ul> 047 * The host, port, bind-dn, and bind-password arguments are required. 048 * The use-starttls and use-ssl arguments are optional and mutually exclusive. 049 * <p> 050 * If the server certificate is self-signed, 051 * or otherwise not trusted out-of-the-box, 052 * then set the trust store by using the JSSE system property 053 * {@code -Djavax.net.ssl.trustStore=/path/to/opendj/config/keystore} 054 * and the trust store password if necessary by using the JSSE system property 055 * {@code -Djavax.net.ssl.trustStorePassword=`cat /path/to/opendj/config/keystore.pin`}. 056 */ 057public final class SimpleAuth { 058 059 /** 060 * Authenticate to the directory either over LDAP, over LDAPS, or using 061 * StartTLS. 062 * 063 * @param args 064 * The command line arguments 065 */ 066 public static void main(final String[] args) { 067 parseArgs(args); 068 // Connect and bind to the server, then close the connection. 069 if (useStartTLS) { 070 connectStartTLS(); 071 } else if (useSSL) { 072 connectSSL(); 073 } else { 074 connect(); 075 } 076 } 077 078 // --- JCite basic auth --- 079 /** 080 * Authenticate over LDAP. 081 */ 082 private static void connect() { 083 final LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port); 084 Connection connection = null; 085 086 try { 087 connection = factory.getConnection(); 088 connection.bind(bindDN, bindPassword.toCharArray()); 089 System.out.println("Authenticated as " + bindDN + "."); 090 } catch (final LdapException e) { 091 System.err.println(e.getMessage()); 092 System.exit(e.getResult().getResultCode().intValue()); 093 return; 094 } finally { 095 if (connection != null) { 096 connection.close(); 097 } 098 } 099 } 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}