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 2015 ForgeRock AS. 015 */ 016 017package org.forgerock.opendj.examples; 018 019import static org.forgerock.util.Utils.closeSilently; 020import org.forgerock.opendj.ldap.Connection; 021import org.forgerock.opendj.ldap.Filter; 022import org.forgerock.opendj.ldap.LDAPConnectionFactory; 023import org.forgerock.opendj.ldap.LdapException; 024import org.forgerock.opendj.ldap.ResultCode; 025import org.forgerock.opendj.ldap.SearchScope; 026import org.forgerock.opendj.ldap.requests.Requests; 027import org.forgerock.opendj.ldap.responses.BindResult; 028import org.forgerock.opendj.ldap.responses.Result; 029import org.forgerock.opendj.ldap.responses.SearchResultEntry; 030import org.forgerock.util.AsyncFunction; 031import org.forgerock.util.promise.ExceptionHandler; 032import org.forgerock.util.promise.Promise; 033import org.forgerock.util.promise.ResultHandler; 034 035import java.io.BufferedReader; 036import java.io.IOException; 037import java.io.InputStreamReader; 038import java.util.concurrent.CountDownLatch; 039 040/** 041 * An interactive command-line client that performs a search and simple bind 042 * using the asynchronous APIs. 043 * <br> 044 * The client prompts for email address and for a password, 045 * and then searches based on the email address, 046 * to bind as the user with the password. 047 * <br> 048 * If successful, the client displays the common name from the user's entry. 049 * <ul> 050 * <li>host - host name of the directory server</li> 051 * <li>port - port number of the directory server</li> 052 * <li>base-dn - base DN for the search, e.g. dc=example,dc=com</li> 053 * </ul> 054 * All arguments are required. 055 */ 056public final class SearchBindAsync { 057 /** Connection to the LDAP server. */ 058 private static Connection connection; 059 /** Email address provided by user. */ 060 private static String mail; 061 /** Password provided by user. */ 062 private static char[] password; 063 /** Bind DN returned by the search. */ 064 private static String bindDn; 065 /** Result for the operation. */ 066 private static int resultCode; 067 /** Count down latch to wait for modify operation to complete. */ 068 private static final CountDownLatch COMPLETION_LATCH = new CountDownLatch(1); 069 070 /** 071 * Prompts for email and password, search and bind, then display message. 072 * 073 * @param args 074 * The command line arguments: host, port, base-dn. 075 */ 076 public static void main(final String[] args) { 077 if (args.length != 3) { 078 System.err.println("Usage: host port base-dn"); 079 System.err.println("For example: localhost 1389 dc=example,dc=com"); 080 System.exit(1); 081 } 082 final String host = args[0]; 083 final int port = Integer.parseInt(args[1]); 084 final String baseDn = args[2]; 085 086 // Prompt for email address and password. 087 try { 088 mail = getInputLine("Email address:"); 089 password = getInputLine("Password:").toCharArray(); 090 } catch (IOException e) { 091 System.err.println(e.getMessage()); 092 System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); 093 return; 094 } 095 096 // Connect to the server, search for the user entry based on email address, and bind. 097 new LDAPConnectionFactory(host, port) 098 .getConnectionAsync() 099 .thenAsync(new AsyncFunction<Connection, SearchResultEntry, LdapException>() { 100 @Override 101 public Promise<SearchResultEntry, LdapException> apply(Connection connection) 102 throws LdapException { 103 SearchBindAsync.connection = connection; 104 return connection.searchSingleEntryAsync( 105 Requests.newSingleEntrySearchRequest( 106 baseDn, 107 SearchScope.WHOLE_SUBTREE, 108 Filter.equality("mail", mail).toString(), 109 "cn")); 110 } 111 }) 112 .thenAsync(new AsyncFunction<SearchResultEntry, BindResult, LdapException>() { 113 @Override 114 public Promise<BindResult, LdapException> apply(SearchResultEntry searchResultEntry) 115 throws LdapException { 116 SearchBindAsync.bindDn = searchResultEntry.getName().toString(); 117 return SearchBindAsync.connection.bindAsync( 118 Requests.newSimpleBindRequest(bindDn, password)); 119 } 120 }) 121 .thenOnResult(new ResultHandler<Result>() { 122 @Override 123 public void handleResult(Result result) { 124 if (result.getResultCode() == ResultCode.SUCCESS) { 125 System.out.println("Authenticated as " + SearchBindAsync.bindDn + "."); 126 } 127 resultCode = result.getResultCode().intValue(); 128 COMPLETION_LATCH.countDown(); 129 } 130 }) 131 .thenOnException(new ExceptionHandler<LdapException>() { 132 @Override 133 public void handleException(LdapException e) { 134 System.err.println(e.getMessage()); 135 resultCode = e.getResult().getResultCode().intValue(); 136 COMPLETION_LATCH.countDown(); 137 } 138 }); 139 140 try { 141 COMPLETION_LATCH.await(); 142 } catch (InterruptedException e) { 143 System.err.println(e.getMessage()); 144 System.exit(ResultCode.CLIENT_SIDE_USER_CANCELLED.intValue()); 145 return; 146 } 147 148 closeSilently(connection); 149 System.exit(resultCode); 150 } 151 152 /** 153 * Returns an input string from System.in, after prompting on System.out. 154 * <br> 155 * Note: The input is echoed to the display. 156 * 157 * @param prompt The prompt asking for input. 158 * @return An input string from System.in. 159 * @throws IOException Failed to read from System.in. 160 */ 161 private static String getInputLine(final String prompt) throws IOException { 162 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 163 System.out.print(prompt + " "); 164 return reader.readLine(); 165 } 166 167 /** 168 * Constructor not used. 169 */ 170 private SearchBindAsync() { 171 // Not used 172 } 173}