001/* 002 * Copyright 2011-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2011-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.ldap.listener; 022 023 024 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.Collection; 028import java.util.Collections; 029import java.util.EnumSet; 030import java.util.HashSet; 031import java.util.Iterator; 032import java.util.LinkedHashMap; 033import java.util.LinkedHashSet; 034import java.util.List; 035import java.util.Map; 036import java.util.Set; 037import java.util.logging.Handler; 038 039import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor; 040import com.unboundid.ldap.sdk.DN; 041import com.unboundid.ldap.sdk.Entry; 042import com.unboundid.ldap.sdk.LDAPException; 043import com.unboundid.ldap.sdk.OperationType; 044import com.unboundid.ldap.sdk.ReadOnlyEntry; 045import com.unboundid.ldap.sdk.ResultCode; 046import com.unboundid.ldap.sdk.Version; 047import com.unboundid.ldap.sdk.schema.Schema; 048import com.unboundid.util.Mutable; 049import com.unboundid.util.NotExtensible; 050import com.unboundid.util.StaticUtils; 051import com.unboundid.util.ThreadSafety; 052import com.unboundid.util.ThreadSafetyLevel; 053 054import static com.unboundid.ldap.listener.ListenerMessages.*; 055 056 057 058/** 059 * This class provides a simple data structure with information that may be 060 * used to control the behavior of an {@link InMemoryDirectoryServer} instance. 061 * At least one base DN must be specified. For all other properties, the 062 * following default values will be used unless an alternate configuration is 063 * provided: 064 * <UL> 065 * <LI>Listeners: The server will provide a single listener that will use an 066 * automatically-selected port on all interfaces, which will not use SSL 067 * or StartTLS.</LI> 068 * <LI>Allowed Operation Types: All types of operations will be allowed.</LI> 069 * <LI>Authentication Required Operation Types: Authentication will not be 070 * required for any types of operations.</LI> 071 * <LI>Schema: The server will use a schema with a number of standard 072 * attribute types and object classes.</LI> 073 * <LI>Additional Bind Credentials: The server will not have any additional 074 * bind credentials.</LI> 075 * <LI>Referential Integrity Attributes: Referential integrity will not be 076 * maintained.</LI> 077 * <LI>Generate Operational Attributes: The server will automatically 078 * generate a number of operational attributes.</LI> 079 * <LI>Extended Operation Handlers: The server will support the password 080 * modify extended operation as defined in RFC 3062, the start and end 081 * transaction extended operations as defined in RFC 5805, and the 082 * "Who Am I?" extended operation as defined in RFC 4532.</LI> 083 * <LI>SASL Bind Handlers: The server will support the SASL PLAIN mechanism 084 * as defined in RFC 4616.</LI> 085 * <LI>Max ChangeLog Entries: The server will not provide an LDAP 086 * changelog.</LI> 087 * <LI>Access Log Handler: The server will not perform any access 088 * logging.</LI> 089 * <LI>Code Log Handler: The server will not perform any code logging.</LI> 090 * <LI>LDAP Debug Log Handler: The server will not perform any LDAP debug 091 * logging.</LI> 092 * <LI>Listener Exception Handler: The server will not use a listener 093 * exception handler.</LI> 094 * <LI>Maximum Size Limit: The server will not enforce a maximum search size 095 * limit.</LI> 096 * <LI>Password Attributes: The server will use userPassword as the only 097 * password attribute.</LI> 098 * <LI>Password Encoders: The server will not use any password encoders by 099 * default, so passwords will remain in clear text.</LI> 100 * </UL> 101 */ 102@NotExtensible() 103@Mutable() 104@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 105public class InMemoryDirectoryServerConfig 106{ 107 // Indicates whether to enforce the requirement that attribute values comply 108 // with the associated attribute syntax. 109 private boolean enforceAttributeSyntaxCompliance; 110 111 // Indicates whether to enforce the requirement that entries contain exactly 112 // one structural object class. 113 private boolean enforceSingleStructuralObjectClass; 114 115 // Indicates whether to automatically generate operational attributes. 116 private boolean generateOperationalAttributes; 117 118 // Indicates whether the code log should include sample code for processing 119 // the requests. 120 private boolean includeRequestProcessingInCodeLog; 121 122 // The base DNs to use for the LDAP listener. 123 private DN[] baseDNs; 124 125 // The log handler that should be used to record access log messages about 126 // operations processed by the server. 127 private Handler accessLogHandler; 128 129 // The log handler that should be used to record detailed protocol-level 130 // messages about LDAP operations processed by the server. 131 private Handler ldapDebugLogHandler; 132 133 // The password encoder that will be used to encode new clear-text passwords. 134 private InMemoryPasswordEncoder primaryPasswordEncoder; 135 136 // The maximum number of entries to retain in a generated changelog. 137 private int maxChangeLogEntries; 138 139 // The maximum number of concurrent connections that will be allowed. 140 private int maxConnections; 141 142 // The maximum number of entries that may be returned in any single search 143 // operation. 144 private int maxSizeLimit; 145 146 // The exception handler that should be used for the listener. 147 private LDAPListenerExceptionHandler exceptionHandler; 148 149 // The extended operation handlers that may be used to process extended 150 // operations in the server. 151 private final List<InMemoryExtendedOperationHandler> 152 extendedOperationHandlers; 153 154 // The listener configurations that should be used for accepting connections 155 // to the server. 156 private final List<InMemoryListenerConfig> listenerConfigs; 157 158 // The operation interceptors that should be used with the in-memory directory 159 // server. 160 private final List<InMemoryOperationInterceptor> operationInterceptors; 161 162 // A list of secondary password encoders that will be used to interact with 163 // existing pre-encoded passwords, but will not be used to encode new 164 // passwords. 165 private final List<InMemoryPasswordEncoder> secondaryPasswordEncoders; 166 167 // The SASL bind handlers that may be used to process SASL bind requests in 168 // the server. 169 private final List<InMemorySASLBindHandler> saslBindHandlers; 170 171 // The names or OIDs of the attributes for which to maintain equality indexes. 172 private final List<String> equalityIndexAttributes; 173 174 // A set of additional credentials that can be used for binding without 175 // requiring a corresponding entry in the data set. 176 private final Map<DN,byte[]> additionalBindCredentials; 177 178 // The entry to use for the server root DSE. 179 private ReadOnlyEntry rootDSEEntry; 180 181 // The schema to use for the server. 182 private Schema schema; 183 184 // The set of operation types that will be supported by the server. 185 private final Set<OperationType> allowedOperationTypes; 186 187 // The set of operation types for which authentication will be required. 188 private final Set<OperationType> authenticationRequiredOperationTypes; 189 190 // The set of attributes for which referential integrity should be maintained. 191 private final Set<String> referentialIntegrityAttributes; 192 193 // The set of attributes that will hold user passwords. 194 private final Set<String> passwordAttributes; 195 196 // The path to a file that should be written with code that may be used to 197 // issue the requests received by the server. 198 private String codeLogPath; 199 200 // The vendor name to report in the server root DSE. 201 private String vendorName; 202 203 // The vendor version to report in the server root DSE. 204 private String vendorVersion; 205 206 207 208 /** 209 * Creates a new in-memory directory server config object with the provided 210 * set of base DNs. 211 * 212 * @param baseDNs The set of base DNs to use for the server. It must not 213 * be {@code null} or empty. 214 * 215 * @throws LDAPException If the provided set of base DN strings is null or 216 * empty, or if any of the provided base DN strings 217 * cannot be parsed as a valid DN. 218 */ 219 public InMemoryDirectoryServerConfig(final String... baseDNs) 220 throws LDAPException 221 { 222 this(parseDNs(Schema.getDefaultStandardSchema(), baseDNs)); 223 } 224 225 226 227 /** 228 * Creates a new in-memory directory server config object with the default 229 * settings. 230 * 231 * @param baseDNs The set of base DNs to use for the server. It must not 232 * be {@code null} or empty. 233 * 234 * @throws LDAPException If the provided set of base DNs is null or empty. 235 */ 236 public InMemoryDirectoryServerConfig(final DN... baseDNs) 237 throws LDAPException 238 { 239 if ((baseDNs == null) || (baseDNs.length == 0)) 240 { 241 throw new LDAPException(ResultCode.PARAM_ERROR, 242 ERR_MEM_DS_CFG_NO_BASE_DNS.get()); 243 } 244 245 this.baseDNs = baseDNs; 246 247 listenerConfigs = new ArrayList<>(1); 248 listenerConfigs.add(InMemoryListenerConfig.createLDAPConfig("default")); 249 250 additionalBindCredentials = 251 new LinkedHashMap<>(StaticUtils.computeMapCapacity(1)); 252 accessLogHandler = null; 253 ldapDebugLogHandler = null; 254 enforceAttributeSyntaxCompliance = true; 255 enforceSingleStructuralObjectClass = true; 256 generateOperationalAttributes = true; 257 maxChangeLogEntries = 0; 258 maxConnections = 0; 259 maxSizeLimit = 0; 260 exceptionHandler = null; 261 equalityIndexAttributes = new ArrayList<>(10); 262 rootDSEEntry = null; 263 schema = Schema.getDefaultStandardSchema(); 264 allowedOperationTypes = EnumSet.allOf(OperationType.class); 265 authenticationRequiredOperationTypes = EnumSet.noneOf(OperationType.class); 266 referentialIntegrityAttributes = new HashSet<>(0); 267 vendorName = "Ping Identity Corporation"; 268 vendorVersion = Version.FULL_VERSION_STRING; 269 codeLogPath = null; 270 includeRequestProcessingInCodeLog = false; 271 272 operationInterceptors = new ArrayList<>(5); 273 274 extendedOperationHandlers = new ArrayList<>(3); 275 extendedOperationHandlers.add(new PasswordModifyExtendedOperationHandler()); 276 extendedOperationHandlers.add(new TransactionExtendedOperationHandler()); 277 extendedOperationHandlers.add(new WhoAmIExtendedOperationHandler()); 278 279 saslBindHandlers = new ArrayList<>(1); 280 saslBindHandlers.add(new PLAINBindHandler()); 281 282 passwordAttributes = new LinkedHashSet<>(StaticUtils.computeMapCapacity(5)); 283 passwordAttributes.add("userPassword"); 284 285 primaryPasswordEncoder = null; 286 287 secondaryPasswordEncoders = new ArrayList<>(5); 288 } 289 290 291 292 /** 293 * Creates a new in-memory directory server config object that is a duplicate 294 * of the provided config and may be altered without impacting the state of 295 * the given config object. 296 * 297 * @param cfg The in-memory directory server config object for to be 298 * duplicated. 299 */ 300 public InMemoryDirectoryServerConfig(final InMemoryDirectoryServerConfig cfg) 301 { 302 baseDNs = new DN[cfg.baseDNs.length]; 303 System.arraycopy(cfg.baseDNs, 0, baseDNs, 0, baseDNs.length); 304 305 listenerConfigs = new ArrayList<>(cfg.listenerConfigs); 306 307 operationInterceptors = new ArrayList<>(cfg.operationInterceptors); 308 309 extendedOperationHandlers = new ArrayList<>(cfg.extendedOperationHandlers); 310 311 saslBindHandlers = new ArrayList<>(cfg.saslBindHandlers); 312 313 additionalBindCredentials = 314 new LinkedHashMap<>(cfg.additionalBindCredentials); 315 316 referentialIntegrityAttributes = 317 new HashSet<>(cfg.referentialIntegrityAttributes); 318 319 allowedOperationTypes = EnumSet.noneOf(OperationType.class); 320 allowedOperationTypes.addAll(cfg.allowedOperationTypes); 321 322 authenticationRequiredOperationTypes = EnumSet.noneOf(OperationType.class); 323 authenticationRequiredOperationTypes.addAll( 324 cfg.authenticationRequiredOperationTypes); 325 326 equalityIndexAttributes = new ArrayList<>(cfg.equalityIndexAttributes); 327 328 enforceAttributeSyntaxCompliance = cfg.enforceAttributeSyntaxCompliance; 329 enforceSingleStructuralObjectClass = cfg.enforceSingleStructuralObjectClass; 330 generateOperationalAttributes = cfg.generateOperationalAttributes; 331 accessLogHandler = cfg.accessLogHandler; 332 ldapDebugLogHandler = cfg.ldapDebugLogHandler; 333 maxChangeLogEntries = cfg.maxChangeLogEntries; 334 maxConnections = cfg.maxConnections; 335 maxSizeLimit = cfg.maxSizeLimit; 336 exceptionHandler = cfg.exceptionHandler; 337 rootDSEEntry = cfg.rootDSEEntry; 338 schema = cfg.schema; 339 vendorName = cfg.vendorName; 340 vendorVersion = cfg.vendorVersion; 341 codeLogPath = cfg.codeLogPath; 342 includeRequestProcessingInCodeLog = cfg.includeRequestProcessingInCodeLog; 343 primaryPasswordEncoder = cfg.primaryPasswordEncoder; 344 345 passwordAttributes = new LinkedHashSet<>(cfg.passwordAttributes); 346 347 secondaryPasswordEncoders = new ArrayList<>(cfg.secondaryPasswordEncoders); 348 } 349 350 351 352 /** 353 * Retrieves the set of base DNs that should be used for the directory server. 354 * 355 * @return The set of base DNs that should be used for the directory server. 356 */ 357 public DN[] getBaseDNs() 358 { 359 return baseDNs; 360 } 361 362 363 364 /** 365 * Specifies the set of base DNs that should be used for the directory server. 366 * 367 * @param baseDNs The set of base DNs that should be used for the directory 368 * server. It must not be {@code null} or empty. 369 * 370 * @throws LDAPException If the provided set of base DN strings is null or 371 * empty, or if any of the provided base DN strings 372 * cannot be parsed as a valid DN. 373 */ 374 public void setBaseDNs(final String... baseDNs) 375 throws LDAPException 376 { 377 setBaseDNs(parseDNs(schema, baseDNs)); 378 } 379 380 381 382 /** 383 * Specifies the set of base DNs that should be used for the directory server. 384 * 385 * @param baseDNs The set of base DNs that should be used for the directory 386 * server. It must not be {@code null} or empty. 387 * 388 * @throws LDAPException If the provided set of base DNs is null or empty. 389 */ 390 public void setBaseDNs(final DN... baseDNs) 391 throws LDAPException 392 { 393 if ((baseDNs == null) || (baseDNs.length == 0)) 394 { 395 throw new LDAPException(ResultCode.PARAM_ERROR, 396 ERR_MEM_DS_CFG_NO_BASE_DNS.get()); 397 } 398 399 this.baseDNs = baseDNs; 400 } 401 402 403 404 /** 405 * Retrieves the list of listener configurations that should be used for the 406 * directory server. 407 * 408 * @return The list of listener configurations that should be used for the 409 * directory server. 410 */ 411 public List<InMemoryListenerConfig> getListenerConfigs() 412 { 413 return listenerConfigs; 414 } 415 416 417 418 /** 419 * Specifies the configurations for all listeners that should be used for the 420 * directory server. 421 * 422 * @param listenerConfigs The configurations for all listeners that should 423 * be used for the directory server. It must not be 424 * {@code null} or empty, and it must not contain 425 * multiple configurations with the same name. 426 * 427 * @throws LDAPException If there is a problem with the provided set of 428 * listener configurations. 429 */ 430 public void setListenerConfigs( 431 final InMemoryListenerConfig... listenerConfigs) 432 throws LDAPException 433 { 434 setListenerConfigs(StaticUtils.toList(listenerConfigs)); 435 } 436 437 438 439 /** 440 * Specifies the configurations for all listeners that should be used for the 441 * directory server. 442 * 443 * @param listenerConfigs The configurations for all listeners that should 444 * be used for the directory server. It must not be 445 * {@code null} or empty, and it must not contain 446 * multiple configurations with the same name. 447 * 448 * @throws LDAPException If there is a problem with the provided set of 449 * listener configurations. 450 */ 451 public void setListenerConfigs( 452 final Collection<InMemoryListenerConfig> listenerConfigs) 453 throws LDAPException 454 { 455 if ((listenerConfigs == null) || listenerConfigs.isEmpty()) 456 { 457 throw new LDAPException(ResultCode.PARAM_ERROR, 458 ERR_MEM_DS_CFG_NO_LISTENERS.get()); 459 } 460 461 final HashSet<String> listenerNames = 462 new HashSet<>(StaticUtils.computeMapCapacity(listenerConfigs.size())); 463 for (final InMemoryListenerConfig c : listenerConfigs) 464 { 465 final String name = StaticUtils.toLowerCase(c.getListenerName()); 466 if (listenerNames.contains(name)) 467 { 468 throw new LDAPException(ResultCode.PARAM_ERROR, 469 ERR_MEM_DS_CFG_CONFLICTING_LISTENER_NAMES.get(name)); 470 } 471 else 472 { 473 listenerNames.add(name); 474 } 475 } 476 477 this.listenerConfigs.clear(); 478 this.listenerConfigs.addAll(listenerConfigs); 479 } 480 481 482 483 /** 484 * Retrieves the set of operation types that will be allowed by the server. 485 * Note that if the server is configured to support StartTLS, then it will be 486 * allowed even if other types of extended operations are not allowed. 487 * 488 * @return The set of operation types that will be allowed by the server. 489 */ 490 public Set<OperationType> getAllowedOperationTypes() 491 { 492 return allowedOperationTypes; 493 } 494 495 496 497 /** 498 * Specifies the set of operation types that will be allowed by the server. 499 * Note that if the server is configured to support StartTLS, then it will be 500 * allowed even if other types of extended operations are not allowed. 501 * 502 * @param operationTypes The set of operation types that will be allowed by 503 * the server. 504 */ 505 public void setAllowedOperationTypes(final OperationType... operationTypes) 506 { 507 allowedOperationTypes.clear(); 508 if (operationTypes != null) 509 { 510 allowedOperationTypes.addAll(Arrays.asList(operationTypes)); 511 } 512 } 513 514 515 516 /** 517 * Specifies the set of operation types that will be allowed by the server. 518 * Note that if the server is configured to support StartTLS, then it will be 519 * allowed even if other types of extended operations are not allowed. 520 * 521 * @param operationTypes The set of operation types that will be allowed by 522 * the server. 523 */ 524 public void setAllowedOperationTypes( 525 final Collection<OperationType> operationTypes) 526 { 527 allowedOperationTypes.clear(); 528 if (operationTypes != null) 529 { 530 allowedOperationTypes.addAll(operationTypes); 531 } 532 } 533 534 535 536 /** 537 * Retrieves the set of operation types that will only be allowed for 538 * authenticated clients. Note that authentication will never be required for 539 * bind operations, and if the server is configured to support StartTLS, then 540 * authentication will never be required for StartTLS operations even if it 541 * is required for other types of extended operations. 542 * 543 * @return The set of operation types that will only be allowed for 544 * authenticated clients. 545 */ 546 public Set<OperationType> getAuthenticationRequiredOperationTypes() 547 { 548 return authenticationRequiredOperationTypes; 549 } 550 551 552 553 /** 554 * Specifies the set of operation types that will only be allowed for 555 * authenticated clients. Note that authentication will never be required for 556 * bind operations, and if the server is configured to support StartTLS, then 557 * authentication will never be required for StartTLS operations even if it 558 * is required for other types of extended operations. 559 * 560 * @param operationTypes The set of operation types that will be allowed for 561 * authenticated clients. 562 */ 563 public void setAuthenticationRequiredOperationTypes( 564 final OperationType... operationTypes) 565 { 566 authenticationRequiredOperationTypes.clear(); 567 if (operationTypes != null) 568 { 569 authenticationRequiredOperationTypes.addAll( 570 Arrays.asList(operationTypes)); 571 } 572 } 573 574 575 576 /** 577 * Specifies the set of operation types that will only be allowed for 578 * authenticated clients. Note that authentication will never be required for 579 * bind operations, and if the server is configured to support StartTLS, then 580 * authentication will never be required for StartTLS operations even if it 581 * is required for other types of extended operations. 582 * 583 * @param operationTypes The set of operation types that will be allowed for 584 * authenticated clients. 585 */ 586 public void setAuthenticationRequiredOperationTypes( 587 final Collection<OperationType> operationTypes) 588 { 589 authenticationRequiredOperationTypes.clear(); 590 if (operationTypes != null) 591 { 592 authenticationRequiredOperationTypes.addAll(operationTypes); 593 } 594 } 595 596 597 598 /** 599 * Retrieves a map containing DNs and passwords of additional users that will 600 * be allowed to bind to the server, even if their entries do not exist in the 601 * data set. This can be used to mimic the functionality of special 602 * administrative accounts (e.g., "cn=Directory Manager" in many directories). 603 * The map that is returned may be altered if desired. 604 * 605 * @return A map containing DNs and passwords of additional users that will 606 * be allowed to bind to the server, even if their entries do not 607 * exist in the data set. 608 */ 609 public Map<DN,byte[]> getAdditionalBindCredentials() 610 { 611 return additionalBindCredentials; 612 } 613 614 615 616 /** 617 * Adds an additional bind DN and password combination that can be used to 618 * bind to the server, even if the corresponding entry does not exist in the 619 * data set. This can be used to mimic the functionality of special 620 * administrative accounts (e.g., "cn=Directory Manager" in many directories). 621 * If a password has already been defined for the given DN, then it will be 622 * replaced with the newly-supplied password. 623 * 624 * @param dn The bind DN to allow. It must not be {@code null} or 625 * represent the null DN. 626 * @param password The password for the provided bind DN. It must not be 627 * {@code null} or empty. 628 * 629 * @throws LDAPException If there is a problem with the provided bind DN or 630 * password. 631 */ 632 public void addAdditionalBindCredentials(final String dn, 633 final String password) 634 throws LDAPException 635 { 636 addAdditionalBindCredentials(dn, StaticUtils.getBytes(password)); 637 } 638 639 640 641 /** 642 * Adds an additional bind DN and password combination that can be used to 643 * bind to the server, even if the corresponding entry does not exist in the 644 * data set. This can be used to mimic the functionality of special 645 * administrative accounts (e.g., "cn=Directory Manager" in many directories). 646 * If a password has already been defined for the given DN, then it will be 647 * replaced with the newly-supplied password. 648 * 649 * @param dn The bind DN to allow. It must not be {@code null} or 650 * represent the null DN. 651 * @param password The password for the provided bind DN. It must not be 652 * {@code null} or empty. 653 * 654 * @throws LDAPException If there is a problem with the provided bind DN or 655 * password. 656 */ 657 public void addAdditionalBindCredentials(final String dn, 658 final byte[] password) 659 throws LDAPException 660 { 661 if (dn == null) 662 { 663 throw new LDAPException(ResultCode.PARAM_ERROR, 664 ERR_MEM_DS_CFG_NULL_ADDITIONAL_BIND_DN.get()); 665 } 666 667 final DN parsedDN = new DN(dn, schema); 668 if (parsedDN.isNullDN()) 669 { 670 throw new LDAPException(ResultCode.PARAM_ERROR, 671 ERR_MEM_DS_CFG_NULL_ADDITIONAL_BIND_DN.get()); 672 } 673 674 if ((password == null) || (password.length == 0)) 675 { 676 throw new LDAPException(ResultCode.PARAM_ERROR, 677 ERR_MEM_DS_CFG_NULL_ADDITIONAL_BIND_PW.get()); 678 } 679 680 additionalBindCredentials.put(parsedDN, password); 681 } 682 683 684 685 /** 686 * Retrieves the object that should be used to handle any errors encountered 687 * while attempting to interact with a client, if defined. 688 * 689 * @return The object that should be used to handle any errors encountered 690 * while attempting to interact with a client, or {@code null} if no 691 * exception handler should be used. 692 */ 693 public LDAPListenerExceptionHandler getListenerExceptionHandler() 694 { 695 return exceptionHandler; 696 } 697 698 699 700 /** 701 * Specifies the LDAP listener exception handler that the server should use to 702 * handle any errors encountered while attempting to interact with a client. 703 * 704 * @param exceptionHandler The LDAP listener exception handler that the 705 * server should use to handle any errors 706 * encountered while attempting to interact with a 707 * client. It may be {@code null} if no exception 708 * handler should be used. 709 */ 710 public void setListenerExceptionHandler( 711 final LDAPListenerExceptionHandler exceptionHandler) 712 { 713 this.exceptionHandler = exceptionHandler; 714 } 715 716 717 718 /** 719 * Retrieves the schema that should be used by the server, if defined. If a 720 * schema is defined, then it will be used to validate entries and determine 721 * which matching rules should be used for various types of matching 722 * operations. 723 * 724 * @return The schema that should be used by the server, or {@code null} if 725 * no schema should be used. 726 */ 727 public Schema getSchema() 728 { 729 return schema; 730 } 731 732 733 734 /** 735 * Specifies the schema that should be used by the server. If a schema is 736 * defined, then it will be used to validate entries and determine which 737 * matching rules should be used for various types of matching operations. 738 * 739 * @param schema The schema that should be used by the server. It may be 740 * {@code null} if no schema should be used. 741 */ 742 public void setSchema(final Schema schema) 743 { 744 this.schema = schema; 745 } 746 747 748 749 /** 750 * Indicates whether the server should reject attribute values which violate 751 * the constraints of the associated syntax. This setting will be ignored if 752 * a {@code null} schema is in place. 753 * 754 * @return {@code true} if the server should reject attribute values which 755 * violate the constraints of the associated syntax, or {@code false} 756 * if not. 757 */ 758 public boolean enforceAttributeSyntaxCompliance() 759 { 760 return enforceAttributeSyntaxCompliance; 761 } 762 763 764 765 /** 766 * Specifies whether the server should reject attribute values which violate 767 * the constraints of the associated syntax. This setting will be ignored if 768 * a {@code null} schema is in place. 769 * 770 * @param enforceAttributeSyntaxCompliance Indicates whether the server 771 * should reject attribute values 772 * which violate the constraints of 773 * the associated syntax. 774 */ 775 public void setEnforceAttributeSyntaxCompliance( 776 final boolean enforceAttributeSyntaxCompliance) 777 { 778 this.enforceAttributeSyntaxCompliance = enforceAttributeSyntaxCompliance; 779 } 780 781 782 783 /** 784 * Indicates whether the server should reject entries which do not contain 785 * exactly one structural object class. This setting will be ignored if a 786 * {@code null} schema is in place. 787 * 788 * @return {@code true} if the server should reject entries which do not 789 * contain exactly one structural object class, or {@code false} if 790 * it should allow entries which do not have any structural class or 791 * that have multiple structural classes. 792 */ 793 public boolean enforceSingleStructuralObjectClass() 794 { 795 return enforceSingleStructuralObjectClass; 796 } 797 798 799 800 /** 801 * Specifies whether the server should reject entries which do not contain 802 * exactly one structural object class. This setting will be ignored if a 803 * {@code null} schema is in place. 804 * 805 * @param enforceSingleStructuralObjectClass Indicates whether the server 806 * should reject entries which do 807 * not contain exactly one 808 * structural object class. 809 */ 810 public void setEnforceSingleStructuralObjectClass( 811 final boolean enforceSingleStructuralObjectClass) 812 { 813 this.enforceSingleStructuralObjectClass = 814 enforceSingleStructuralObjectClass; 815 } 816 817 818 819 /** 820 * Retrieves the log handler that should be used to record access log messages 821 * about operations processed by the server, if any. 822 * 823 * @return The log handler that should be used to record access log messages 824 * about operations processed by the server, or {@code null} if no 825 * access logging should be performed. 826 */ 827 public Handler getAccessLogHandler() 828 { 829 return accessLogHandler; 830 } 831 832 833 834 /** 835 * Specifies the log handler that should be used to record access log messages 836 * about operations processed by the server. 837 * 838 * @param accessLogHandler The log handler that should be used to record 839 * access log messages about operations processed by 840 * the server. It may be {@code null} if no access 841 * logging should be performed. 842 */ 843 public void setAccessLogHandler(final Handler accessLogHandler) 844 { 845 this.accessLogHandler = accessLogHandler; 846 } 847 848 849 850 /** 851 * Retrieves the log handler that should be used to record detailed messages 852 * about LDAP communication to and from the server, which may be useful for 853 * debugging purposes. 854 * 855 * @return The log handler that should be used to record detailed 856 * protocol-level debug messages about LDAP communication to and from 857 * the server, or {@code null} if no debug logging should be 858 * performed. 859 */ 860 public Handler getLDAPDebugLogHandler() 861 { 862 return ldapDebugLogHandler; 863 } 864 865 866 867 /** 868 * Specifies the log handler that should be used to record detailed messages 869 * about LDAP communication to and from the server, which may be useful for 870 * debugging purposes. 871 * 872 * @param ldapDebugLogHandler The log handler that should be used to record 873 * detailed messages about LDAP communication to 874 * and from the server. It may be {@code null} 875 * if no LDAP debug logging should be performed. 876 */ 877 public void setLDAPDebugLogHandler(final Handler ldapDebugLogHandler) 878 { 879 this.ldapDebugLogHandler = ldapDebugLogHandler; 880 } 881 882 883 884 /** 885 * Retrieves the path to a file to be written with generated code that may 886 * be used to construct the requests processed by the server. 887 * 888 * @return The path to a file to be written with generated code that may be 889 * used to construct the requests processed by the server, or 890 * {@code null} if no code log should be written. 891 */ 892 public String getCodeLogPath() 893 { 894 return codeLogPath; 895 } 896 897 898 899 /** 900 * Indicates whether the code log should include sample code for processing 901 * the generated requests. This will only be used if {@link #getCodeLogPath} 902 * returns a non-{@code null} value. 903 * 904 * @return {@code false} if the code log should only include code that 905 * corresponds to requests received from clients, or {@code true} if 906 * the code log should also include sample code for processing the 907 * generated requests and interpreting the results. 908 */ 909 public boolean includeRequestProcessingInCodeLog() 910 { 911 return includeRequestProcessingInCodeLog; 912 } 913 914 915 916 /** 917 * Specifies information about code logging that should be performed by the 918 * server, if any. 919 * 920 * @param codeLogPath The path to the file to which a code log should 921 * be written. It may be {@code null} if no code 922 * log should be written. 923 * @param includeProcessing Indicates whether to include sample code that 924 * demonstrates how to process the requests and 925 * interpret the results. This will only be 926 * used if the {@code codeLogPath} argument is 927 * non-{@code null}. 928 */ 929 public void setCodeLogDetails(final String codeLogPath, 930 final boolean includeProcessing) 931 { 932 this.codeLogPath = codeLogPath; 933 includeRequestProcessingInCodeLog = includeProcessing; 934 } 935 936 937 938 /** 939 * Retrieves a list of the operation interceptors that may be used to 940 * intercept and transform requests before they are processed by the in-memory 941 * directory server, and/or to intercept and transform responses before they 942 * are returned to the client. The contents of the list may be altered by the 943 * caller. 944 * 945 * @return An updatable list of the operation interceptors that may be used 946 * to intercept and transform requests and/or responses. 947 */ 948 public List<InMemoryOperationInterceptor> getOperationInterceptors() 949 { 950 return operationInterceptors; 951 } 952 953 954 955 /** 956 * Adds the provided operation interceptor to the list of operation 957 * interceptors that may be used to transform requests before they are 958 * processed by the in-memory directory server, and/or to transform responses 959 * before they are returned to the client. 960 * 961 * @param interceptor The operation interceptor that should be invoked in 962 * the course of processing requests and responses. 963 */ 964 public void addInMemoryOperationInterceptor( 965 final InMemoryOperationInterceptor interceptor) 966 { 967 operationInterceptors.add(interceptor); 968 } 969 970 971 972 /** 973 * Retrieves a list of the extended operation handlers that may be used to 974 * process extended operations in the server. The contents of the list may 975 * be altered by the caller. 976 * 977 * @return An updatable list of the extended operation handlers that may be 978 * used to process extended operations in the server. 979 */ 980 public List<InMemoryExtendedOperationHandler> getExtendedOperationHandlers() 981 { 982 return extendedOperationHandlers; 983 } 984 985 986 987 /** 988 * Adds the provided extended operation handler for use by the server for 989 * processing certain types of extended operations. 990 * 991 * @param handler The extended operation handler that should be used by the 992 * server for processing certain types of extended 993 * operations. 994 */ 995 public void addExtendedOperationHandler( 996 final InMemoryExtendedOperationHandler handler) 997 { 998 extendedOperationHandlers.add(handler); 999 } 1000 1001 1002 1003 /** 1004 * Retrieves a list of the SASL bind handlers that may be used to process 1005 * SASL bind requests in the server. The contents of the list may be altered 1006 * by the caller. 1007 * 1008 * @return An updatable list of the SASL bind handlers that may be used to 1009 * process SASL bind requests in the server. 1010 */ 1011 public List<InMemorySASLBindHandler> getSASLBindHandlers() 1012 { 1013 return saslBindHandlers; 1014 } 1015 1016 1017 1018 /** 1019 * Adds the provided SASL bind handler for use by the server for processing 1020 * certain types of SASL bind requests. 1021 * 1022 * @param handler The SASL bind handler that should be used by the server 1023 * for processing certain types of SASL bind requests. 1024 */ 1025 public void addSASLBindHandler(final InMemorySASLBindHandler handler) 1026 { 1027 saslBindHandlers.add(handler); 1028 } 1029 1030 1031 1032 /** 1033 * Indicates whether the server should automatically generate operational 1034 * attributes (including entryDN, entryUUID, creatorsName, createTimestamp, 1035 * modifiersName, modifyTimestamp, and subschemaSubentry) for entries in the 1036 * server. 1037 * 1038 * @return {@code true} if the server should automatically generate 1039 * operational attributes for entries in the server, or {@code false} 1040 * if not. 1041 */ 1042 public boolean generateOperationalAttributes() 1043 { 1044 return generateOperationalAttributes; 1045 } 1046 1047 1048 1049 /** 1050 * Specifies whether the server should automatically generate operational 1051 * attributes (including entryDN, entryUUID, creatorsName, createTimestamp, 1052 * modifiersName, modifyTimestamp, and subschemaSubentry) for entries in the 1053 * server. 1054 * 1055 * @param generateOperationalAttributes Indicates whether the server should 1056 * automatically generate operational 1057 * attributes for entries in the 1058 * server. 1059 */ 1060 public void setGenerateOperationalAttributes( 1061 final boolean generateOperationalAttributes) 1062 { 1063 this.generateOperationalAttributes = generateOperationalAttributes; 1064 } 1065 1066 1067 1068 /** 1069 * Retrieves the maximum number of changelog entries that the server should 1070 * maintain. 1071 * 1072 * @return The maximum number of changelog entries that the server should 1073 * maintain, or 0 if the server should not maintain a changelog. 1074 */ 1075 public int getMaxChangeLogEntries() 1076 { 1077 return maxChangeLogEntries; 1078 } 1079 1080 1081 1082 /** 1083 * Specifies the maximum number of changelog entries that the server should 1084 * maintain. A value less than or equal to zero indicates that the server 1085 * should not attempt to maintain a changelog. 1086 * 1087 * @param maxChangeLogEntries The maximum number of changelog entries that 1088 * the server should maintain. 1089 */ 1090 public void setMaxChangeLogEntries(final int maxChangeLogEntries) 1091 { 1092 if (maxChangeLogEntries < 0) 1093 { 1094 this.maxChangeLogEntries = 0; 1095 } 1096 else 1097 { 1098 this.maxChangeLogEntries = maxChangeLogEntries; 1099 } 1100 } 1101 1102 1103 1104 /** 1105 * Retrieves the maximum number of concurrent connections that the server will 1106 * allow. If a client tries to establish a new connection while the server 1107 * already has the maximum number of concurrent connections, then the new 1108 * connection will be rejected. Note that if the server is configured with 1109 * multiple listeners, then each listener will be allowed to have up to this 1110 * number of connections. 1111 * 1112 * @return The maximum number of concurrent connections that the server will 1113 * allow, or zero if no limit should be enforced. 1114 */ 1115 public int getMaxConnections() 1116 { 1117 return maxConnections; 1118 } 1119 1120 1121 1122 /** 1123 * Specifies the maximum number of concurrent connections that the server will 1124 * allow. If a client tries to establish a new connection while the server 1125 * already has the maximum number of concurrent connections, then the new 1126 * connection will be rejected. Note that if the server is configured with 1127 * multiple listeners, then each listener will be allowed to have up to this 1128 * number of connections. 1129 * 1130 * @param maxConnections The maximum number of concurrent connections that 1131 * the server will allow. A value that is less than 1132 * or equal to zero indicates no limit. 1133 */ 1134 public void setMaxConnections(final int maxConnections) 1135 { 1136 if (maxConnections > 0) 1137 { 1138 this.maxConnections = maxConnections; 1139 } 1140 else 1141 { 1142 this.maxConnections = 0; 1143 } 1144 } 1145 1146 1147 1148 /** 1149 * Retrieves the maximum number of entries that the server should return in 1150 * any search operation. 1151 * 1152 * @return The maximum number of entries that the server should return in any 1153 * search operation, or zero if no limit should be enforced. 1154 */ 1155 public int getMaxSizeLimit() 1156 { 1157 return maxSizeLimit; 1158 } 1159 1160 1161 1162 /** 1163 * Specifies the maximum number of entries that the server should return in 1164 * any search operation. A value less than or equal to zero indicates that no 1165 * maximum limit should be enforced. 1166 * 1167 * @param maxSizeLimit The maximum number of entries that the server should 1168 * return in any search operation. 1169 */ 1170 public void setMaxSizeLimit(final int maxSizeLimit) 1171 { 1172 if (maxSizeLimit > 0) 1173 { 1174 this.maxSizeLimit = maxSizeLimit; 1175 } 1176 else 1177 { 1178 this.maxSizeLimit = 0; 1179 } 1180 } 1181 1182 1183 1184 /** 1185 * Retrieves a list containing the names or OIDs of the attribute types for 1186 * which to maintain an equality index to improve the performance of certain 1187 * kinds of searches. 1188 * 1189 * @return A list containing the names or OIDs of the attribute types for 1190 * which to maintain an equality index to improve the performance of 1191 * certain kinds of searches, or an empty list if no equality indexes 1192 * should be created. 1193 */ 1194 public List<String> getEqualityIndexAttributes() 1195 { 1196 return equalityIndexAttributes; 1197 } 1198 1199 1200 1201 /** 1202 * Specifies the names or OIDs of the attribute types for which to maintain an 1203 * equality index to improve the performance of certain kinds of searches. 1204 * 1205 * @param equalityIndexAttributes The names or OIDs of the attributes for 1206 * which to maintain an equality index to 1207 * improve the performance of certain kinds 1208 * of searches. It may be {@code null} or 1209 * empty to indicate that no equality indexes 1210 * should be maintained. 1211 */ 1212 public void setEqualityIndexAttributes( 1213 final String... equalityIndexAttributes) 1214 { 1215 setEqualityIndexAttributes(StaticUtils.toList(equalityIndexAttributes)); 1216 } 1217 1218 1219 1220 /** 1221 * Specifies the names or OIDs of the attribute types for which to maintain an 1222 * equality index to improve the performance of certain kinds of searches. 1223 * 1224 * @param equalityIndexAttributes The names or OIDs of the attributes for 1225 * which to maintain an equality index to 1226 * improve the performance of certain kinds 1227 * of searches. It may be {@code null} or 1228 * empty to indicate that no equality indexes 1229 * should be maintained. 1230 */ 1231 public void setEqualityIndexAttributes( 1232 final Collection<String> equalityIndexAttributes) 1233 { 1234 this.equalityIndexAttributes.clear(); 1235 if (equalityIndexAttributes != null) 1236 { 1237 this.equalityIndexAttributes.addAll(equalityIndexAttributes); 1238 } 1239 } 1240 1241 1242 1243 /** 1244 * Retrieves the names of the attributes for which referential integrity 1245 * should be maintained. If referential integrity is to be provided and an 1246 * entry is removed, then any other entries containing one of the specified 1247 * attributes with a value equal to the DN of the entry that was removed, then 1248 * that value will also be removed. Similarly, if an entry is moved or 1249 * renamed, then any references to that entry in one of the specified 1250 * attributes will be updated to reflect the new DN. 1251 * 1252 * @return The names of the attributes for which referential integrity should 1253 * be maintained, or an empty set if referential integrity should not 1254 * be maintained for any attributes. 1255 */ 1256 public Set<String> getReferentialIntegrityAttributes() 1257 { 1258 return referentialIntegrityAttributes; 1259 } 1260 1261 1262 1263 /** 1264 * Specifies the names of the attributes for which referential integrity 1265 * should be maintained. If referential integrity is to be provided and an 1266 * entry is removed, then any other entries containing one of the specified 1267 * attributes with a value equal to the DN of the entry that was removed, then 1268 * that value will also be removed. Similarly, if an entry is moved or 1269 * renamed, then any references to that entry in one of the specified 1270 * attributes will be updated to reflect the new DN. 1271 * 1272 * @param referentialIntegrityAttributes The names of the attributes for 1273 * which referential integrity should 1274 * be maintained. The values of 1275 * these attributes should be DNs. 1276 * It may be {@code null} or empty if 1277 * referential integrity should not 1278 * be maintained. 1279 */ 1280 public void setReferentialIntegrityAttributes( 1281 final String... referentialIntegrityAttributes) 1282 { 1283 setReferentialIntegrityAttributes( 1284 StaticUtils.toList(referentialIntegrityAttributes)); 1285 } 1286 1287 1288 1289 /** 1290 * Specifies the names of the attributes for which referential integrity 1291 * should be maintained. If referential integrity is to be provided and an 1292 * entry is removed, then any other entries containing one of the specified 1293 * attributes with a value equal to the DN of the entry that was removed, then 1294 * that value will also be removed. Similarly, if an entry is moved or 1295 * renamed, then any references to that entry in one of the specified 1296 * attributes will be updated to reflect the new DN. 1297 * 1298 * @param referentialIntegrityAttributes The names of the attributes for 1299 * which referential integrity should 1300 * be maintained. The values of 1301 * these attributes should be DNs. 1302 * It may be {@code null} or empty if 1303 * referential integrity should not 1304 * be maintained. 1305 */ 1306 public void setReferentialIntegrityAttributes( 1307 final Collection<String> referentialIntegrityAttributes) 1308 { 1309 this.referentialIntegrityAttributes.clear(); 1310 if (referentialIntegrityAttributes != null) 1311 { 1312 this.referentialIntegrityAttributes.addAll( 1313 referentialIntegrityAttributes); 1314 } 1315 } 1316 1317 1318 1319 /** 1320 * Retrieves the vendor name value to report in the server root DSE. 1321 * 1322 * @return The vendor name value to report in the server root DSE, or 1323 * {@code null} if no vendor name should appear. 1324 */ 1325 public String getVendorName() 1326 { 1327 return vendorName; 1328 } 1329 1330 1331 1332 /** 1333 * Specifies the vendor name value to report in the server root DSE. 1334 * 1335 * @param vendorName The vendor name value to report in the server root DSE. 1336 * It may be {@code null} if no vendor name should appear. 1337 */ 1338 public void setVendorName(final String vendorName) 1339 { 1340 this.vendorName = vendorName; 1341 } 1342 1343 1344 1345 /** 1346 * Retrieves the vendor version value to report in the server root DSE. 1347 * 1348 * @return The vendor version value to report in the server root DSE, or 1349 * {@code null} if no vendor version should appear. 1350 */ 1351 public String getVendorVersion() 1352 { 1353 return vendorVersion; 1354 } 1355 1356 1357 1358 /** 1359 * Specifies the vendor version value to report in the server root DSE. 1360 * 1361 * @param vendorVersion The vendor version value to report in the server 1362 * root DSE. It may be {@code null} if no vendor 1363 * version should appear. 1364 */ 1365 public void setVendorVersion(final String vendorVersion) 1366 { 1367 this.vendorVersion = vendorVersion; 1368 } 1369 1370 1371 1372 /** 1373 * Retrieves a predefined entry that should always be returned as the 1374 * in-memory directory server's root DSE, if defined. 1375 * 1376 * @return A predefined entry that should always be returned as the in-memory 1377 * directory server's root DSE, or {@code null} if the root DSE 1378 * should be dynamically generated. 1379 */ 1380 public ReadOnlyEntry getRootDSEEntry() 1381 { 1382 return rootDSEEntry; 1383 } 1384 1385 1386 1387 /** 1388 * Specifies an entry that should always be returned as the in-memory 1389 * directory server's root DSE. Note that if a specific root DSE entry is 1390 * provided, then 1391 * 1392 * @param rootDSEEntry An entry that should always be returned as the 1393 * in-memory directory server's root DSE, or 1394 * {@code null} to indicate that the root DSE should be 1395 * dynamically generated. 1396 */ 1397 public void setRootDSEEntry(final Entry rootDSEEntry) 1398 { 1399 if (rootDSEEntry == null) 1400 { 1401 this.rootDSEEntry = null; 1402 return; 1403 } 1404 1405 final Entry e = rootDSEEntry.duplicate(); 1406 e.setDN(""); 1407 this.rootDSEEntry = new ReadOnlyEntry(e); 1408 } 1409 1410 1411 1412 /** 1413 * Retrieves an unmodifiable set containing the names or OIDs of the 1414 * attributes that may hold passwords. These are the attributes whose values 1415 * will be used in bind processing, and clear-text values stored in these 1416 * attributes may be encoded using an {@link InMemoryPasswordEncoder}. 1417 * 1418 * @return An unmodifiable set containing the names or OIDs of the attributes 1419 * that may hold passwords, or an empty set if no password attributes 1420 * have been defined. 1421 */ 1422 public Set<String> getPasswordAttributes() 1423 { 1424 return Collections.unmodifiableSet(passwordAttributes); 1425 } 1426 1427 1428 1429 /** 1430 * Specifies the names or OIDs of the attributes that may hold passwords. 1431 * These are the attributes whose values will be used in bind processing, and 1432 * clear-text values stored in these attributes may be encoded using an 1433 * {@link InMemoryPasswordEncoder}. 1434 * 1435 * @param passwordAttributes The names or OIDs of the attributes that may 1436 * hold passwords. It may be {@code null} or 1437 * empty if there should not be any password 1438 * attributes, but that will prevent user 1439 * authentication from succeeding. 1440 */ 1441 public void setPasswordAttributes(final String... passwordAttributes) 1442 { 1443 setPasswordAttributes(StaticUtils.toList(passwordAttributes)); 1444 } 1445 1446 1447 1448 /** 1449 * Specifies the names or OIDs of the attributes that may hold passwords. 1450 * These are the attributes whose values will be used in bind processing, and 1451 * clear-text values stored in these attributes may be encoded using an 1452 * {@link InMemoryPasswordEncoder}. 1453 * 1454 * @param passwordAttributes The names or OIDs of the attributes that may 1455 * hold passwords. It may be {@code null} or 1456 * empty if there should not be any password 1457 * attributes, but that will prevent user 1458 * authentication from succeeding. 1459 */ 1460 public void setPasswordAttributes(final Collection<String> passwordAttributes) 1461 { 1462 this.passwordAttributes.clear(); 1463 1464 if (passwordAttributes != null) 1465 { 1466 this.passwordAttributes.addAll(passwordAttributes); 1467 } 1468 } 1469 1470 1471 1472 /** 1473 * Retrieves the primary password encoder for the in-memory directory server, 1474 * if any. The primary password encoder will be used to encode the values of 1475 * any clear-text passwords provided in add or modify operations and in LDIF 1476 * imports, and will also be used during authentication processing for any 1477 * encoded passwords that start with the same prefix as this password encoder. 1478 * 1479 * @return The primary password encoder for the in-memory directory server, 1480 * or {@code null} if clear-text passwords should be left in the 1481 * clear without any encoding. 1482 */ 1483 public InMemoryPasswordEncoder getPrimaryPasswordEncoder() 1484 { 1485 return primaryPasswordEncoder; 1486 } 1487 1488 1489 1490 /** 1491 * Retrieves an unmodifiable map of the secondary password encoders for the 1492 * in-memory directory server, indexed by prefix. The secondary password 1493 * encoders will be used to interact with pre-encoded passwords, but will not 1494 * be used to encode new clear-text passwords. 1495 * 1496 * @return An unmodifiable map of the secondary password encoders for the 1497 * in-memory directory server, or an empty map if no secondary 1498 * encoders are defined. 1499 */ 1500 public List<InMemoryPasswordEncoder> getSecondaryPasswordEncoders() 1501 { 1502 return Collections.unmodifiableList(secondaryPasswordEncoders); 1503 } 1504 1505 1506 1507 /** 1508 * Specifies the set of password encoders to use for the in-memory directory 1509 * server. There must not be any conflicts between the prefixes used for any 1510 * of the password encoders (that is, none of the secondary password encoders 1511 * may use the same prefix as the primary password encoder or the same prefix 1512 * as any other secondary password encoder). 1513 * <BR><BR> 1514 * Either or both the primary and secondary encoders may be left undefined. 1515 * If both primary and secondary encoders are left undefined, then the server 1516 * will assume that all passwords are in the clear. If only a primary encoder 1517 * is configured without any secondary encoders, then the server will encode 1518 * all new passwords that don't start with its prefix. If only secondary 1519 * encoders are configured without a primary encoder, then all new passwords 1520 * will be left in the clear, but any existing pre-encoded passwords using 1521 * those mechanisms will be handled properly. 1522 * 1523 * @param primaryEncoder The primary password encoder to use for the 1524 * in-memory directory server. This encoder will 1525 * be used to encode any new clear-text passwords 1526 * that are provided to the server in add or modify 1527 * operations or in LDIF imports. It will also be 1528 * used to interact with pre-encoded passwords 1529 * for any encoded passwords that start with the 1530 * same prefix as this password encoder. It may be 1531 * {@code null} if no password encoder is desired 1532 * and clear-text passwords should remain in the 1533 * clear. 1534 * @param secondaryEncoders The secondary password encoders to use when 1535 * interacting with pre-encoded passwords, but that 1536 * will not be used to encode new clear-text 1537 * passwords. This may be {@code null} or empty if 1538 * no secondary password encoders are needed. 1539 * 1540 * @throws LDAPException If there is a conflict between the prefixes used by 1541 * two or more of the provided encoders. 1542 */ 1543 public void setPasswordEncoders(final InMemoryPasswordEncoder primaryEncoder, 1544 final InMemoryPasswordEncoder... secondaryEncoders) 1545 throws LDAPException 1546 { 1547 setPasswordEncoders(primaryEncoder, StaticUtils.toList(secondaryEncoders)); 1548 } 1549 1550 1551 1552 /** 1553 * Specifies the set of password encoders to use for the in-memory directory 1554 * server. There must not be any conflicts between the prefixes used for any 1555 * of the password encoders (that is, none of the secondary password encoders 1556 * may use the same prefix as the primary password encoder or the same prefix 1557 * as any other secondary password encoder). 1558 * <BR><BR> 1559 * Either or both the primary and secondary encoders may be left undefined. 1560 * If both primary and secondary encoders are left undefined, then the server 1561 * will assume that all passwords are in the clear. If only a primary encoder 1562 * is configured without any secondary encoders, then the server will encode 1563 * all new passwords that don't start with its prefix. If only secondary 1564 * encoders are configured without a primary encoder, then all new passwords 1565 * will be left in the clear, but any existing pre-encoded passwords using 1566 * those mechanisms will be handled properly. 1567 * 1568 * @param primaryEncoder The primary password encoder to use for the 1569 * in-memory directory server. This encoder will 1570 * be used to encode any new clear-text passwords 1571 * that are provided to the server in add or modify 1572 * operations or in LDIF imports. It will also be 1573 * used to interact with pre-encoded passwords 1574 * for any encoded passwords that start with the 1575 * same prefix as this password encoder. It may be 1576 * {@code null} if no password encoder is desired 1577 * and clear-text passwords should remain in the 1578 * clear. 1579 * @param secondaryEncoders The secondary password encoders to use when 1580 * interacting with pre-encoded passwords, but that 1581 * will not be used to encode new clear-text 1582 * passwords. This may be {@code null} or empty if 1583 * no secondary password encoders are needed. 1584 * 1585 * @throws LDAPException If there is a conflict between the prefixes used by 1586 * two or more of the provided encoders. 1587 */ 1588 public void setPasswordEncoders(final InMemoryPasswordEncoder primaryEncoder, 1589 final Collection<InMemoryPasswordEncoder> secondaryEncoders) 1590 throws LDAPException 1591 { 1592 // Before applying the change, make sure that there aren't any conflicts in 1593 // their prefixes. 1594 final LinkedHashMap<String,InMemoryPasswordEncoder> newEncoderMap = 1595 new LinkedHashMap<>(StaticUtils.computeMapCapacity(10)); 1596 if (primaryEncoder != null) 1597 { 1598 newEncoderMap.put(primaryEncoder.getPrefix(), primaryEncoder); 1599 } 1600 1601 if (secondaryEncoders != null) 1602 { 1603 for (final InMemoryPasswordEncoder encoder : secondaryEncoders) 1604 { 1605 if (newEncoderMap.containsKey(encoder.getPrefix())) 1606 { 1607 throw new LDAPException(ResultCode.PARAM_ERROR, 1608 ERR_MEM_DS_CFG_PW_ENCODER_CONFLICT.get(encoder.getPrefix())); 1609 } 1610 else 1611 { 1612 newEncoderMap.put(encoder.getPrefix(), encoder); 1613 } 1614 } 1615 } 1616 1617 primaryPasswordEncoder = primaryEncoder; 1618 1619 if (primaryEncoder != null) 1620 { 1621 newEncoderMap.remove(primaryEncoder.getPrefix()); 1622 } 1623 1624 secondaryPasswordEncoders.clear(); 1625 secondaryPasswordEncoders.addAll(newEncoderMap.values()); 1626 } 1627 1628 1629 1630 /** 1631 * Parses the provided set of strings as DNs. 1632 * 1633 * @param dnStrings The array of strings to be parsed as DNs. 1634 * @param schema The schema to use to generate the normalized 1635 * representations of the DNs, if available. 1636 * 1637 * @return The array of parsed DNs. 1638 * 1639 * @throws LDAPException If any of the provided strings cannot be parsed as 1640 * DNs. 1641 */ 1642 private static DN[] parseDNs(final Schema schema, final String... dnStrings) 1643 throws LDAPException 1644 { 1645 if (dnStrings == null) 1646 { 1647 return null; 1648 } 1649 1650 final DN[] dns = new DN[dnStrings.length]; 1651 for (int i=0; i < dns.length; i++) 1652 { 1653 dns[i] = new DN(dnStrings[i], schema); 1654 } 1655 return dns; 1656 } 1657 1658 1659 1660 /** 1661 * Retrieves a string representation of this in-memory directory server 1662 * configuration. 1663 * 1664 * @return A string representation of this in-memory directory server 1665 * configuration. 1666 */ 1667 @Override() 1668 public String toString() 1669 { 1670 final StringBuilder buffer = new StringBuilder(); 1671 toString(buffer); 1672 return buffer.toString(); 1673 } 1674 1675 1676 1677 /** 1678 * Appends a string representation of this in-memory directory server 1679 * configuration to the provided buffer. 1680 * 1681 * @param buffer The buffer to which the string representation should be 1682 * appended. 1683 */ 1684 public void toString(final StringBuilder buffer) 1685 { 1686 buffer.append("InMemoryDirectoryServerConfig(baseDNs={"); 1687 1688 for (int i=0; i < baseDNs.length; i++) 1689 { 1690 if (i > 0) 1691 { 1692 buffer.append(", "); 1693 } 1694 1695 buffer.append('\''); 1696 baseDNs[i].toString(buffer); 1697 buffer.append('\''); 1698 } 1699 buffer.append('}'); 1700 1701 buffer.append(", listenerConfigs={"); 1702 1703 final Iterator<InMemoryListenerConfig> listenerCfgIterator = 1704 listenerConfigs.iterator(); 1705 while (listenerCfgIterator.hasNext()) 1706 { 1707 listenerCfgIterator.next().toString(buffer); 1708 if (listenerCfgIterator.hasNext()) 1709 { 1710 buffer.append(", "); 1711 } 1712 } 1713 buffer.append('}'); 1714 1715 buffer.append(", schemaProvided="); 1716 buffer.append((schema != null)); 1717 buffer.append(", enforceAttributeSyntaxCompliance="); 1718 buffer.append(enforceAttributeSyntaxCompliance); 1719 buffer.append(", enforceSingleStructuralObjectClass="); 1720 buffer.append(enforceSingleStructuralObjectClass); 1721 1722 if (! additionalBindCredentials.isEmpty()) 1723 { 1724 buffer.append(", additionalBindDNs={"); 1725 1726 final Iterator<DN> bindDNIterator = 1727 additionalBindCredentials.keySet().iterator(); 1728 while (bindDNIterator.hasNext()) 1729 { 1730 buffer.append('\''); 1731 bindDNIterator.next().toString(buffer); 1732 buffer.append('\''); 1733 if (bindDNIterator.hasNext()) 1734 { 1735 buffer.append(", "); 1736 } 1737 } 1738 buffer.append('}'); 1739 } 1740 1741 if (! equalityIndexAttributes.isEmpty()) 1742 { 1743 buffer.append(", equalityIndexAttributes={"); 1744 1745 final Iterator<String> attrIterator = equalityIndexAttributes.iterator(); 1746 while (attrIterator.hasNext()) 1747 { 1748 buffer.append('\''); 1749 buffer.append(attrIterator.next()); 1750 buffer.append('\''); 1751 if (attrIterator.hasNext()) 1752 { 1753 buffer.append(", "); 1754 } 1755 } 1756 buffer.append('}'); 1757 } 1758 1759 if (! referentialIntegrityAttributes.isEmpty()) 1760 { 1761 buffer.append(", referentialIntegrityAttributes={"); 1762 1763 final Iterator<String> attrIterator = 1764 referentialIntegrityAttributes.iterator(); 1765 while (attrIterator.hasNext()) 1766 { 1767 buffer.append('\''); 1768 buffer.append(attrIterator.next()); 1769 buffer.append('\''); 1770 if (attrIterator.hasNext()) 1771 { 1772 buffer.append(", "); 1773 } 1774 } 1775 buffer.append('}'); 1776 } 1777 1778 buffer.append(", generateOperationalAttributes="); 1779 buffer.append(generateOperationalAttributes); 1780 1781 if (maxChangeLogEntries > 0) 1782 { 1783 buffer.append(", maxChangelogEntries="); 1784 buffer.append(maxChangeLogEntries); 1785 } 1786 1787 buffer.append(", maxConnections="); 1788 buffer.append(maxConnections); 1789 buffer.append(", maxSizeLimit="); 1790 buffer.append(maxSizeLimit); 1791 1792 if (! extendedOperationHandlers.isEmpty()) 1793 { 1794 buffer.append(", extendedOperationHandlers={"); 1795 1796 final Iterator<InMemoryExtendedOperationHandler> 1797 handlerIterator = extendedOperationHandlers.iterator(); 1798 while (handlerIterator.hasNext()) 1799 { 1800 buffer.append(handlerIterator.next().toString()); 1801 if (handlerIterator.hasNext()) 1802 { 1803 buffer.append(", "); 1804 } 1805 } 1806 buffer.append('}'); 1807 } 1808 1809 if (! saslBindHandlers.isEmpty()) 1810 { 1811 buffer.append(", saslBindHandlers={"); 1812 1813 final Iterator<InMemorySASLBindHandler> 1814 handlerIterator = saslBindHandlers.iterator(); 1815 while (handlerIterator.hasNext()) 1816 { 1817 buffer.append(handlerIterator.next().toString()); 1818 if (handlerIterator.hasNext()) 1819 { 1820 buffer.append(", "); 1821 } 1822 } 1823 buffer.append('}'); 1824 } 1825 1826 buffer.append(", passwordAttributes={"); 1827 final Iterator<String> pwAttrIterator = passwordAttributes.iterator(); 1828 while (pwAttrIterator.hasNext()) 1829 { 1830 buffer.append('\''); 1831 buffer.append(pwAttrIterator.next()); 1832 buffer.append('\''); 1833 1834 if (pwAttrIterator.hasNext()) 1835 { 1836 buffer.append(", "); 1837 } 1838 } 1839 buffer.append('}'); 1840 1841 if (primaryPasswordEncoder == null) 1842 { 1843 buffer.append(", primaryPasswordEncoder=null"); 1844 } 1845 else 1846 { 1847 buffer.append(", primaryPasswordEncoderPrefix='"); 1848 buffer.append(primaryPasswordEncoder.getPrefix()); 1849 buffer.append('\''); 1850 } 1851 1852 buffer.append(", secondaryPasswordEncoderPrefixes={"); 1853 final Iterator<InMemoryPasswordEncoder> encoderIterator = 1854 secondaryPasswordEncoders.iterator(); 1855 while (encoderIterator.hasNext()) 1856 { 1857 buffer.append('\''); 1858 buffer.append(encoderIterator.next().getPrefix()); 1859 buffer.append('\''); 1860 1861 if (encoderIterator.hasNext()) 1862 { 1863 buffer.append(", "); 1864 } 1865 } 1866 buffer.append('}'); 1867 1868 if (accessLogHandler != null) 1869 { 1870 buffer.append(", accessLogHandlerClass='"); 1871 buffer.append(accessLogHandler.getClass().getName()); 1872 buffer.append('\''); 1873 } 1874 1875 if (ldapDebugLogHandler != null) 1876 { 1877 buffer.append(", ldapDebugLogHandlerClass='"); 1878 buffer.append(ldapDebugLogHandler.getClass().getName()); 1879 buffer.append('\''); 1880 } 1881 1882 if (codeLogPath != null) 1883 { 1884 buffer.append(", codeLogPath='"); 1885 buffer.append(codeLogPath); 1886 buffer.append("', includeRequestProcessingInCodeLog="); 1887 buffer.append(includeRequestProcessingInCodeLog); 1888 } 1889 1890 if (exceptionHandler != null) 1891 { 1892 buffer.append(", listenerExceptionHandlerClass='"); 1893 buffer.append(exceptionHandler.getClass().getName()); 1894 buffer.append('\''); 1895 } 1896 1897 if (vendorName != null) 1898 { 1899 buffer.append(", vendorName='"); 1900 buffer.append(vendorName); 1901 buffer.append('\''); 1902 } 1903 1904 if (vendorVersion != null) 1905 { 1906 buffer.append(", vendorVersion='"); 1907 buffer.append(vendorVersion); 1908 buffer.append('\''); 1909 } 1910 1911 buffer.append(')'); 1912 } 1913}