001/* 002 * Copyright 2011-2025 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2011-2025 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-2025 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.io.File; 041import java.io.OutputStream; 042import java.io.Serializable; 043import java.net.Socket; 044import java.util.ArrayList; 045import java.util.EnumSet; 046import java.util.Iterator; 047import java.util.LinkedHashMap; 048import java.util.List; 049import java.util.Map; 050import java.util.Set; 051import java.util.TreeMap; 052import java.util.logging.FileHandler; 053import java.util.logging.Level; 054import java.util.logging.StreamHandler; 055import javax.net.ssl.KeyManager; 056import javax.net.ssl.TrustManager; 057 058import com.unboundid.ldap.sdk.DN; 059import com.unboundid.ldap.sdk.LDAPException; 060import com.unboundid.ldap.sdk.OperationType; 061import com.unboundid.ldap.sdk.ResultCode; 062import com.unboundid.ldap.sdk.Version; 063import com.unboundid.ldap.sdk.schema.Schema; 064import com.unboundid.ldap.sdk.schema.SchemaValidator; 065import com.unboundid.util.CommandLineTool; 066import com.unboundid.util.CryptoHelper; 067import com.unboundid.util.Debug; 068import com.unboundid.util.MinimalLogFormatter; 069import com.unboundid.util.NotMutable; 070import com.unboundid.util.NotNull; 071import com.unboundid.util.Nullable; 072import com.unboundid.util.ObjectPair; 073import com.unboundid.util.StaticUtils; 074import com.unboundid.util.ThreadSafety; 075import com.unboundid.util.ThreadSafetyLevel; 076import com.unboundid.util.args.ArgumentException; 077import com.unboundid.util.args.ArgumentParser; 078import com.unboundid.util.args.BooleanArgument; 079import com.unboundid.util.args.DNArgument; 080import com.unboundid.util.args.IntegerArgument; 081import com.unboundid.util.args.FileArgument; 082import com.unboundid.util.args.StringArgument; 083import com.unboundid.util.ssl.KeyStoreKeyManager; 084import com.unboundid.util.ssl.SSLUtil; 085import com.unboundid.util.ssl.TrustAllTrustManager; 086import com.unboundid.util.ssl.TrustStoreTrustManager; 087import com.unboundid.util.ssl.cert.CertException; 088 089import static com.unboundid.ldap.listener.ListenerMessages.*; 090 091 092 093/** 094 * This class provides a command-line tool that can be used to run an instance 095 * of the in-memory directory server. Instances of the server may also be 096 * created and controlled programmatically using the 097 * {@link InMemoryDirectoryServer} class. 098 * <BR><BR> 099 * The following command-line arguments may be used with this class: 100 * <UL> 101 * <LI>"-b {baseDN}" or "--baseDN {baseDN}" -- specifies a base DN to use for 102 * the server. At least one base DN must be specified, and multiple 103 * base DNs may be provided as separate arguments.</LI> 104 * <LI>"-p {port}" or "--port {port}" -- specifies the port on which the 105 * server should listen for client connections. If this is not provided, 106 * then a free port will be automatically chosen for use by the 107 * server.</LI> 108 * <LI>"-l {path}" or "--ldifFile {path}" -- specifies the path to an LDIF 109 * file to use to initially populate the server. If this is not provided, 110 * then the server will initially be empty. The LDIF file will not be 111 * updated as operations are processed in the server.</LI> 112 * <LI>"-D {bindDN}" or "--additionalBindDN {bindDN}" -- specifies an 113 * additional DN that can be used to authenticate to the server, even if 114 * there is no account for that user. If this is provided, then the 115 * --additionalBindPassword argument must also be given.</LI> 116 * <LI>"-w {password}" or "--additionalBindPassword {password}" -- specifies 117 * the password that should be used when attempting to bind as the user 118 * specified with the "-additionalBindDN" argument. If this is provided, 119 * then the --additionalBindDN argument must also be given.</LI> 120 * <LI>"-c {count}" or "--maxChangeLogEntries {count}" -- Indicates whether an 121 * LDAP changelog should be enabled, and if so how many changelog records 122 * should be maintained. If this argument is not provided, or if it is 123 * provided with a value of zero, then no changelog will be 124 * maintained.</LI> 125 * <LI>"-A" or "--accessLogToStandardOut" -- indicates that access log 126 * information should be written to standard output. This cannot be 127 * provided in conjunction with the "--accessLogFile" argument. If 128 * neither argument is provided, then no access logging will be 129 * performed</LI> 130 * <LI>"-a {path}" or "--accessLogFile {path}" -- specifies the path to a file 131 * that should be used as a server access log. This cannot be provided in 132 * conjunction with the "--accessLogToStandardOut" argument. If neither 133 * argument is provided, then no access logging will be performed</LI> 134 * <LI>"---jsonAccessLogToStandardOut" -- indicates that JSON-formatted access 135 * log information should be written to standard output. This cannot be 136 * provided in conjunction with the "--jsonAccessLogFile" argument. If 137 * neither argument is provided, then no JSON-formatted access logging 138 * will be performed</LI> 139 * <LI>"--jsonAccessLogFile {path}" -- specifies the path to a file that 140 * should be used as a server access log with JSON-formatted messages. 141 * This cannot be provided in conjunction with the 142 * "--jsonAccessLogToStandardOut" argument. If neither argument is 143 * provided, then no JSON-formatted access logging will be performed</LI> 144 * <LI>"--ldapDebugLogToStandardOut" -- Indicates that LDAP debug log 145 * information should be written to standard output. This cannot be 146 * provided in conjunction with the "--ldapDebugLogFile" argument. If 147 * neither argument is provided, then no debug logging will be 148 * performed.</LI> 149 * <LI>"-d {path}" or "--ldapDebugLogFile {path}" -- specifies the path to a 150 * file that should be used as a server LDAP debug log. This cannot be 151 * provided in conjunction with the "--ldapDebugLogToStandardOut" 152 * argument. If neither argument is provided, then no debug logging will 153 * be performed.</LI> 154 * <LI>"-s" or "--useDefaultSchema" -- Indicates that the server should use 155 * the default standard schema provided as part of the LDAP SDK. If 156 * neither this argument nor the "--useSchemaFile" argument is provided, 157 * then the server will not enforce schema compliance.</LI> 158 * <LI>"-S {path}" or "--useSchemaFile {path}" -- specifies the path to a file 159 * or directory containing schema definitions to use for the server. If 160 * neither this argument nor the "--useDefaultSchema" argument is 161 * provided, then the server will not enforce schema compliance. If 162 * the specified path represents a file, then it must be an LDIF file 163 * containing a valid LDAP subschema subentry. If the path is a 164 * directory, then its files will be processed in lexicographic order by 165 * name.</LI> 166 * <LI>"--doNotValidateSchemaDefinitions" -- indicates that the server should 167 * not perform any validation for the custom schema provided using the 168 * --useSchemaFile argument. If this argument is not used and a custom 169 * schema is configured, then the server will validate that schema and 170 * report errors or warnings for any issues that it identifies with that 171 * schema.</LI> 172 * <LI>"--doNotGenerateOperationalAttributes" -- indicates that the server 173 * should not maintain any operational attributes (including entryDN, 174 * entryUUID, subschemaSubentry, creatorsName, createTimestamp, 175 * modifiersName, and modifyTimestamp) in entries.</LI> 176 * <LI>"-I {attr}" or "--equalityIndex {attr}" -- specifies that an equality 177 * index should be maintained for the specified attribute. The equality 178 * index may be used to speed up certain kinds of searches, although it 179 * will cause the server to consume more memory.</LI> 180 * <LI>"-Z" or "--useSSL" -- indicates that the server should encrypt all 181 * communication using SSL. If this is provided, then the 182 * "--keyStorePath" and "--keyStorePassword" arguments must also be 183 * provided, and the "--useStartTLS" argument must not be provided.</LI> 184 * <LI>"-q" or "--useStartTLS" -- indicates that the server should support the 185 * use of the StartTLS extended request. If this is provided, then the 186 * "--keyStorePath" and "--keyStorePassword" arguments must also be 187 * provided, and the "--useSSL" argument must not be provided.</LI> 188 * <LI>"-K {path}" or "--keyStorePath {path}" -- specifies the path to the JKS 189 * key store file that should be used to obtain the server certificate to 190 * use for SSL communication. If this argument is provided, then the 191 * "--keyStorePassword" argument must also be provided, along with exactly 192 * one of the "--useSSL" or "--useStartTLS" arguments.</LI> 193 * <LI>"-W {password}" or "--keyStorePassword {password}" -- specifies the 194 * password that should be used to access the contents of the SSL key 195 * store. If this argument is provided, then the "--keyStorePath" 196 * argument must also be provided, along with exactly one of the 197 * "--useSSL" or "--useStartTLS" arguments.</LI> 198 * <LI>"--keyStoreType {type}" -- specifies the type of keystore represented 199 * by the file specified by the keystore path. If this argument is 200 * provided, then the "--keyStorePath" argument must also be provided, 201 * along with exactly one of the "--useSSL" or "--useStartTLS" arguments. 202 * If this argument is not provided, then a default key store type of 203 * "JKS" will be assumed.</LI> 204 * <LI>"--generateSelfSignedCertificate" -- indicates that the server should 205 * generate a self-signed certificate to use for SSL or StartTLS 206 * communication. If this argument is provided, then exactly one of the 207 * "--useSSL" or "--useStartTLS" arguments must also be specified.</LI> 208 * <LI>"-P {path}" or "--trustStorePath {path}" -- specifies the path to the 209 * JKS trust store file that should be used to determine whether to trust 210 * any SSL certificates that may be presented by the client. If this 211 * argument is provided, then exactly one of the "--useSSL" or 212 * "--useStartTLS" arguments must also be provided. If this argument is 213 * not provided but SSL or StartTLS is to be used, then all client 214 * certificates will be automatically trusted.</LI> 215 * <LI>"-T {password}" or "--trustStorePassword {password}" -- specifies the 216 * password that should be used to access the contents of the SSL trust 217 * store. If this argument is provided, then the "--trustStorePath" 218 * argument must also be provided, along with exactly one of the 219 * "--useSSL" or "--useStartTLS" arguments. If an SSL trust store path 220 * was provided without a trust store password, then the server will 221 * attempt to use the trust store without a password.</LI> 222 * <LI>"--trustStoreType {type}" -- specifies the type of trust store 223 * represented by the file specified by the trust store path. If this 224 * argument is provided, then the "--trustStorePath" argument must also 225 * be provided, along with exactly one of the "--useSSL" or 226 * "--useStartTLS" arguments. If this argument is not provided, then a 227 * default trust store type of "JKS" will be assumed.</LI> 228 * <LI>"--maxConcurrentConnections {num}" -- specifies the maximum number of 229 * concurrent connections that the server will allow.</LI> 230 * <LI>"--sizeLimit {num}" -- specifies the maximum number of entries that 231 * the server will return for a single search operation.</LI> 232 * <LI>"--passwordAttribute {attr}" -- specifies an attribute that will hold 233 * user passwords.</LI> 234 * <LI>"--defaultPasswordEncoding {scheme}" -- specifies the name of the 235 * default scheme that the server will use to encode clear-text 236 * passwords. Allowed values include MD5, SMD5, SHA, SSHA, SHA256, 237 * SSHA256, SHA384, SSHA384, SHA512, SSHA512, CLEAR, BASE64, and HEX.</LI> 238 * <LI>"--allowedOperationType {type}" -- specifies a type of operation that 239 * the server will allow. Allowed values include add, bind, compare, 240 * delete, extended, modify, modify-dn, and search.</LI> 241 * <LI>"--authenticationRequiredOperationType {type}" -- specifies a type of 242 * operation that the server will only allow for authenticated clients. 243 * Allowed values include add, compare, delete, extended, modify, 244 * modify-dn, and search.</LI> 245 * <LI>"--vendorName {name}" -- specifies the vendor name value to appear in 246 * the server root DSE.</LI> 247 * <LI>"--vendorVersion {version}" -- specifies the vendor version value to 248 * appear in the server root DSE.</LI> 249 * </UL> 250 */ 251@NotMutable() 252@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 253public final class InMemoryDirectoryServerTool 254 extends CommandLineTool 255 implements Serializable, LDAPListenerExceptionHandler 256{ 257 /** 258 * The column at which long lines should be wrapped. 259 */ 260 private static final int WRAP_COLUMN = StaticUtils.TERMINAL_WIDTH_COLUMNS - 1; 261 262 263 264 /** 265 * The SSL client authentication policy value that indicates that the server 266 * should not ask the client to present a certificate chain. 267 */ 268 @NotNull private static final String SSL_CLIENT_AUTH_POLICY_PROHIBITED = 269 "prohibited"; 270 271 272 273 /** 274 * The SSL client authentication policy value that indicates that the server 275 * should ask the client to present a certificate chain but will not require 276 * one. 277 */ 278 @NotNull private static final String SSL_CLIENT_AUTH_POLICY_OPTIONAL = 279 "optional"; 280 281 282 283 /** 284 * The SSL client authentication policy value that indicates that the server 285 * should require the client to present a certificate chain. 286 */ 287 @NotNull private static final String SSL_CLIENT_AUTH_POLICY_REQUIRED = 288 "required"; 289 290 291 292 /** 293 * The serial version UID for this serializable class. 294 */ 295 private static final long serialVersionUID = 6484637038039050412L; 296 297 298 299 // The argument used to indicate that access log information should be written 300 // to standard output. 301 @Nullable private BooleanArgument accessLogToStandardOutArgument; 302 303 // Indicates that the should not maintain operational attributes in entries. 304 @Nullable private BooleanArgument doNotGenerateOperationalAttributesArgument; 305 306 // Indicates that the should not attempt to validate custom schema definitions 307 // provided by the useSchemaFile argument. 308 @Nullable private BooleanArgument doNotValidateSchemaDefinitionsArgument; 309 310 // The argument used to prevent the in-memory server from starting. This is 311 // only intended to be used for internal testing purposes. 312 @Nullable private BooleanArgument dontStartArgument; 313 314 // The argument used to indicate that the server should generate a self-signed 315 // certificate for use in SSL or StartTLS negotiation. 316 @Nullable private BooleanArgument generateSelfSignedCertificateArgument; 317 318 // The argument used to indicate that JSON-formatted access log information 319 // should be written to standard output. 320 @Nullable private BooleanArgument jsonAccessLogToStandardOutArgument; 321 322 // The argument used to indicate that LDAP debug log information should be 323 // written to standard output. 324 @Nullable private BooleanArgument ldapDebugLogToStandardOutArgument; 325 326 // The argument used to indicate that the default standard schema should be 327 // used. 328 @Nullable private BooleanArgument useDefaultSchemaArgument; 329 330 // The argument used to indicate that the server should use SSL 331 @Nullable private BooleanArgument useSSLArgument; 332 333 // The argument used to indicate that the server should support the StartTLS 334 // extended operation 335 @Nullable private BooleanArgument useStartTLSArgument; 336 337 // The argument used to specify an additional bind DN to use for the server. 338 @Nullable private DNArgument additionalBindDNArgument; 339 340 // The argument used to specify the base DNs to use for the server. 341 @Nullable private DNArgument baseDNArgument; 342 343 // The argument used to specify the path to an access log file to which 344 // information should be written about operations processed by the server. 345 @Nullable private FileArgument accessLogFileArgument; 346 347 // The argument used to specify the code log file to use, if any. 348 @Nullable private FileArgument codeLogFile; 349 350 // The argument used to specify the path to an access log file to which 351 // JSON-formatted operation should be written about operations processed by 352 // the server. 353 @Nullable private FileArgument jsonAccessLogFileArgument; 354 355 // The argument used to specify the path to the SSL key store file. 356 @Nullable private FileArgument keyStorePathArgument; 357 358 // The argument used to specify the path to an LDAP debug log file to which 359 // information should be written about detailed LDAP communication performed 360 // by the server. 361 @Nullable private FileArgument ldapDebugLogFileArgument; 362 363 // The argument used to specify the path to an LDIF file with data to use to 364 // initially populate the server. 365 @Nullable private FileArgument ldifFileArgument; 366 367 // The argument used to specify the path to the SSL trust store file. 368 @Nullable private FileArgument trustStorePathArgument; 369 370 // The argument used to specify the path to a directory containing schema 371 // definitions. 372 @Nullable private FileArgument useSchemaFileArgument; 373 374 // The in-memory directory server instance that has been created by this tool. 375 @Nullable private InMemoryDirectoryServer directoryServer; 376 377 // The argument used to specify the maximum number of changelog entries that 378 // the server should maintain. 379 @Nullable private IntegerArgument maxChangeLogEntriesArgument; 380 381 // The argument used to specify the maximum number of concurrent connections. 382 @Nullable private IntegerArgument maxConcurrentConnectionsArgument; 383 384 // The argument used to specify the port on which the server should listen. 385 @Nullable private IntegerArgument portArgument; 386 387 // The argument used to specify the maximum search size limit. 388 @Nullable private IntegerArgument sizeLimitArgument; 389 390 // The argument used to specify the password for the additional bind DN. 391 @Nullable private StringArgument additionalBindPasswordArgument; 392 393 // The argument used to specify the types of allowed operations. 394 @Nullable private StringArgument allowedOperationTypeArgument; 395 396 // The argument used to specify the types of operations for which 397 // authentication is required. 398 @Nullable private StringArgument authenticationRequiredOperationTypeArgument; 399 400 // The argument used to specify the name of the default encoding scheme to use 401 // use for clear-text passwords. 402 @Nullable private StringArgument defaultPasswordEncodingArgument; 403 404 // The argument used to specify the attributes for which to maintain equality 405 // indexes. 406 @Nullable private StringArgument equalityIndexArgument; 407 408 // The argument used to specify the password to use to access the contents of 409 // the SSL key store 410 @Nullable private StringArgument keyStorePasswordArgument; 411 412 // The argument used to specify the key store type. 413 @Nullable private StringArgument keyStoreTypeArgument; 414 415 // The argument used to specify the password attribute types. 416 @Nullable private StringArgument passwordAttributeArgument; 417 418 // The argument used to specify the policy the server should use for TLS 419 // client authentication. 420 @Nullable private StringArgument sslClientAuthPolicy; 421 422 // The argument used to specify the password to use to access the contents of 423 // the SSL trust store 424 @Nullable private StringArgument trustStorePasswordArgument; 425 426 // The argument used to specify the trust store type. 427 @Nullable private StringArgument trustStoreTypeArgument; 428 429 // The argument used to specify the server vendor name. 430 @Nullable private StringArgument vendorNameArgument; 431 432 // The argument used to specify the server vendor version. 433 @Nullable private StringArgument vendorVersionArgument; 434 435 436 437 /** 438 * Parse the provided command line arguments and uses them to start the 439 * directory server. 440 * 441 * @param args The command line arguments provided to this program. 442 */ 443 public static void main(@NotNull final String... args) 444 { 445 final ResultCode resultCode = main(args, System.out, System.err); 446 if (resultCode != ResultCode.SUCCESS) 447 { 448 System.exit(resultCode.intValue()); 449 } 450 } 451 452 453 454 /** 455 * Parse the provided command line arguments and uses them to start the 456 * directory server. 457 * 458 * @param outStream The output stream to which standard out should be 459 * written. It may be {@code null} if output should be 460 * suppressed. 461 * @param errStream The output stream to which standard error should be 462 * written. It may be {@code null} if error messages 463 * should be suppressed. 464 * @param args The command line arguments provided to this program. 465 * 466 * @return A result code indicating whether the processing was successful. 467 */ 468 @NotNull() 469 public static ResultCode main(@NotNull final String[] args, 470 @Nullable final OutputStream outStream, 471 @Nullable final OutputStream errStream) 472 { 473 final InMemoryDirectoryServerTool tool = 474 new InMemoryDirectoryServerTool(outStream, errStream); 475 return tool.runTool(args); 476 } 477 478 479 480 /** 481 * Creates a new instance of this tool that use the provided output streams 482 * for standard output and standard error. 483 * 484 * @param outStream The output stream to use for standard output. It may be 485 * {@code System.out} for the JVM's default standard output 486 * stream, {@code null} if no output should be generated, 487 * or a custom output stream if the output should be sent 488 * to an alternate location. 489 * @param errStream The output stream to use for standard error. It may be 490 * {@code System.err} for the JVM's default standard error 491 * stream, {@code null} if no output should be generated, 492 * or a custom output stream if the output should be sent 493 * to an alternate location. 494 */ 495 public InMemoryDirectoryServerTool(@Nullable final OutputStream outStream, 496 @Nullable final OutputStream errStream) 497 { 498 super(outStream, errStream); 499 500 directoryServer = null; 501 doNotGenerateOperationalAttributesArgument = null; 502 doNotValidateSchemaDefinitionsArgument = null; 503 dontStartArgument = null; 504 generateSelfSignedCertificateArgument = null; 505 useDefaultSchemaArgument = null; 506 useSSLArgument = null; 507 useStartTLSArgument = null; 508 additionalBindDNArgument = null; 509 baseDNArgument = null; 510 accessLogToStandardOutArgument = null; 511 accessLogFileArgument = null; 512 jsonAccessLogToStandardOutArgument = null; 513 jsonAccessLogFileArgument = null; 514 keyStorePathArgument = null; 515 ldapDebugLogToStandardOutArgument = null; 516 ldapDebugLogFileArgument = null; 517 ldifFileArgument = null; 518 trustStorePathArgument = null; 519 useSchemaFileArgument = null; 520 maxChangeLogEntriesArgument = null; 521 maxConcurrentConnectionsArgument = null; 522 portArgument = null; 523 sizeLimitArgument = null; 524 additionalBindPasswordArgument = null; 525 allowedOperationTypeArgument = null; 526 authenticationRequiredOperationTypeArgument = null; 527 defaultPasswordEncodingArgument = null; 528 equalityIndexArgument = null; 529 keyStorePasswordArgument = null; 530 keyStoreTypeArgument = null; 531 passwordAttributeArgument = null; 532 sslClientAuthPolicy = null; 533 trustStorePasswordArgument = null; 534 trustStoreTypeArgument = null; 535 vendorNameArgument = null; 536 vendorVersionArgument = null; 537 } 538 539 540 541 /** 542 * {@inheritDoc} 543 */ 544 @Override() 545 @NotNull() 546 public String getToolName() 547 { 548 return "in-memory-directory-server"; 549 } 550 551 552 553 /** 554 * {@inheritDoc} 555 */ 556 @Override() 557 @NotNull() 558 public String getToolDescription() 559 { 560 return INFO_MEM_DS_TOOL_DESC.get(InMemoryDirectoryServer.class.getName()); 561 } 562 563 564 565 /** 566 * Retrieves the version string for this tool. 567 * 568 * @return The version string for this tool. 569 */ 570 @Override() 571 @NotNull() 572 public String getToolVersion() 573 { 574 return Version.NUMERIC_VERSION_STRING; 575 } 576 577 578 579 /** 580 * {@inheritDoc} 581 */ 582 @Override() 583 public void addToolArguments(@NotNull final ArgumentParser parser) 584 throws ArgumentException 585 { 586 portArgument = new IntegerArgument('p', "port", false, 1, 587 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PORT.get(), 588 INFO_MEM_DS_TOOL_ARG_DESC_PORT.get(), 0, 65_535); 589 portArgument.setArgumentGroupName( 590 INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get()); 591 parser.addArgument(portArgument); 592 593 useSSLArgument = new BooleanArgument('Z', "useSSL", 594 INFO_MEM_DS_TOOL_ARG_DESC_USE_SSL.get()); 595 useSSLArgument.setArgumentGroupName( 596 INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get()); 597 useSSLArgument.addLongIdentifier("use-ssl", true); 598 parser.addArgument(useSSLArgument); 599 600 useStartTLSArgument = new BooleanArgument('q', "useStartTLS", 601 INFO_MEM_DS_TOOL_ARG_DESC_USE_START_TLS.get()); 602 useStartTLSArgument.setArgumentGroupName( 603 INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get()); 604 useStartTLSArgument.addLongIdentifier("use-starttls", true); 605 useStartTLSArgument.addLongIdentifier("use-start-tls", true); 606 parser.addArgument(useStartTLSArgument); 607 608 keyStorePathArgument = new FileArgument('K', "keyStorePath", false, 1, 609 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PATH.get(), 610 INFO_MEM_DS_TOOL_ARG_DESC_KEY_STORE_PATH.get(), true, true, true, 611 false); 612 keyStorePathArgument.setArgumentGroupName( 613 INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get()); 614 keyStorePathArgument.addLongIdentifier("key-store-path", true); 615 parser.addArgument(keyStorePathArgument); 616 617 keyStorePasswordArgument = new StringArgument('W', "keyStorePassword", 618 false, 1, INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PASSWORD.get(), 619 INFO_MEM_DS_TOOL_ARG_DESC_KEY_STORE_PW.get()); 620 keyStorePasswordArgument.setSensitive(true); 621 keyStorePasswordArgument.setArgumentGroupName( 622 INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get()); 623 keyStorePasswordArgument.addLongIdentifier("keyStorePIN", true); 624 keyStorePasswordArgument.addLongIdentifier("key-store-password", true); 625 keyStorePasswordArgument.addLongIdentifier("key-store-pin", true); 626 parser.addArgument(keyStorePasswordArgument); 627 628 keyStoreTypeArgument = new StringArgument(null, "keyStoreType", 629 false, 1, "{type}", INFO_MEM_DS_TOOL_ARG_DESC_KEY_STORE_TYPE.get(), 630 CryptoHelper.KEY_STORE_TYPE_JKS); 631 keyStoreTypeArgument.setArgumentGroupName( 632 INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get()); 633 keyStoreTypeArgument.addLongIdentifier("keyStoreFormat", true); 634 keyStoreTypeArgument.addLongIdentifier("key-store-type", true); 635 keyStoreTypeArgument.addLongIdentifier("key-store-format", true); 636 parser.addArgument(keyStoreTypeArgument); 637 638 generateSelfSignedCertificateArgument = new BooleanArgument(null, 639 "generateSelfSignedCertificate", 1, 640 INFO_MEM_DS_TOOL_ARG_DESC_SELF_SIGNED_CERT.get()); 641 generateSelfSignedCertificateArgument.setArgumentGroupName( 642 INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get()); 643 generateSelfSignedCertificateArgument.addLongIdentifier( 644 "useSelfSignedCertificate", true); 645 generateSelfSignedCertificateArgument.addLongIdentifier( 646 "selfSignedCertificate", true); 647 generateSelfSignedCertificateArgument.addLongIdentifier( 648 "generate-self-signed-certificate", true); 649 generateSelfSignedCertificateArgument.addLongIdentifier( 650 "use-self-signed-certificate", true); 651 generateSelfSignedCertificateArgument.addLongIdentifier( 652 "self-signed-certificate", true); 653 parser.addArgument(generateSelfSignedCertificateArgument); 654 655 trustStorePathArgument = new FileArgument('P', "trustStorePath", false, 1, 656 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PATH.get(), 657 INFO_MEM_DS_TOOL_ARG_DESC_TRUST_STORE_PATH.get(), true, true, true, 658 false); 659 trustStorePathArgument.setArgumentGroupName( 660 INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get()); 661 trustStorePathArgument.addLongIdentifier("trust-store-path", true); 662 parser.addArgument(trustStorePathArgument); 663 664 trustStorePasswordArgument = new StringArgument('T', "trustStorePassword", 665 false, 1, INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PASSWORD.get(), 666 INFO_MEM_DS_TOOL_ARG_DESC_TRUST_STORE_PW.get()); 667 trustStorePasswordArgument.setSensitive(true); 668 trustStorePasswordArgument.setArgumentGroupName( 669 INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get()); 670 trustStorePasswordArgument.addLongIdentifier("trustStorePIN", true); 671 trustStorePasswordArgument.addLongIdentifier("trust-store-password", true); 672 trustStorePasswordArgument.addLongIdentifier("trust-store-pin", true); 673 parser.addArgument(trustStorePasswordArgument); 674 675 trustStoreTypeArgument = new StringArgument(null, "trustStoreType", 676 false, 1, "{type}", INFO_MEM_DS_TOOL_ARG_DESC_TRUST_STORE_TYPE.get(), 677 CryptoHelper.KEY_STORE_TYPE_JKS); 678 trustStoreTypeArgument.setArgumentGroupName( 679 INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get()); 680 trustStoreTypeArgument.addLongIdentifier("trustStoreFormat", true); 681 trustStoreTypeArgument.addLongIdentifier("trust-store-type", true); 682 trustStoreTypeArgument.addLongIdentifier("trust-store-format", true); 683 parser.addArgument(trustStoreTypeArgument); 684 685 sslClientAuthPolicy = new StringArgument(null, "sslClientAuthPolicy", false, 686 1, INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_SSL_CLIENT_AUTH_POLICY.get(), 687 INFO_MEM_DS_TOOL_ARG_DESC_SSL_CLIENT_AUTH_POLICY.get(), 688 StaticUtils.setOf( 689 SSL_CLIENT_AUTH_POLICY_PROHIBITED, 690 SSL_CLIENT_AUTH_POLICY_OPTIONAL, 691 SSL_CLIENT_AUTH_POLICY_REQUIRED), 692 SSL_CLIENT_AUTH_POLICY_PROHIBITED); 693 sslClientAuthPolicy.addLongIdentifier("ssl-client-auth-policy", true); 694 sslClientAuthPolicy.addLongIdentifier("sslClientAuthenticationPolicy", 695 true); 696 sslClientAuthPolicy.addLongIdentifier("ssl-client-authentication-policy", 697 true); 698 sslClientAuthPolicy.addLongIdentifier("sslClientCertificatePolicy", true); 699 sslClientAuthPolicy.addLongIdentifier("ssl-client-certificate-policy", 700 true); 701 sslClientAuthPolicy.addLongIdentifier("sslClientCertPolicy", true); 702 sslClientAuthPolicy.addLongIdentifier("ssl-client-cert-policy", true); 703 sslClientAuthPolicy.setArgumentGroupName( 704 INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get()); 705 parser.addArgument(sslClientAuthPolicy); 706 707 maxConcurrentConnectionsArgument = new IntegerArgument(null, 708 "maxConcurrentConnections", false, 1, null, 709 INFO_MEM_DS_TOOL_ARG_DESC_MAX_CONNECTIONS.get(), 1, 710 Integer.MAX_VALUE, Integer.MAX_VALUE); 711 maxConcurrentConnectionsArgument.setArgumentGroupName( 712 INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get()); 713 maxConcurrentConnectionsArgument.addLongIdentifier( 714 "maximumConcurrentConnections", true); 715 maxConcurrentConnectionsArgument.addLongIdentifier( 716 "maxConnections", true); 717 maxConcurrentConnectionsArgument.addLongIdentifier( 718 "maximumConnections", true); 719 maxConcurrentConnectionsArgument.addLongIdentifier( 720 "max-concurrent-connections", true); 721 maxConcurrentConnectionsArgument.addLongIdentifier( 722 "maximum-concurrent-connections", true); 723 maxConcurrentConnectionsArgument.addLongIdentifier( 724 "max-connections", true); 725 maxConcurrentConnectionsArgument.addLongIdentifier( 726 "maximum-connections", true); 727 parser.addArgument(maxConcurrentConnectionsArgument); 728 729 dontStartArgument = new BooleanArgument(null, "dontStart", 730 INFO_MEM_DS_TOOL_ARG_DESC_DONT_START.get()); 731 dontStartArgument.setArgumentGroupName( 732 INFO_MEM_DS_TOOL_GROUP_CONNECTIVITY.get()); 733 dontStartArgument.setHidden(true); 734 dontStartArgument.addLongIdentifier("doNotStart", true); 735 dontStartArgument.addLongIdentifier("dont-start", true); 736 dontStartArgument.addLongIdentifier("do-not-start", true); 737 parser.addArgument(dontStartArgument); 738 739 baseDNArgument = new DNArgument('b', "baseDN", true, 0, 740 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_BASE_DN.get(), 741 INFO_MEM_DS_TOOL_ARG_DESC_BASE_DN.get()); 742 baseDNArgument.setArgumentGroupName(INFO_MEM_DS_TOOL_GROUP_DATA.get()); 743 baseDNArgument.addLongIdentifier("base-dn", true); 744 parser.addArgument(baseDNArgument); 745 746 ldifFileArgument = new FileArgument('l', "ldifFile", false, 1, 747 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PATH.get(), 748 INFO_MEM_DS_TOOL_ARG_DESC_LDIF_FILE.get(), true, true, true, false); 749 ldifFileArgument.setArgumentGroupName(INFO_MEM_DS_TOOL_GROUP_DATA.get()); 750 ldifFileArgument.addLongIdentifier("ldif-file", true); 751 parser.addArgument(ldifFileArgument); 752 753 additionalBindDNArgument = new DNArgument('D', "additionalBindDN", false, 1, 754 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_BIND_DN.get(), 755 INFO_MEM_DS_TOOL_ARG_DESC_ADDITIONAL_BIND_DN.get()); 756 additionalBindDNArgument.setArgumentGroupName( 757 INFO_MEM_DS_TOOL_GROUP_DATA.get()); 758 additionalBindDNArgument.addLongIdentifier("additional-bind-dn", true); 759 parser.addArgument(additionalBindDNArgument); 760 761 additionalBindPasswordArgument = new StringArgument('w', 762 "additionalBindPassword", false, 1, 763 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PASSWORD.get(), 764 INFO_MEM_DS_TOOL_ARG_DESC_ADDITIONAL_BIND_PW.get()); 765 additionalBindPasswordArgument.setSensitive(true); 766 additionalBindPasswordArgument.setArgumentGroupName( 767 INFO_MEM_DS_TOOL_GROUP_DATA.get()); 768 additionalBindPasswordArgument.addLongIdentifier( 769 "additional-bind-password", true); 770 parser.addArgument(additionalBindPasswordArgument); 771 772 useDefaultSchemaArgument = new BooleanArgument('s', "useDefaultSchema", 773 INFO_MEM_DS_TOOL_ARG_DESC_USE_DEFAULT_SCHEMA.get()); 774 useDefaultSchemaArgument.setArgumentGroupName( 775 INFO_MEM_DS_TOOL_GROUP_DATA.get()); 776 useDefaultSchemaArgument.addLongIdentifier("use-default-schema", true); 777 parser.addArgument(useDefaultSchemaArgument); 778 779 useSchemaFileArgument = new FileArgument('S', "useSchemaFile", false, 0, 780 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PATH.get(), 781 INFO_MEM_DS_TOOL_ARG_DESC_USE_SCHEMA_FILE.get(), true, true, false, 782 false); 783 useSchemaFileArgument.setArgumentGroupName( 784 INFO_MEM_DS_TOOL_GROUP_DATA.get()); 785 useSchemaFileArgument.addLongIdentifier("use-schema-file", true); 786 parser.addArgument(useSchemaFileArgument); 787 788 doNotValidateSchemaDefinitionsArgument = new BooleanArgument(null, 789 "doNotValidateSchemaDefinitions", 1, 790 INFO_MEM_DS_TOOL_ARG_DESC_DO_NOT_VALIDATE_SCHEMA.get( 791 useSchemaFileArgument.getIdentifierString())); 792 doNotValidateSchemaDefinitionsArgument.setArgumentGroupName( 793 INFO_MEM_DS_TOOL_GROUP_DATA.get()); 794 doNotValidateSchemaDefinitionsArgument.addLongIdentifier( 795 "do-not-validate-schema-definitions", true); 796 parser.addArgument(doNotValidateSchemaDefinitionsArgument); 797 798 doNotGenerateOperationalAttributesArgument = new BooleanArgument(null, 799 "doNotGenerateOperationalAttributes", 1, 800 INFO_MEM_DS_TOOL_ARG_DESC_DO_NOT_GENERATE_OP_ATTRS.get()); 801 doNotGenerateOperationalAttributesArgument.setArgumentGroupName( 802 INFO_MEM_DS_TOOL_GROUP_DATA.get()); 803 doNotGenerateOperationalAttributesArgument.addLongIdentifier( 804 "do-not-generate-operational-attributes"); 805 parser.addArgument(doNotGenerateOperationalAttributesArgument); 806 807 equalityIndexArgument = new StringArgument('I', "equalityIndex", false, 0, 808 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_ATTR.get(), 809 INFO_MEM_DS_TOOL_ARG_DESC_EQ_INDEX.get()); 810 equalityIndexArgument.setArgumentGroupName( 811 INFO_MEM_DS_TOOL_GROUP_DATA.get()); 812 equalityIndexArgument.addLongIdentifier("equality-index", true); 813 parser.addArgument(equalityIndexArgument); 814 815 maxChangeLogEntriesArgument = new IntegerArgument('c', 816 "maxChangeLogEntries", false, 1, 817 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_COUNT.get(), 818 INFO_MEM_DS_TOOL_ARG_DESC_MAX_CHANGELOG_ENTRIES.get(), 0, 819 Integer.MAX_VALUE, 0); 820 maxChangeLogEntriesArgument.setArgumentGroupName( 821 INFO_MEM_DS_TOOL_GROUP_DATA.get()); 822 maxChangeLogEntriesArgument.addLongIdentifier("max-changelog-entries", 823 true); 824 maxChangeLogEntriesArgument.addLongIdentifier("max-change-log-entries", 825 true); 826 parser.addArgument(maxChangeLogEntriesArgument); 827 828 sizeLimitArgument = new IntegerArgument(null, "sizeLimit", false, 1, null, 829 INFO_MEM_DS_TOOL_ARG_DESC_SIZE_LIMIT.get(), 1, Integer.MAX_VALUE, 830 Integer.MAX_VALUE); 831 sizeLimitArgument.setArgumentGroupName(INFO_MEM_DS_TOOL_GROUP_DATA.get()); 832 sizeLimitArgument.addLongIdentifier("searchSizeLimit", true); 833 sizeLimitArgument.addLongIdentifier("size-limit", true); 834 sizeLimitArgument.addLongIdentifier("search-size-limit", true); 835 parser.addArgument(sizeLimitArgument); 836 837 passwordAttributeArgument = new StringArgument(null, "passwordAttribute", 838 false, 1, INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_ATTR.get(), 839 INFO_MEM_DS_TOOL_ARG_DESC_PASSWORD_ATTRIBUTE.get(), "userPassword"); 840 passwordAttributeArgument.setArgumentGroupName( 841 INFO_MEM_DS_TOOL_GROUP_DATA.get()); 842 passwordAttributeArgument.addLongIdentifier("passwordAttributeType", true); 843 passwordAttributeArgument.addLongIdentifier("password-attribute", true); 844 passwordAttributeArgument.addLongIdentifier("password-attribute-type", 845 true); 846 parser.addArgument(passwordAttributeArgument); 847 848 final Set<String> allowedSchemes = StaticUtils.setOf("md5", "smd5", "sha", 849 "ssha", "sha256", "ssha256", "sha384", "ssha384", "sha512", "ssha512", 850 "clear", "base64", "hex"); 851 defaultPasswordEncodingArgument = new StringArgument(null, 852 "defaultPasswordEncoding", false, 1, 853 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_SCHEME.get(), 854 INFO_MEM_DS_TOOL_ARG_DESC_DEFAULT_PASSWORD_ENCODING.get(), 855 allowedSchemes); 856 defaultPasswordEncodingArgument.setArgumentGroupName( 857 INFO_MEM_DS_TOOL_GROUP_DATA.get()); 858 defaultPasswordEncodingArgument.addLongIdentifier( 859 "defaultPasswordEncodingScheme", true); 860 defaultPasswordEncodingArgument.addLongIdentifier( 861 "defaultPasswordStorageScheme", true); 862 defaultPasswordEncodingArgument.addLongIdentifier( 863 "defaultPasswordScheme", true); 864 defaultPasswordEncodingArgument.addLongIdentifier( 865 "default-password-encoding", true); 866 defaultPasswordEncodingArgument.addLongIdentifier( 867 "default-password-encoding-scheme", true); 868 defaultPasswordEncodingArgument.addLongIdentifier( 869 "default-password-storage-scheme", true); 870 defaultPasswordEncodingArgument.addLongIdentifier( 871 "default-password-scheme", true); 872 parser.addArgument(defaultPasswordEncodingArgument); 873 874 final Set<String> allowedOperationTypeAllowedValues = StaticUtils.setOf( 875 "add", "bind", "compare", "delete", "extended", "modify", "modify-dn", 876 "search"); 877 allowedOperationTypeArgument = new StringArgument(null, 878 "allowedOperationType", false, 0, 879 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_TYPE.get(), 880 INFO_MEM_DS_TOOL_ARG_DESC_ALLOWED_OP_TYPE.get(), 881 allowedOperationTypeAllowedValues); 882 allowedOperationTypeArgument.setArgumentGroupName( 883 INFO_MEM_DS_TOOL_GROUP_DATA.get()); 884 allowedOperationTypeArgument.addLongIdentifier("allowed-operation-type", 885 true); 886 parser.addArgument(allowedOperationTypeArgument); 887 888 final Set<String> authRequiredTypeAllowedValues = StaticUtils.setOf("add", 889 "compare", "delete", "extended", "modify", "modify-dn", "search"); 890 authenticationRequiredOperationTypeArgument = new StringArgument(null, 891 "authenticationRequiredOperationType", false, 0, 892 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_TYPE.get(), 893 INFO_MEM_DS_TOOL_ARG_DESC_AUTH_REQUIRED_OP_TYPE.get(), 894 authRequiredTypeAllowedValues); 895 authenticationRequiredOperationTypeArgument.setArgumentGroupName( 896 INFO_MEM_DS_TOOL_GROUP_DATA.get()); 897 authenticationRequiredOperationTypeArgument.addLongIdentifier( 898 "requiredAuthenticationOperationType", true); 899 authenticationRequiredOperationTypeArgument.addLongIdentifier( 900 "requireAuthenticationOperationType", true); 901 authenticationRequiredOperationTypeArgument.addLongIdentifier( 902 "authentication-required-operation-type", true); 903 authenticationRequiredOperationTypeArgument.addLongIdentifier( 904 "required-authentication-operation-type", true); 905 authenticationRequiredOperationTypeArgument.addLongIdentifier( 906 "require-authentication-operation-type", true); 907 parser.addArgument(authenticationRequiredOperationTypeArgument); 908 909 vendorNameArgument = new StringArgument(null, "vendorName", false, 1, 910 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_VALUE.get(), 911 INFO_MEM_DS_TOOL_ARG_DESC_VENDOR_NAME.get()); 912 vendorNameArgument.setArgumentGroupName(INFO_MEM_DS_TOOL_GROUP_DATA.get()); 913 vendorNameArgument.addLongIdentifier("vendor-name", true); 914 parser.addArgument(vendorNameArgument); 915 916 vendorVersionArgument = new StringArgument(null, "vendorVersion", false, 1, 917 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_VALUE.get(), 918 INFO_MEM_DS_TOOL_ARG_DESC_VENDOR_VERSION.get()); 919 vendorVersionArgument.setArgumentGroupName( 920 INFO_MEM_DS_TOOL_GROUP_DATA.get()); 921 vendorVersionArgument.addLongIdentifier("vendor-version", true); 922 parser.addArgument(vendorVersionArgument); 923 924 accessLogToStandardOutArgument = new BooleanArgument('A', 925 "accessLogToStandardOut", 926 INFO_MEM_DS_TOOL_ARG_DESC_ACCESS_LOG_TO_STDOUT.get()); 927 accessLogToStandardOutArgument.setArgumentGroupName( 928 INFO_MEM_DS_TOOL_GROUP_LOGGING.get()); 929 accessLogToStandardOutArgument.addLongIdentifier( 930 "access-log-to-standard-out", true); 931 parser.addArgument(accessLogToStandardOutArgument); 932 933 accessLogFileArgument = new FileArgument('a', "accessLogFile", false, 1, 934 INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PATH.get(), 935 INFO_MEM_DS_TOOL_ARG_DESC_ACCESS_LOG_FILE.get(), false, true, true, 936 false); 937 accessLogFileArgument.setArgumentGroupName( 938 INFO_MEM_DS_TOOL_GROUP_LOGGING.get()); 939 accessLogFileArgument.addLongIdentifier("access-log-format", true); 940 parser.addArgument(accessLogFileArgument); 941 942 jsonAccessLogToStandardOutArgument = new BooleanArgument(null, 943 "jsonAccessLogToStandardOut", 944 INFO_MEM_DS_TOOL_ARG_DESC_JSON_ACCESS_LOG_TO_STDOUT.get()); 945 jsonAccessLogToStandardOutArgument.setArgumentGroupName( 946 INFO_MEM_DS_TOOL_GROUP_LOGGING.get()); 947 jsonAccessLogToStandardOutArgument.addLongIdentifier( 948 "json-access-log-to-standard-out", true); 949 parser.addArgument(jsonAccessLogToStandardOutArgument); 950 951 jsonAccessLogFileArgument = new FileArgument(null, "jsonAccessLogFile", 952 false, 1, INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PATH.get(), 953 INFO_MEM_DS_TOOL_ARG_DESC_JSON_ACCESS_LOG_FILE.get(), false, true, 954 true, false); 955 jsonAccessLogFileArgument.setArgumentGroupName( 956 INFO_MEM_DS_TOOL_GROUP_LOGGING.get()); 957 jsonAccessLogFileArgument.addLongIdentifier("json-access-log-format", true); 958 parser.addArgument(jsonAccessLogFileArgument); 959 960 ldapDebugLogToStandardOutArgument = new BooleanArgument(null, 961 "ldapDebugLogToStandardOut", 962 INFO_MEM_DS_TOOL_ARG_DESC_LDAP_DEBUG_LOG_TO_STDOUT.get()); 963 ldapDebugLogToStandardOutArgument.setArgumentGroupName( 964 INFO_MEM_DS_TOOL_GROUP_LOGGING.get()); 965 ldapDebugLogToStandardOutArgument.addLongIdentifier( 966 "ldap-debug-log-to-standard-out", true); 967 parser.addArgument(ldapDebugLogToStandardOutArgument); 968 969 ldapDebugLogFileArgument = new FileArgument('d', "ldapDebugLogFile", false, 970 1, INFO_MEM_DS_TOOL_ARG_PLACEHOLDER_PATH.get(), 971 INFO_MEM_DS_TOOL_ARG_DESC_LDAP_DEBUG_LOG_FILE.get(), false, true, true, 972 false); 973 ldapDebugLogFileArgument.setArgumentGroupName( 974 INFO_MEM_DS_TOOL_GROUP_LOGGING.get()); 975 ldapDebugLogFileArgument.addLongIdentifier("ldap-debug-log-file", true); 976 parser.addArgument(ldapDebugLogFileArgument); 977 978 codeLogFile = new FileArgument('C', "codeLogFile", false, 1, "{path}", 979 INFO_MEM_DS_TOOL_ARG_DESC_CODE_LOG_FILE.get(), false, true, true, 980 false); 981 codeLogFile.setArgumentGroupName(INFO_MEM_DS_TOOL_GROUP_LOGGING.get()); 982 codeLogFile.addLongIdentifier("code-log-file", true); 983 parser.addArgument(codeLogFile); 984 985 parser.addExclusiveArgumentSet(useDefaultSchemaArgument, 986 useSchemaFileArgument); 987 988 parser.addDependentArgumentSet(doNotValidateSchemaDefinitionsArgument, 989 useSchemaFileArgument); 990 991 parser.addExclusiveArgumentSet(useSSLArgument, useStartTLSArgument); 992 993 parser.addExclusiveArgumentSet(keyStorePathArgument, 994 generateSelfSignedCertificateArgument); 995 996 parser.addExclusiveArgumentSet(accessLogToStandardOutArgument, 997 accessLogFileArgument); 998 999 parser.addExclusiveArgumentSet(jsonAccessLogToStandardOutArgument, 1000 jsonAccessLogFileArgument); 1001 1002 parser.addExclusiveArgumentSet(ldapDebugLogToStandardOutArgument, 1003 ldapDebugLogFileArgument); 1004 1005 parser.addDependentArgumentSet(additionalBindDNArgument, 1006 additionalBindPasswordArgument); 1007 1008 parser.addDependentArgumentSet(additionalBindPasswordArgument, 1009 additionalBindDNArgument); 1010 1011 parser.addDependentArgumentSet(useSSLArgument, keyStorePathArgument, 1012 generateSelfSignedCertificateArgument); 1013 1014 parser.addDependentArgumentSet(keyStorePathArgument, 1015 keyStorePasswordArgument); 1016 1017 parser.addDependentArgumentSet(keyStorePasswordArgument, 1018 keyStorePathArgument); 1019 1020 parser.addDependentArgumentSet(keyStoreTypeArgument, 1021 keyStorePathArgument); 1022 1023 parser.addDependentArgumentSet(useStartTLSArgument, keyStorePathArgument, 1024 generateSelfSignedCertificateArgument); 1025 1026 parser.addDependentArgumentSet(keyStorePathArgument, useSSLArgument, 1027 useStartTLSArgument); 1028 1029 parser.addDependentArgumentSet(generateSelfSignedCertificateArgument, 1030 useSSLArgument, useStartTLSArgument); 1031 1032 parser.addDependentArgumentSet(trustStorePathArgument, useSSLArgument, 1033 useStartTLSArgument); 1034 1035 parser.addDependentArgumentSet(trustStorePasswordArgument, 1036 trustStorePathArgument); 1037 1038 parser.addDependentArgumentSet(trustStoreTypeArgument, 1039 trustStorePathArgument); 1040 } 1041 1042 1043 1044 /** 1045 * {@inheritDoc} 1046 */ 1047 @Override() 1048 public boolean supportsInteractiveMode() 1049 { 1050 return true; 1051 } 1052 1053 1054 1055 /** 1056 * {@inheritDoc} 1057 */ 1058 @Override() 1059 public boolean defaultsToInteractiveMode() 1060 { 1061 return true; 1062 } 1063 1064 1065 1066 /** 1067 * Indicates whether this tool supports the use of a properties file for 1068 * specifying default values for arguments that aren't specified on the 1069 * command line. 1070 * 1071 * @return {@code true} if this tool supports the use of a properties file 1072 * for specifying default values for arguments that aren't specified 1073 * on the command line, or {@code false} if not. 1074 */ 1075 @Override() 1076 public boolean supportsPropertiesFile() 1077 { 1078 return true; 1079 } 1080 1081 1082 1083 /** 1084 * {@inheritDoc} 1085 */ 1086 @Override() 1087 protected boolean supportsDebugLogging() 1088 { 1089 return true; 1090 } 1091 1092 1093 1094 /** 1095 * {@inheritDoc} 1096 */ 1097 @Override() 1098 @NotNull() 1099 public ResultCode doToolProcessing() 1100 { 1101 // Create a base configuration. 1102 final InMemoryDirectoryServerConfig serverConfig; 1103 try 1104 { 1105 serverConfig = getConfig(); 1106 } 1107 catch (final LDAPException le) 1108 { 1109 Debug.debugException(le); 1110 wrapErr(0, WRAP_COLUMN, 1111 ERR_MEM_DS_TOOL_ERROR_INITIALIZING_CONFIG.get(le.getMessage())); 1112 return le.getResultCode(); 1113 } 1114 1115 1116 // Create the server instance using the provided configuration, but don't 1117 // start it yet. 1118 try 1119 { 1120 directoryServer = new InMemoryDirectoryServer(serverConfig); 1121 } 1122 catch (final LDAPException le) 1123 { 1124 Debug.debugException(le); 1125 wrapErr(0, WRAP_COLUMN, 1126 ERR_MEM_DS_TOOL_ERROR_CREATING_SERVER_INSTANCE.get(le.getMessage())); 1127 return le.getResultCode(); 1128 } 1129 1130 1131 // If an LDIF file was provided, then use it to populate the server. 1132 if (ldifFileArgument.isPresent()) 1133 { 1134 final File ldifFile = ldifFileArgument.getValue(); 1135 try 1136 { 1137 final int numEntries = directoryServer.importFromLDIF(true, 1138 ldifFile.getAbsolutePath()); 1139 wrapOut(0, WRAP_COLUMN, 1140 INFO_MEM_DS_TOOL_ADDED_ENTRIES_FROM_LDIF.get(numEntries, 1141 ldifFile.getAbsolutePath())); 1142 } 1143 catch (final LDAPException le) 1144 { 1145 Debug.debugException(le); 1146 wrapErr(0, WRAP_COLUMN, 1147 ERR_MEM_DS_TOOL_ERROR_POPULATING_SERVER_INSTANCE.get( 1148 ldifFile.getAbsolutePath(), le.getMessage())); 1149 return le.getResultCode(); 1150 } 1151 } 1152 1153 1154 // Start the server. 1155 try 1156 { 1157 if (! dontStartArgument.isPresent()) 1158 { 1159 directoryServer.startListening(); 1160 wrapOut(0, WRAP_COLUMN, 1161 INFO_MEM_DS_TOOL_LISTENING.get(directoryServer.getListenPort())); 1162 } 1163 } 1164 catch (final Exception e) 1165 { 1166 Debug.debugException(e); 1167 wrapErr(0, WRAP_COLUMN, 1168 ERR_MEM_DS_TOOL_ERROR_STARTING_SERVER.get( 1169 StaticUtils.getExceptionMessage(e))); 1170 return ResultCode.LOCAL_ERROR; 1171 } 1172 1173 return ResultCode.SUCCESS; 1174 } 1175 1176 1177 1178 /** 1179 * Creates a server configuration based on information provided with 1180 * command line arguments. 1181 * 1182 * @return The configuration that was created. 1183 * 1184 * @throws LDAPException If a problem is encountered while creating the 1185 * configuration. 1186 */ 1187 @NotNull() 1188 private InMemoryDirectoryServerConfig getConfig() 1189 throws LDAPException 1190 { 1191 final List<DN> dnList = baseDNArgument.getValues(); 1192 final DN[] baseDNs = new DN[dnList.size()]; 1193 dnList.toArray(baseDNs); 1194 1195 final InMemoryDirectoryServerConfig serverConfig = 1196 new InMemoryDirectoryServerConfig(baseDNs); 1197 1198 1199 // If a listen port was specified, then update the configuration to use it. 1200 int listenPort = 0; 1201 if (portArgument.isPresent()) 1202 { 1203 listenPort = portArgument.getValue(); 1204 } 1205 1206 1207 // If schema should be used, then get it. 1208 if (useDefaultSchemaArgument.isPresent()) 1209 { 1210 serverConfig.setSchema(Schema.getDefaultStandardSchema()); 1211 } 1212 else if (useSchemaFileArgument.isPresent()) 1213 { 1214 final Map<String,File> schemaFiles = new TreeMap<>(); 1215 for (final File f : useSchemaFileArgument.getValues()) 1216 { 1217 if (f.exists()) 1218 { 1219 if (f.isFile()) 1220 { 1221 schemaFiles.put(f.getName(), f); 1222 } 1223 else 1224 { 1225 for (final File subFile : f.listFiles()) 1226 { 1227 if (subFile.isFile()) 1228 { 1229 schemaFiles.put(subFile.getName(), subFile); 1230 } 1231 } 1232 } 1233 } 1234 else 1235 { 1236 throw new LDAPException(ResultCode.PARAM_ERROR, 1237 ERR_MEM_DS_TOOL_NO_SUCH_SCHEMA_FILE.get(f.getAbsolutePath())); 1238 } 1239 } 1240 1241 if (! doNotValidateSchemaDefinitionsArgument.isPresent()) 1242 { 1243 Schema schema = null; 1244 final List<String> errorMessages = new ArrayList<>(); 1245 final SchemaValidator schemaValidator = new SchemaValidator(); 1246 for (final File schemaFile : schemaFiles.values()) 1247 { 1248 schema = schemaValidator.validateSchema(schemaFile, schema, 1249 errorMessages); 1250 } 1251 1252 if (! errorMessages.isEmpty()) 1253 { 1254 wrapErr(0, WRAP_COLUMN, 1255 WARN_MEM_DS_TOOL_SCHEMA_ISSUES_IDENTIFIED.get()); 1256 for (final String message : errorMessages) 1257 { 1258 err(); 1259 final List<String> wrappedLines = StaticUtils.wrapLine(message, 1260 (WRAP_COLUMN - 2)); 1261 final Iterator<String> iterator = wrappedLines.iterator(); 1262 err("* " + iterator.next()); 1263 while (iterator.hasNext()) 1264 { 1265 err(" " + iterator.next()); 1266 } 1267 } 1268 err(); 1269 wrapErr(0, WRAP_COLUMN, 1270 WARN_MEM_DS_TOOL_WILL_CONTINUE_WITH_SCHEMA.get( 1271 doNotValidateSchemaDefinitionsArgument. 1272 getIdentifierString())); 1273 err(); 1274 } 1275 } 1276 1277 try 1278 { 1279 serverConfig.setSchema(Schema.getSchema( 1280 new ArrayList<File>(schemaFiles.values()))); 1281 } 1282 catch (final Exception e) 1283 { 1284 Debug.debugException(e); 1285 1286 final StringBuilder fileList = new StringBuilder(); 1287 final Iterator<File> fileIterator = schemaFiles.values().iterator(); 1288 while (fileIterator.hasNext()) 1289 { 1290 fileList.append(fileIterator.next().getAbsolutePath()); 1291 if (fileIterator.hasNext()) 1292 { 1293 fileList.append(", "); 1294 } 1295 } 1296 1297 throw new LDAPException(ResultCode.LOCAL_ERROR, 1298 ERR_MEM_DS_TOOL_ERROR_READING_SCHEMA.get( 1299 fileList, StaticUtils.getExceptionMessage(e)), 1300 e); 1301 } 1302 } 1303 else 1304 { 1305 serverConfig.setSchema(null); 1306 } 1307 1308 1309 // If an additional bind DN and password are provided, then include them in 1310 // the configuration. 1311 if (additionalBindDNArgument.isPresent()) 1312 { 1313 serverConfig.addAdditionalBindCredentials( 1314 additionalBindDNArgument.getValue().toString(), 1315 additionalBindPasswordArgument.getValue()); 1316 } 1317 1318 1319 // If a maximum number of changelog entries was specified, then update the 1320 // configuration with that. 1321 if (maxChangeLogEntriesArgument.isPresent()) 1322 { 1323 serverConfig.setMaxChangeLogEntries( 1324 maxChangeLogEntriesArgument.getValue()); 1325 } 1326 1327 1328 // If a maximum number of concurrent connections was specified, then update 1329 // the configuration with that. 1330 if (maxConcurrentConnectionsArgument.isPresent()) 1331 { 1332 serverConfig.setMaxConnections( 1333 maxConcurrentConnectionsArgument.getValue()); 1334 } 1335 1336 1337 // If a size limit was specified, then update the configuration with that. 1338 if (sizeLimitArgument.isPresent()) 1339 { 1340 serverConfig.setMaxSizeLimit(sizeLimitArgument.getValue()); 1341 } 1342 1343 1344 // If the password argument was specified, then set the password arguments. 1345 if (passwordAttributeArgument.isPresent()) 1346 { 1347 serverConfig.setPasswordAttributes(passwordAttributeArgument.getValues()); 1348 } 1349 1350 1351 // Configure password encodings for the server. 1352 final LinkedHashMap<String,InMemoryPasswordEncoder> passwordEncoders = 1353 new LinkedHashMap<>(10); 1354 addUnsaltedEncoder("MD5", "MD5", passwordEncoders); 1355 addUnsaltedEncoder("SHA", "SHA-1", passwordEncoders); 1356 addUnsaltedEncoder("SHA1", "SHA-1", passwordEncoders); 1357 addUnsaltedEncoder("SHA-1", "SHA-1", passwordEncoders); 1358 addUnsaltedEncoder("SHA256", "SHA-256", passwordEncoders); 1359 addUnsaltedEncoder("SHA-256", "SHA-256", passwordEncoders); 1360 addUnsaltedEncoder("SHA384", "SHA-384", passwordEncoders); 1361 addUnsaltedEncoder("SHA-384", "SHA-384", passwordEncoders); 1362 addUnsaltedEncoder("SHA512", "SHA-512", passwordEncoders); 1363 addUnsaltedEncoder("SHA-512", "SHA-512", passwordEncoders); 1364 addSaltedEncoder("SMD5", "MD5", passwordEncoders); 1365 addSaltedEncoder("SSHA", "SHA-1", passwordEncoders); 1366 addSaltedEncoder("SSHA1", "SHA-1", passwordEncoders); 1367 addSaltedEncoder("SSHA-1", "SHA-1", passwordEncoders); 1368 addSaltedEncoder("SSHA256", "SHA-256", passwordEncoders); 1369 addSaltedEncoder("SSHA-256", "SHA-256", passwordEncoders); 1370 addSaltedEncoder("SSHA384", "SHA-384", passwordEncoders); 1371 addSaltedEncoder("SSHA-384", "SHA-384", passwordEncoders); 1372 addSaltedEncoder("SSHA512", "SHA-512", passwordEncoders); 1373 addSaltedEncoder("SSHA-512", "SHA-512", passwordEncoders); 1374 addClearEncoder("CLEAR", null, passwordEncoders); 1375 addClearEncoder("BASE64", 1376 Base64PasswordEncoderOutputFormatter.getInstance(), passwordEncoders); 1377 addClearEncoder("HEX", 1378 HexPasswordEncoderOutputFormatter.getLowercaseInstance(), 1379 passwordEncoders); 1380 1381 final InMemoryPasswordEncoder primaryEncoder; 1382 if (defaultPasswordEncodingArgument.isPresent()) 1383 { 1384 primaryEncoder = passwordEncoders.remove( 1385 StaticUtils.toLowerCase(defaultPasswordEncodingArgument.getValue())); 1386 if (primaryEncoder == null) 1387 { 1388 throw new LDAPException(ResultCode.PARAM_ERROR, 1389 ERR_MEM_DS_TOOL_UNAVAILABLE_PW_ENCODING.get( 1390 defaultPasswordEncodingArgument.getValue(), 1391 String.valueOf(passwordEncoders.keySet()))); 1392 } 1393 } 1394 else 1395 { 1396 primaryEncoder = null; 1397 } 1398 1399 serverConfig.setPasswordEncoders(primaryEncoder, 1400 passwordEncoders.values()); 1401 1402 1403 // Configure the allowed operation types. 1404 if (allowedOperationTypeArgument.isPresent()) 1405 { 1406 final EnumSet<OperationType> operationTypes = 1407 EnumSet.noneOf(OperationType.class); 1408 for (final String operationTypeName : 1409 allowedOperationTypeArgument.getValues()) 1410 { 1411 final OperationType name = OperationType.forName(operationTypeName); 1412 if (name == null) 1413 { 1414 throw new LDAPException(ResultCode.PARAM_ERROR, 1415 ERR_MEM_DS_TOOL_UNSUPPORTED_ALLOWED_OP_TYPE.get(name)); 1416 } 1417 else 1418 { 1419 switch (name) 1420 { 1421 case ADD: 1422 case BIND: 1423 case COMPARE: 1424 case DELETE: 1425 case EXTENDED: 1426 case MODIFY: 1427 case MODIFY_DN: 1428 case SEARCH: 1429 operationTypes.add(name); 1430 break; 1431 case ABANDON: 1432 case UNBIND: 1433 default: 1434 throw new LDAPException(ResultCode.PARAM_ERROR, 1435 ERR_MEM_DS_TOOL_UNSUPPORTED_ALLOWED_OP_TYPE.get(name)); 1436 } 1437 } 1438 } 1439 1440 serverConfig.setAllowedOperationTypes(operationTypes); 1441 } 1442 1443 1444 // Configure the authentication required operation types. 1445 if (authenticationRequiredOperationTypeArgument.isPresent()) 1446 { 1447 final EnumSet<OperationType> operationTypes = 1448 EnumSet.noneOf(OperationType.class); 1449 for (final String operationTypeName : 1450 authenticationRequiredOperationTypeArgument.getValues()) 1451 { 1452 final OperationType name = OperationType.forName(operationTypeName); 1453 if (name == null) 1454 { 1455 throw new LDAPException(ResultCode.PARAM_ERROR, 1456 ERR_MEM_DS_TOOL_UNSUPPORTED_AUTH_REQUIRED_OP_TYPE.get(name)); 1457 } 1458 else 1459 { 1460 switch (name) 1461 { 1462 case ADD: 1463 case COMPARE: 1464 case DELETE: 1465 case EXTENDED: 1466 case MODIFY: 1467 case MODIFY_DN: 1468 case SEARCH: 1469 operationTypes.add(name); 1470 break; 1471 case ABANDON: 1472 case UNBIND: 1473 default: 1474 throw new LDAPException(ResultCode.PARAM_ERROR, 1475 ERR_MEM_DS_TOOL_UNSUPPORTED_AUTH_REQUIRED_OP_TYPE.get(name)); 1476 } 1477 } 1478 } 1479 1480 serverConfig.setAuthenticationRequiredOperationTypes(operationTypes); 1481 } 1482 1483 1484 // If an access log file was specified, then create the appropriate log 1485 // handler. 1486 if (accessLogToStandardOutArgument.isPresent()) 1487 { 1488 final StreamHandler handler = new StreamHandler(System.out, 1489 new MinimalLogFormatter(null, false, false, true)); 1490 StaticUtils.setLogHandlerLevel(handler, Level.INFO); 1491 serverConfig.setAccessLogHandler(handler); 1492 } 1493 else if (accessLogFileArgument.isPresent()) 1494 { 1495 final File logFile = accessLogFileArgument.getValue(); 1496 try 1497 { 1498 final FileHandler handler = 1499 new FileHandler(logFile.getAbsolutePath(), true); 1500 StaticUtils.setLogHandlerLevel(handler, Level.INFO); 1501 handler.setFormatter(new MinimalLogFormatter(null, false, false, 1502 true)); 1503 serverConfig.setAccessLogHandler(handler); 1504 } 1505 catch (final Exception e) 1506 { 1507 Debug.debugException(e); 1508 throw new LDAPException(ResultCode.LOCAL_ERROR, 1509 ERR_MEM_DS_TOOL_ERROR_CREATING_LOG_HANDLER.get( 1510 logFile.getAbsolutePath(), 1511 StaticUtils.getExceptionMessage(e)), 1512 e); 1513 } 1514 } 1515 1516 1517 // If a JSON-formatted access log file was specified, then create the 1518 // appropriate log handler. 1519 if (jsonAccessLogToStandardOutArgument.isPresent()) 1520 { 1521 final StreamHandler handler = new StreamHandler(System.out, 1522 new MinimalLogFormatter(null, false, false, true)); 1523 StaticUtils.setLogHandlerLevel(handler, Level.INFO); 1524 serverConfig.setJSONAccessLogHandler(handler); 1525 } 1526 else if (jsonAccessLogFileArgument.isPresent()) 1527 { 1528 final File logFile = jsonAccessLogFileArgument.getValue(); 1529 try 1530 { 1531 final FileHandler handler = 1532 new FileHandler(logFile.getAbsolutePath(), true); 1533 StaticUtils.setLogHandlerLevel(handler, Level.INFO); 1534 handler.setFormatter(new MinimalLogFormatter(null, false, false, 1535 true)); 1536 serverConfig.setJSONAccessLogHandler(handler); 1537 } 1538 catch (final Exception e) 1539 { 1540 Debug.debugException(e); 1541 throw new LDAPException(ResultCode.LOCAL_ERROR, 1542 ERR_MEM_DS_TOOL_ERROR_CREATING_LOG_HANDLER.get( 1543 logFile.getAbsolutePath(), 1544 StaticUtils.getExceptionMessage(e)), 1545 e); 1546 } 1547 } 1548 1549 1550 // If an LDAP debug log file was specified, then create the appropriate log 1551 // handler. 1552 if (ldapDebugLogToStandardOutArgument.isPresent()) 1553 { 1554 final StreamHandler handler = new StreamHandler(System.out, 1555 new MinimalLogFormatter(null, false, false, true)); 1556 StaticUtils.setLogHandlerLevel(handler, Level.INFO); 1557 serverConfig.setLDAPDebugLogHandler(handler); 1558 } 1559 else if (ldapDebugLogFileArgument.isPresent()) 1560 { 1561 final File logFile = ldapDebugLogFileArgument.getValue(); 1562 try 1563 { 1564 final FileHandler handler = 1565 new FileHandler(logFile.getAbsolutePath(), true); 1566 StaticUtils.setLogHandlerLevel(handler, Level.INFO); 1567 handler.setFormatter(new MinimalLogFormatter(null, false, false, 1568 true)); 1569 serverConfig.setLDAPDebugLogHandler(handler); 1570 } 1571 catch (final Exception e) 1572 { 1573 Debug.debugException(e); 1574 throw new LDAPException(ResultCode.LOCAL_ERROR, 1575 ERR_MEM_DS_TOOL_ERROR_CREATING_LOG_HANDLER.get( 1576 logFile.getAbsolutePath(), 1577 StaticUtils.getExceptionMessage(e)), 1578 e); 1579 } 1580 } 1581 1582 1583 // If a code log file was specified, then update the configuration 1584 // accordingly. 1585 if (codeLogFile.isPresent()) 1586 { 1587 serverConfig.setCodeLogDetails(codeLogFile.getValue().getAbsolutePath(), 1588 true); 1589 } 1590 1591 1592 // If SSL is to be used, then create the corresponding socket factories. 1593 if (useSSLArgument.isPresent() || useStartTLSArgument.isPresent()) 1594 { 1595 final File keyStorePath; 1596 final char[] keyStorePIN; 1597 final String keyStoreType; 1598 if (keyStorePathArgument.isPresent()) 1599 { 1600 keyStorePath = keyStorePathArgument.getValue(); 1601 keyStorePIN = keyStorePasswordArgument.getValue().toCharArray(); 1602 keyStoreType = keyStoreTypeArgument.getValue(); 1603 } 1604 else 1605 { 1606 try 1607 { 1608 keyStoreType = CryptoHelper.KEY_STORE_TYPE_JKS; 1609 final ObjectPair<File,char[]> keyStoreInfo = 1610 SelfSignedCertificateGenerator. 1611 generateTemporarySelfSignedCertificate( 1612 getToolName(), keyStoreType); 1613 keyStorePath = keyStoreInfo.getFirst(); 1614 keyStorePIN = keyStoreInfo.getSecond(); 1615 } 1616 catch (final CertException e) 1617 { 1618 Debug.debugException(e); 1619 throw new LDAPException(ResultCode.LOCAL_ERROR, e.getMessage(), e); 1620 } 1621 } 1622 1623 1624 try 1625 { 1626 final KeyManager keyManager = new KeyStoreKeyManager(keyStorePath, 1627 keyStorePIN, keyStoreType, null, true); 1628 1629 final TrustManager trustManager; 1630 if (trustStorePathArgument.isPresent()) 1631 { 1632 final char[] password; 1633 if (trustStorePasswordArgument.isPresent()) 1634 { 1635 password = trustStorePasswordArgument.getValue().toCharArray(); 1636 } 1637 else 1638 { 1639 password = null; 1640 } 1641 1642 trustManager = new TrustStoreTrustManager( 1643 trustStorePathArgument.getValue(), password, 1644 trustStoreTypeArgument.getValue(), true); 1645 } 1646 else 1647 { 1648 trustManager = new TrustAllTrustManager(); 1649 } 1650 1651 final SSLUtil serverSSLUtil = new SSLUtil(keyManager, trustManager); 1652 1653 final boolean requestCertificate; 1654 final boolean requireCertificate; 1655 final String clientAuthPolicy = sslClientAuthPolicy.getValue(); 1656 if (clientAuthPolicy.equalsIgnoreCase( 1657 SSL_CLIENT_AUTH_POLICY_OPTIONAL)) 1658 { 1659 requestCertificate = true; 1660 requireCertificate = false; 1661 } 1662 else if (clientAuthPolicy.equalsIgnoreCase( 1663 SSL_CLIENT_AUTH_POLICY_REQUIRED)) 1664 { 1665 requestCertificate = true; 1666 requireCertificate = true; 1667 } 1668 else 1669 { 1670 requestCertificate = false; 1671 requireCertificate = false; 1672 } 1673 1674 if (useSSLArgument.isPresent()) 1675 { 1676 final SSLUtil clientSSLUtil = new SSLUtil(new TrustAllTrustManager()); 1677 serverConfig.setListenerConfigs( 1678 InMemoryListenerConfig.createLDAPSConfig("LDAPS", null, 1679 listenPort, serverSSLUtil.createSSLServerSocketFactory(), 1680 clientSSLUtil.createSSLSocketFactory(), 1681 requestCertificate, requireCertificate)); 1682 } 1683 else 1684 { 1685 serverConfig.setListenerConfigs( 1686 InMemoryListenerConfig.createLDAPConfig("LDAP+StartTLS", null, 1687 listenPort, serverSSLUtil.createSSLSocketFactory(), 1688 requestCertificate, requireCertificate)); 1689 } 1690 } 1691 catch (final Exception e) 1692 { 1693 Debug.debugException(e); 1694 throw new LDAPException(ResultCode.LOCAL_ERROR, 1695 ERR_MEM_DS_TOOL_ERROR_INITIALIZING_SSL.get( 1696 StaticUtils.getExceptionMessage(e)), 1697 e); 1698 } 1699 } 1700 else 1701 { 1702 serverConfig.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig( 1703 "LDAP", listenPort)); 1704 } 1705 1706 1707 // If vendor name and/or vendor version values were provided, then configure 1708 // them for use. 1709 if (vendorNameArgument.isPresent()) 1710 { 1711 serverConfig.setVendorName(vendorNameArgument.getValue()); 1712 } 1713 1714 if (vendorVersionArgument.isPresent()) 1715 { 1716 serverConfig.setVendorVersion(vendorVersionArgument.getValue()); 1717 } 1718 1719 1720 // If equality indexing is to be performed, then configure it. 1721 if (equalityIndexArgument.isPresent()) 1722 { 1723 serverConfig.setEqualityIndexAttributes( 1724 equalityIndexArgument.getValues()); 1725 } 1726 1727 1728 // Update the configuration to indicate whether to generate operational 1729 // attributes. 1730 serverConfig.setGenerateOperationalAttributes( 1731 ! doNotGenerateOperationalAttributesArgument.isPresent()); 1732 1733 1734 return serverConfig; 1735 } 1736 1737 1738 1739 /** 1740 * Updates the map with an unsalted password encoder with the provided 1741 * information. 1742 * 1743 * @param schemeName The name to use to identify the scheme, without 1744 * the curly braces. 1745 * @param digestAlgorithm The name of the message digest algorithm to use 1746 * for the password encoder. 1747 * @param encoderMap The map to which the encoder will bea added. 1748 */ 1749 private static void addUnsaltedEncoder(@NotNull final String schemeName, 1750 @NotNull final String digestAlgorithm, 1751 @NotNull final Map<String,InMemoryPasswordEncoder> encoderMap) 1752 { 1753 try 1754 { 1755 final UnsaltedMessageDigestInMemoryPasswordEncoder encoder = 1756 new UnsaltedMessageDigestInMemoryPasswordEncoder( 1757 '{' + schemeName + '}', 1758 Base64PasswordEncoderOutputFormatter.getInstance(), 1759 CryptoHelper.getMessageDigest(digestAlgorithm)); 1760 encoderMap.put(StaticUtils.toLowerCase(schemeName), encoder); 1761 } 1762 catch (final Exception e) 1763 { 1764 Debug.debugException(e); 1765 } 1766 } 1767 1768 1769 1770 /** 1771 * Updates the map with a salted password encoder with the provided 1772 * information. 1773 * 1774 * @param schemeName The name to use to identify the scheme, without 1775 * the curly braces. 1776 * @param digestAlgorithm The name of the message digest algorithm to use 1777 * for the password encoder. 1778 * @param encoderMap The map to which the encoder will bea added. 1779 */ 1780 private static void addSaltedEncoder(@NotNull final String schemeName, 1781 @NotNull final String digestAlgorithm, 1782 @NotNull final Map<String,InMemoryPasswordEncoder> encoderMap) 1783 { 1784 try 1785 { 1786 final SaltedMessageDigestInMemoryPasswordEncoder encoder = 1787 new SaltedMessageDigestInMemoryPasswordEncoder( 1788 '{' + schemeName + '}', 1789 Base64PasswordEncoderOutputFormatter.getInstance(), 1790 CryptoHelper.getMessageDigest(digestAlgorithm), 8, true, true); 1791 encoderMap.put(StaticUtils.toLowerCase(schemeName), encoder); 1792 } 1793 catch (final Exception e) 1794 { 1795 Debug.debugException(e); 1796 } 1797 } 1798 1799 1800 1801 /** 1802 * Updates the map with a clear-text password encoder with the provided 1803 * information. 1804 * 1805 * @param schemeName The name to use to identify the scheme, without 1806 * the curly braces. 1807 * @param outputFormatter The output formatter to use. It may be 1808 * {@code null} if the output should remain in the 1809 * clear. 1810 * @param encoderMap The map to which the encoder will bea added. 1811 */ 1812 private static void addClearEncoder(@NotNull final String schemeName, 1813 @Nullable final PasswordEncoderOutputFormatter outputFormatter, 1814 @NotNull final Map<String,InMemoryPasswordEncoder> encoderMap) 1815 { 1816 final ClearInMemoryPasswordEncoder encoder = 1817 new ClearInMemoryPasswordEncoder('{' + schemeName + '}', 1818 outputFormatter); 1819 encoderMap.put(StaticUtils.toLowerCase(schemeName), encoder); 1820 } 1821 1822 1823 1824 /** 1825 * {@inheritDoc} 1826 */ 1827 @Override() 1828 @NotNull() 1829 public LinkedHashMap<String[],String> getExampleUsages() 1830 { 1831 final LinkedHashMap<String[],String> exampleUsages = 1832 new LinkedHashMap<>(StaticUtils.computeMapCapacity(2)); 1833 1834 final String[] example1Args = 1835 { 1836 "--baseDN", "dc=example,dc=com" 1837 }; 1838 exampleUsages.put(example1Args, INFO_MEM_DS_TOOL_EXAMPLE_1.get()); 1839 1840 final String[] example2Args = 1841 { 1842 "--baseDN", "dc=example,dc=com", 1843 "--port", "1389", 1844 "--ldifFile", "test.ldif", 1845 "--accessLogFile", "access.log", 1846 "--useDefaultSchema" 1847 }; 1848 exampleUsages.put(example2Args, INFO_MEM_DS_TOOL_EXAMPLE_2.get()); 1849 1850 return exampleUsages; 1851 } 1852 1853 1854 1855 /** 1856 * Retrieves the in-memory directory server instance that has been created by 1857 * this tool. It will only be valid after the {@link #doToolProcessing()} 1858 * method has been called. 1859 * 1860 * @return The in-memory directory server instance that has been created by 1861 * this tool, or {@code null} if the directory server instance has 1862 * not been successfully created. 1863 */ 1864 @Nullable() 1865 public InMemoryDirectoryServer getDirectoryServer() 1866 { 1867 return directoryServer; 1868 } 1869 1870 1871 1872 /** 1873 * {@inheritDoc} 1874 */ 1875 @Override() 1876 public void connectionCreationFailure(@Nullable final Socket socket, 1877 @NotNull final Throwable cause) 1878 { 1879 wrapErr(0, WRAP_COLUMN, 1880 ERR_MEM_DS_TOOL_ERROR_ACCEPTING_CONNECTION.get( 1881 StaticUtils.getExceptionMessage(cause))); 1882 } 1883 1884 1885 1886 /** 1887 * {@inheritDoc} 1888 */ 1889 @Override() 1890 public void connectionTerminated( 1891 @NotNull final LDAPListenerClientConnection connection, 1892 @NotNull final LDAPException cause) 1893 { 1894 wrapErr(0, WRAP_COLUMN, 1895 ERR_MEM_DS_TOOL_CONNECTION_TERMINATED_BY_EXCEPTION.get( 1896 StaticUtils.getExceptionMessage(cause))); 1897 } 1898}