001/* 002 * Copyright 2015-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2015-2019 Ping Identity Corporation 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 */ 021package com.unboundid.util.json; 022 023 024 025import java.io.BufferedReader; 026import java.io.File; 027import java.io.FileInputStream; 028import java.io.FileReader; 029import java.io.InputStream; 030import java.io.IOException; 031import java.util.Arrays; 032import java.util.HashSet; 033 034import com.unboundid.ldap.sdk.BindRequest; 035import com.unboundid.ldap.sdk.LDAPConnection; 036import com.unboundid.ldap.sdk.LDAPConnectionPool; 037import com.unboundid.ldap.sdk.LDAPException; 038import com.unboundid.ldap.sdk.ResultCode; 039import com.unboundid.ldap.sdk.ServerSet; 040import com.unboundid.util.ByteStringBuffer; 041import com.unboundid.util.Debug; 042import com.unboundid.util.NotMutable; 043import com.unboundid.util.StaticUtils; 044import com.unboundid.util.ThreadSafety; 045import com.unboundid.util.ThreadSafetyLevel; 046 047import 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-authentication-health-checks" -- Indicates whether the connection 1079 * pool should invoke health check processing on connections just after they 1080 * have been authenticated. This includes after a successful bind on a 1081 * newly-created connection, and after calls to the connection pool's 1082 * {@code bindAndRevertAuthentication} and 1083 * {@code releaseAndReAuthenticateConnection} methods. If this field is 1084 * present, then its value must be a boolean. If it is not present, then a 1085 * default of {@code false} will be assumed. 1086 * </LI> 1087 * <LI> 1088 * "invoke-exception-health-checks" -- Indicates whether the connection pool 1089 * should invoke health check processing on connections just after an 1090 * exception is caught that might indicate that the connection is no longer 1091 * valid. Note that this only applies to exceptions caught during 1092 * operations processed directly against the connection pool and not to 1093 * exceptions caught on a connection checked out of the pool. If this field 1094 * is present, then its value must be a boolean. If it is not present, then 1095 * a default of {@code true} will be assumed. 1096 * </LI> 1097 * <LI> 1098 * "invoke-release-health-checks" -- Indicates whether the connection pool 1099 * should invoke health check processing on connections just before they are 1100 * released back to the pool to ensure that they are valid. If this field 1101 * is present, then its value must be a boolean. If it is not present, then 1102 * a default of {@code false} will be assumed. 1103 * </LI> 1104 * <LI> 1105 * "maximum-connection-age-millis" -- Specifies the maximum length of time 1106 * (in milliseconds) that a connection should be allowed to remain 1107 * established before it is eligible to be closed and replaced with a 1108 * newly-created connection. If present, then the value must be a positive 1109 * integer to specify the maximum age, or zero to indicate that no maximum 1110 * age should be applied. If it is not present, then a default value of 1111 * zero will be used. 1112 * </LI> 1113 * <LI> 1114 * "maximum-defunct-replacement-connection-age-millis" -- Specifies the 1115 * maximum connection age (in milliseconds) that should be used for 1116 * connections created to replace a defunct connection. If present, then 1117 * the value must be a positive integer to specify the maximum age, or zero 1118 * to indicate that no maximum age should be applied. If it is not present, 1119 * then the value of the "maximum-connection-age-millis" field will be used 1120 * for connections created as replacements for defunct connections. 1121 * </LI> 1122 * <LI> 1123 * "maximum-wait-time-millis" -- Specifies the maximum length of time (in 1124 * milliseconds) that the pool should wait for a connection to be released 1125 * if one is needed but none are immediately available. If present, then 1126 * this value must be a positive integer to specify the length of time to 1127 * wait, or zero to indicate that it should not wait at all. If it is not 1128 * provided, then a default value of zero will be used. 1129 * </LI> 1130 * <LI> 1131 * "retry-failed-operations-due-to-invalid-connections" -- Indicates whether 1132 * the pool should automatically attempt to retry operations attempted 1133 * directly against the pool (but not for connections checked out of the 1134 * pool) if the initial attempt fails in a manner that may indicate that the 1135 * connection is no longer valid. If this field is present, then its value 1136 * may be either a boolean to indicate whether to enable retry for all types 1137 * of operations or no operations, or it may be an array of strings 1138 * indicating the operation types ("add", "bind", "compare", "delete", 1139 * "extended", "modify", "modify-dn", or "search") that should be retried 1140 * in the event of a failure. If this field is not present, then no 1141 * automatic retry will be attempted. 1142 * </LI> 1143 * </UL> 1144 * <BR> 1145 * The "connection-pool-options" field is optional, and if it is omitted from 1146 * the specification then the default values will be used for all options. 1147 */ 1148@NotMutable() 1149@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 1150public final class LDAPConnectionDetailsJSONSpecification 1151{ 1152 /** 1153 * The name of the top-level field that may be used to provide information to 1154 * use to authenticate connections to the server. 1155 */ 1156 static final String FIELD_AUTHENTICATION_DETAILS = "authentication-details"; 1157 1158 1159 1160 /** 1161 * The name of the top-level field that may be used to provide information 1162 * about the type of communication security that should be used. 1163 */ 1164 static final String FIELD_COMMUNICATION_SECURITY = "communication-security"; 1165 1166 1167 1168 /** 1169 * The name of the top-level field that may be used to provide information 1170 * about options that should be set when establishing connections. 1171 */ 1172 static final String FIELD_CONNECTION_OPTIONS = "connection-options"; 1173 1174 1175 1176 /** 1177 * The name of the top-level field that may be used to provide information 1178 * about options that should be set when creating a connection pool. 1179 */ 1180 static final String FIELD_CONNECTION_POOL_OPTIONS = 1181 "connection-pool-options"; 1182 1183 1184 1185 /** 1186 * The name of the top-level field that may be used to provide information 1187 * about the directory server(s) to which the connection should be 1188 * established. 1189 */ 1190 static final String FIELD_SERVER_DETAILS = "server-details"; 1191 1192 1193 1194 // The bind request that will be used to authenticate connections. 1195 private final BindRequest bindRequest; 1196 1197 // The processed connection pool options portion of the specification. 1198 private final ConnectionPoolOptions connectionPoolOptionsSpec; 1199 1200 // The processed security options portion of the specification. 1201 private final SecurityOptions securityOptionsSpec; 1202 1203 // The server set that will be used to create connections. 1204 private final ServerSet serverSet; 1205 1206 1207 1208 /** 1209 * Creates a new LDAP connection details object from the specification 1210 * contained in the provided JSON object. 1211 * 1212 * @param connectionDetailsObject The JSON object that contains information 1213 * that may be used to create LDAP 1214 * connections. 1215 * 1216 * @throws LDAPException If the provided JSON object does not contain a 1217 * valid connection details specification. 1218 */ 1219 public LDAPConnectionDetailsJSONSpecification( 1220 final JSONObject connectionDetailsObject) 1221 throws LDAPException 1222 { 1223 validateTopLevelFields(connectionDetailsObject); 1224 1225 try 1226 { 1227 securityOptionsSpec = new SecurityOptions(connectionDetailsObject); 1228 } 1229 catch (final LDAPException le) 1230 { 1231 Debug.debugException(le); 1232 throw new LDAPException(le.getResultCode(), 1233 ERR_LDAP_SPEC_ERROR_PROCESSING_FIELD.get( 1234 FIELD_COMMUNICATION_SECURITY, le.getMessage()), 1235 le); 1236 } 1237 1238 final ConnectionOptions connectionOptionsSpec; 1239 try 1240 { 1241 connectionOptionsSpec = new ConnectionOptions(connectionDetailsObject); 1242 } 1243 catch (final LDAPException le) 1244 { 1245 Debug.debugException(le); 1246 throw new LDAPException(le.getResultCode(), 1247 ERR_LDAP_SPEC_ERROR_PROCESSING_FIELD.get( 1248 FIELD_CONNECTION_OPTIONS, le.getMessage()), 1249 le); 1250 } 1251 1252 try 1253 { 1254 final ServerDetails serverDetailsSpec = 1255 new ServerDetails(connectionDetailsObject, securityOptionsSpec, 1256 connectionOptionsSpec); 1257 serverSet = serverDetailsSpec.getServerSet(); 1258 } 1259 catch (final LDAPException le) 1260 { 1261 Debug.debugException(le); 1262 throw new LDAPException(le.getResultCode(), 1263 ERR_LDAP_SPEC_ERROR_PROCESSING_FIELD.get( 1264 FIELD_SERVER_DETAILS, le.getMessage()), 1265 le); 1266 } 1267 1268 try 1269 { 1270 final AuthenticationDetails authenticationDetailsSpec = 1271 new AuthenticationDetails(connectionDetailsObject); 1272 bindRequest = authenticationDetailsSpec.getBindRequest(); 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_AUTHENTICATION_DETAILS, le.getMessage()), 1280 le); 1281 } 1282 1283 try 1284 { 1285 connectionPoolOptionsSpec = 1286 new ConnectionPoolOptions(connectionDetailsObject); 1287 } 1288 catch (final LDAPException le) 1289 { 1290 Debug.debugException(le); 1291 throw new LDAPException(le.getResultCode(), 1292 ERR_LDAP_SPEC_ERROR_PROCESSING_FIELD.get( 1293 FIELD_CONNECTION_POOL_OPTIONS, le.getMessage()), 1294 le); 1295 } 1296 } 1297 1298 1299 1300 /** 1301 * Creates a new LDAP connection details object from the specification 1302 * contained in the JSON object represented by the given string. 1303 * 1304 * @param jsonString The string representation of the JSON object that 1305 * contains information that may be used to create LDAP 1306 * connections. 1307 * 1308 * @return The LDAP connection details object parsed from the provided 1309 * JSON object string. 1310 * 1311 * @throws JSONException If the provided string cannot be parsed as a valid 1312 * JSON object. 1313 * 1314 * @throws LDAPException If the parsed JSON object does not contain a valid 1315 * connection details specification. 1316 */ 1317 public static LDAPConnectionDetailsJSONSpecification fromString( 1318 final String jsonString) 1319 throws JSONException, LDAPException 1320 { 1321 return new LDAPConnectionDetailsJSONSpecification( 1322 new JSONObject(jsonString)); 1323 } 1324 1325 1326 1327 /** 1328 * Creates a new LDAP connection details object from the specification 1329 * contained in the JSON object read from the indicated file. 1330 * 1331 * @param path The path to a file containing a JSON object with information 1332 * that may be used to create LDAP connections. 1333 * 1334 * @return The LDAP connection details object parsed from the information in 1335 * the specified file. 1336 * 1337 * @throws IOException If a problem is encountered while reading from the 1338 * specified file. 1339 * 1340 * @throws JSONException If the contents of the specified file cannot be 1341 * parsed as a valid JSON object. 1342 * 1343 * @throws LDAPException If the parsed JSON object does not contain a valid 1344 * connection details specification. 1345 */ 1346 public static LDAPConnectionDetailsJSONSpecification fromFile( 1347 final String path) 1348 throws IOException, JSONException, LDAPException 1349 { 1350 return fromFile(new File(path)); 1351 } 1352 1353 1354 1355 /** 1356 * Creates a new LDAP connection details object from the specification 1357 * contained in the JSON object read from the indicated file. 1358 * 1359 * @param file The file containing a JSON object with information that may 1360 * be used to create LDAP connections. 1361 * 1362 * @return The LDAP connection details object parsed from the information in 1363 * the specified file. 1364 * 1365 * @throws IOException If a problem is encountered while reading from the 1366 * specified file. 1367 * 1368 * @throws JSONException If the contents of the specified file cannot be 1369 * parsed as a valid JSON object. 1370 * 1371 * @throws LDAPException If the parsed JSON object does not contain a valid 1372 * connection details specification. 1373 */ 1374 public static LDAPConnectionDetailsJSONSpecification fromFile(final File file) 1375 throws IOException, JSONException, LDAPException 1376 { 1377 return fromInputStream(new FileInputStream(file)); 1378 } 1379 1380 1381 1382 /** 1383 * Creates a new LDAP connection details object from the specification 1384 * contained in the JSON object read from the provided input stream. The 1385 * entire contents of the stream must be exactly one JSON object. Because the 1386 * input stream will be fully read, it will always be closed by this method. 1387 * 1388 * @param inputStream The input stream from which to read a JSON object with 1389 * information that may be used to create LDAP 1390 * connections. The entire contents of the stream must 1391 * be exactly one JSON object. Because the input stream 1392 * will be fully read, it will always be closed by this 1393 * method. 1394 * 1395 * @return The LDAP connection details object parsed from the information 1396 * read from the provided input stream. 1397 * 1398 * @throws IOException If a problem is encountered while reading from the 1399 * provided input stream. 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 public static LDAPConnectionDetailsJSONSpecification fromInputStream( 1408 final InputStream inputStream) 1409 throws IOException, JSONException, LDAPException 1410 { 1411 try 1412 { 1413 final ByteStringBuffer b = new ByteStringBuffer(); 1414 final byte[] readBuffer = new byte[8192]; 1415 while (true) 1416 { 1417 final int bytesRead = inputStream.read(readBuffer); 1418 if (bytesRead < 0) 1419 { 1420 break; 1421 } 1422 else 1423 { 1424 b.append(readBuffer, 0, bytesRead); 1425 } 1426 } 1427 1428 return new LDAPConnectionDetailsJSONSpecification( 1429 new JSONObject(b.toString())); 1430 } 1431 finally 1432 { 1433 inputStream.close(); 1434 } 1435 } 1436 1437 1438 1439 /** 1440 * Retrieves the server set that may be used to create new connections based 1441 * on the JSON specification. 1442 * 1443 * @return The server set that may be used to create new connections based on 1444 * the JSON specification. 1445 */ 1446 public ServerSet getServerSet() 1447 { 1448 return serverSet; 1449 } 1450 1451 1452 1453 /** 1454 * Retrieves the bind request that may be used to authenticate connections 1455 * created from the JSON specification. 1456 * 1457 * @return The bind request that may be used to authenticate connections 1458 * created from the JSON specification, or {@code null} if the 1459 * connections should be unauthenticated. 1460 */ 1461 public BindRequest getBindRequest() 1462 { 1463 return bindRequest; 1464 } 1465 1466 1467 1468 /** 1469 * Creates a new LDAP connection based on the JSON specification. The 1470 * connection will be authenticated if appropriate. 1471 * 1472 * @return The LDAP connection that was created. 1473 * 1474 * @throws LDAPException If a problem is encountered while trying to 1475 * establish or authenticate the connection. 1476 */ 1477 public LDAPConnection createConnection() 1478 throws LDAPException 1479 { 1480 final LDAPConnection connection = createUnauthenticatedConnection(); 1481 1482 if (bindRequest != null) 1483 { 1484 try 1485 { 1486 connection.bind(bindRequest); 1487 } 1488 catch (final LDAPException le) 1489 { 1490 Debug.debugException(le); 1491 connection.close(); 1492 throw le; 1493 } 1494 } 1495 1496 return connection; 1497 } 1498 1499 1500 1501 /** 1502 * Creates a new LDAP connection based on the JSON specification. No 1503 * authentication will be performed on the connection. 1504 * 1505 * @return The LDAP connection that was created. 1506 * 1507 * @throws LDAPException If a problem is encountered while trying to 1508 * establish the connection. 1509 */ 1510 public LDAPConnection createUnauthenticatedConnection() 1511 throws LDAPException 1512 { 1513 return serverSet.getConnection(); 1514 } 1515 1516 1517 1518 /** 1519 * Creates a new LDAP connection pool based on the JSON specification. The 1520 * pooled connections will be authenticated if appropriate. 1521 * 1522 * @param initialConnections The number of connections that should be 1523 * established at the time the pool is created. 1524 * @param maximumConnections The maximum number of connections that should 1525 * be available in the pool at any time. 1526 * 1527 * @return The LDAP connection pool that was created. 1528 * 1529 * @throws LDAPException If a problem is encountered while attempting to 1530 * create the connection pool. 1531 */ 1532 public LDAPConnectionPool createConnectionPool(final int initialConnections, 1533 final int maximumConnections) 1534 throws LDAPException 1535 { 1536 final LDAPConnectionPool connectionPool = new LDAPConnectionPool(serverSet, 1537 bindRequest, initialConnections, maximumConnections, 1538 connectionPoolOptionsSpec.getInitialConnectThreads(), 1539 securityOptionsSpec.getPostConnectProcessor(), false, 1540 connectionPoolOptionsSpec.getHealthCheck()); 1541 1542 connectionPoolOptionsSpec.applyConnectionPoolSettings(connectionPool); 1543 return connectionPool; 1544 } 1545 1546 1547 1548 /** 1549 * Creates a new LDAP connection pool based on the JSON specification. No 1550 * authentication will be used for connections that are part of the pool. 1551 * 1552 * @param initialConnections The number of connections that should be 1553 * established at the time the pool is created. 1554 * @param maximumConnections The maximum number of connections that should 1555 * be available in the pool at any time. 1556 * 1557 * @return The LDAP connection pool that was created. 1558 * 1559 * @throws LDAPException If a problem is encountered while attempting to 1560 * create the connection pool. 1561 */ 1562 public LDAPConnectionPool createUnauthenticatedConnectionPool( 1563 final int initialConnections, 1564 final int maximumConnections) 1565 throws LDAPException 1566 { 1567 final LDAPConnectionPool connectionPool = new LDAPConnectionPool(serverSet, 1568 null, initialConnections, maximumConnections, 1569 connectionPoolOptionsSpec.getInitialConnectThreads(), 1570 securityOptionsSpec.getPostConnectProcessor(), false, 1571 connectionPoolOptionsSpec.getHealthCheck()); 1572 1573 connectionPoolOptionsSpec.applyConnectionPoolSettings(connectionPool); 1574 return connectionPool; 1575 } 1576 1577 1578 1579 /** 1580 * Validates the top-level fields in the provided JSON object to ensure that 1581 * all required fields are present and no unrecognized fields are present. 1582 * 1583 * @param o The JSON object to validate. 1584 * 1585 * @throws LDAPException If there is a problem with the set of top-level 1586 * fields in the provided JSON object. 1587 */ 1588 private static void validateTopLevelFields(final JSONObject o) 1589 throws LDAPException 1590 { 1591 boolean serverDetailsProvided = false; 1592 for (final String s : o.getFields().keySet()) 1593 { 1594 if (s.equals(FIELD_SERVER_DETAILS)) 1595 { 1596 // This is a required top-level field. 1597 serverDetailsProvided = true; 1598 } 1599 else if (s.equals(FIELD_CONNECTION_OPTIONS) || 1600 s.equals(FIELD_COMMUNICATION_SECURITY) || 1601 s.equals(FIELD_AUTHENTICATION_DETAILS) || 1602 s.equals(FIELD_CONNECTION_POOL_OPTIONS)) 1603 { 1604 // These are optional top-level fields. 1605 } 1606 else 1607 { 1608 // This is not a valid top-level field. 1609 throw new LDAPException(ResultCode.PARAM_ERROR, 1610 ERR_LDAP_SPEC_UNRECOGNIZED_TOP_LEVEL_FIELD.get(s)); 1611 } 1612 } 1613 1614 if (! serverDetailsProvided) 1615 { 1616 throw new LDAPException(ResultCode.PARAM_ERROR, 1617 ERR_LDAP_SPEC_MISSING_SERVER_DETAILS.get(FIELD_SERVER_DETAILS)); 1618 } 1619 } 1620 1621 1622 1623 /** 1624 * Validates that the set of fields contained in the JSON object that is the 1625 * value of the indicated field. 1626 * 1627 * @param o The JSON object to validate. 1628 * @param f The name of the field whose value is the provided JSON object. 1629 * @param a The names of the fields that are allowed to be present. 1630 * 1631 * @throws LDAPException If the provided JSON object contains any fields 1632 * that are not contained in the allowed set. 1633 */ 1634 static void validateAllowedFields(final JSONObject o, final String f, 1635 final String... a) 1636 throws LDAPException 1637 { 1638 final HashSet<String> s = new HashSet<>(Arrays.asList(a)); 1639 for (final String n : o.getFields().keySet()) 1640 { 1641 if (! s.contains(n)) 1642 { 1643 throw new LDAPException(ResultCode.PARAM_ERROR, 1644 ERR_LDAP_SPEC_UNRECOGNIZED_FIELD.get(n, f)); 1645 } 1646 } 1647 } 1648 1649 1650 1651 /** 1652 * Retrieves the value of the specified JSON object field as a boolean. 1653 * 1654 * @param o The object from which to retrieve the boolean value. 1655 * @param f The name of the field to retrieve. 1656 * @param d The default value to return if the specified field does not 1657 * exist. 1658 * 1659 * @return The requested boolean value. 1660 * 1661 * @throws LDAPException If the specified field exists but is not a boolean. 1662 */ 1663 static boolean getBoolean(final JSONObject o, final String f, final boolean d) 1664 throws LDAPException 1665 { 1666 final JSONValue v = o.getField(f); 1667 if (v == null) 1668 { 1669 return d; 1670 } 1671 1672 if (v instanceof JSONBoolean) 1673 { 1674 return ((JSONBoolean) v).booleanValue(); 1675 } 1676 else 1677 { 1678 throw new LDAPException(ResultCode.PARAM_ERROR, 1679 ERR_LDAP_SPEC_VALUE_NOT_BOOLEAN.get(f)); 1680 } 1681 } 1682 1683 1684 1685 /** 1686 * Retrieves the value of the specified JSON object field as an integer. 1687 * 1688 * @param o The object from which to retrieve the integer value. 1689 * @param f The name of the field to retrieve. 1690 * @param d The default value to return if the specified field does not 1691 * exist. 1692 * @param n The minimum allowed value for the field, if any. 1693 * @param x The maximum allowed value for the field, if any. 1694 * 1695 * @return The requested integer value. 1696 * 1697 * @throws LDAPException If the specified field exists but is not an 1698 * integer. 1699 */ 1700 static Integer getInt(final JSONObject o, final String f, final Integer d, 1701 final Integer n, final Integer x) 1702 throws LDAPException 1703 { 1704 final JSONValue v = o.getField(f); 1705 if (v == null) 1706 { 1707 return d; 1708 } 1709 1710 if (v instanceof JSONNumber) 1711 { 1712 try 1713 { 1714 final int i =((JSONNumber) v).getValue().intValueExact(); 1715 if ((n != null) && (i < n)) 1716 { 1717 throw new LDAPException(ResultCode.PARAM_ERROR, 1718 ERR_LDAP_SPEC_VALUE_BELOW_MIN.get(f, n)); 1719 } 1720 1721 if ((x != null) && (i > x)) 1722 { 1723 throw new LDAPException(ResultCode.PARAM_ERROR, 1724 ERR_LDAP_SPEC_VALUE_ABOVE_MAX.get(f, n)); 1725 } 1726 1727 return i; 1728 } 1729 catch (final LDAPException le) 1730 { 1731 Debug.debugException(le); 1732 throw le; 1733 } 1734 catch (final Exception e) 1735 { 1736 Debug.debugException(e); 1737 throw new LDAPException(ResultCode.PARAM_ERROR, 1738 ERR_LDAP_SPEC_VALUE_NOT_INTEGER.get(f), e); 1739 } 1740 } 1741 else 1742 { 1743 throw new LDAPException(ResultCode.PARAM_ERROR, 1744 ERR_LDAP_SPEC_VALUE_NOT_INTEGER.get(f)); 1745 } 1746 } 1747 1748 1749 1750 /** 1751 * Retrieves the value of the specified JSON object field as a long. 1752 * 1753 * @param o The object from which to retrieve the long value. 1754 * @param f The name of the field to retrieve. 1755 * @param d The default value to return if the specified field does not 1756 * exist. 1757 * @param n The minimum allowed value for the field, if any. 1758 * @param x The maximum allowed value for the field, if any. 1759 * 1760 * @return The requested long value. 1761 * 1762 * @throws LDAPException If the specified field exists but is not a long. 1763 */ 1764 static Long getLong(final JSONObject o, final String f, final Long d, 1765 final Long n, final Long x) 1766 throws LDAPException 1767 { 1768 final JSONValue v = o.getField(f); 1769 if (v == null) 1770 { 1771 return d; 1772 } 1773 1774 if (v instanceof JSONNumber) 1775 { 1776 try 1777 { 1778 final long l =((JSONNumber) v).getValue().longValueExact(); 1779 if ((n != null) && (l < n)) 1780 { 1781 throw new LDAPException(ResultCode.PARAM_ERROR, 1782 ERR_LDAP_SPEC_VALUE_BELOW_MIN.get(f, n)); 1783 } 1784 1785 if ((x != null) && (l > x)) 1786 { 1787 throw new LDAPException(ResultCode.PARAM_ERROR, 1788 ERR_LDAP_SPEC_VALUE_ABOVE_MAX.get(f, n)); 1789 } 1790 1791 return l; 1792 } 1793 catch (final LDAPException le) 1794 { 1795 Debug.debugException(le); 1796 throw le; 1797 } 1798 catch (final Exception e) 1799 { 1800 Debug.debugException(e); 1801 throw new LDAPException(ResultCode.PARAM_ERROR, 1802 ERR_LDAP_SPEC_VALUE_NOT_INTEGER.get(f), e); 1803 } 1804 } 1805 else 1806 { 1807 throw new LDAPException(ResultCode.PARAM_ERROR, 1808 ERR_LDAP_SPEC_VALUE_NOT_INTEGER.get(f)); 1809 } 1810 } 1811 1812 1813 1814 /** 1815 * Retrieves the value of the specified JSON object field as an object. 1816 * 1817 * @param o The object from which to retrieve the object value. 1818 * @param f The name of the field to retrieve. 1819 * 1820 * @return The requested object value. 1821 * 1822 * @throws LDAPException If the specified field exists but is not an object. 1823 */ 1824 static JSONObject getObject(final JSONObject o, final String f) 1825 throws LDAPException 1826 { 1827 final JSONValue v = o.getField(f); 1828 if (v == null) 1829 { 1830 return null; 1831 } 1832 1833 if (v instanceof JSONObject) 1834 { 1835 return (JSONObject) v; 1836 } 1837 else 1838 { 1839 throw new LDAPException(ResultCode.PARAM_ERROR, 1840 ERR_LDAP_SPEC_VALUE_NOT_OBJECT.get(f)); 1841 } 1842 } 1843 1844 1845 1846 /** 1847 * Retrieves the value of the specified JSON object field as a string. 1848 * 1849 * @param o The object from which to retrieve the string value. 1850 * @param f The name of the field to retrieve. 1851 * @param d The default value to return if the specified field does not 1852 * exist. 1853 * 1854 * @return The requested string value. 1855 * 1856 * @throws LDAPException If the specified field exists but is not a string. 1857 */ 1858 static String getString(final JSONObject o, final String f, final String d) 1859 throws LDAPException 1860 { 1861 final JSONValue v = o.getField(f); 1862 if (v == null) 1863 { 1864 return d; 1865 } 1866 1867 if (v instanceof JSONString) 1868 { 1869 return ((JSONString) v).stringValue(); 1870 } 1871 else 1872 { 1873 throw new LDAPException(ResultCode.PARAM_ERROR, 1874 ERR_LDAP_SPEC_VALUE_NOT_STRING.get(f)); 1875 } 1876 } 1877 1878 1879 1880 /** 1881 * Retrieves a string value read from the specified file. The file must 1882 * contain exactly one line, and that line must not be empty. 1883 * 1884 * @param path The path to the file from which to read the string. 1885 * @param fieldName The name of the field from which the path was obtained. 1886 * 1887 * @return The string read from the specified file. 1888 * 1889 * @throws LDAPException If a problem is encountered while reading from the 1890 * specified file, if the file does not contain 1891 * exactly one line, or if the line contained in the 1892 * file is empty. 1893 */ 1894 static String getStringFromFile(final String path, final String fieldName) 1895 throws LDAPException 1896 { 1897 BufferedReader r = null; 1898 try 1899 { 1900 r = new BufferedReader(new FileReader(path)); 1901 1902 final String line = r.readLine(); 1903 if (line == null) 1904 { 1905 throw new LDAPException(ResultCode.PARAM_ERROR, 1906 ERR_LDAP_SPEC_READ_FILE_EMPTY.get(path, fieldName)); 1907 } 1908 1909 if (r.readLine() != null) 1910 { 1911 throw new LDAPException(ResultCode.PARAM_ERROR, 1912 ERR_LDAP_SPEC_READ_FILE_MULTIPLE_LINES.get(path, fieldName)); 1913 } 1914 1915 if (line.isEmpty()) 1916 { 1917 throw new LDAPException(ResultCode.PARAM_ERROR, 1918 ERR_LDAP_SPEC_READ_FILE_EMPTY_LINE.get(path, fieldName)); 1919 } 1920 1921 return line; 1922 } 1923 catch (final LDAPException le) 1924 { 1925 Debug.debugException(le); 1926 throw le; 1927 } 1928 catch (final Exception e) 1929 { 1930 Debug.debugException(e); 1931 throw new LDAPException(ResultCode.PARAM_ERROR, 1932 ERR_LDAP_SPEC_READ_FILE_ERROR.get(path, fieldName, 1933 StaticUtils.getExceptionMessage(e)), 1934 e); 1935 } 1936 finally 1937 { 1938 if (r != null) 1939 { 1940 try 1941 { 1942 r.close(); 1943 } 1944 catch (final Exception e) 1945 { 1946 Debug.debugException(e); 1947 } 1948 } 1949 } 1950 } 1951 1952 1953 1954 /** 1955 * Verifies that none of the indicated fields exist in the provided JSON 1956 * object because they would conflict with the specified existing field. 1957 * 1958 * @param o The JSON object to examine. 1959 * @param existingField The name of a field known to be present in the 1960 * JSON object that cannot coexist with the 1961 * indicated conflicting fields. 1962 * @param conflictingFields The names of the fields that cannot be used in 1963 * conjunction with the specified existing field. 1964 * 1965 * @throws LDAPException If the provided JSON object has one or more fields 1966 * that conflict with the specified existing field. 1967 */ 1968 static void rejectConflictingFields(final JSONObject o, 1969 final String existingField, 1970 final String... conflictingFields) 1971 throws LDAPException 1972 { 1973 for (final String fieldName : conflictingFields) 1974 { 1975 if (o.getField(fieldName) != null) 1976 { 1977 throw new LDAPException(ResultCode.PARAM_ERROR, 1978 ERR_LDAP_SPEC_CONFLICTING_FIELD.get(fieldName, existingField)); 1979 } 1980 } 1981 } 1982 1983 1984 1985 /** 1986 * Verifies that none of the indicated fields exist in the provided JSON 1987 * object because they can only be provided if the specified required field is 1988 * present. 1989 * 1990 * @param o The JSON object to examine. 1991 * @param requiredField The name of a field known to be missing from the 1992 * JSON object, but must be present to allow any of 1993 * the indicated dependent fields to be provided. 1994 * @param dependentFields The names of the fields that can only be present 1995 * if the specified required field is present. 1996 * 1997 * @throws LDAPException If the provided JSON object has one or more 1998 * unresolved dependencies. 1999 */ 2000 static void rejectUnresolvedDependency(final JSONObject o, 2001 final String requiredField, 2002 final String... dependentFields) 2003 throws LDAPException 2004 { 2005 for (final String fieldName : dependentFields) 2006 { 2007 if (o.getField(fieldName) != null) 2008 { 2009 throw new LDAPException(ResultCode.PARAM_ERROR, 2010 ERR_LDAP_SPEC_MISSING_DEPENDENT_FIELD.get(fieldName, 2011 requiredField)); 2012 } 2013 } 2014 } 2015}