001 /*
002 * Copyright 2015-2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2015-2016 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.util.json;
022
023
024
025 import java.io.BufferedReader;
026 import java.io.File;
027 import java.io.FileInputStream;
028 import java.io.FileReader;
029 import java.io.InputStream;
030 import java.io.IOException;
031 import java.util.Arrays;
032 import java.util.HashSet;
033
034 import com.unboundid.ldap.sdk.BindRequest;
035 import com.unboundid.ldap.sdk.LDAPConnection;
036 import com.unboundid.ldap.sdk.LDAPConnectionPool;
037 import com.unboundid.ldap.sdk.LDAPException;
038 import com.unboundid.ldap.sdk.ResultCode;
039 import com.unboundid.ldap.sdk.ServerSet;
040 import com.unboundid.util.ByteStringBuffer;
041 import com.unboundid.util.Debug;
042 import com.unboundid.util.NotMutable;
043 import com.unboundid.util.StaticUtils;
044 import com.unboundid.util.ThreadSafety;
045 import com.unboundid.util.ThreadSafetyLevel;
046
047 import static com.unboundid.util.json.JSONMessages.*;
048
049
050
051 /**
052 * This class provides a utility that may be used to obtain information that may
053 * be used to create LDAP connections to one or more servers from a definition
054 * contained in a JSON object. This makes it easier to create applications that
055 * provide the information necessary for creating LDAP connections and
056 * connection pools in a JSON-formatted configuration file.
057 * <BR><BR>
058 * The JSON-based specification is organized into five sections:
059 * <OL>
060 * <LI>
061 * A "server-details" section that provides information about the directory
062 * server(s) to access. The specification supports accessing a single
063 * server, as well as a number of schemes for establishing connections
064 * across multiple servers.
065 * </LI>
066 * <LI>
067 * A "communication-security" section that provides information that may be
068 * used to secure communication using SSL or StartTLS.
069 * </LI>
070 * <LI>
071 * A "connection-options" section that can be used customize a number of
072 * connection-related options, like connect and response timeouts, whether
073 * to follow referrals, whether to retrieve schema from the backend server
074 * for client-side use, and whether to use synchronous mode for more
075 * efficient communication if connections will not be used in an
076 * asynchronous manner.
077 * </LI>
078 * <LI>
079 * An "authentication-details" section that provides information for
080 * authenticating connections using a number of mechanisms.
081 * </LI>
082 * <LI>
083 * A "connection-pool-options" section that provides information to use to
084 * customize the behavior to use for connection pools created from this
085 * specification.
086 * </LI>
087 * </OL>
088 * Each of these sections will be described in more detail below.
089 * <BR><BR>
090 * <H2>The "server-details" Section</H2>
091 * The JSON object that comprises the LDAP connection details specification must
092 * have a top-level "server-details" field whose value is a JSON object that
093 * provides information about the server(s) to which connections may be
094 * established. The value of the "server-details" field must itself be a JSON
095 * object, and that object must have exactly one field, which depends on the
096 * mechanism that the LDAP SDK should use to select the target directory
097 * servers.
098 * <BR><BR>
099 * <B>The "server-details" Section for Connecting to a Single Server</B>
100 * <BR>
101 * When establishing a connection to a single server, the "server-details"
102 * value should be a JSON object that contains a "single-server" field whose
103 * value is a JSON object with "address" and "port" fields. For example, the
104 * following is a valid specification that may be used to establish connections
105 * to the server at ldap.example.com on port 389:
106 * <PRE>
107 * {
108 * "server-details":
109 * {
110 * "single-server":
111 * {
112 * "address":"ldap.example.com",
113 * "port":389
114 * }
115 * }
116 * }
117 * </PRE>
118 * <BR>
119 * <B>The "server-details" Section for Selecting from a Set of Servers in a
120 * Round-Robin Manner</B>
121 * <BR>
122 * If you have a set of servers that you want to connect to in a round-robin
123 * manner (in which the LDAP SDK will maintain a circular list of servers and
124 * each new connection will go to the next server in the list), the
125 * "server-details" value should be a JSON object that contains a
126 * "round-robin-set" field whose value is a JSON object that contains a "server"
127 * field with an array of JSON objects, each of which contains "address" and
128 * "port" fields for a target server. For example, the following is a valid
129 * specification that may be used to establish connections across the servers
130 * ldap1.example.com, ldap2.example.com, and ldap3.example.com, all on port 389:
131 * <PRE>
132 * {
133 * "server-details":
134 * {
135 * "round-robin-set":
136 * {
137 * "servers":
138 * [
139 * {
140 * "address":"ldap1.example.com",
141 * "port":389
142 * },
143 * {
144 * "address":"ldap2.example.com",
145 * "port":389
146 * },
147 * {
148 * "address":"ldap2.example.com",
149 * "port":389
150 * }
151 * ]
152 * }
153 * }
154 * }
155 * </PRE>
156 * <BR>
157 * <B>The "server-details" Section for Selecting from a Set of Servers in a
158 * Fewest Connections Manner</B>
159 * <BR>
160 * If you have a set of servers that you want to connect to in a manner that
161 * selects the server with the fewest established connections (at least
162 * connections created from this specification), the "server-details" value
163 * should be a JSON object that contains a "fewest-connections-set" field whose
164 * value is a JSON object that contains a "server" field with an array of JSON
165 * objects, each of which contains "address" and "port" fields for a target
166 * server. For example, the following is a valid specification that may be used
167 * to establish connections across the servers ldap1.example.com,
168 * ldap2.example.com, and ldap3.example.com, all on port 389:
169 * <PRE>
170 * {
171 * "server-details":
172 * {
173 * "fewest-connections-set":
174 * {
175 * "servers":
176 * [
177 * {
178 * "address":"ldap1.example.com",
179 * "port":389
180 * },
181 * {
182 * "address":"ldap2.example.com",
183 * "port":389
184 * },
185 * {
186 * "address":"ldap2.example.com",
187 * "port":389
188 * }
189 * ]
190 * }
191 * }
192 * }
193 * </PRE>
194 * <BR>
195 * <B>The "server-details" Section for Selecting from a Set of Servers in a
196 * Fastest Connect Manner</B>
197 * <BR>
198 * If you have a set of servers that you want to connect to in a manner that
199 * attempts to minimize the time required to establish new connections (by
200 * simultaneously attempting to create connections to every server in the set
201 * and taking the first connection to be established), the "server-details"
202 * value should be a JSON object that contains a "fastest-connect-set" field
203 * whose value is a JSON object that contains a "server" field with an array of
204 * JSON objects, each of which contains "address" and "port" fields for a target
205 * server. For example, the following is a valid specification that may be used
206 * to establish connections across the servers ldap1.example.com,
207 * ldap2.example.com, and ldap3.example.com, all on port 389:
208 * <PRE>
209 * {
210 * "server-details":
211 * {
212 * "fastest-connect-set":
213 * {
214 * "servers":
215 * [
216 * {
217 * "address":"ldap1.example.com",
218 * "port":389
219 * },
220 * {
221 * "address":"ldap2.example.com",
222 * "port":389
223 * },
224 * {
225 * "address":"ldap2.example.com",
226 * "port":389
227 * }
228 * ]
229 * }
230 * }
231 * }
232 * </PRE>
233 * <BR>
234 * <B>The "server-details" Section for Selecting from a Set of Servers in a
235 * Failover Manner</B>
236 * <BR>
237 * If you have a set of servers that you want to connect to in a manner that
238 * attempts to consistently establish connections to the same server (as long as
239 * it is available, and use a consistent failover order if the preferred server
240 * isn't available), the "server-details" value should be a JSON object that
241 * contains a "failover-set" field whose value is a JSON object that contains a
242 * "failover-order" field that provides a list of the details to use in order
243 * to establish the connections. For example, the following is a valid
244 * specification that may be used to always try to establish connections to
245 * ldap1.example.com:389, then try ldap2.example.com:389, and then try
246 * ldap3.example.com:389:
247 * <PRE>
248 * {
249 * "server-details":
250 * {
251 * "failover-set":
252 * {
253 * "failover-order":
254 * [
255 * {
256 * "single-server":
257 * {
258 * "address":"ldap1.example.com",
259 * "port":389
260 * }
261 * },
262 * {
263 * "single-server":
264 * {
265 * "address":"ldap2.example.com",
266 * "port":389
267 * }
268 * },
269 * {
270 * "single-server":
271 * {
272 * "address":"ldap2.example.com",
273 * "port":389
274 * }
275 * }
276 * ]
277 * }
278 * }
279 * }
280 * </PRE>
281 * The failover set actually has the ability to perform failover across any kind
282 * of set. This is a powerful capability that can be useful to define a
283 * hierarchy of sets, for example for sets referring to servers in different
284 * data centers (e.g., to prefer connecting to one of the servers in the local
285 * data center over servers in a remote data center). For example, the
286 * following is a valid specification that may be used to connect to the server
287 * with the fewest connections in the east data center, but if no east servers
288 * are available then it will fail over to select the server with the fewest
289 * connections in the west data center:
290 * <PRE>
291 * {
292 * "server-details":
293 * {
294 * "failover-set":
295 * {
296 * "failover-order":
297 * [
298 * {
299 * "fewest-connections-set":
300 * {
301 * "servers":
302 * [
303 * {
304 * "address":"ldap1.east.example.com",
305 * "port":389
306 * },
307 * {
308 * "address":"ldap2.east.example.com",
309 * "port":389
310 * }
311 * ]
312 * }
313 * },
314 * {
315 * "fewest-connections-set":
316 * {
317 * "servers":
318 * [
319 * {
320 * "address":"ldap1.west.example.com",
321 * "port":389
322 * },
323 * {
324 * "address":"ldap2.west.example.com",
325 * "port":389
326 * }
327 * ]
328 * }
329 * }
330 * ]
331 * }
332 * }
333 * }
334 * </PRE>
335 * For connections that are part of a connection pool, failover sets have the
336 * ability to assign a different maximum connection age to connections created
337 * to a non-preferred server. This can help allow failover connections to be
338 * migrated back to the preferred server more quickly once that server is
339 * available again. If you wish to specify an alternate maximum connection age
340 * for connections to a non-preferred server, you may include the
341 * "maximum-failover-connection-age-millis" field in the "failover-set" object.
342 * The value of this field should be a number that is greater than zero to
343 * specify the maximum age (in milliseconds) for those connections, or a value
344 * of zero to indicate that they should not be subject to a maximum age. If
345 * this field is not present, then these connections will be assigned the
346 * default maximum connection age configured for the pool.
347 * <BR><BR>
348 * <H2>The "communication-security" Section</H2>
349 * This section may be used to provide information about the type of security to
350 * use to protect communication with directory servers. If the specification
351 * includes information about multiple servers, then all servers will use the
352 * same type of security.
353 * <BR><BR>
354 * If present, the "communication-security" field should have a value that is a
355 * JSON object. This object must have a "security-type" field with one of the
356 * following values:
357 * <UL>
358 * <LI>
359 * "none" -- Indicates that no communication security should be used. The
360 * communication will not be encrypted.
361 * </LI>
362 * <LI>
363 * "SSL" -- Indicates that all communication should be encrypted with the
364 * SSL (secure sockets layer) protocol, or more likely its more secure
365 * successor TLS (transport-layer security) protocol. You can also specify
366 * a value of "TLS" to use this type of security.
367 * </LI>
368 * <LI>
369 * "StartTLS" -- Indicates that the connection will be initially established
370 * in a non-secure manner, but will be immediately secured with the StartTLS
371 * extended operation.
372 * </LI>
373 * </UL>
374 * If you do not wish to use any form of communication security, then the
375 * "security-type" field is the only one that should be present. For example,
376 * the following is a valid specification that will use unencrypted
377 * communication to the server ldap.example.com on port 389:
378 * <PRE>
379 * {
380 * "server-details":
381 * {
382 * "single-server":
383 * {
384 * "address":"ldap.example.com",
385 * "port":389
386 * }
387 * },
388 * "communication-security":
389 * {
390 * "security-type":"none"
391 * }
392 * }
393 * </PRE>
394 * <BR>
395 * If you wish to secure the communication with either SSL or StartTLS, then
396 * there are a number of other options that may be specified using fields in the
397 * "communication-security" object. Those options fall into two basic
398 * categories: fields that provide information about how the client should
399 * determine whether to trust the certificate presented by the server, and
400 * fields that provide information about whether the client should present its
401 * own certificate to the server. The fields related to client trust include:
402 * <UL>
403 * <LI>
404 * "trust-all-certificates" -- Indicates whether the client should blindly
405 * trust any certificate that the server presents to it. Using blind trust
406 * is convenient for testing and troubleshooting purposes, but is not
407 * recommended for production use because it can leave the communication
408 * susceptible to man-in-the-middle attacks. If this field is present, then
409 * it should have a boolean value. If it is not present, a default value
410 * of {@code false} will be assumed. If it is present with a value of
411 * {@code true}, then the "trust-store-file", "trust-store-type",
412 * "trust-store-pin", and "trust-store-pin-file" fields should not be used.
413 * </LI>
414 * <LI>
415 * "trust-store-file" -- Specifies the path to a trust store file (in JKS
416 * or PKCS#12 format). If this is present, then the presented certificate
417 * will only be trusted if the trust store file contains information about
418 * all of the issuers in the certificate chain.
419 * </LI>
420 * <LI>
421 * "trust-store-type" -- Indicates the format for the trust store file.
422 * If this is present, then its value should be a string that is either
423 * "JKS" or "PKCS12". If it is not present, then a default trust store type
424 * of "JKS" will be assumed.
425 * </LI>
426 * <LI>
427 * "trust-store-pin" -- Specifies the PIN that should be used to access the
428 * contents of the trust store. If this field is present, then its value
429 * should be a string that is the clear-text PIN. If it is not present,
430 * then the PIN may be read from a file specified using the
431 * "trust-store-pin-file" field. If neither the "trust-store-pin" field nor
432 * the "trust-store-pin-file" field is present, then no PIN will be used
433 * when attempting to access the trust store (and in many cases, no trust
434 * store PIN will be required).
435 * </LI>
436 * <LI>
437 * "trust-store-pin-file" -- Specifies the path to a file that contains the
438 * PIN to use to access the contents of the trust store. If this field is
439 * present, then its value must be the path to a file containing a single
440 * line, which is the clear-text PIN. If it is not present, then the PIN
441 * may be obtained from the "trust-store-pin" field. If neither the
442 * "trust-store-pin" field nor the "trust-store-pin-file" field is present,
443 * then no PIN will be used when attempting to access the trust store (and
444 * in many cases, no trust store PIN will be required).
445 * </LI>
446 * <LI>
447 * "trust-expired-certificates" -- Indicates whether the client should
448 * trust certificates that are not yet valid or that have expired. If this
449 * field is present, then its value must be a boolean. If the value is
450 * {@code true}, then the certificate validity dates will not be taken into
451 * consideration when deciding whether to trust a certificate. If the value
452 * is {@code false}, then any certificate whose validity window does not
453 * include the current time will not be trusted (even if
454 * "trust-all-certificates" is {@code true}). If this field is not present,
455 * then a default of {@code false} will be assumed.
456 * </LI>
457 * <LI>
458 * "verify-address-in-certificate" -- Indicates whether the client should
459 * examine the information contained in the certificate to verify that the
460 * address the client used to connect to the server matches address
461 * information contained in the certificate (whether in the CN attribute of
462 * the certificate's subject, or in a subjectAltName extension of type
463 * dNSName, uniformResourceIdentifier, or iPAddress). If this field is
464 * present, then its value must be a boolean. If it is absent, then a
465 * default value of {@code false} will be assumed.
466 * </LI>
467 * </UL>
468 * If none of the above fields are provided, then the JVM's default trust
469 * mechanism will be used. This will generally only trust certificates signed
470 * by a well-known certification authority.
471 * <BR><BR>
472 * The fields related to presenting a client certificate include:
473 * <UL>
474 * <LI>
475 * "key-store-file" -- Specifies the path to a key store file (in JKS or
476 * PKCS#12 format) that contains the certificate that the client should
477 * present to the server. If this is present, then the value must be a
478 * string that is the path to the key store file. If it is not present,
479 * then no key store file will be used.
480 * </LI>
481 * <LI>
482 * "key-store-type" -- Specifies the type of key store that should be used.
483 * If this is present, then its value must be a string, and that string
484 * should be "JKS" or "PKCS12" (if a "key-store-file" value is present), or
485 * "PKCS11" (if the client certificate is contained in a security module
486 * accessible via the PKCS#11 API. If this field is not present but a
487 * "key-store-file" value is provided, then a default value of "JKS" will be
488 * assumed.
489 * </LI>
490 * <LI>
491 * "key-store-pin" -- Specifies the PIN that should be used to access the
492 * contents of the key store. If this field is present, then its value
493 * should be a string that is the clear-text PIN. If it is not present,
494 * then the PIN may be read from a file specified using the
495 * "key-store-pin-file" field. If neither the "key-store-pin" field nor the
496 * "key-store-pin-file" field is present, then no PIN will be used when
497 * attempting to access the key store (although key stores generally require
498 * a PIN in order to access private key information).
499 * </LI>
500 * <LI>
501 * "key-store-pin-file" -- Specifies the path to a file containing the PIN
502 * that should be used to access the contents of the key store. If this
503 * field is present, then its value should be the path to a file containing
504 * the clear-text PIN. If it is not present, then the PIN may be obtained
505 * from the "key-store-pin" field. If neither the "key-store-pin" field nor
506 * the "key-store-pin-file" field is present, then no PIN will be used when
507 * attempting to access the key store (although key stores generally require
508 * a PIN in order to access private key information).
509 * </LI>
510 * <LI>
511 * "client-certificate-alias" -- Specifies the alias (also known as the
512 * nickname) of the client certificate that should be presented to the
513 * directory server. If this field is present, then its value should be a
514 * string that is the alias for a valid certificate that exists in the
515 * key store. If this field is not present, then the JVM will automatically
516 * attempt to select a suitable client certificate.
517 * </LI>
518 * </UL>
519 * If none of the above fields are provided, then the client will not attempt to
520 * present a certificate to the server.
521 * <BR><BR>
522 * The following example demonstrates a simple specification that can be used to
523 * establish SSL-based connections to a single server. The client will use a
524 * trust store to determine whether to trust the certificate presented by the
525 * server, and will not attempt to present its own certificate to the server.
526 * <PRE>
527 * {
528 * "server-details":
529 * {
530 * "single-server":
531 * {
532 * "address":"ldap.example.com",
533 * "port":636
534 * }
535 * },
536 * "communication-security":
537 * {
538 * "security-type":"SSL",
539 * "trust-store-file":"/path/to/trust-store.jks",
540 * "trust-store-type":"JKS",
541 * "verify-address-in-certificate":true
542 * }
543 * }
544 * </PRE>
545 * <BR>
546 * The "communication-security" field is optional, and if it is omitted from the
547 * specification then it will be equivalent to including it with a
548 * "security-type" value of "none".
549 * <BR><BR>
550 * <H2>The "connection-options" Section</H2>
551 * The "connection-options" section may be used to provide information about a
552 * number of settings that may be used in the course of establishing a
553 * connection, or that may affect the behavior of the connection. The value
554 * of the "connection-options" field must be a JSON object, and the following
555 * fields may appear in that object:
556 * <UL>
557 * <LI>
558 * "connect-timeout-millis" -- Specifies the maximum length of time (in
559 * milliseconds) that a connection attempt may block while waiting for the
560 * connection to be established. If this field is present, then its value
561 * must be a positive integer to specify the timeout, or a value of zero to
562 * indicate that no timeout should be enforced by the LDAP SDK. Note that
563 * the underlying operating system may enforce its own connect timeout, and
564 * if that value is smaller than the LDAP SDK timeout then the operating
565 * system's timeout value will be used. If this field is not present, then
566 * a default of 60000 (1 minute) will be used.
567 * </LI>
568 * <LI>
569 * "default-response-timeout-millis" -- Specifies the default timeout (in
570 * milliseconds) that will be used when waiting for a response to a request
571 * sent to the server. If this field is present, then its value must be a
572 * positive integer to specify the timeout, or a value of zero to indicate
573 * that no timeout should be enforced. If this field is not present, then a
574 * default of 300000 (5 minutes) will be used. Note that this default
575 * response timeout can be overridden on a per-request basis using the
576 * {@code setResponseTimeoutMillis} method provided by the request object.
577 * </LI>
578 * <LI>
579 * "follow-referrals" -- Indicates whether the LDAP SDK should automatically
580 * attempt to follow any referrals that are returned during processing. If
581 * this field is present, the value should be a boolean. If it is absent,
582 * then a default of {@code false} will be assumed.
583 * </LI>
584 * <LI>
585 * "use-schema" -- Indicates whether the LDAP SDK should attempt to retrieve
586 * schema information from the directory server upon establishing a
587 * connection to that server, and should then use that schema information
588 * for more accurate client-side matching operations. If present, this
589 * field should have a boolean value. If it is not present, then a default
590 * value of {@code false} will be used.
591 * </LI>
592 * <LI>
593 * "use-synchronous-mode" -- Indicates whether connections should be created
594 * in synchronous mode, which may be more efficient and less resource
595 * intensive than connections not created in synchronous mode, but may only
596 * be used if no attempt will be made to issue asynchronous requests over
597 * the connection, or to attempt to use the connection simultaneously by
598 * multiple threads. If this field is present, then its value must be a
599 * boolean. If it is not present, then a default value of {@code false}
600 * will be used.
601 * </LI>
602 * </UL>
603 * <BR>
604 * The "connection-options" field is optional, and if it is omitted from the
605 * specification then the default values will be used for all options.
606 * <BR><BR>
607 * <H2>The "authentication-details" Section</H2>
608 * The "authentication-details" section may be used to provide information for
609 * authenticating the connections that are created. The value of the
610 * "authentication-details" field must be a JSON object, and it must include an
611 * "authentication-type" field to specify the mechanism to use to authenticate.
612 * The selected authentication type dictates the other fields that may be
613 * present in the object.
614 * <BR><BR>
615 * <B>The "none" Authentication Type</B>
616 * <BR>
617 * If no authentication should be performed, then the "authentication-type"
618 * value should be "none". No other fields should be specified in the
619 * "authentication-details". For example:
620 * <PRE>
621 * {
622 * "server-details":
623 * {
624 * "single-server":
625 * {
626 * "address":"ldap.example.com",
627 * "port":389
628 * }
629 * },
630 * "authentication-details":
631 * {
632 * "authentication-type":"none"
633 * }
634 * }
635 * </PRE>
636 * <BR>
637 * <B>The "simple" Authentication Type</B>
638 * <BR>
639 * If you wish to authenticate connections with an LDAP simple bind, then you
640 * can specify an "authentication-type" value of "simple". The following
641 * additional fields may be included in the "authentication-details" object for
642 * this authentication type:
643 * <UL>
644 * <LI>
645 * "dn" -- The DN to use to bind to the server. This field must be present,
646 * and its value must be a string containing the bind DN, or an empty string
647 * to indicate anonymous simple authentication.
648 * </LI>
649 * <LI>
650 * "password" -- The password to use to bind to the server. If this field
651 * is present, then its value must be a string that contains the clear-text
652 * password, or an empty string to indicate anonymous simple
653 * authentication. If it is not provided, then the "password-file" field
654 * must be used to specify the path to a file containing the bind password.
655 * </LI>
656 * <LI>
657 * "password-file" -- The path to a file containing the password to use to
658 * bind to the server. If this field is present, then its value must be a
659 * string that represents the path to a file containing a single line that
660 * contains the clear-text password. If it is not provided, then the
661 * "password" field must be used to specify the password.
662 * </LI>
663 * </UL>
664 * For example:
665 * <PRE>
666 * {
667 * "server-details":
668 * {
669 * "single-server":
670 * {
671 * "address":"ldap.example.com",
672 * "port":389
673 * }
674 * },
675 * "authentication-details":
676 * {
677 * "authentication-type":"simple",
678 * "dn":"uid=john.doe,ou=People,dc=example,dc=com",
679 * "password-file":"/path/to/password.txt"
680 * }
681 * }
682 * </PRE>
683 * <BR>
684 * <B>The "CRAM-MD5" Authentication Type</B>
685 * If you wish to authenticate connections with the CRAM-MD5 SASL mechanism,
686 * then you can specify an "authentication-type" value of "CRAM-MD5". The
687 * following additional fields may be included in the "authentication-details"
688 * object for this authentication type:
689 * <UL>
690 * <LI>
691 * "authentication-id" -- The authentication ID to use to bind. This field
692 * must be present, and its value must be a string containing the
693 * authentication ID. Authentication ID values typically take the form
694 * "dn:" followed by the user DN, or "u:" followed by the username.
695 * </LI>
696 * <LI>
697 * "password" -- The password to use to bind to the server. If this field
698 * is present, then its value must be a string that contains the clear-text
699 * password, or an empty string to indicate anonymous simple
700 * authentication. If it is not provided, then the "password-file" field
701 * must be used to specify the path to a file containing the bind password.
702 * </LI>
703 * <LI>
704 * "password-file" -- The path to a file containing the password to use to
705 * bind to the server. If this field is present, then its value must be a
706 * string that represents the path to a file containing a single line that
707 * contains the clear-text password. If it is not provided, then the
708 * "password" field must be used to specify the password.
709 * </LI>
710 * </UL>
711 * For Example:
712 * <PRE>
713 * {
714 * "server-details":
715 * {
716 * "single-server":
717 * {
718 * "address":"ldap.example.com",
719 * "port":389
720 * }
721 * },
722 * "authentication-details":
723 * {
724 * "authentication-type":"CRAM-MD5",
725 * "authentication-id":"u:john.doe",
726 * "password-file":"/path/to/password.txt"
727 * }
728 * }
729 * </PRE>
730 * <BR>
731 * <B>The "DIGEST-MD5" Authentication Type</B>
732 * If you wish to authenticate connections with the DIGEST-MD5 SASL mechanism,
733 * then you can specify an "authentication-type" value of "DIGEST-MD5". The
734 * following additional fields may be included in the "authentication-details"
735 * object for this authentication type:
736 * <UL>
737 * <LI>
738 * "authentication-id" -- The authentication ID to use to bind. This field
739 * must be present, and its value must be a string containing the
740 * authentication ID. Authentication ID values typically take the form
741 * "dn:" followed by the user DN, or "u:" followed by the username.
742 * </LI>
743 * <LI>
744 * "authorization-id" -- The alternate authorization identity to use for the
745 * connection after the bind has completed. If present, the value must be
746 * a string containing the desired authorization identity. If this field is
747 * absent, then no alternate authorization identity will be used.
748 * </LI>
749 * <LI>
750 * "password" -- The password to use to bind to the server. If this field
751 * is present, then its value must be a string that contains the clear-text
752 * password, or an empty string to indicate anonymous simple
753 * authentication. If it is not provided, then the "password-file" field
754 * must be used to specify the path to a file containing the bind password.
755 * </LI>
756 * <LI>
757 * "password-file" -- The path to a file containing the password to use to
758 * bind to the server. If this field is present, then its value must be a
759 * string that represents the path to a file containing a single line that
760 * contains the clear-text password. If it is not provided, then the
761 * "password" field must be used to specify the password.
762 * </LI>
763 * <LI>
764 * "realm" -- The realm to use for the bind request. If this field is
765 * present, then its value must be a string containing the name of the
766 * realm. If it is not provided, then the realm will not be included in the
767 * bind request.
768 * </LI>
769 * <LI>
770 * "qop" -- The allowed quality of protection value(s) that may be used for
771 * the bind operation. If this field is present, then its value may be a
772 * single string or an array of strings indicating the allowed QoP values.
773 * Allowed values include "auth" (for just authentication), "auth-int" (for
774 * authentication followed by integrity protection for subsequent
775 * communication on the connection), and "auth-conf" (for authentication
776 * followed by confidentiality for subsequent communication on the
777 * connection). If this field is not present, then a default value of
778 * "auth" will be assumed.
779 * </LI>
780 * </UL>
781 * For Example:
782 * <PRE>
783 * {
784 * "server-details":
785 * {
786 * "single-server":
787 * {
788 * "address":"ldap.example.com",
789 * "port":389
790 * }
791 * },
792 * "authentication-details":
793 * {
794 * "authentication-type":"DIGEST-MD5",
795 * "authentication-id":"u:john.doe",
796 * "password-file":"/path/to/password.txt"
797 * }
798 * }
799 * </PRE>
800 * <BR>
801 * <B>The "EXTERNAL" Authentication Type</B>
802 * If you wish to authenticate connections with the EXTERNAL SASL mechanism,
803 * then you can specify an "authentication-type" value of "EXTERNAL". The
804 * connection must be secured with SSL or StartTLS, and the following additional
805 * field may be present in the "authentication-details" object:
806 * <UL>
807 * <LI>
808 * "authorization-id" -- The authorization identity for the bind request.
809 * If this field is present, then it must be a string containing the
810 * desired authorization ID, or an empty string if the server should
811 * determine the authorization identity. If this field is omitted, then
812 * the bind request will not include any SASL credentials, which may be
813 * required for use with some servers that cannot handle the possibility of
814 * an authorization ID in the bind request.
815 * </LI>
816 * </UL>
817 * For Example:
818 * <PRE>
819 * {
820 * "server-details":
821 * {
822 * "single-server":
823 * {
824 * "address":"ldap.example.com",
825 * "port":636
826 * }
827 * },
828 * "communication-security":
829 * {
830 * "security-type":"SSL",
831 * "trust-store-file":"/path/to/trust-store.jks",
832 * "trust-store-type":"JKS",
833 * "verify-address-in-certificate":true
834 * },
835 * "authentication-details":
836 * {
837 * "authentication-type":"EXTERNAL",
838 * "authorization-id":""
839 * }
840 * }
841 * </PRE>
842 * <BR>
843 * <B>The "GSSAPI" Authentication Type</B>
844 * If you wish to authenticate connections with the GSSAPI SASL mechanism,
845 * then you can specify an "authentication-type" value of "GSSAPI". The
846 * following additional fields may be included in the "authentication-details"
847 * object for this authentication type:
848 * <UL>
849 * <LI>
850 * "authentication-id" -- The authentication ID to use to bind. This field
851 * must be present, and its value must be a string containing the
852 * authentication ID. Authentication ID values for a GSSAPI bind request
853 * are typically the Kerberos principal for the user to authenticate.
854 * </LI>
855 * <LI>
856 * "authorization-id" -- The alternate authorization identity to use for the
857 * connection after the bind has completed. If present, the value must be
858 * a string containing the desired authorization identity. If this field is
859 * absent, then no alternate authorization identity will be used.
860 * </LI>
861 * <LI>
862 * "password" -- The password to use to bind to the server. If this field
863 * is present, then its value must be a string that contains the clear-text
864 * password, or an empty string to indicate anonymous simple
865 * authentication. If it is not provided, then the "password-file" field
866 * may be used to specify the path to a file containing the bind password.
867 * If authentication will require the use of cached credentials, then the
868 * password may be omitted.
869 * </LI>
870 * <LI>
871 * "password-file" -- The path to a file containing the password to use to
872 * bind to the server. If this field is present, then its value must be a
873 * string that represents the path to a file containing a single line that
874 * contains the clear-text password. If it is not provided, then the
875 * "password" field may be used to specify the password. If authentication
876 * will require the use of cached credentials, then the password may be
877 * omitted.
878 * </LI>
879 * <LI>
880 * "realm" -- The realm to use for the bind request. If this field is
881 * present, then its value must be a string containing the name of the
882 * realm. If it is not provided, then the JVM will attempt to determine the
883 * realm from the underlying system configuration.
884 * </LI>
885 * <LI>
886 * "qop" -- The allowed quality of protection value(s) that may be used for
887 * the bind operation. If this field is present, then its value may be a
888 * single string or an array of strings indicating the allowed QoP values.
889 * Allowed values include "auth" (for just authentication), "auth-int" (for
890 * authentication followed by integrity protection for subsequent
891 * communication on the connection), and "auth-conf" (for authentication
892 * followed by confidentiality for subsequent communication on the
893 * connection). If this field is not present, then a default value of
894 * "auth" will be assumed.
895 * </LI>
896 * <LI>
897 * "kdc-address" -- The address of the Kerberos KDC to use during
898 * authentication. If this field is present, then its value must be a
899 * string containing the target address. If it is not provided, then the
900 * JVM will attempt to determine the address of the KDC from the underlying
901 * system configuration.
902 * </LI>
903 * <LI>
904 * "config-file-path" -- The path to a JAAS configuration file to use for
905 * bind processing. If this field is present, then its value must be a
906 * string containing the path to a valid JAAS configuration file. If it is
907 * not provided, a temporary JAAS configuration file will be created for the
908 * bind operation.
909 * </LI>
910 * <LI>
911 * "renew-tgt" -- Indicates whether successful authentication should attempt
912 * to renew the ticket-granting ticket for an existing session. If this
913 * field is present, then its value must be a boolean. If it is not
914 * provided, then a default of {@code false} will be assumed.
915 * </LI>
916 * <LI>
917 * "require-cached-credentials" -- Indicates whether the authentication
918 * process should require the use of cached credentials leveraged from an
919 * existing Kerberos session rather than try to create a new session. if
920 * this field is present, then its value must be a boolean. If it is not
921 * provided, then a default of {@code false} will be assumed.
922 * </LI>
923 * <LI>
924 * "use-ticket-cache" -- Indicates whether the authentication process should
925 * leverage a ticket cache in order to leverage an existing Kerberos
926 * session if the user has already authenticated to the KDC. If present,
927 * then its value must be a boolean. If it is not provided, then a default
928 * of {@code true} will be used.
929 * </LI>
930 * <LI>
931 * "ticket-cache-path" -- Specifies the path to the Kerberos ticket cache to
932 * use. If this is provided, its value must be a string with the path to
933 * the desired ticket cache. If it is not provided, then the JVM will
934 * attempt to determine the appropriate ticket cache from the underlying
935 * system configuration.
936 * </LI>
937 * <LI>
938 * "use-subject-credentials-only" -- Indicates whether authentication should
939 * require the client will be required to use credentials that match the
940 * current subject. If it is provided, then the value must be a boolean.
941 * If it is not provided, then a default of {@code true} will be assumed.
942 * </LI>
943 * </UL>
944 * For Example:
945 * <PRE>
946 * {
947 * "server-details":
948 * {
949 * "single-server":
950 * {
951 * "address":"ldap.example.com",
952 * "port":389
953 * }
954 * },
955 * "authentication-details":
956 * {
957 * "authentication-type":"GSSAPI",
958 * "authentication-id":"john.doe@EXAMPLE.COM",
959 * "password-file":"/path/to/password.txt",
960 * "renew-tgt":true
961 * }
962 * }
963 * </PRE>
964 * <BR>
965 * <B>The "PLAIN" Authentication Type</B>
966 * If you wish to authenticate connections with the PLAIN SASL mechanism,
967 * then you can specify an "authentication-type" value of "PLAIN". The
968 * following additional fields may be included in the "authentication-details"
969 * object for this authentication type:
970 * <UL>
971 * <LI>
972 * "authentication-id" -- The authentication ID to use to bind. This field
973 * must be present, and its value must be a string containing the
974 * authentication ID. Authentication ID values typically take the form
975 * "dn:" followed by the user DN, or "u:" followed by the username.
976 * </LI>
977 * <LI>
978 * "authorization-id" -- The alternate authorization identity to use for the
979 * connection after the bind has completed. If present, the value must be
980 * a string containing the desired authorization identity. If this field is
981 * absent, then no alternate authorization identity will be used.
982 * </LI>
983 * <LI>
984 * "password" -- The password to use to bind to the server. If this field
985 * is present, then its value must be a string that contains the clear-text
986 * password, or an empty string to indicate anonymous simple
987 * authentication. If it is not provided, then the "password-file" field
988 * must be used to specify the path to a file containing the bind password.
989 * </LI>
990 * <LI>
991 * "password-file" -- The path to a file containing the password to use to
992 * bind to the server. If this field is present, then its value must be a
993 * string that represents the path to a file containing a single line that
994 * contains the clear-text password. If it is not provided, then the
995 * "password" field must be used to specify the password.
996 * </LI>
997 * </UL>
998 * For Example:
999 * <PRE>
1000 * {
1001 * "server-details":
1002 * {
1003 * "single-server":
1004 * {
1005 * "address":"ldap.example.com",
1006 * "port":389
1007 * }
1008 * },
1009 * "authentication-details":
1010 * {
1011 * "authentication-type":"PLAIN",
1012 * "authentication-id":"dn:uid=john.doe,ou=People,dc=example,dc=com",
1013 * "password-file":"/path/to/password.txt"
1014 * }
1015 * }
1016 * </PRE>
1017 * <BR>
1018 * The "authentication-details" field is optional, and if it is omitted from the
1019 * specification then no authentication will be performed.
1020 * <BR><BR>
1021 * <H2>The "connection-pool-options" Section</H2>
1022 * The "connection-pool-options" section may be used to provide information
1023 * about a number of settings that may be used in the course of creating or
1024 * maintaining a connection pool. The value of the "connection-pool-options"
1025 * field must be a JSON object, and the following fields may appear in that
1026 * object:
1027 * <UL>
1028 * <LI>
1029 * "create-if-necessary" -- Indicates whether the connection pool should
1030 * create a new connection if one is needed but none are available. If
1031 * present, the value must be a boolean. If it is absent, then a default
1032 * of {@code true} will be assumed.
1033 * </LI>
1034 * <LI>
1035 * "health-check-get-entry-dn" -- The DN of an entry that should be
1036 * retrieved during health check processing. If present, the value must be
1037 * a string that represents the DN of the entry to retrieve, or an empty
1038 * string to indicate that the server root DSE should be retrieved. If this
1039 * field is absent, then no entry will be retrieved during health check
1040 * processing.
1041 * </LI>
1042 * <LI>
1043 * "health-check-get-entry-maximum-response-time-millis" -- The maximum
1044 * length of time in milliseconds to wait for the entry to be returned in a
1045 * get entry health check. If present, the value must be a positive
1046 * integer. If it is not provided, then a default of 10000 (ten seconds)
1047 * will be used.
1048 * </LI>
1049 * <LI>
1050 * "initial-connect-threads" -- The number of threads to use when creating
1051 * the initial set of connections for the pool. If this field is present,
1052 * then the value must be a positive integer, with a value of one indicating
1053 * that connection should be created in a single-threaded manner, and a
1054 * value greater than one indicating that the initial connections should be
1055 * established in parallel. If it is not provided, then a default of one
1056 * will be used.
1057 * </LI>
1058 * <LI>
1059 * "invoke-background-health-checks" -- Indicates whether the connection
1060 * pool should periodically invoke health check processing on idle
1061 * connections. If this field is present, then its value must be a boolean.
1062 * If it is not present, then a default of {@code true} will be assumed.
1063 * </LI>
1064 * <LI>
1065 * "invoke-checkout-health-checks" -- Indicates whether the connection pool
1066 * should invoke health check processing on connections just before they are
1067 * checked out of the pool to ensure that they are valid. If this field is
1068 * present, then its value must be a boolean. If it is not present, then a
1069 * default of {@code false} will be assumed.
1070 * </LI>
1071 * <LI>
1072 * "invoke-create-health-checks" -- Indicates whether the connection pool
1073 * should invoke health check processing on connections just after they are
1074 * created. If this field is present, then its value must be a boolean. If
1075 * it is not present, then a default of {@code false} will be assumed.
1076 * </LI>
1077 * <LI>
1078 * "invoke-exception-health-checks" -- Indicates whether the connection pool
1079 * should invoke health check processing on connections just after an
1080 * exception is caught that might indicate that the connection is no longer
1081 * valid. Note that this only applies to exceptions caught during
1082 * operations processed directly against the connection pool and not to
1083 * exceptions caught on a connection checked out of the pool. If this field
1084 * is present, then its value must be a boolean. If it is not present, then
1085 * a default of {@code true} will be assumed.
1086 * </LI>
1087 * <LI>
1088 * "invoke-release-health-checks" -- Indicates whether the connection pool
1089 * should invoke health check processing on connections just before they are
1090 * released back to the pool to ensure that they are valid. If this field
1091 * is present, then its value must be a boolean. If it is not present, then
1092 * a default of {@code false} will be assumed.
1093 * </LI>
1094 * <LI>
1095 * "maximum-connection-age-millis" -- Specifies the maximum length of time
1096 * (in milliseconds) that a connection should be allowed to remain
1097 * established before it is eligible to be closed and replaced with a
1098 * newly-created connection. If present, then the value must be a positive
1099 * integer to specify the maximum age, or zero to indicate that no maximum
1100 * age should be applied. If it is not present, then a default value of
1101 * zero will be used.
1102 * </LI>
1103 * <LI>
1104 * "maximum-defunct-replacement-connection-age-millis" -- Specifies the
1105 * maximum connection age (in milliseconds) that should be used for
1106 * connections created to replace a defunct connection. If present, then
1107 * the value must be a positive integer to specify the maximum age, or zero
1108 * to indicate that no maximum age should be applied. If it is not present,
1109 * then the value of the "maximum-connection-age-millis" field will be used
1110 * for connections created as replacements for defunct connections.
1111 * </LI>
1112 * <LI>
1113 * "maximum-wait-time-millis" -- Specifies the maximum length of time (in
1114 * milliseconds) that the pool should wait for a connection to be released
1115 * if one is needed but none are immediately available. If present, then
1116 * this value must be a positive integer to specify the length of time to
1117 * wait, or zero to indicate that it should not wait at all. If it is not
1118 * provided, then a default value of zero will be used.
1119 * </LI>
1120 * <LI>
1121 * "retry-failed-operations-due-to-invalid-connections" -- Indicates whether
1122 * the pool should automatically attempt to retry operations attempted
1123 * directly against the pool (but not for connections checked out of the
1124 * pool) if the initial attempt fails in a manner that may indicate that the
1125 * connection is no longer valid. If this field is present, then its value
1126 * may be either a boolean to indicate whether to enable retry for all types
1127 * of operations or no operations, or it may be an array of strings
1128 * indicating the operation types ("add", "bind", "compare", "delete",
1129 * "extended", "modify", "modify-dn", or "search") that should be retried
1130 * in the event of a failure. If this field is not present, then no
1131 * automatic retry will be attempted.
1132 * </LI>
1133 * </UL>
1134 * <BR>
1135 * The "connection-pool-options" field is optional, and if it is omitted from
1136 * the specification then the default values will be used for all options.
1137 */
1138 @NotMutable()
1139 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
1140 public final class LDAPConnectionDetailsJSONSpecification
1141 {
1142 /**
1143 * The name of the top-level field that may be used to provide information to
1144 * use to authenticate connections to the server.
1145 */
1146 static final String FIELD_AUTHENTICATION_DETAILS = "authentication-details";
1147
1148
1149
1150 /**
1151 * The name of the top-level field that may be used to provide information
1152 * about the type of communication security that should be used.
1153 */
1154 static final String FIELD_COMMUNICATION_SECURITY = "communication-security";
1155
1156
1157
1158 /**
1159 * The name of the top-level field that may be used to provide information
1160 * about options that should be set when establishing connections.
1161 */
1162 static final String FIELD_CONNECTION_OPTIONS = "connection-options";
1163
1164
1165
1166 /**
1167 * The name of the top-level field that may be used to provide information
1168 * about options that should be set when creating a connection pool.
1169 */
1170 static final String FIELD_CONNECTION_POOL_OPTIONS =
1171 "connection-pool-options";
1172
1173
1174
1175 /**
1176 * The name of the top-level field that may be used to provide information
1177 * about the directory server(s) to which the connection should be
1178 * established.
1179 */
1180 static final String FIELD_SERVER_DETAILS = "server-details";
1181
1182
1183
1184 // The bind request that will be used to authenticate connections.
1185 private final BindRequest bindRequest;
1186
1187 // The processed connection pool options portion of the specification.
1188 private final ConnectionPoolOptions connectionPoolOptionsSpec;
1189
1190 // The processed security options portion of the specification.
1191 private final SecurityOptions securityOptionsSpec;
1192
1193 // The server set that will be used to create connections.
1194 private final ServerSet serverSet;
1195
1196
1197
1198 /**
1199 * Creates a new LDAP connection details object from the specification
1200 * contained in the provided JSON object.
1201 *
1202 * @param connectionDetailsObject The JSON object that contains information
1203 * that may be used to create LDAP
1204 * connections.
1205 *
1206 * @throws LDAPException If the provided JSON object does not contain a
1207 * valid connection details specification.
1208 */
1209 public LDAPConnectionDetailsJSONSpecification(
1210 final JSONObject connectionDetailsObject)
1211 throws LDAPException
1212 {
1213 validateTopLevelFields(connectionDetailsObject);
1214
1215 try
1216 {
1217 securityOptionsSpec = new SecurityOptions(connectionDetailsObject);
1218 }
1219 catch (final LDAPException le)
1220 {
1221 Debug.debugException(le);
1222 throw new LDAPException(le.getResultCode(),
1223 ERR_LDAP_SPEC_ERROR_PROCESSING_FIELD.get(
1224 FIELD_COMMUNICATION_SECURITY, le.getMessage()),
1225 le);
1226 }
1227
1228 final ConnectionOptions connectionOptionsSpec;
1229 try
1230 {
1231 connectionOptionsSpec = new ConnectionOptions(connectionDetailsObject);
1232 }
1233 catch (final LDAPException le)
1234 {
1235 Debug.debugException(le);
1236 throw new LDAPException(le.getResultCode(),
1237 ERR_LDAP_SPEC_ERROR_PROCESSING_FIELD.get(
1238 FIELD_CONNECTION_OPTIONS, le.getMessage()),
1239 le);
1240 }
1241
1242 try
1243 {
1244 final ServerDetails serverDetailsSpec =
1245 new ServerDetails(connectionDetailsObject, securityOptionsSpec,
1246 connectionOptionsSpec);
1247 serverSet = serverDetailsSpec.getServerSet();
1248 }
1249 catch (final LDAPException le)
1250 {
1251 Debug.debugException(le);
1252 throw new LDAPException(le.getResultCode(),
1253 ERR_LDAP_SPEC_ERROR_PROCESSING_FIELD.get(
1254 FIELD_SERVER_DETAILS, le.getMessage()),
1255 le);
1256 }
1257
1258 try
1259 {
1260 final AuthenticationDetails authenticationDetailsSpec =
1261 new AuthenticationDetails(connectionDetailsObject);
1262 bindRequest = authenticationDetailsSpec.getBindRequest();
1263 }
1264 catch (final LDAPException le)
1265 {
1266 Debug.debugException(le);
1267 throw new LDAPException(le.getResultCode(),
1268 ERR_LDAP_SPEC_ERROR_PROCESSING_FIELD.get(
1269 FIELD_AUTHENTICATION_DETAILS, le.getMessage()),
1270 le);
1271 }
1272
1273 try
1274 {
1275 connectionPoolOptionsSpec =
1276 new ConnectionPoolOptions(connectionDetailsObject);
1277 }
1278 catch (final LDAPException le)
1279 {
1280 Debug.debugException(le);
1281 throw new LDAPException(le.getResultCode(),
1282 ERR_LDAP_SPEC_ERROR_PROCESSING_FIELD.get(
1283 FIELD_CONNECTION_POOL_OPTIONS, le.getMessage()),
1284 le);
1285 }
1286 }
1287
1288
1289
1290 /**
1291 * Creates a new LDAP connection details object from the specification
1292 * contained in the JSON object represented by the given string.
1293 *
1294 * @param jsonString The string representation of the JSON object that
1295 * contains information that may be used to create LDAP
1296 * connections.
1297 *
1298 * @return The LDAP connection details object parsed from the provided
1299 * JSON object string.
1300 *
1301 * @throws JSONException If the provided string cannot be parsed as a valid
1302 * JSON object.
1303 *
1304 * @throws LDAPException If the parsed JSON object does not contain a valid
1305 * connection details specification.
1306 */
1307 public static LDAPConnectionDetailsJSONSpecification fromString(
1308 final String jsonString)
1309 throws JSONException, LDAPException
1310 {
1311 return new LDAPConnectionDetailsJSONSpecification(
1312 new JSONObject(jsonString));
1313 }
1314
1315
1316
1317 /**
1318 * Creates a new LDAP connection details object from the specification
1319 * contained in the JSON object read from the indicated file.
1320 *
1321 * @param path The path to a file containing a JSON object with information
1322 * that may be used to create LDAP connections.
1323 *
1324 * @return The LDAP connection details object parsed from the information in
1325 * the specified file.
1326 *
1327 * @throws IOException If a problem is encountered while reading from the
1328 * specified file.
1329 *
1330 * @throws JSONException If the contents of the specified file cannot be
1331 * parsed as a valid JSON object.
1332 *
1333 * @throws LDAPException If the parsed JSON object does not contain a valid
1334 * connection details specification.
1335 */
1336 public static LDAPConnectionDetailsJSONSpecification fromFile(
1337 final String path)
1338 throws IOException, JSONException, LDAPException
1339 {
1340 return fromFile(new File(path));
1341 }
1342
1343
1344
1345 /**
1346 * Creates a new LDAP connection details object from the specification
1347 * contained in the JSON object read from the indicated file.
1348 *
1349 * @param file The file containing a JSON object with information that may
1350 * be used to create LDAP connections.
1351 *
1352 * @return The LDAP connection details object parsed from the information in
1353 * the specified file.
1354 *
1355 * @throws IOException If a problem is encountered while reading from the
1356 * specified file.
1357 *
1358 * @throws JSONException If the contents of the specified file cannot be
1359 * parsed as a valid JSON object.
1360 *
1361 * @throws LDAPException If the parsed JSON object does not contain a valid
1362 * connection details specification.
1363 */
1364 public static LDAPConnectionDetailsJSONSpecification fromFile(final File file)
1365 throws IOException, JSONException, LDAPException
1366 {
1367 return fromInputStream(new FileInputStream(file));
1368 }
1369
1370
1371
1372 /**
1373 * Creates a new LDAP connection details object from the specification
1374 * contained in the JSON object read from the provided input stream. The
1375 * entire contents of the stream must be exactly one JSON object. Because the
1376 * input stream will be fully read, it will always be closed by this method.
1377 *
1378 * @param inputStream The input stream from which to read a JSON object with
1379 * information that may be used to create LDAP
1380 * connections. The entire contents of the stream must
1381 * be exactly one JSON object. Because the input stream
1382 * will be fully read, it will always be closed by this
1383 * method.
1384 *
1385 * @return The LDAP connection details object parsed from the information
1386 * read from the provided input stream.
1387 *
1388 * @throws IOException If a problem is encountered while reading from the
1389 * provided input stream.
1390 *
1391 * @throws JSONException If the contents of the specified file cannot be
1392 * parsed as a valid JSON object.
1393 *
1394 * @throws LDAPException If the parsed JSON object does not contain a valid
1395 * connection details specification.
1396 */
1397 public static LDAPConnectionDetailsJSONSpecification fromInputStream(
1398 final InputStream inputStream)
1399 throws IOException, JSONException, LDAPException
1400 {
1401 try
1402 {
1403 final ByteStringBuffer b = new ByteStringBuffer();
1404 final byte[] readBuffer = new byte[8192];
1405 while (true)
1406 {
1407 final int bytesRead = inputStream.read(readBuffer);
1408 if (bytesRead < 0)
1409 {
1410 break;
1411 }
1412 else
1413 {
1414 b.append(readBuffer, 0, bytesRead);
1415 }
1416 }
1417
1418 return new LDAPConnectionDetailsJSONSpecification(
1419 new JSONObject(b.toString()));
1420 }
1421 finally
1422 {
1423 inputStream.close();
1424 }
1425 }
1426
1427
1428
1429 /**
1430 * Retrieves the server set that may be used to create new connections based
1431 * on the JSON specification.
1432 *
1433 * @return The server set that may be used to create new connections based on
1434 * the JSON specification.
1435 */
1436 public ServerSet getServerSet()
1437 {
1438 return serverSet;
1439 }
1440
1441
1442
1443 /**
1444 * Retrieves the bind request that may be used to authenticate connections
1445 * created from the JSON specification.
1446 *
1447 * @return The bind request that may be used to authenticate connections
1448 * created from the JSON specification, or {@code null} if the
1449 * connections should be unauthenticated.
1450 */
1451 public BindRequest getBindRequest()
1452 {
1453 return bindRequest;
1454 }
1455
1456
1457
1458 /**
1459 * Creates a new LDAP connection based on the JSON specification. The
1460 * connection will be authenticated if appropriate.
1461 *
1462 * @return The LDAP connection that was created.
1463 *
1464 * @throws LDAPException If a problem is encountered while trying to
1465 * establish or authenticate the connection.
1466 */
1467 public LDAPConnection createConnection()
1468 throws LDAPException
1469 {
1470 final LDAPConnection connection = createUnauthenticatedConnection();
1471
1472 if (bindRequest != null)
1473 {
1474 try
1475 {
1476 connection.bind(bindRequest);
1477 }
1478 catch (final LDAPException le)
1479 {
1480 Debug.debugException(le);
1481 connection.close();
1482 throw le;
1483 }
1484 }
1485
1486 return connection;
1487 }
1488
1489
1490
1491 /**
1492 * Creates a new LDAP connection based on the JSON specification. No
1493 * authentication will be performed on the connection.
1494 *
1495 * @return The LDAP connection that was created.
1496 *
1497 * @throws LDAPException If a problem is encountered while trying to
1498 * establish the connection.
1499 */
1500 public LDAPConnection createUnauthenticatedConnection()
1501 throws LDAPException
1502 {
1503 return serverSet.getConnection();
1504 }
1505
1506
1507
1508 /**
1509 * Creates a new LDAP connection pool based on the JSON specification. The
1510 * pooled connections will be authenticated if appropriate.
1511 *
1512 * @param initialConnections The number of connections that should be
1513 * established at the time the pool is created.
1514 * @param maximumConnections The maximum number of connections that should
1515 * be available in the pool at any time.
1516 *
1517 * @return The LDAP connection pool that was created.
1518 *
1519 * @throws LDAPException If a problem is encountered while attempting to
1520 * create the connection pool.
1521 */
1522 public LDAPConnectionPool createConnectionPool(final int initialConnections,
1523 final int maximumConnections)
1524 throws LDAPException
1525 {
1526 final LDAPConnectionPool connectionPool = new LDAPConnectionPool(serverSet,
1527 bindRequest, initialConnections, maximumConnections,
1528 connectionPoolOptionsSpec.getInitialConnectThreads(),
1529 securityOptionsSpec.getPostConnectProcessor(), false,
1530 connectionPoolOptionsSpec.getHealthCheck());
1531
1532 connectionPoolOptionsSpec.applyConnectionPoolSettings(connectionPool);
1533 return connectionPool;
1534 }
1535
1536
1537
1538 /**
1539 * Creates a new LDAP connection pool based on the JSON specification. No
1540 * authentication will be used for connections that are part of the pool.
1541 *
1542 * @param initialConnections The number of connections that should be
1543 * established at the time the pool is created.
1544 * @param maximumConnections The maximum number of connections that should
1545 * be available in the pool at any time.
1546 *
1547 * @return The LDAP connection pool that was created.
1548 *
1549 * @throws LDAPException If a problem is encountered while attempting to
1550 * create the connection pool.
1551 */
1552 public LDAPConnectionPool createUnauthenticatedConnectionPool(
1553 final int initialConnections,
1554 final int maximumConnections)
1555 throws LDAPException
1556 {
1557 final LDAPConnectionPool connectionPool = new LDAPConnectionPool(serverSet,
1558 null, initialConnections, maximumConnections,
1559 connectionPoolOptionsSpec.getInitialConnectThreads(),
1560 securityOptionsSpec.getPostConnectProcessor(), false,
1561 connectionPoolOptionsSpec.getHealthCheck());
1562
1563 connectionPoolOptionsSpec.applyConnectionPoolSettings(connectionPool);
1564 return connectionPool;
1565 }
1566
1567
1568
1569 /**
1570 * Validates the top-level fields in the provided JSON object to ensure that
1571 * all required fields are present and no unrecognized fields are present.
1572 *
1573 * @param o The JSON object to validate.
1574 *
1575 * @throws LDAPException If there is a problem with the set of top-level
1576 * fields in the provided JSON object.
1577 */
1578 private static void validateTopLevelFields(final JSONObject o)
1579 throws LDAPException
1580 {
1581 boolean serverDetailsProvided = false;
1582 for (final String s : o.getFields().keySet())
1583 {
1584 if (s.equals(FIELD_SERVER_DETAILS))
1585 {
1586 // This is a required top-level field.
1587 serverDetailsProvided = true;
1588 }
1589 else if (s.equals(FIELD_CONNECTION_OPTIONS) ||
1590 s.equals(FIELD_COMMUNICATION_SECURITY) ||
1591 s.equals(FIELD_AUTHENTICATION_DETAILS) ||
1592 s.equals(FIELD_CONNECTION_POOL_OPTIONS))
1593 {
1594 // These are optional top-level fields.
1595 }
1596 else
1597 {
1598 // This is not a valid top-level field.
1599 throw new LDAPException(ResultCode.PARAM_ERROR,
1600 ERR_LDAP_SPEC_UNRECOGNIZED_TOP_LEVEL_FIELD.get(s));
1601 }
1602 }
1603
1604 if (! serverDetailsProvided)
1605 {
1606 throw new LDAPException(ResultCode.PARAM_ERROR,
1607 ERR_LDAP_SPEC_MISSING_SERVER_DETAILS.get(FIELD_SERVER_DETAILS));
1608 }
1609 }
1610
1611
1612
1613 /**
1614 * Validates that the set of fields contained in the JSON object that is the
1615 * value of the indicated field.
1616 *
1617 * @param o The JSON object to validate.
1618 * @param f The name of the field whose value is the provided JSON object.
1619 * @param a The names of the fields that are allowed to be present.
1620 *
1621 * @throws LDAPException If the provided JSON object contains any fields
1622 * that are not contained in the allowed set.
1623 */
1624 static void validateAllowedFields(final JSONObject o, final String f,
1625 final String... a)
1626 throws LDAPException
1627 {
1628 final HashSet<String> s = new HashSet<String>(Arrays.asList(a));
1629 for (final String n : o.getFields().keySet())
1630 {
1631 if (! s.contains(n))
1632 {
1633 throw new LDAPException(ResultCode.PARAM_ERROR,
1634 ERR_LDAP_SPEC_UNRECOGNIZED_FIELD.get(n, f));
1635 }
1636 }
1637 }
1638
1639
1640
1641 /**
1642 * Retrieves the value of the specified JSON object field as a boolean.
1643 *
1644 * @param o The object from which to retrieve the boolean value.
1645 * @param f The name of the field to retrieve.
1646 * @param d The default value to return if the specified field does not
1647 * exist.
1648 *
1649 * @return The requested boolean value.
1650 *
1651 * @throws LDAPException If the specified field exists but is not a boolean.
1652 */
1653 static boolean getBoolean(final JSONObject o, final String f, final boolean d)
1654 throws LDAPException
1655 {
1656 final JSONValue v = o.getField(f);
1657 if (v == null)
1658 {
1659 return d;
1660 }
1661
1662 if (v instanceof JSONBoolean)
1663 {
1664 return ((JSONBoolean) v).booleanValue();
1665 }
1666 else
1667 {
1668 throw new LDAPException(ResultCode.PARAM_ERROR,
1669 ERR_LDAP_SPEC_VALUE_NOT_BOOLEAN.get(f));
1670 }
1671 }
1672
1673
1674
1675 /**
1676 * Retrieves the value of the specified JSON object field as an integer.
1677 *
1678 * @param o The object from which to retrieve the integer value.
1679 * @param f The name of the field to retrieve.
1680 * @param d The default value to return if the specified field does not
1681 * exist.
1682 * @param n The minimum allowed value for the field, if any.
1683 * @param x The maximum allowed value for the field, if any.
1684 *
1685 * @return The requested integer value.
1686 *
1687 * @throws LDAPException If the specified field exists but is not an
1688 * integer.
1689 */
1690 static Integer getInt(final JSONObject o, final String f, final Integer d,
1691 final Integer n, final Integer x)
1692 throws LDAPException
1693 {
1694 final JSONValue v = o.getField(f);
1695 if (v == null)
1696 {
1697 return d;
1698 }
1699
1700 if (v instanceof JSONNumber)
1701 {
1702 try
1703 {
1704 final int i =((JSONNumber) v).getValue().intValueExact();
1705 if ((n != null) && (i < n))
1706 {
1707 throw new LDAPException(ResultCode.PARAM_ERROR,
1708 ERR_LDAP_SPEC_VALUE_BELOW_MIN.get(f, n));
1709 }
1710
1711 if ((x != null) && (i > x))
1712 {
1713 throw new LDAPException(ResultCode.PARAM_ERROR,
1714 ERR_LDAP_SPEC_VALUE_ABOVE_MAX.get(f, n));
1715 }
1716
1717 return i;
1718 }
1719 catch (final LDAPException le)
1720 {
1721 Debug.debugException(le);
1722 throw le;
1723 }
1724 catch (final Exception e)
1725 {
1726 Debug.debugException(e);
1727 throw new LDAPException(ResultCode.PARAM_ERROR,
1728 ERR_LDAP_SPEC_VALUE_NOT_INTEGER.get(f), e);
1729 }
1730 }
1731 else
1732 {
1733 throw new LDAPException(ResultCode.PARAM_ERROR,
1734 ERR_LDAP_SPEC_VALUE_NOT_INTEGER.get(f));
1735 }
1736 }
1737
1738
1739
1740 /**
1741 * Retrieves the value of the specified JSON object field as a long.
1742 *
1743 * @param o The object from which to retrieve the long value.
1744 * @param f The name of the field to retrieve.
1745 * @param d The default value to return if the specified field does not
1746 * exist.
1747 * @param n The minimum allowed value for the field, if any.
1748 * @param x The maximum allowed value for the field, if any.
1749 *
1750 * @return The requested long value.
1751 *
1752 * @throws LDAPException If the specified field exists but is not a long.
1753 */
1754 static Long getLong(final JSONObject o, final String f, final Long d,
1755 final Long n, final Long x)
1756 throws LDAPException
1757 {
1758 final JSONValue v = o.getField(f);
1759 if (v == null)
1760 {
1761 return d;
1762 }
1763
1764 if (v instanceof JSONNumber)
1765 {
1766 try
1767 {
1768 final long l =((JSONNumber) v).getValue().longValueExact();
1769 if ((n != null) && (l < n))
1770 {
1771 throw new LDAPException(ResultCode.PARAM_ERROR,
1772 ERR_LDAP_SPEC_VALUE_BELOW_MIN.get(f, n));
1773 }
1774
1775 if ((x != null) && (l > x))
1776 {
1777 throw new LDAPException(ResultCode.PARAM_ERROR,
1778 ERR_LDAP_SPEC_VALUE_ABOVE_MAX.get(f, n));
1779 }
1780
1781 return l;
1782 }
1783 catch (final LDAPException le)
1784 {
1785 Debug.debugException(le);
1786 throw le;
1787 }
1788 catch (final Exception e)
1789 {
1790 Debug.debugException(e);
1791 throw new LDAPException(ResultCode.PARAM_ERROR,
1792 ERR_LDAP_SPEC_VALUE_NOT_INTEGER.get(f), e);
1793 }
1794 }
1795 else
1796 {
1797 throw new LDAPException(ResultCode.PARAM_ERROR,
1798 ERR_LDAP_SPEC_VALUE_NOT_INTEGER.get(f));
1799 }
1800 }
1801
1802
1803
1804 /**
1805 * Retrieves the value of the specified JSON object field as an object.
1806 *
1807 * @param o The object from which to retrieve the object value.
1808 * @param f The name of the field to retrieve.
1809 *
1810 * @return The requested object value.
1811 *
1812 * @throws LDAPException If the specified field exists but is not an object.
1813 */
1814 static JSONObject getObject(final JSONObject o, final String f)
1815 throws LDAPException
1816 {
1817 final JSONValue v = o.getField(f);
1818 if (v == null)
1819 {
1820 return null;
1821 }
1822
1823 if (v instanceof JSONObject)
1824 {
1825 return (JSONObject) v;
1826 }
1827 else
1828 {
1829 throw new LDAPException(ResultCode.PARAM_ERROR,
1830 ERR_LDAP_SPEC_VALUE_NOT_OBJECT.get(f));
1831 }
1832 }
1833
1834
1835
1836 /**
1837 * Retrieves the value of the specified JSON object field as a string.
1838 *
1839 * @param o The object from which to retrieve the string value.
1840 * @param f The name of the field to retrieve.
1841 * @param d The default value to return if the specified field does not
1842 * exist.
1843 *
1844 * @return The requested string value.
1845 *
1846 * @throws LDAPException If the specified field exists but is not a string.
1847 */
1848 static String getString(final JSONObject o, final String f, final String d)
1849 throws LDAPException
1850 {
1851 final JSONValue v = o.getField(f);
1852 if (v == null)
1853 {
1854 return d;
1855 }
1856
1857 if (v instanceof JSONString)
1858 {
1859 return ((JSONString) v).stringValue();
1860 }
1861 else
1862 {
1863 throw new LDAPException(ResultCode.PARAM_ERROR,
1864 ERR_LDAP_SPEC_VALUE_NOT_STRING.get(f));
1865 }
1866 }
1867
1868
1869
1870 /**
1871 * Retrieves a string value read from the specified file. The file must
1872 * contain exactly one line, and that line must not be empty.
1873 *
1874 * @param path The path to the file from which to read the string.
1875 * @param fieldName The name of the field from which the path was obtained.
1876 *
1877 * @return The string read from the specified file.
1878 *
1879 * @throws LDAPException If a problem is encountered while reading from the
1880 * specified file, if the file does not contain
1881 * exactly one line, or if the line contained in the
1882 * file is empty.
1883 */
1884 static String getStringFromFile(final String path, final String fieldName)
1885 throws LDAPException
1886 {
1887 BufferedReader r = null;
1888 try
1889 {
1890 r = new BufferedReader(new FileReader(path));
1891
1892 final String line = r.readLine();
1893 if (line == null)
1894 {
1895 throw new LDAPException(ResultCode.PARAM_ERROR,
1896 ERR_LDAP_SPEC_READ_FILE_EMPTY.get(path, fieldName));
1897 }
1898
1899 if (r.readLine() != null)
1900 {
1901 throw new LDAPException(ResultCode.PARAM_ERROR,
1902 ERR_LDAP_SPEC_READ_FILE_MULTIPLE_LINES.get(path, fieldName));
1903 }
1904
1905 if (line.length() == 0)
1906 {
1907 throw new LDAPException(ResultCode.PARAM_ERROR,
1908 ERR_LDAP_SPEC_READ_FILE_EMPTY_LINE.get(path, fieldName));
1909 }
1910
1911 return line;
1912 }
1913 catch (final LDAPException le)
1914 {
1915 Debug.debugException(le);
1916 throw le;
1917 }
1918 catch (final Exception e)
1919 {
1920 Debug.debugException(e);
1921 throw new LDAPException(ResultCode.PARAM_ERROR,
1922 ERR_LDAP_SPEC_READ_FILE_ERROR.get(path, fieldName,
1923 StaticUtils.getExceptionMessage(e)),
1924 e);
1925 }
1926 finally
1927 {
1928 if (r != null)
1929 {
1930 try
1931 {
1932 r.close();
1933 }
1934 catch (final Exception e)
1935 {
1936 Debug.debugException(e);
1937 }
1938 }
1939 }
1940 }
1941
1942
1943
1944 /**
1945 * Verifies that none of the indicated fields exist in the provided JSON
1946 * object because they would conflict with the specified existing field.
1947 *
1948 * @param o The JSON object to examine.
1949 * @param existingField The name of a field known to be present in the
1950 * JSON object that cannot coexist with the
1951 * indicated conflicting fields.
1952 * @param conflictingFields The names of the fields that cannot be used in
1953 * conjunction with the specified existing field.
1954 *
1955 * @throws LDAPException If the provided JSON object has one or more fields
1956 * that conflict with the specified existing field.
1957 */
1958 static void rejectConflictingFields(final JSONObject o,
1959 final String existingField,
1960 final String... conflictingFields)
1961 throws LDAPException
1962 {
1963 for (final String fieldName : conflictingFields)
1964 {
1965 if (o.getField(fieldName) != null)
1966 {
1967 throw new LDAPException(ResultCode.PARAM_ERROR,
1968 ERR_LDAP_SPEC_CONFLICTING_FIELD.get(fieldName, existingField));
1969 }
1970 }
1971 }
1972
1973
1974
1975 /**
1976 * Verifies that none of the indicated fields exist in the provided JSON
1977 * object because they can only be provided if the specified required field is
1978 * present.
1979 *
1980 * @param o The JSON object to examine.
1981 * @param requiredField The name of a field known to be missing from the
1982 * JSON object, but must be present to allow any of
1983 * the indicated dependent fields to be provided.
1984 * @param dependentFields The names of the fields that can only be present
1985 * if the specified required field is present.
1986 *
1987 * @throws LDAPException If the provided JSON object has one or more
1988 * unresolved dependencies.
1989 */
1990 static void rejectUnresolvedDependency(final JSONObject o,
1991 final String requiredField,
1992 final String... dependentFields)
1993 throws LDAPException
1994 {
1995 for (final String fieldName : dependentFields)
1996 {
1997 if (o.getField(fieldName) != null)
1998 {
1999 throw new LDAPException(ResultCode.PARAM_ERROR,
2000 ERR_LDAP_SPEC_MISSING_DEPENDENT_FIELD.get(fieldName,
2001 requiredField));
2002 }
2003 }
2004 }
2005 }