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