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