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