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