View Javadoc
1   /*
2    * The contents of this file are subject to the terms of the Common Development and
3    * Distribution License (the License). You may not use this file except in compliance with the
4    * License.
5    *
6    * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7    * specific language governing permission and limitations under the License.
8    *
9    * When distributing Covered Software, include this CDDL Header Notice in each file and include
10   * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11   * Header, with the fields enclosed by brackets [] replaced by your own identifying
12   * information: "Portions Copyright [year] [name of copyright owner]".
13   *
14   * Copyright 2015 ForgeRock AS.
15   */
16  
17  package org.forgerock.opendj.examples;
18  
19  import static org.forgerock.util.Utils.closeSilently;
20  import org.forgerock.opendj.ldap.Connection;
21  import org.forgerock.opendj.ldap.Filter;
22  import org.forgerock.opendj.ldap.LDAPConnectionFactory;
23  import org.forgerock.opendj.ldap.LdapException;
24  import org.forgerock.opendj.ldap.ResultCode;
25  import org.forgerock.opendj.ldap.SearchScope;
26  import org.forgerock.opendj.ldap.requests.Requests;
27  import org.forgerock.opendj.ldap.responses.BindResult;
28  import org.forgerock.opendj.ldap.responses.Result;
29  import org.forgerock.opendj.ldap.responses.SearchResultEntry;
30  import org.forgerock.util.AsyncFunction;
31  import org.forgerock.util.promise.ExceptionHandler;
32  import org.forgerock.util.promise.Promise;
33  import org.forgerock.util.promise.ResultHandler;
34  
35  import java.io.BufferedReader;
36  import java.io.IOException;
37  import java.io.InputStreamReader;
38  import java.util.concurrent.CountDownLatch;
39  
40  /**
41   * An interactive command-line client that performs a search and simple bind
42   * using the asynchronous APIs.
43   * <br>
44   * The client prompts for email address and for a password,
45   * and then searches based on the email address,
46   * to bind as the user with the password.
47   * <br>
48   * If successful, the client displays the common name from the user's entry.
49   * <ul>
50   * <li>host - host name of the directory server</li>
51   * <li>port - port number of the directory server</li>
52   * <li>base-dn - base DN for the search, e.g. dc=example,dc=com</li>
53   * </ul>
54   * All arguments are required.
55   */
56  public final class SearchBindAsync {
57      /** Connection to the LDAP server. */
58      private static Connection connection;
59      /** Email address provided by user. */
60      private static String mail;
61      /** Password provided by user. */
62      private static char[] password;
63      /** Bind DN returned by the search. */
64      private static String bindDn;
65      /** Result for the operation. */
66      private static int resultCode;
67      /** Count down latch to wait for modify operation to complete. */
68      private static final CountDownLatch COMPLETION_LATCH = new CountDownLatch(1);
69  
70      /**
71       * Prompts for email and password, search and bind, then display message.
72       *
73       * @param args
74       *            The command line arguments: host, port, base-dn.
75       */
76      public static void main(final String[] args) {
77          if (args.length != 3) {
78              System.err.println("Usage: host port base-dn");
79              System.err.println("For example: localhost 1389 dc=example,dc=com");
80              System.exit(1);
81          }
82          final String host   = args[0];
83          final int    port   = Integer.parseInt(args[1]);
84          final String baseDn = args[2];
85  
86          // Prompt for email address and password.
87          try {
88              mail = getInputLine("Email address:");
89              password = getInputLine("Password:").toCharArray();
90          } catch (IOException e) {
91              System.err.println(e.getMessage());
92              System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue());
93              return;
94          }
95  
96          // Connect to the server, search for the user entry based on email address, and bind.
97          new LDAPConnectionFactory(host, port)
98                  .getConnectionAsync()
99                  .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 }