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