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