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