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    }