001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 028 package org.opends.server.tools; 029 030 import static org.opends.messages.AdminToolMessages.*; 031 import static org.opends.messages.QuickSetupMessages.*; 032 import static org.opends.messages.ToolMessages.*; 033 import static org.opends.messages.UtilityMessages.*; 034 035 import java.io.File; 036 import java.io.InputStream; 037 import java.io.OutputStream; 038 import java.io.PrintStream; 039 import java.security.KeyStoreException; 040 import java.util.Collection; 041 import java.util.LinkedList; 042 import java.util.logging.Level; 043 import java.util.logging.Logger; 044 045 import org.opends.messages.Message; 046 import org.opends.messages.ToolMessages; 047 import org.opends.quicksetup.ApplicationException; 048 import org.opends.quicksetup.Constants; 049 import org.opends.quicksetup.CurrentInstallStatus; 050 import org.opends.quicksetup.Installation; 051 import org.opends.quicksetup.QuickSetupLog; 052 import org.opends.quicksetup.ReturnCode; 053 import org.opends.quicksetup.SecurityOptions; 054 import org.opends.quicksetup.UserData; 055 import org.opends.quicksetup.UserDataException; 056 import org.opends.quicksetup.event.ProgressUpdateEvent; 057 import org.opends.quicksetup.event.ProgressUpdateListener; 058 import org.opends.quicksetup.installer.NewSuffixOptions; 059 import org.opends.quicksetup.installer.offline.OfflineInstaller; 060 import org.opends.quicksetup.installer.ui.InstallReviewPanel; 061 import org.opends.quicksetup.ui.QuickSetupStepPanel; 062 import org.opends.quicksetup.util.IncompatibleVersionException; 063 import org.opends.quicksetup.util.PlainTextProgressMessageFormatter; 064 import org.opends.quicksetup.util.Utils; 065 import org.opends.server.core.DirectoryServer; 066 import org.opends.server.types.DN; 067 import org.opends.server.types.InitializationException; 068 import org.opends.server.types.NullOutputStream; 069 import org.opends.server.util.CertificateManager; 070 import org.opends.server.util.SetupUtils; 071 import org.opends.server.util.args.ArgumentException; 072 import org.opends.server.util.args.IntegerArgument; 073 import org.opends.server.util.args.StringArgument; 074 import org.opends.server.util.cli.CLIException; 075 import org.opends.server.util.cli.ConsoleApplication; 076 import org.opends.server.util.cli.Menu; 077 import org.opends.server.util.cli.MenuBuilder; 078 import org.opends.server.util.cli.MenuResult; 079 /** 080 * This class provides a very simple mechanism for installing the OpenDS 081 * Directory Service. It performs the following tasks: 082 * <UL> 083 * <LI>Checks if the server is already installed and running</LI> 084 * <LI>Ask the user what base DN should be used for the data</LI> 085 * <LI>Ask the user whether to create the base entry, or to import LDIF</LI> 086 * <LI>Ask the user for the LDAP port and make sure it's available</LI> 087 * <LI>Ask the user for the default root DN and password</LI> 088 * <LI>Ask the user to enable SSL or not and for the type of certificate that 089 * the server must use</LI> 090 * <LI>Ask the user if they want to start the server when done installing</LI> 091 * </UL> 092 */ 093 public class InstallDS extends ConsoleApplication 094 { 095 private PlainTextProgressMessageFormatter formatter = 096 new PlainTextProgressMessageFormatter(); 097 /** Prefix for log files. */ 098 static public final String LOG_FILE_PREFIX = "opends-setup-"; 099 100 /** Suffix for log files. */ 101 static public final String LOG_FILE_SUFFIX = ".log"; 102 103 /** 104 * The enumeration containing the different return codes that the command-line 105 * can have. 106 * 107 */ 108 enum ErrorReturnCode 109 { 110 /** 111 * Successful setup. 112 */ 113 SUCCESSFUL(0), 114 /** 115 * We did no have an error but the setup was not executed (displayed 116 * version or usage). 117 */ 118 SUCCESSFUL_NOP(0), 119 /** 120 * Unexpected error (potential bug). 121 */ 122 ERROR_UNEXPECTED(1), 123 /** 124 * Cannot parse arguments or data provided by user is not valid. 125 */ 126 ERROR_USER_DATA(2), 127 /** 128 * Error server already installed. 129 */ 130 ERROR_SERVER_ALREADY_INSTALLED(3), 131 /** 132 * Error initializing server. 133 */ 134 ERROR_INITIALIZING_SERVER(4), 135 /** 136 * The user failed providing password (for the keystore for instance). 137 */ 138 ERROR_PASSWORD_LIMIT(5), 139 /** 140 * The user cancelled the setup. 141 */ 142 ERROR_USER_CANCELLED(6); 143 144 private int returnCode; 145 private ErrorReturnCode(int returnCode) 146 { 147 this.returnCode = returnCode; 148 } 149 150 /** 151 * Get the corresponding return code value. 152 * 153 * @return The corresponding return code value. 154 */ 155 public int getReturnCode() 156 { 157 return returnCode; 158 } 159 }; 160 161 /** 162 * Enumeration describing the different answer that the user can provide 163 * when we ask to finalize the setup. Note that the code associated 164 * correspond to the order in the confirmation menu that is displayed at the 165 * end of the setup in interactive mode. 166 */ 167 private enum ConfirmCode 168 { 169 // Continue with the install 170 CONTINUE(1), 171 // Provide information again 172 PROVIDE_INFORMATION_AGAIN(2), 173 // Cancel the install 174 CANCEL(3); 175 176 private int returnCode; 177 private ConfirmCode(int returnCode) 178 { 179 this.returnCode = returnCode; 180 } 181 182 /** 183 * Get the corresponding return code value. 184 * 185 * @return The corresponding return code value. 186 */ 187 public int getReturnCode() 188 { 189 return returnCode; 190 } 191 } 192 193 private static final int LIMIT_KEYSTORE_PASSWORD_PROMPT = 7; 194 195 // Different variables we use when the user decides to provide data again. 196 private NewSuffixOptions.Type lastResetPopulateOption = null; 197 198 private String lastResetImportFile = null; 199 200 private String lastResetRejectedFile = null; 201 202 private String lastResetSkippedFile = null; 203 204 private Integer lastResetNumEntries = null; 205 206 private Boolean lastResetEnableSSL = null; 207 208 private Boolean lastResetEnableStartTLS = null; 209 210 private SecurityOptions.CertificateType lastResetCertType = null; 211 212 private String lastResetKeyStorePath = null; 213 214 private Boolean lastResetEnableWindowsService = null; 215 216 private Boolean lastResetStartServer = null; 217 218 /** 219 * The Logger. 220 */ 221 static private final Logger LOG = Logger.getLogger(InstallDS.class.getName()); 222 223 // The argument parser 224 private InstallDSArgumentParser argParser; 225 226 /** 227 * Constructor for the InstallDS object. 228 * 229 * @param out the print stream to use for standard output. 230 * @param err the print stream to use for standard error. 231 * @param in the input stream to use for standard input. 232 */ 233 public InstallDS(PrintStream out, PrintStream err, InputStream in) 234 { 235 super(in, out, err); 236 } 237 238 /** 239 * The main method for the InstallDS CLI tool. 240 * 241 * @param args the command-line arguments provided to this program. 242 */ 243 244 public static void main(String[] args) 245 { 246 int retCode = mainCLI(args, true, System.out, System.err, System.in); 247 248 System.exit(retCode); 249 } 250 251 /** 252 * Parses the provided command-line arguments and uses that information to 253 * run the setup tool. 254 * 255 * @param args the command-line arguments provided to this program. 256 * 257 * @return The error code. 258 */ 259 260 public static int mainCLI(String[] args) 261 { 262 return mainCLI(args, true, System.out, System.err, System.in); 263 } 264 265 /** 266 * Parses the provided command-line arguments and uses that information to 267 * run the setup tool. 268 * 269 * @param args The command-line arguments provided to this 270 * program. 271 * @param initializeServer Indicates whether to initialize the server. 272 * @param outStream The output stream to use for standard output, or 273 * <CODE>null</CODE> if standard output is not 274 * needed. 275 * @param errStream The output stream to use for standard error, or 276 * <CODE>null</CODE> if standard error is not 277 * needed. 278 * @param inStream The input stream to use for standard input. 279 * @return The error code. 280 */ 281 282 public static int mainCLI(String[] args, boolean initializeServer, 283 OutputStream outStream, OutputStream errStream, InputStream inStream) 284 { 285 PrintStream out; 286 if (outStream == null) 287 { 288 out = NullOutputStream.printStream(); 289 } 290 else 291 { 292 out = new PrintStream(outStream); 293 } 294 295 System.setProperty(Constants.CLI_JAVA_PROPERTY, "true"); 296 297 PrintStream err; 298 if (errStream == null) 299 { 300 err = NullOutputStream.printStream(); 301 } 302 else 303 { 304 err = new PrintStream(errStream); 305 } 306 307 try { 308 QuickSetupLog.initLogFileHandler( 309 QuickSetupLog.isInitialized() ? null : 310 File.createTempFile(LOG_FILE_PREFIX, LOG_FILE_SUFFIX), 311 "org.opends.server.tools"); 312 QuickSetupLog.disableConsoleLogging(); 313 } catch (Throwable t) { 314 System.err.println("Unable to initialize log"); 315 t.printStackTrace(); 316 } 317 318 InstallDS install = new InstallDS(out, err, inStream); 319 320 return install.execute(args, initializeServer); 321 } 322 323 /** 324 * Parses the provided command-line arguments and uses that information to 325 * run the setup CLI. 326 * 327 * @param args the command-line arguments provided to this program. 328 * @param initializeServer Indicates whether to initialize the server. 329 * 330 * @return the return code (SUCCESSFUL, USER_DATA_ERROR or BUG). 331 */ 332 public int execute(String[] args, boolean initializeServer) 333 { 334 argParser = new InstallDSArgumentParser(InstallDS.class.getName()); 335 try 336 { 337 argParser.initializeArguments(); 338 } 339 catch (ArgumentException ae) 340 { 341 Message message = 342 ToolMessages.ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage()); 343 println(message); 344 return ErrorReturnCode.ERROR_UNEXPECTED.getReturnCode(); 345 } 346 347 // Validate user provided data 348 try 349 { 350 argParser.parseArguments(args); 351 } 352 catch (ArgumentException ae) 353 { 354 Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage()); 355 println(message); 356 println(); 357 println(Message.raw(argParser.getUsage())); 358 359 return ErrorReturnCode.ERROR_USER_DATA.getReturnCode(); 360 } 361 362 // Delete the log file that does not contain any information. The test only 363 // mode is called several times by the setup script and if we do not remove 364 // it we have a lot of empty log files. 365 if (argParser.testOnlyArg.isPresent()) 366 { 367 try 368 { 369 QuickSetupLog.getLogFile().deleteOnExit(); 370 } 371 catch (Throwable t) 372 { 373 LOG.log(Level.WARNING, "Error while trying to update the contents of "+ 374 "the set-java-home file in test only mode: "+t, t); 375 } 376 // Test that we are running a compatible java 1.5 version. 377 try 378 { 379 Utils.checkJavaVersion(); 380 } 381 catch (IncompatibleVersionException ive) 382 { 383 println(ive.getMessageObject()); 384 return ReturnCode.JAVA_VERSION_INCOMPATIBLE.getReturnCode(); 385 } 386 } 387 388 // If either the showUsage or testOnly or version arguments were provided, 389 // then we're done. 390 if (argParser.usageOrVersionDisplayed() || 391 argParser.testOnlyArg.isPresent()) 392 { 393 return ErrorReturnCode.SUCCESSFUL_NOP.getReturnCode(); 394 } 395 396 try 397 { 398 checkInstallStatus(); 399 } 400 catch (InitializationException ie) 401 { 402 println(ie.getMessageObject()); 403 return ErrorReturnCode.ERROR_SERVER_ALREADY_INSTALLED.getReturnCode(); 404 } 405 406 if (initializeServer) 407 { 408 try 409 { 410 initializeDirectoryServer(argParser.configFileArg.getValue(), 411 argParser.configClassArg.getValue()); 412 } 413 catch (InitializationException ie) 414 { 415 println(ie.getMessageObject()); 416 return ErrorReturnCode.ERROR_INITIALIZING_SERVER.getReturnCode(); 417 } 418 } 419 420 boolean userApproved = false; 421 422 UserData uData = new UserData(); 423 while (!userApproved) 424 { 425 try 426 { 427 if (isInteractive()) 428 { 429 promptIfRequired(uData); 430 } 431 else 432 { 433 initializeUserDataWithParser(uData); 434 } 435 } 436 catch (UserDataException ude) 437 { 438 println(ude.getMessageObject()); 439 if (isPasswordTriesError(ude.getMessageObject())) 440 { 441 return ErrorReturnCode.ERROR_PASSWORD_LIMIT.getReturnCode(); 442 } 443 else 444 { 445 return ErrorReturnCode.ERROR_USER_DATA.getReturnCode(); 446 } 447 } 448 if (isInteractive()) 449 { 450 ConfirmCode confirm = askForConfirmation(uData); 451 switch (confirm) 452 { 453 case CONTINUE: 454 userApproved = true; 455 break; 456 case CANCEL: 457 LOG.log(Level.INFO, "User cancelled setup."); 458 return ErrorReturnCode.ERROR_USER_CANCELLED.getReturnCode(); 459 default: 460 // Reset the arguments 461 try 462 { 463 resetArguments(uData); 464 } 465 catch (Throwable t) 466 { 467 LOG.log(Level.WARNING, "Error resetting arg parser: "+t, t); 468 } 469 userApproved = false; 470 } 471 } 472 else 473 { 474 userApproved = true; 475 } 476 } 477 System.setProperty(Constants.CLI_JAVA_PROPERTY, "true"); 478 OfflineInstaller installer = new OfflineInstaller(); 479 installer.setUserData(uData); 480 installer.setProgressMessageFormatter(formatter); 481 installer.addProgressUpdateListener( 482 new ProgressUpdateListener() { 483 public void progressUpdate(ProgressUpdateEvent ev) { 484 if (ev.getNewLogs() != null) 485 { 486 printProgress(ev.getNewLogs()); 487 } 488 } 489 }); 490 printlnProgress(); 491 492 installer.run(); 493 494 ApplicationException ue = installer.getRunError(); 495 496 String cmd; 497 // Use this instead a call to Installation to avoid to launch a new JVM 498 // just to retrieve a path. 499 String root = Utils.getInstallPathFromClasspath(); 500 if (SetupUtils.isWindows()) 501 { 502 String binDir = Utils.getPath(root, 503 Installation.WINDOWS_BINARIES_PATH_RELATIVE); 504 cmd = Utils.getPath(binDir, Installation.WINDOWS_STATUSCLI_FILE_NAME); 505 } 506 else 507 { 508 String binDir = Utils.getPath(root, 509 Installation.UNIX_BINARIES_PATH_RELATIVE); 510 cmd = Utils.getPath(binDir, Installation.UNIX_STATUSCLI_FILE_NAME); 511 } 512 printlnProgress(); 513 printProgress(INFO_INSTALLDS_STATUS_COMMAND_LINE.get(cmd)); 514 printlnProgress(); 515 516 if (ue != null) 517 { 518 return ue.getType().getReturnCode(); 519 } 520 else 521 { 522 return ErrorReturnCode.SUCCESSFUL.getReturnCode(); 523 } 524 } 525 526 /** 527 * Checks if the server is installed or not. 528 * @throws InitializationException if the server is already installed and 529 * configured or if the user did not accept to overwrite the existing 530 * databases. 531 */ 532 private void checkInstallStatus() throws InitializationException 533 { 534 CurrentInstallStatus installStatus = new CurrentInstallStatus(); 535 if (installStatus.canOverwriteCurrentInstall()) 536 { 537 if (isInteractive()) 538 { 539 println(installStatus.getInstallationMsg()); 540 try 541 { 542 if (!confirmAction(INFO_CLI_DO_YOU_WANT_TO_CONTINUE.get(), true)) 543 { 544 throw new InitializationException(Message.EMPTY, null); 545 } 546 } 547 catch (CLIException ce) 548 { 549 LOG.log(Level.SEVERE, "Unexpected error: "+ce, ce); 550 throw new InitializationException(Message.EMPTY, null); 551 } 552 } 553 else 554 { 555 println(installStatus.getInstallationMsg()); 556 } 557 } 558 else if (installStatus.isInstalled()) 559 { 560 throw new InitializationException(installStatus.getInstallationMsg(), 561 null); 562 } 563 } 564 565 /** 566 * Initialize the directory server to be able to perform the operations 567 * required during the installation. 568 * @param configFile the configuration file to be used to initialize the 569 * server. 570 * @param configClass the configuration class to be used to initialize the 571 * server. 572 * @throws InitializationException if there was an error during 573 * initialization. 574 */ 575 private void initializeDirectoryServer(String configFile, String configClass) 576 throws InitializationException 577 { 578 printlnProgress(); 579 printProgress(Message.raw(DirectoryServer.getVersionString())); 580 printlnProgress(); 581 printProgress(INFO_INSTALLDS_INITIALIZING.get()); 582 printlnProgress(); 583 584 // Perform a base-level initialization that will be required to get 585 // minimal functionality like DN parsing to work. 586 DirectoryServer directoryServer = DirectoryServer.getInstance(); 587 DirectoryServer.bootstrapClient(); 588 589 try 590 { 591 DirectoryServer.initializeJMX(); 592 } 593 catch (Throwable t) 594 { 595 Message message = ERR_INSTALLDS_CANNOT_INITIALIZE_JMX.get( 596 String.valueOf(configFile), t.getMessage()); 597 throw new InitializationException(message, t); 598 } 599 600 try 601 { 602 directoryServer.initializeConfiguration(configClass, configFile); 603 } 604 catch (Throwable t) 605 { 606 Message message = ERR_INSTALLDS_CANNOT_INITIALIZE_CONFIG.get( 607 configFile, t.getMessage()); 608 throw new InitializationException(message, t); 609 } 610 611 try 612 { 613 directoryServer.initializeSchema(); 614 } 615 catch (Throwable t) 616 { 617 Message message = ERR_INSTALLDS_CANNOT_INITIALIZE_SCHEMA.get( 618 configFile, t.getMessage()); 619 throw new InitializationException(message, t); 620 } 621 } 622 623 /** 624 * {@inheritDoc} 625 */ 626 public boolean isQuiet() 627 { 628 return argParser.quietArg.isPresent(); 629 } 630 631 /** 632 * {@inheritDoc} 633 */ 634 public boolean isInteractive() 635 { 636 return !argParser.noPromptArg.isPresent(); 637 } 638 639 /** 640 * {@inheritDoc} 641 */ 642 @Override 643 public boolean isMenuDrivenMode() { 644 return true; 645 } 646 647 /** 648 * {@inheritDoc} 649 */ 650 public boolean isScriptFriendly() { 651 return false; 652 } 653 654 /** 655 * {@inheritDoc} 656 */ 657 public boolean isAdvancedMode() { 658 return false; 659 } 660 661 662 /** 663 * {@inheritDoc} 664 */ 665 public boolean isVerbose() { 666 return argParser.verboseArg.isPresent(); 667 } 668 669 /** 670 * This method updates the contents of a UserData object with what the user 671 * specified in the command-line. It assumes that it is being called in no 672 * prompt mode. 673 * @param uData the UserData object. 674 * @throws UserDataException if something went wrong checking the data. 675 */ 676 private void initializeUserDataWithParser(UserData uData) 677 throws UserDataException 678 { 679 LinkedList<Message> errorMessages = new LinkedList<Message>(); 680 uData.setConfigurationClassName(argParser.configClassArg.getValue()); 681 uData.setConfigurationFile(argParser.configFileArg.getValue()); 682 uData.setQuiet(isQuiet()); 683 uData.setVerbose(isVerbose()); 684 // Check the validity of the directory manager DNs 685 String dmDN = argParser.directoryManagerDNArg.getValue(); 686 687 try 688 { 689 DN.decode(dmDN); 690 if (dmDN.trim().length() == 0) 691 { 692 errorMessages.add(ERR_INSTALLDS_EMPTY_DN_RESPONSE.get()); 693 } 694 } 695 catch (Exception e) 696 { 697 Message message = 698 ERR_INSTALLDS_CANNOT_PARSE_DN.get(dmDN, e.getMessage()); 699 errorMessages.add(message); 700 } 701 uData.setDirectoryManagerDn(dmDN); 702 703 uData.setDirectoryManagerPwd(argParser.getDirectoryManagerPassword()); 704 705 // Check the validity of the base DNs 706 LinkedList<String> baseDNs = argParser.baseDNArg.getValues(); 707 if (baseDNs.isEmpty()) 708 { 709 baseDNs.add(argParser.baseDNArg.getDefaultValue()); 710 } 711 for (String baseDN : baseDNs) 712 { 713 try 714 { 715 DN.decode(baseDN); 716 } 717 catch (Exception e) 718 { 719 Message message = 720 ERR_INSTALLDS_CANNOT_PARSE_DN.get(baseDN, e.getMessage()); 721 errorMessages.add(message); 722 } 723 } 724 725 try 726 { 727 int ldapPort = argParser.ldapPortArg.getIntValue(); 728 uData.setServerPort(ldapPort); 729 if (!argParser.skipPortCheckArg.isPresent()) 730 { 731 // Check if the port can be used. 732 if (!SetupUtils.canUseAsPort(ldapPort)) 733 { 734 Message message; 735 if (SetupUtils.isPriviledgedPort(ldapPort)) 736 { 737 message = ERR_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT.get( 738 ldapPort); 739 } 740 else 741 { 742 message = ERR_INSTALLDS_CANNOT_BIND_TO_PORT.get(ldapPort); 743 } 744 errorMessages.add(message); 745 } 746 } 747 if (argParser.jmxPortArg.isPresent()) 748 { 749 int jmxPort = argParser.jmxPortArg.getIntValue(); 750 uData.setServerJMXPort(jmxPort); 751 // Check if the port can be used. 752 if (!argParser.skipPortCheckArg.isPresent()) 753 { 754 if (!SetupUtils.canUseAsPort(jmxPort)) 755 { 756 Message message; 757 if (SetupUtils.isPriviledgedPort(jmxPort)) 758 { 759 message = ERR_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT.get( 760 jmxPort); 761 } 762 else 763 { 764 message = ERR_INSTALLDS_CANNOT_BIND_TO_PORT.get(jmxPort); 765 } 766 errorMessages.add(message); 767 } 768 } 769 } 770 } 771 catch (ArgumentException ae) 772 { 773 errorMessages.add(ae.getMessageObject()); 774 } 775 776 777 778 NewSuffixOptions dataOptions; 779 if (argParser.importLDIFArg.isPresent()) 780 { 781 // Check that the files exist 782 LinkedList<String> nonExistingFiles = new LinkedList<String>(); 783 for (String file : argParser.importLDIFArg.getValues()) 784 { 785 if (!Utils.fileExists(file)) 786 { 787 nonExistingFiles.add(file); 788 } 789 } 790 if (nonExistingFiles.size() > 0) 791 { 792 errorMessages.add(ERR_INSTALLDS_NO_SUCH_LDIF_FILE.get( 793 Utils.getStringFromCollection(nonExistingFiles, ", "))); 794 } 795 String rejectedFile = argParser.rejectedImportFileArg.getValue(); 796 if (rejectedFile != null) 797 { 798 if (!Utils.canWrite(rejectedFile)) 799 { 800 errorMessages.add( 801 ERR_INSTALLDS_CANNOT_WRITE_REJECTED.get(rejectedFile)); 802 } 803 } 804 String skippedFile = argParser.skippedImportFileArg.getValue(); 805 if (skippedFile != null) 806 { 807 if (!Utils.canWrite(skippedFile)) 808 { 809 errorMessages.add(ERR_INSTALLDS_CANNOT_WRITE_SKIPPED.get( 810 skippedFile)); 811 } 812 } 813 dataOptions = NewSuffixOptions.createImportFromLDIF(baseDNs, 814 argParser.importLDIFArg.getValues(), 815 rejectedFile, skippedFile); 816 } 817 else if (argParser.addBaseEntryArg.isPresent()) 818 { 819 dataOptions = NewSuffixOptions.createBaseEntry(baseDNs); 820 } 821 else if (argParser.sampleDataArg.isPresent()) 822 { 823 dataOptions = NewSuffixOptions.createAutomaticallyGenerated(baseDNs, 824 new Integer(argParser.sampleDataArg.getValue())); 825 } 826 else 827 { 828 dataOptions = NewSuffixOptions.createEmpty(baseDNs); 829 } 830 uData.setNewSuffixOptions(dataOptions); 831 832 // Check that the security data provided is valid. 833 String certNickname = argParser.certNicknameArg.getValue(); 834 String pwd = argParser.getKeyStorePassword(); 835 boolean enableSSL = argParser.ldapsPortArg.isPresent(); 836 boolean enableStartTLS = argParser.enableStartTLSArg.isPresent(); 837 int ldapsPort = -1; 838 839 try 840 { 841 ldapsPort = enableSSL ? argParser.ldapsPortArg.getIntValue() : -1; 842 } 843 catch (ArgumentException ae) 844 { 845 errorMessages.add(ae.getMessageObject()); 846 } 847 if (enableSSL) 848 { 849 if (!argParser.skipPortCheckArg.isPresent()) 850 { 851 if (!SetupUtils.canUseAsPort(ldapsPort)) 852 { 853 if (SetupUtils.isPriviledgedPort(ldapsPort)) 854 { 855 errorMessages.add( 856 ERR_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT.get(ldapsPort)); 857 } 858 else 859 { 860 errorMessages.add(ERR_INSTALLDS_CANNOT_BIND_TO_PORT.get(ldapsPort)); 861 } 862 } 863 } 864 } 865 SecurityOptions securityOptions; 866 LinkedList<String> keystoreAliases = new LinkedList<String>(); 867 if (argParser.generateSelfSignedCertificateArg.isPresent()) 868 { 869 securityOptions = SecurityOptions.createSelfSignedCertificateOptions( 870 enableSSL, enableStartTLS, ldapsPort); 871 } 872 else if (argParser.useJavaKeyStoreArg.isPresent()) 873 { 874 String path = argParser.useJavaKeyStoreArg.getValue(); 875 checkCertificateInKeystore(SecurityOptions.CertificateType.JKS, path, pwd, 876 certNickname, errorMessages, keystoreAliases); 877 securityOptions = SecurityOptions.createJKSCertificateOptions( 878 path, pwd, enableSSL, enableStartTLS, ldapsPort, certNickname); 879 } 880 else if (argParser.usePkcs12Arg.isPresent()) 881 { 882 String path = argParser.usePkcs12Arg.getValue(); 883 checkCertificateInKeystore(SecurityOptions.CertificateType.PKCS12, path, 884 pwd, certNickname, errorMessages, keystoreAliases); 885 securityOptions = SecurityOptions.createPKCS12CertificateOptions( 886 path, pwd, enableSSL, enableStartTLS, ldapsPort, certNickname); 887 } 888 else if (argParser.usePkcs11Arg.isPresent()) 889 { 890 checkCertificateInKeystore(SecurityOptions.CertificateType.PKCS11, null, 891 pwd, certNickname, errorMessages, keystoreAliases); 892 securityOptions = SecurityOptions.createPKCS11CertificateOptions( 893 pwd, enableSSL, enableStartTLS, ldapsPort, certNickname); 894 } 895 else 896 { 897 securityOptions = SecurityOptions.createNoCertificateOptions(); 898 } 899 uData.setSecurityOptions(securityOptions); 900 901 uData.setEnableWindowsService( 902 argParser.enableWindowsServiceArg.isPresent()); 903 uData.setStartServer(!argParser.doNotStartArg.isPresent()); 904 905 906 if (errorMessages.size() > 0) 907 { 908 throw new UserDataException(null, 909 Utils.getMessageFromCollection(errorMessages, 910 formatter.getLineBreak().toString())); 911 } 912 } 913 914 /** 915 * This method updates the contents of a UserData object with what the user 916 * specified in the command-line. If the user did not provide explicitly some 917 * data or if the provided data is not valid, it prompts the user to provide 918 * it. 919 * @param uData the UserData object to be updated. 920 * @throws UserDataException if the user did not manage to provide the 921 * keystore password after a certain number of tries. 922 */ 923 private void promptIfRequired(UserData uData) throws UserDataException 924 { 925 uData.setConfigurationClassName(argParser.configClassArg.getValue()); 926 uData.setConfigurationFile(argParser.configFileArg.getValue()); 927 uData.setQuiet(isQuiet()); 928 uData.setVerbose(isVerbose()); 929 930 promptIfRequiredForDirectoryManager(uData); 931 promptIfRequiredForPortData(uData); 932 promptIfRequiredForImportData(uData); 933 promptIfRequiredForSecurityData(uData); 934 promptIfRequiredForWindowsService(uData); 935 promptIfRequiredForStartServer(uData); 936 } 937 938 /** 939 * This method updates the contents of a UserData object with what the user 940 * specified in the command-line for the Directory Manager parameters. 941 * If the user did not provide explicitly some data or if the provided data is 942 * not valid, it prompts the user to provide it. 943 * @param uData the UserData object to be updated. 944 * @throws UserDataException if something went wrong checking the data. 945 */ 946 private void promptIfRequiredForDirectoryManager(UserData uData) 947 throws UserDataException 948 { 949 LinkedList<String> dns = promptIfRequiredForDNs( 950 argParser.directoryManagerDNArg, INFO_INSTALLDS_PROMPT_ROOT_DN.get(), 951 true); 952 uData.setDirectoryManagerDn(dns.getFirst()); 953 954 String pwd = argParser.getDirectoryManagerPassword(); 955 int nTries = 0; 956 while (pwd == null) 957 { 958 if (nTries >= CONFIRMATION_MAX_TRIES) 959 { 960 throw new UserDataException(null, 961 ERR_TRIES_LIMIT_REACHED.get(CONFIRMATION_MAX_TRIES)); 962 } 963 String pwd1 = null; 964 // Prompt for password and confirm. 965 966 while (pwd1 == null) 967 { 968 pwd1 = readPassword(INFO_INSTALLDS_PROMPT_ROOT_PASSWORD.get(), LOG); 969 if ((pwd1 == null) || "".equals(pwd1)) 970 { 971 pwd1 = null; 972 println(); 973 println(INFO_EMPTY_PWD.get()); 974 println(); 975 } 976 } 977 String pwd2 = 978 readPassword(INFO_INSTALLDS_PROMPT_CONFIRM_ROOT_PASSWORD.get(), LOG); 979 980 if (pwd1.equals(pwd2)) 981 { 982 pwd = pwd1; 983 } 984 else 985 { 986 println(); 987 println(ERR_INSTALLDS_PASSWORDS_DONT_MATCH.get()); 988 } 989 990 nTries++; 991 } 992 uData.setDirectoryManagerPwd(pwd); 993 } 994 995 /** 996 * This method returns a list of DNs. It checks that the provided list of 997 * DNs actually contain some values. If no valid values are found it prompts 998 * the user to provide a valid DN. 999 * @param arg the Argument that the user provided to specify the DNs. 1000 * @param promptMsg the prompt message to be displayed. 1001 * @param includeLineBreak whether to include a line break before the first 1002 * prompt or not. 1003 * @return a list of valid DNs. 1004 * @throws UserDataException if something went wrong checking the data. 1005 */ 1006 private LinkedList<String> promptIfRequiredForDNs(StringArgument arg, 1007 Message promptMsg, boolean includeLineBreak) throws UserDataException 1008 { 1009 LinkedList<String> dns = new LinkedList<String>(); 1010 1011 boolean usedProvided = false; 1012 boolean firstPrompt = true; 1013 int nTries = 0; 1014 while (dns.isEmpty()) 1015 { 1016 if (nTries >= CONFIRMATION_MAX_TRIES) 1017 { 1018 throw new UserDataException(null, 1019 ERR_TRIES_LIMIT_REACHED.get(CONFIRMATION_MAX_TRIES)); 1020 } 1021 boolean prompted = false; 1022 if (usedProvided || !arg.isPresent()) 1023 { 1024 if (firstPrompt && includeLineBreak) 1025 { 1026 println(); 1027 } 1028 try 1029 { 1030 String dn = readInput(promptMsg, arg.getDefaultValue()); 1031 firstPrompt = false; 1032 dns.add(dn); 1033 prompted = true; 1034 } 1035 catch (CLIException ce) 1036 { 1037 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 1038 } 1039 } 1040 else 1041 { 1042 dns.addAll(arg.getValues()); 1043 usedProvided = true; 1044 } 1045 LinkedList<String> toRemove = new LinkedList<String>(); 1046 for (String dn : dns) 1047 { 1048 try 1049 { 1050 DN.decode(dn); 1051 if (dn.trim().length() == 0) 1052 { 1053 toRemove.add(dn); 1054 println(ERR_INSTALLDS_EMPTY_DN_RESPONSE.get()); 1055 } 1056 } 1057 catch (Exception e) 1058 { 1059 toRemove.add(dn); 1060 Message message = prompted ? ERR_INSTALLDS_INVALID_DN_RESPONSE.get() : 1061 ERR_INSTALLDS_CANNOT_PARSE_DN.get(dn, e.getMessage()); 1062 println(message); 1063 } 1064 } 1065 if (toRemove.size() > 0) 1066 { 1067 println(); 1068 } 1069 dns.removeAll(toRemove); 1070 nTries++; 1071 } 1072 return dns; 1073 } 1074 1075 /** 1076 * This method updates the contents of a UserData object with what the user 1077 * specified in the command-line for the LDAP and JMX port parameters. 1078 * If the user did not provide explicitly some data or if the provided data is 1079 * not valid, it prompts the user to provide it. 1080 * Note: this method does not update nor check the LDAPS port. 1081 * @param uData the UserData object to be updated. 1082 */ 1083 private void promptIfRequiredForPortData(UserData uData) 1084 { 1085 LinkedList<Integer> usedPorts = new LinkedList<Integer>(); 1086 // Determine the LDAP port number. 1087 int ldapPort = promptIfRequiredForPortData(argParser.ldapPortArg, 1088 INFO_INSTALLDS_PROMPT_LDAPPORT.get(), usedPorts, true); 1089 uData.setServerPort(ldapPort); 1090 usedPorts.add(ldapPort); 1091 if (argParser.jmxPortArg.isPresent()) 1092 { 1093 int jmxPort = promptIfRequiredForPortData(argParser.jmxPortArg, 1094 INFO_INSTALLDS_PROMPT_JMXPORT.get(), usedPorts, true); 1095 uData.setServerJMXPort(jmxPort); 1096 } 1097 else 1098 { 1099 uData.setServerJMXPort(-1); 1100 } 1101 } 1102 1103 /** 1104 * This method returns a valid port value. It checks that the provided 1105 * argument contains a valid port. If a valid port is not found it prompts 1106 * the user to provide a valid port. 1107 * @param arg the Argument that the user provided to specify the port. 1108 * @param promptMsg the prompt message to be displayed. 1109 * @param usedPorts the list of ports the user provided before for other 1110 * connection handlers. 1111 * @param includeLineBreak whether to include a line break before the first 1112 * prompt or not. 1113 * @return a valid port number. 1114 */ 1115 private int promptIfRequiredForPortData(IntegerArgument portArg, 1116 Message promptMsg, Collection<Integer> usedPorts, 1117 boolean includeLineBreak) 1118 { 1119 int portNumber = -1; 1120 boolean usedProvided = false; 1121 boolean firstPrompt = true; 1122 while (portNumber == -1) 1123 { 1124 try 1125 { 1126 boolean prompted = false; 1127 if (usedProvided || !portArg.isPresent()) 1128 { 1129 int defaultValue = -1; 1130 if (portArg.getDefaultValue() != null) 1131 { 1132 defaultValue = Integer.parseInt(portArg.getDefaultValue()); 1133 } 1134 if (firstPrompt && includeLineBreak) 1135 { 1136 println(); 1137 } 1138 portNumber = -1; 1139 while (portNumber == -1) 1140 { 1141 try 1142 { 1143 portNumber = readPort(promptMsg, defaultValue); 1144 } 1145 catch (CLIException ce) 1146 { 1147 portNumber = -1; 1148 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 1149 } 1150 } 1151 prompted = true; 1152 firstPrompt = false; 1153 } 1154 else 1155 { 1156 portNumber = portArg.getIntValue(); 1157 usedProvided = true; 1158 } 1159 1160 if (!argParser.skipPortCheckArg.isPresent()) 1161 { 1162 // Check if the port can be used. 1163 if (!SetupUtils.canUseAsPort(portNumber)) 1164 { 1165 Message message; 1166 if (SetupUtils.isPriviledgedPort(portNumber)) 1167 { 1168 if (prompted || includeLineBreak) 1169 { 1170 println(); 1171 } 1172 message = ERR_INSTALLDS_CANNOT_BIND_TO_PRIVILEGED_PORT.get( 1173 portNumber); 1174 println(message); 1175 portNumber = -1; 1176 } 1177 else 1178 { 1179 if (prompted || includeLineBreak) 1180 { 1181 println(); 1182 } 1183 message = ERR_INSTALLDS_CANNOT_BIND_TO_PORT.get(portNumber); 1184 println(message); 1185 println(); 1186 portNumber = -1; 1187 } 1188 } 1189 } 1190 if (portNumber != -1) 1191 { 1192 if (usedPorts.contains(portNumber)) 1193 { 1194 Message message = ERR_CONFIGDS_PORT_ALREADY_SPECIFIED.get( 1195 String.valueOf(portNumber)); 1196 println(message); 1197 println(); 1198 portNumber = -1; 1199 } 1200 } 1201 } 1202 catch (ArgumentException ae) 1203 { 1204 println(ae.getMessageObject()); 1205 } 1206 } 1207 return portNumber; 1208 } 1209 1210 /** 1211 * This method updates the contents of a UserData object with what the user 1212 * specified in the command-line for the base DN and data import parameters. 1213 * If the user did not provide explicitly some data or if the provided data is 1214 * not valid, it prompts the user to provide it. 1215 * @param uData the UserData object to be updated. 1216 * @throws UserDataException if something went wrong checking the data. 1217 */ 1218 private void promptIfRequiredForImportData(UserData uData) 1219 throws UserDataException 1220 { 1221 // Check the validity of the base DNs 1222 LinkedList<String> baseDNs = promptIfRequiredForDNs( 1223 argParser.baseDNArg, INFO_INSTALLDS_PROMPT_BASEDN.get(), true); 1224 1225 NewSuffixOptions dataOptions; 1226 if (argParser.importLDIFArg.isPresent()) 1227 { 1228 // Check that the files exist 1229 LinkedList<String> nonExistingFiles = new LinkedList<String>(); 1230 LinkedList<String> importLDIFFiles = new LinkedList<String>(); 1231 for (String file : argParser.importLDIFArg.getValues()) 1232 { 1233 if (!Utils.fileExists(file)) 1234 { 1235 nonExistingFiles.add(file); 1236 } 1237 else 1238 { 1239 importLDIFFiles.add(file); 1240 } 1241 } 1242 if (nonExistingFiles.size() > 0) 1243 { 1244 println(); 1245 println(ERR_INSTALLDS_NO_SUCH_LDIF_FILE.get( 1246 Utils.getStringFromCollection(nonExistingFiles, ", "))); 1247 } 1248 while (importLDIFFiles.isEmpty()) 1249 { 1250 println(); 1251 try 1252 { 1253 String path = readInput(INFO_INSTALLDS_PROMPT_IMPORT_FILE.get(), 1254 lastResetImportFile); 1255 if (!Utils.fileExists(path)) 1256 { 1257 println(); 1258 println(ERR_INSTALLDS_NO_SUCH_LDIF_FILE.get(path)); 1259 } 1260 else 1261 { 1262 importLDIFFiles.add(path); 1263 } 1264 } 1265 catch (CLIException ce) 1266 { 1267 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 1268 } 1269 } 1270 String rejectedFile = argParser.rejectedImportFileArg.getValue(); 1271 if (rejectedFile != null) 1272 { 1273 while (!Utils.canWrite(rejectedFile)) 1274 { 1275 println(); 1276 println(ERR_INSTALLDS_CANNOT_WRITE_REJECTED.get(rejectedFile)); 1277 println(); 1278 try 1279 { 1280 rejectedFile = 1281 readInput(INFO_INSTALLDS_PROMPT_REJECTED_FILE.get(), 1282 lastResetRejectedFile); 1283 } 1284 catch (CLIException ce) 1285 { 1286 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 1287 } 1288 } 1289 } 1290 String skippedFile = argParser.skippedImportFileArg.getValue(); 1291 if (skippedFile != null) 1292 { 1293 while (!Utils.canWrite(skippedFile)) 1294 { 1295 println(); 1296 println(ERR_INSTALLDS_CANNOT_WRITE_SKIPPED.get(skippedFile)); 1297 println(); 1298 try 1299 { 1300 skippedFile = 1301 readInput(INFO_INSTALLDS_PROMPT_SKIPPED_FILE.get(), 1302 lastResetSkippedFile); 1303 } 1304 catch (CLIException ce) 1305 { 1306 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 1307 } 1308 } 1309 } 1310 1311 dataOptions = NewSuffixOptions.createImportFromLDIF(baseDNs, 1312 importLDIFFiles, rejectedFile, skippedFile); 1313 } 1314 else if (argParser.addBaseEntryArg.isPresent()) 1315 { 1316 dataOptions = NewSuffixOptions.createBaseEntry(baseDNs); 1317 } 1318 else if (argParser.sampleDataArg.isPresent()) 1319 { 1320 int numUsers; 1321 try 1322 { 1323 numUsers = argParser.sampleDataArg.getIntValue(); 1324 } 1325 catch (ArgumentException ae) 1326 { 1327 println(); 1328 println(ae.getMessageObject()); 1329 Message message = INFO_INSTALLDS_PROMPT_NUM_ENTRIES.get(); 1330 numUsers = promptForInteger(message, 2000, 0, Integer.MAX_VALUE); 1331 } 1332 dataOptions = NewSuffixOptions.createAutomaticallyGenerated(baseDNs, 1333 numUsers); 1334 } 1335 else 1336 { 1337 final int POPULATE_TYPE_BASE_ONLY = 1; 1338 final int POPULATE_TYPE_LEAVE_EMPTY = 2; 1339 final int POPULATE_TYPE_IMPORT_FROM_LDIF = 3; 1340 final int POPULATE_TYPE_GENERATE_SAMPLE_DATA = 4; 1341 1342 int[] indexes = {POPULATE_TYPE_BASE_ONLY, POPULATE_TYPE_LEAVE_EMPTY, 1343 POPULATE_TYPE_IMPORT_FROM_LDIF, POPULATE_TYPE_GENERATE_SAMPLE_DATA}; 1344 Message[] msgs = new Message[] { 1345 INFO_INSTALLDS_POPULATE_OPTION_BASE_ONLY.get(), 1346 INFO_INSTALLDS_POPULATE_OPTION_LEAVE_EMPTY.get(), 1347 INFO_INSTALLDS_POPULATE_OPTION_IMPORT_LDIF.get(), 1348 INFO_INSTALLDS_POPULATE_OPTION_GENERATE_SAMPLE.get() 1349 }; 1350 1351 MenuBuilder<Integer> builder = new MenuBuilder<Integer>(this); 1352 builder.setPrompt(INFO_INSTALLDS_HEADER_POPULATE_TYPE.get()); 1353 1354 for (int i=0; i<indexes.length; i++) 1355 { 1356 builder.addNumberedOption(msgs[i], MenuResult.success(indexes[i])); 1357 } 1358 1359 if (lastResetPopulateOption == null) 1360 { 1361 builder.setDefault(Message.raw( 1362 String.valueOf(POPULATE_TYPE_BASE_ONLY)), 1363 MenuResult.success(POPULATE_TYPE_BASE_ONLY)); 1364 } 1365 else 1366 { 1367 switch (lastResetPopulateOption) 1368 { 1369 case LEAVE_DATABASE_EMPTY: 1370 builder.setDefault(Message.raw( 1371 String.valueOf(POPULATE_TYPE_LEAVE_EMPTY)), 1372 MenuResult.success(POPULATE_TYPE_LEAVE_EMPTY)); 1373 break; 1374 case IMPORT_FROM_LDIF_FILE: 1375 builder.setDefault(Message.raw( 1376 String.valueOf(POPULATE_TYPE_IMPORT_FROM_LDIF)), 1377 MenuResult.success(POPULATE_TYPE_IMPORT_FROM_LDIF)); 1378 break; 1379 case IMPORT_AUTOMATICALLY_GENERATED_DATA: 1380 builder.setDefault(Message.raw( 1381 String.valueOf(POPULATE_TYPE_GENERATE_SAMPLE_DATA)), 1382 MenuResult.success(POPULATE_TYPE_GENERATE_SAMPLE_DATA)); 1383 break; 1384 default: 1385 builder.setDefault(Message.raw( 1386 String.valueOf(POPULATE_TYPE_BASE_ONLY)), 1387 MenuResult.success(POPULATE_TYPE_BASE_ONLY)); 1388 } 1389 } 1390 1391 Menu<Integer> menu = builder.toMenu(); 1392 int populateType; 1393 try 1394 { 1395 MenuResult<Integer> m = menu.run(); 1396 if (m.isSuccess()) 1397 { 1398 populateType = m.getValue(); 1399 } 1400 else 1401 { 1402 // Should never happen. 1403 throw new RuntimeException(); 1404 } 1405 } 1406 catch (CLIException ce) 1407 { 1408 populateType = POPULATE_TYPE_BASE_ONLY; 1409 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 1410 } 1411 1412 if (populateType == POPULATE_TYPE_IMPORT_FROM_LDIF) 1413 { 1414 LinkedList<String> importLDIFFiles = new LinkedList<String>(); 1415 while (importLDIFFiles.isEmpty()) 1416 { 1417 Message message = INFO_INSTALLDS_PROMPT_IMPORT_FILE.get(); 1418 println(); 1419 try 1420 { 1421 String path = readInput(message, null); 1422 if (Utils.fileExists(path)) 1423 { 1424 importLDIFFiles.add(path); 1425 } 1426 else 1427 { 1428 message = ERR_INSTALLDS_NO_SUCH_LDIF_FILE.get(path); 1429 println(); 1430 println(message); 1431 } 1432 } 1433 catch (CLIException ce) 1434 { 1435 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 1436 } 1437 } 1438 String rejectedFile = argParser.rejectedImportFileArg.getValue(); 1439 if (rejectedFile != null) 1440 { 1441 while (!Utils.canWrite(rejectedFile)) 1442 { 1443 println(); 1444 println( 1445 ERR_INSTALLDS_CANNOT_WRITE_REJECTED.get(rejectedFile)); 1446 println(); 1447 try 1448 { 1449 rejectedFile = 1450 readInput(INFO_INSTALLDS_PROMPT_REJECTED_FILE.get(), null); 1451 } 1452 catch (CLIException ce) 1453 { 1454 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 1455 } 1456 } 1457 } 1458 String skippedFile = argParser.skippedImportFileArg.getValue(); 1459 if (skippedFile != null) 1460 { 1461 while (!Utils.canWrite(skippedFile)) 1462 { 1463 println(); 1464 println(ERR_INSTALLDS_CANNOT_WRITE_SKIPPED.get(skippedFile)); 1465 println(); 1466 try 1467 { 1468 skippedFile = 1469 readInput(INFO_INSTALLDS_PROMPT_SKIPPED_FILE.get(), null); 1470 } 1471 catch (CLIException ce) 1472 { 1473 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 1474 } 1475 } 1476 } 1477 dataOptions = NewSuffixOptions.createImportFromLDIF(baseDNs, 1478 importLDIFFiles, rejectedFile, skippedFile); 1479 } 1480 else if (populateType == POPULATE_TYPE_GENERATE_SAMPLE_DATA) 1481 { 1482 Message message = INFO_INSTALLDS_PROMPT_NUM_ENTRIES.get(); 1483 int defaultValue; 1484 if (lastResetNumEntries == null) 1485 { 1486 defaultValue = 2000; 1487 } 1488 else 1489 { 1490 defaultValue = lastResetNumEntries; 1491 } 1492 int numUsers = promptForInteger(message, defaultValue, 0, 1493 Integer.MAX_VALUE); 1494 1495 dataOptions = NewSuffixOptions.createAutomaticallyGenerated(baseDNs, 1496 numUsers); 1497 } 1498 else if (populateType == POPULATE_TYPE_LEAVE_EMPTY) 1499 { 1500 dataOptions = NewSuffixOptions.createEmpty(baseDNs); 1501 } 1502 else if (populateType == POPULATE_TYPE_BASE_ONLY) 1503 { 1504 dataOptions = NewSuffixOptions.createBaseEntry(baseDNs); 1505 } 1506 else 1507 { 1508 throw new IllegalStateException("Unexpected populateType: "+ 1509 populateType); 1510 } 1511 } 1512 uData.setNewSuffixOptions(dataOptions); 1513 } 1514 1515 /** 1516 * This method updates the contents of a UserData object with what the user 1517 * specified in the command-line for the security parameters. 1518 * If the user did not provide explicitly some data or if the provided data is 1519 * not valid, it prompts the user to provide it. 1520 * @param uData the UserData object to be updated. 1521 * @throws UserDataException if the user did not manage to provide the 1522 * keystore password after a certain number of tries. 1523 */ 1524 private void promptIfRequiredForSecurityData(UserData uData) 1525 throws UserDataException 1526 { 1527 // Check that the security data provided is valid. 1528 boolean enableSSL = false; 1529 boolean enableStartTLS = false; 1530 int ldapsPort = -1; 1531 1532 LinkedList<Integer> usedPorts = new LinkedList<Integer>(); 1533 usedPorts.add(uData.getServerPort()); 1534 if (uData.getServerJMXPort() != -1) 1535 { 1536 usedPorts.add(uData.getServerJMXPort()); 1537 } 1538 1539 // Ask to enable SSL 1540 ldapsPort = -1; 1541 1542 if (!argParser.ldapsPortArg.isPresent()) 1543 { 1544 println(); 1545 try 1546 { 1547 boolean defaultValue = lastResetEnableSSL != null ? lastResetEnableSSL : 1548 false; 1549 enableSSL = confirmAction(INFO_INSTALLDS_PROMPT_ENABLE_SSL.get(), 1550 defaultValue); 1551 if (enableSSL) 1552 { 1553 ldapsPort = promptIfRequiredForPortData(argParser.ldapsPortArg, 1554 INFO_INSTALLDS_PROMPT_LDAPSPORT.get(), usedPorts, false); 1555 } 1556 } 1557 catch (CLIException ce) 1558 { 1559 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 1560 } 1561 } 1562 else 1563 { 1564 ldapsPort = promptIfRequiredForPortData(argParser.ldapsPortArg, 1565 INFO_INSTALLDS_PROMPT_LDAPSPORT.get(), usedPorts, true); 1566 enableSSL = true; 1567 } 1568 1569 // Ask to enable Start TLS 1570 if (!argParser.enableStartTLSArg.isPresent()) 1571 { 1572 println(); 1573 try 1574 { 1575 boolean defaultValue = lastResetEnableStartTLS != null ? 1576 lastResetEnableStartTLS : false; 1577 enableStartTLS = confirmAction(INFO_INSTALLDS_ENABLE_STARTTLS.get(), 1578 defaultValue); 1579 } 1580 catch (CLIException ce) 1581 { 1582 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 1583 } 1584 } 1585 else 1586 { 1587 enableStartTLS = true; 1588 } 1589 1590 SecurityOptions securityOptions; 1591 if (argParser.generateSelfSignedCertificateArg.isPresent()) 1592 { 1593 securityOptions = SecurityOptions.createSelfSignedCertificateOptions( 1594 enableSSL, enableStartTLS, ldapsPort); 1595 } 1596 else if (argParser.useJavaKeyStoreArg.isPresent()) 1597 { 1598 securityOptions = 1599 createSecurityOptionsPrompting(SecurityOptions.CertificateType.JKS, 1600 enableSSL, enableStartTLS, ldapsPort); 1601 } 1602 else if (argParser.usePkcs12Arg.isPresent()) 1603 { 1604 securityOptions = 1605 createSecurityOptionsPrompting(SecurityOptions.CertificateType.PKCS12, 1606 enableSSL, enableStartTLS, ldapsPort); 1607 } 1608 else if (argParser.usePkcs11Arg.isPresent()) 1609 { 1610 securityOptions = 1611 createSecurityOptionsPrompting(SecurityOptions.CertificateType.PKCS11, 1612 enableSSL, enableStartTLS, ldapsPort); 1613 } 1614 else 1615 { 1616 if (!enableSSL && !enableStartTLS) 1617 { 1618 // If the user did not want to enable SSL or start TLS do not ask 1619 // to create a certificate. 1620 securityOptions = SecurityOptions.createNoCertificateOptions(); 1621 } 1622 else 1623 { 1624 final int SELF_SIGNED = 1; 1625 final int JKS = 2; 1626 final int PKCS12 = 3; 1627 final int PKCS11 = 4; 1628 int[] indexes = {SELF_SIGNED, JKS, PKCS12, PKCS11}; 1629 Message[] msgs = { 1630 INFO_INSTALLDS_CERT_OPTION_SELF_SIGNED.get(), 1631 INFO_INSTALLDS_CERT_OPTION_JKS.get(), 1632 INFO_INSTALLDS_CERT_OPTION_PKCS12.get(), 1633 INFO_INSTALLDS_CERT_OPTION_PKCS11.get() 1634 }; 1635 1636 1637 MenuBuilder<Integer> builder = new MenuBuilder<Integer>(this); 1638 builder.setPrompt(INFO_INSTALLDS_HEADER_CERT_TYPE.get()); 1639 1640 for (int i=0; i<indexes.length; i++) 1641 { 1642 builder.addNumberedOption(msgs[i], MenuResult.success(indexes[i])); 1643 } 1644 1645 if (lastResetCertType == null) 1646 { 1647 builder.setDefault(Message.raw(String.valueOf(SELF_SIGNED)), 1648 MenuResult.success(SELF_SIGNED)); 1649 } 1650 else 1651 { 1652 switch (lastResetCertType) 1653 { 1654 case JKS: 1655 builder.setDefault(Message.raw(String.valueOf(JKS)), 1656 MenuResult.success(JKS)); 1657 break; 1658 case PKCS11: 1659 builder.setDefault(Message.raw(String.valueOf(PKCS11)), 1660 MenuResult.success(PKCS11)); 1661 break; 1662 case PKCS12: 1663 builder.setDefault(Message.raw(String.valueOf(PKCS12)), 1664 MenuResult.success(PKCS12)); 1665 break; 1666 default: 1667 builder.setDefault(Message.raw(String.valueOf(SELF_SIGNED)), 1668 MenuResult.success(SELF_SIGNED)); 1669 } 1670 } 1671 1672 Menu<Integer> menu = builder.toMenu(); 1673 int certType; 1674 try 1675 { 1676 MenuResult<Integer> m = menu.run(); 1677 if (m.isSuccess()) 1678 { 1679 certType = m.getValue(); 1680 } 1681 else 1682 { 1683 // Should never happen. 1684 throw new RuntimeException(); 1685 } 1686 } 1687 catch (CLIException ce) 1688 { 1689 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 1690 certType = SELF_SIGNED; 1691 } 1692 if (certType == SELF_SIGNED) 1693 { 1694 securityOptions = SecurityOptions.createSelfSignedCertificateOptions( 1695 enableSSL, enableStartTLS, ldapsPort); 1696 } 1697 else if (certType == JKS) 1698 { 1699 securityOptions = 1700 createSecurityOptionsPrompting(SecurityOptions.CertificateType.JKS, 1701 enableSSL, enableStartTLS, ldapsPort); 1702 } 1703 else if (certType == PKCS12) 1704 { 1705 securityOptions = 1706 createSecurityOptionsPrompting( 1707 SecurityOptions.CertificateType.PKCS12, enableSSL, 1708 enableStartTLS, ldapsPort); 1709 } 1710 else if (certType == PKCS11) 1711 { 1712 securityOptions = 1713 createSecurityOptionsPrompting( 1714 SecurityOptions.CertificateType.PKCS11, enableSSL, 1715 enableStartTLS, ldapsPort); 1716 } 1717 else 1718 { 1719 throw new IllegalStateException("Unexpected cert type: "+ certType); 1720 } 1721 } 1722 } 1723 uData.setSecurityOptions(securityOptions); 1724 } 1725 1726 /** 1727 * This method updates the contents of a UserData object with what the user 1728 * specified in the command-line for the Windows Service parameters. 1729 * If the user did not provide explicitly the data, it prompts the user to 1730 * provide it. 1731 * @param uData the UserData object to be updated. 1732 */ 1733 private void promptIfRequiredForWindowsService(UserData uData) 1734 { 1735 boolean enableService = false; 1736 // If we are in Windows ask if the server must run as a windows service. 1737 if (SetupUtils.isWindows()) 1738 { 1739 if (argParser.enableWindowsServiceArg.isPresent()) 1740 { 1741 enableService = true; 1742 } 1743 else 1744 { 1745 println(); 1746 Message message = INFO_INSTALLDS_PROMPT_ENABLE_SERVICE.get(); 1747 try 1748 { 1749 boolean defaultValue = (lastResetEnableWindowsService == null) ? 1750 false : lastResetEnableWindowsService; 1751 enableService = confirmAction(message, defaultValue); 1752 } 1753 catch (CLIException ce) 1754 { 1755 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 1756 } 1757 } 1758 } 1759 uData.setEnableWindowsService(enableService); 1760 } 1761 1762 /** 1763 * This method updates the contents of a UserData object with what the user 1764 * specified in the command-line for the Directory Manager parameters. 1765 * If the user did not provide explicitly the data, it prompts the user to 1766 * provide it. 1767 * @param uData the UserData object to be updated. 1768 */ 1769 private void promptIfRequiredForStartServer(UserData uData) 1770 { 1771 boolean startServer = false; 1772 if (!argParser.doNotStartArg.isPresent()) 1773 { 1774 println(); 1775 Message message = INFO_INSTALLDS_PROMPT_START_SERVER.get(); 1776 try 1777 { 1778 boolean defaultValue = (lastResetStartServer == null) ? 1779 true : lastResetStartServer; 1780 startServer = confirmAction(message, defaultValue); 1781 } 1782 catch (CLIException ce) 1783 { 1784 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 1785 startServer = true; 1786 } 1787 } 1788 uData.setStartServer(startServer); 1789 } 1790 1791 /** 1792 * Checks that the provided parameters are valid to access an existing 1793 * keystore. This method adds the encountered errors to the provided 1794 * list of Message. It also adds the alias (nicknames) found to the provided 1795 * list of String. 1796 * @param type the type of keystore. 1797 * @param path the path of the keystore. 1798 * @param pwd the password (PIN) to access the keystore. 1799 * @param certNickname the certificate nickname that we are looking for (or 1800 * null if we just one to get the one that is in the keystore). 1801 * @param errorMessages the list that will be updated with the errors 1802 * encountered. 1803 * @param nicknameList the list that will be updated with the nicknames found 1804 * in the keystore. 1805 */ 1806 private void checkCertificateInKeystore(SecurityOptions.CertificateType type, 1807 String path, String pwd, String certNickname, 1808 LinkedList<Message> errorMessages, LinkedList<String> nicknameList) 1809 { 1810 boolean errorWithPath = false; 1811 if (type != SecurityOptions.CertificateType.PKCS11) 1812 { 1813 File f = new File(path); 1814 if (!f.exists()) 1815 { 1816 errorMessages.add(INFO_KEYSTORE_PATH_DOES_NOT_EXIST.get()); 1817 errorWithPath = true; 1818 } 1819 else if (!f.isFile()) 1820 { 1821 errorMessages.add(INFO_KEYSTORE_PATH_NOT_A_FILE.get()); 1822 errorWithPath = true; 1823 } 1824 } 1825 boolean pwdProvided = true; 1826 if (pwd == null) 1827 { 1828 pwdProvided = false; 1829 errorMessages.add(INFO_ERROR_NO_KEYSTORE_PASSWORD.get()); 1830 } 1831 else if (pwd.length() == 0) 1832 { 1833 pwdProvided = false; 1834 errorMessages.add(INFO_ERROR_EMPTY_KEYSTORE_PASSWORD.get()); 1835 } 1836 if (!errorWithPath && pwdProvided) 1837 { 1838 try 1839 { 1840 CertificateManager certManager; 1841 switch (type) 1842 { 1843 case JKS: 1844 certManager = new CertificateManager( 1845 path, 1846 CertificateManager.KEY_STORE_TYPE_JKS, 1847 pwd); 1848 break; 1849 1850 case PKCS12: 1851 certManager = new CertificateManager( 1852 path, 1853 CertificateManager.KEY_STORE_TYPE_PKCS12, 1854 pwd); 1855 break; 1856 1857 case PKCS11: 1858 certManager = new CertificateManager( 1859 CertificateManager.KEY_STORE_PATH_PKCS11, 1860 CertificateManager.KEY_STORE_TYPE_PKCS11, 1861 pwd); 1862 break; 1863 1864 default: 1865 throw new IllegalArgumentException("Invalid type: "+type); 1866 } 1867 String[] aliases = certManager.getCertificateAliases(); 1868 if ((aliases == null) || (aliases.length == 0)) 1869 { 1870 // Could not retrieve any certificate 1871 switch (type) 1872 { 1873 case JKS: 1874 errorMessages.add(INFO_PKCS11_KEYSTORE_DOES_NOT_EXIST.get()); 1875 break; 1876 1877 case PKCS12: 1878 errorMessages.add(INFO_JKS_KEYSTORE_DOES_NOT_EXIST.get()); 1879 break; 1880 case PKCS11: 1881 errorMessages.add(INFO_PKCS12_KEYSTORE_DOES_NOT_EXIST.get()); 1882 break; 1883 default: 1884 throw new IllegalArgumentException("Invalid type: "+type); 1885 } 1886 } 1887 else 1888 { 1889 for (int i=0; i<aliases.length; i++) 1890 { 1891 nicknameList.add(aliases[i]); 1892 } 1893 String aliasString = Utils.getStringFromCollection(nicknameList, 1894 ", "); 1895 if (certNickname != null) 1896 { 1897 // Check if the cert alias is in the list. 1898 boolean found = false; 1899 for (int i=0; i<aliases.length && !found; i++) 1900 { 1901 found = aliases[i].equalsIgnoreCase(certNickname); 1902 } 1903 if (!found) 1904 { 1905 errorMessages.add(ERR_INSTALLDS_CERTNICKNAME_NOT_FOUND.get( 1906 aliasString)); 1907 } 1908 } 1909 else if (aliases.length > 1) 1910 { 1911 errorMessages.add(ERR_INSTALLDS_MUST_PROVIDE_CERTNICKNAME.get( 1912 aliasString)); 1913 } 1914 } 1915 } 1916 catch (KeyStoreException ke) 1917 { 1918 // Could not access to the keystore: because the password is no good, 1919 // because the provided file is not a valid keystore, etc. 1920 switch (type) 1921 { 1922 case JKS: 1923 errorMessages.add(INFO_ERROR_ACCESSING_JKS_KEYSTORE.get()); 1924 break; 1925 1926 case PKCS12: 1927 errorMessages.add(INFO_ERROR_ACCESSING_PKCS12_KEYSTORE.get()); 1928 break; 1929 case PKCS11: 1930 errorMessages.add(INFO_ERROR_ACCESSING_PKCS11_KEYSTORE.get()); 1931 break; 1932 default: 1933 throw new IllegalArgumentException("Invalid type: "+type); 1934 } 1935 } 1936 } 1937 } 1938 1939 /** 1940 * Creates a SecurityOptions object that corresponds to the provided 1941 * parameters. If the parameters are not valid, it prompts the user to 1942 * provide them. 1943 * @param type the keystore type. 1944 * @param enableSSL whether to enable SSL or not. 1945 * @param enableStartTLS whether to enable StartTLS or not. 1946 * @param ldapsPort the LDAPS port to use. 1947 * @return a SecurityOptions object that corresponds to the provided 1948 * parameters (or to what the user provided after being prompted). 1949 * @throws UserDataException if the user did not manage to provide the 1950 * keystore password after a certain number of tries. 1951 */ 1952 private SecurityOptions createSecurityOptionsPrompting( 1953 SecurityOptions.CertificateType type, boolean enableSSL, 1954 boolean enableStartTLS, int ldapsPort) throws UserDataException 1955 { 1956 SecurityOptions securityOptions; 1957 String path; 1958 String certNickname = argParser.certNicknameArg.getValue(); 1959 String pwd = argParser.getKeyStorePassword(); 1960 if (pwd != null) 1961 { 1962 if (pwd.length() == 0) 1963 { 1964 pwd = null; 1965 } 1966 } 1967 Message pathPrompt; 1968 String defaultPathValue; 1969 1970 switch (type) 1971 { 1972 case JKS: 1973 path = argParser.useJavaKeyStoreArg.getValue(); 1974 pathPrompt = INFO_INSTALLDS_PROMPT_JKS_PATH.get(); 1975 defaultPathValue = argParser.useJavaKeyStoreArg.getValue(); 1976 if (defaultPathValue == null) 1977 { 1978 defaultPathValue = lastResetKeyStorePath; 1979 } 1980 break; 1981 case PKCS11: 1982 path = null; 1983 defaultPathValue = null; 1984 pathPrompt = null; 1985 break; 1986 case PKCS12: 1987 path = argParser.usePkcs12Arg.getValue(); 1988 defaultPathValue = argParser.usePkcs12Arg.getValue(); 1989 if (defaultPathValue == null) 1990 { 1991 defaultPathValue = lastResetKeyStorePath; 1992 } 1993 pathPrompt = INFO_INSTALLDS_PROMPT_PKCS12_PATH.get(); 1994 break; 1995 default: 1996 throw new IllegalStateException( 1997 "Called promptIfRequiredCertificate with invalid type: "+type); 1998 } 1999 LinkedList<Message> errorMessages = new LinkedList<Message>(); 2000 LinkedList<String> keystoreAliases = new LinkedList<String>(); 2001 boolean firstTry = true; 2002 int nPasswordPrompts = 0; 2003 2004 while ((errorMessages.size() > 0) || firstTry) 2005 { 2006 boolean prompted = false; 2007 if (errorMessages.size() > 0) 2008 { 2009 println(); 2010 println(Utils.getMessageFromCollection(errorMessages, 2011 formatter.getLineBreak().toString())); 2012 } 2013 2014 if (type != SecurityOptions.CertificateType.PKCS11) 2015 { 2016 if (containsKeyStorePathErrorMessage(errorMessages) || (path == null)) 2017 { 2018 println(); 2019 try 2020 { 2021 path = readInput(pathPrompt, defaultPathValue); 2022 } 2023 catch (CLIException ce) 2024 { 2025 path = ""; 2026 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 2027 } 2028 2029 prompted = true; 2030 if (pwd != null) 2031 { 2032 errorMessages.clear(); 2033 keystoreAliases.clear(); 2034 checkCertificateInKeystore(type, path, pwd, certNickname, 2035 errorMessages, keystoreAliases); 2036 if (!errorMessages.isEmpty()) 2037 { 2038 // Reset password: this might be a new keystore 2039 pwd = null; 2040 } 2041 } 2042 } 2043 } 2044 if (containsKeyStorePasswordErrorMessage(errorMessages) || 2045 (pwd == null)) 2046 { 2047 if (!prompted) 2048 { 2049 println(); 2050 } 2051 pwd = null; 2052 while (pwd == null) 2053 { 2054 if (nPasswordPrompts > LIMIT_KEYSTORE_PASSWORD_PROMPT) 2055 { 2056 throw new UserDataException(null, 2057 ERR_INSTALLDS_TOO_MANY_KEYSTORE_PASSWORD_TRIES.get( 2058 String.valueOf(LIMIT_KEYSTORE_PASSWORD_PROMPT))); 2059 } 2060 pwd = readPassword( 2061 INFO_INSTALLDS_PROMPT_KEYSTORE_PASSWORD.get(), LOG); 2062 nPasswordPrompts ++; 2063 } 2064 } 2065 if (containsCertNicknameErrorMessage(errorMessages)) 2066 { 2067 if (!prompted) 2068 { 2069 println(); 2070 } 2071 certNickname = promptForCertificateNickname(keystoreAliases); 2072 } 2073 errorMessages.clear(); 2074 keystoreAliases.clear(); 2075 checkCertificateInKeystore(type, path, pwd, certNickname, errorMessages, 2076 keystoreAliases); 2077 firstTry = false; 2078 } 2079 if (certNickname == null) 2080 { 2081 certNickname = keystoreAliases.getFirst(); 2082 } 2083 switch (type) 2084 { 2085 case JKS: 2086 securityOptions = SecurityOptions.createJKSCertificateOptions( 2087 path, pwd, enableSSL, enableStartTLS, ldapsPort, certNickname); 2088 break; 2089 case PKCS12: 2090 securityOptions = SecurityOptions.createPKCS12CertificateOptions( 2091 path, pwd, enableSSL, enableStartTLS, ldapsPort, certNickname); 2092 break; 2093 case PKCS11: 2094 securityOptions = SecurityOptions.createPKCS11CertificateOptions( 2095 pwd, enableSSL, enableStartTLS, ldapsPort, certNickname); 2096 break; 2097 default: 2098 throw new IllegalStateException( 2099 "Called createSecurityOptionsPrompting with invalid type: "+type); 2100 } 2101 return securityOptions; 2102 } 2103 2104 /** 2105 * Tells if any of the error messages provided corresponds to a problem 2106 * with the key store path. 2107 * @param msgs the messages to analyze. 2108 * @return <CODE>true</CODE> if any of the error messages provided corresponds 2109 * to a problem with the key store path and <CODE>false</CODE> otherwise. 2110 */ 2111 private boolean containsKeyStorePathErrorMessage(Collection<Message> msgs) 2112 { 2113 boolean found = false; 2114 for (Message msg : msgs) 2115 { 2116 if (msg.getDescriptor().equals(INFO_KEYSTORE_PATH_DOES_NOT_EXIST) || 2117 msg.getDescriptor().equals(INFO_KEYSTORE_PATH_NOT_A_FILE) || 2118 msg.getDescriptor().equals(INFO_JKS_KEYSTORE_DOES_NOT_EXIST) || 2119 msg.getDescriptor().equals(INFO_PKCS12_KEYSTORE_DOES_NOT_EXIST) || 2120 msg.getDescriptor().equals(INFO_PKCS11_KEYSTORE_DOES_NOT_EXIST) || 2121 msg.getDescriptor().equals(INFO_ERROR_ACCESSING_JKS_KEYSTORE) || 2122 msg.getDescriptor().equals(INFO_ERROR_ACCESSING_PKCS12_KEYSTORE) || 2123 msg.getDescriptor().equals(INFO_ERROR_ACCESSING_PKCS11_KEYSTORE)) 2124 { 2125 found = true; 2126 break; 2127 } 2128 } 2129 return found; 2130 } 2131 2132 /** 2133 * Tells if any of the error messages provided corresponds to a problem 2134 * with the key store password. 2135 * @param msgs the messages to analyze. 2136 * @return <CODE>true</CODE> if any of the error messages provided corresponds 2137 * to a problem with the key store password and <CODE>false</CODE> otherwise. 2138 */ 2139 private boolean containsKeyStorePasswordErrorMessage(Collection<Message> msgs) 2140 { 2141 boolean found = false; 2142 for (Message msg : msgs) 2143 { 2144 if (msg.getDescriptor().equals(INFO_JKS_KEYSTORE_DOES_NOT_EXIST) || 2145 msg.getDescriptor().equals(INFO_PKCS12_KEYSTORE_DOES_NOT_EXIST) || 2146 msg.getDescriptor().equals(INFO_PKCS11_KEYSTORE_DOES_NOT_EXIST) || 2147 msg.getDescriptor().equals(INFO_ERROR_ACCESSING_JKS_KEYSTORE) || 2148 msg.getDescriptor().equals(INFO_ERROR_ACCESSING_PKCS12_KEYSTORE) || 2149 msg.getDescriptor().equals(INFO_ERROR_ACCESSING_PKCS11_KEYSTORE) || 2150 msg.getDescriptor().equals(INFO_ERROR_NO_KEYSTORE_PASSWORD) || 2151 msg.getDescriptor().equals(INFO_ERROR_EMPTY_KEYSTORE_PASSWORD)) 2152 { 2153 found = true; 2154 break; 2155 } 2156 } 2157 return found; 2158 } 2159 2160 /** 2161 * Tells if any of the error messages provided corresponds to a problem 2162 * with the certificate nickname. 2163 * @param msgs the messages to analyze. 2164 * @return <CODE>true</CODE> if any of the error messages provided corresponds 2165 * to a problem with the certificate nickname and <CODE>false</CODE> 2166 * otherwise. 2167 */ 2168 private boolean containsCertNicknameErrorMessage(Collection<Message> msgs) 2169 { 2170 boolean found = false; 2171 for (Message msg : msgs) 2172 { 2173 if (msg.getDescriptor().equals(ERR_INSTALLDS_CERTNICKNAME_NOT_FOUND) || 2174 msg.getDescriptor().equals(ERR_INSTALLDS_MUST_PROVIDE_CERTNICKNAME)) 2175 { 2176 found = true; 2177 break; 2178 } 2179 } 2180 return found; 2181 } 2182 2183 /** 2184 * Tells if the error messages provided corresponds to a problem with the 2185 * password tries. 2186 * @param msg the message to analyze. 2187 * @return <CODE>true</CODE> if the error message provided corresponds to a 2188 * problem with the password tries and <CODE>false</CODE> otherwise. 2189 */ 2190 private boolean isPasswordTriesError(Message msg) 2191 { 2192 return msg.getDescriptor().equals( 2193 ERR_INSTALLDS_TOO_MANY_KEYSTORE_PASSWORD_TRIES); 2194 } 2195 2196 /** 2197 * Interactively prompts (on standard output) the user to provide an integer 2198 * value. The answer provided must be parseable as an integer, and may be 2199 * required to be within a given set of bounds. It will keep prompting until 2200 * an acceptable value is given. 2201 * 2202 * @param prompt The prompt to present to the user. 2203 * @param defaultValue The default value to assume if the user presses ENTER 2204 * without typing anything, or <CODE>null</CODE> if 2205 * there should not be a default and the user must 2206 * explicitly provide a value. 2207 * @param lowerBound The lower bound that should be enforced, or 2208 * <CODE>null</CODE> if there is none. 2209 * @param upperBound The upper bound that should be enforced, or 2210 * <CODE>null</CODE> if there is none. 2211 * 2212 * @return The <CODE>int</CODE> value read from the user input. 2213 */ 2214 private int promptForInteger(Message prompt, Integer defaultValue, 2215 Integer lowerBound, Integer upperBound) 2216 { 2217 int returnValue = -1; 2218 while (returnValue == -1) 2219 { 2220 String s; 2221 try 2222 { 2223 s = readInput(prompt, String.valueOf(defaultValue)); 2224 } 2225 catch (CLIException ce) 2226 { 2227 s = ""; 2228 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 2229 } 2230 if (s.equals("")) 2231 { 2232 if (defaultValue == null) 2233 { 2234 Message message = ERR_INSTALLDS_INVALID_INTEGER_RESPONSE.get(); 2235 println(message); 2236 println(); 2237 } 2238 else 2239 { 2240 returnValue = defaultValue; 2241 } 2242 } 2243 else 2244 { 2245 try 2246 { 2247 int intValue = Integer.parseInt(s); 2248 if ((lowerBound != null) && (intValue < lowerBound)) 2249 { 2250 Message message = 2251 ERR_INSTALLDS_INTEGER_BELOW_LOWER_BOUND.get(lowerBound); 2252 println(message); 2253 println(); 2254 } 2255 else if ((upperBound != null) && (intValue > upperBound)) 2256 { 2257 Message message = 2258 ERR_INSTALLDS_INTEGER_ABOVE_UPPER_BOUND.get(upperBound); 2259 println(message); 2260 println(); 2261 } 2262 else 2263 { 2264 returnValue = intValue; 2265 } 2266 } 2267 catch (NumberFormatException nfe) 2268 { 2269 Message message = ERR_INSTALLDS_INVALID_INTEGER_RESPONSE.get(); 2270 println(message); 2271 println(); 2272 } 2273 } 2274 } 2275 return returnValue; 2276 } 2277 2278 /** 2279 * Prompts the user to accept on the certificates that appears on the list 2280 * and returns the chosen certificate nickname. 2281 * @param nicknames the list of certificates the user must choose from. 2282 * @return the chosen certificate nickname. 2283 */ 2284 private String promptForCertificateNickname(LinkedList<String> nicknames) 2285 { 2286 String nickname = null; 2287 while (nickname == null) 2288 { 2289 for (String n : nicknames) 2290 { 2291 try 2292 { 2293 if (confirmAction(INFO_INSTALLDS_PROMPT_CERTNICKNAME.get(n), true)) 2294 { 2295 nickname = n; 2296 break; 2297 } 2298 } 2299 catch (CLIException ce) 2300 { 2301 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 2302 } 2303 } 2304 } 2305 return nickname; 2306 } 2307 2308 /** 2309 * This method asks the user to confirm to continue the setup. It basically 2310 * displays the information provided by the user and at the end proposes a 2311 * menu with the different options to choose from. 2312 * @param uData the UserData that the user provided. 2313 * @return the answer provided by the user: cancel setup, continue setup or 2314 * provide information again. 2315 */ 2316 private ConfirmCode askForConfirmation(UserData uData) 2317 { 2318 ConfirmCode returnValue; 2319 2320 println(); 2321 println(); 2322 println(INFO_INSTALLDS_SUMMARY.get()); 2323 Message[] labels = 2324 { 2325 INFO_SERVER_PORT_LABEL.get(), 2326 INFO_INSTALLDS_SERVER_JMXPORT_LABEL.get(), 2327 INFO_SERVER_SECURITY_LABEL.get(), 2328 INFO_SERVER_DIRECTORY_MANAGER_DN_LABEL.get(), 2329 INFO_DIRECTORY_DATA_LABEL.get() 2330 }; 2331 2332 int jmxPort = uData.getServerJMXPort(); 2333 2334 Message[] values = 2335 { 2336 Message.raw(String.valueOf(uData.getServerPort())), 2337 Message.raw(jmxPort != -1 ? String.valueOf(jmxPort) : null), 2338 Message.raw( 2339 QuickSetupStepPanel.getSecurityOptionsString( 2340 uData.getSecurityOptions(), false)), 2341 Message.raw(uData.getDirectoryManagerDn()), 2342 Message.raw(InstallReviewPanel.getDataDisplayString(uData)), 2343 }; 2344 int maxWidth = 0; 2345 StringBuilder sb = new StringBuilder(); 2346 for (Message l : labels) 2347 { 2348 maxWidth = Math.max(maxWidth, l.length()); 2349 } 2350 2351 for (int i=0; i<labels.length; i++) 2352 { 2353 if (values[i] != null) 2354 { 2355 Message l = labels[i]; 2356 sb.append(l.toString()); 2357 2358 sb.append(" "); 2359 String[] lines = values[i].toString().split(Constants.LINE_SEPARATOR); 2360 for (int j=0; j<lines.length; j++) 2361 { 2362 if (j != 0) 2363 { 2364 sb.append(Constants.LINE_SEPARATOR); 2365 for (int k=0; k <= maxWidth; k++) 2366 { 2367 sb.append(" "); 2368 } 2369 } 2370 else 2371 { 2372 for (int k=0; k<maxWidth - l.length(); k++) 2373 { 2374 sb.append(" "); 2375 } 2376 } 2377 sb.append(lines[j].toString()); 2378 } 2379 sb.append(Constants.LINE_SEPARATOR); 2380 } 2381 } 2382 2383 println(Message.raw(sb)); 2384 println(); 2385 if (uData.getStartServer()) 2386 { 2387 println(INFO_INSTALLDS_START_SERVER.get()); 2388 } 2389 else 2390 { 2391 println(INFO_INSTALLDS_DO_NOT_START_SERVER.get()); 2392 } 2393 2394 println(); 2395 println(); 2396 2397 Message[] msgs = new Message[] { 2398 INFO_INSTALLDS_CONFIRM_INSTALL.get(), 2399 INFO_INSTALLDS_PROVIDE_DATA_AGAIN.get(), 2400 INFO_INSTALLDS_CANCEL.get() 2401 }; 2402 2403 MenuBuilder<ConfirmCode> builder = new MenuBuilder<ConfirmCode>(this); 2404 builder.setPrompt(INFO_INSTALLDS_CONFIRM_INSTALL_PROMPT.get()); 2405 2406 int i=0; 2407 for (ConfirmCode code : ConfirmCode.values()) 2408 { 2409 builder.addNumberedOption(msgs[i], MenuResult.success(code)); 2410 i++; 2411 } 2412 2413 builder.setDefault(Message.raw( 2414 String.valueOf(ConfirmCode.CONTINUE.getReturnCode())), 2415 MenuResult.success(ConfirmCode.CONTINUE)); 2416 2417 Menu<ConfirmCode> menu = builder.toMenu(); 2418 2419 try 2420 { 2421 MenuResult<ConfirmCode> m = menu.run(); 2422 if (m.isSuccess()) 2423 { 2424 returnValue = m.getValue(); 2425 } 2426 else 2427 { 2428 // Should never happen. 2429 throw new RuntimeException(); 2430 } 2431 } 2432 catch (CLIException ce) 2433 { 2434 returnValue = ConfirmCode.CANCEL; 2435 LOG.log(Level.WARNING, "Error reading input: "+ce, ce); 2436 } 2437 return returnValue; 2438 } 2439 2440 private void resetArguments(UserData uData) 2441 { 2442 argParser = new InstallDSArgumentParser(InstallDS.class.getName()); 2443 try 2444 { 2445 argParser.initializeArguments(); 2446 argParser.directoryManagerDNArg.setDefaultValue( 2447 uData.getDirectoryManagerDn()); 2448 argParser.ldapPortArg.setDefaultValue( 2449 String.valueOf(uData.getServerPort())); 2450 int jmxPort = uData.getServerJMXPort(); 2451 if (jmxPort != -1) 2452 { 2453 argParser.jmxPortArg.setDefaultValue(String.valueOf(jmxPort)); 2454 } 2455 LinkedList<String> baseDNs = uData.getNewSuffixOptions().getBaseDns(); 2456 if (!baseDNs.isEmpty()) 2457 { 2458 argParser.baseDNArg.setDefaultValue(baseDNs.getFirst()); 2459 } 2460 NewSuffixOptions suffixOptions = uData.getNewSuffixOptions(); 2461 lastResetPopulateOption = suffixOptions.getType(); 2462 if (lastResetPopulateOption == 2463 NewSuffixOptions.Type.IMPORT_AUTOMATICALLY_GENERATED_DATA) 2464 { 2465 lastResetNumEntries = suffixOptions.getNumberEntries(); 2466 } 2467 else if (lastResetPopulateOption == 2468 NewSuffixOptions.Type.IMPORT_FROM_LDIF_FILE) 2469 { 2470 lastResetImportFile = suffixOptions.getLDIFPaths().getFirst(); 2471 lastResetRejectedFile = suffixOptions.getRejectedFile(); 2472 lastResetSkippedFile = suffixOptions.getSkippedFile(); 2473 } 2474 SecurityOptions sec = uData.getSecurityOptions(); 2475 if (sec.getEnableSSL()) 2476 { 2477 argParser.ldapsPortArg.setDefaultValue( 2478 String.valueOf(sec.getSslPort())); 2479 } 2480 lastResetEnableSSL = sec.getEnableSSL(); 2481 lastResetEnableStartTLS = sec.getEnableStartTLS(); 2482 lastResetCertType = sec.getCertificateType(); 2483 if (lastResetCertType == SecurityOptions.CertificateType.JKS || 2484 lastResetCertType == SecurityOptions.CertificateType.PKCS11) 2485 { 2486 lastResetKeyStorePath = sec.getKeystorePath(); 2487 } 2488 else 2489 { 2490 lastResetKeyStorePath = null; 2491 } 2492 2493 lastResetEnableWindowsService = uData.getEnableWindowsService(); 2494 lastResetStartServer = uData.getStartServer(); 2495 } 2496 catch (Throwable t) 2497 { 2498 LOG.log(Level.WARNING, "Error resetting arguments: "+t, t); 2499 } 2500 } 2501 }