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