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 2008 Sun Microsystems, Inc. 026 */ 027 028 package org.opends.server.util.cli; 029 030 import org.opends.messages.Message; 031 import static org.opends.messages.UtilityMessages.*; 032 import static org.opends.messages.QuickSetupMessages.*; 033 import static org.opends.messages.ToolMessages.*; 034 035 import org.opends.quicksetup.Step; 036 import org.opends.quicksetup.UserDataCertificateException; 037 import org.opends.quicksetup.util.Utils; 038 import org.opends.server.tools.dsconfig.ArgumentExceptionFactory; 039 import org.opends.server.tools.LDAPConnectionOptions; 040 import org.opends.server.tools.SSLConnectionFactory; 041 import org.opends.server.tools.SSLConnectionException; 042 import org.opends.server.admin.client.cli.SecureConnectionCliArgs; 043 import org.opends.server.util.args.ArgumentException; 044 import org.opends.server.util.SelectableCertificateKeyManager; 045 import org.opends.admin.ads.ADSContext; 046 import org.opends.admin.ads.util.ApplicationTrustManager; 047 import org.opends.admin.ads.util.ApplicationKeyManager; 048 049 import javax.net.ssl.KeyManager; 050 import javax.net.ssl.TrustManager; 051 import java.net.InetAddress; 052 import java.net.URI; 053 import java.net.UnknownHostException; 054 import java.io.File; 055 import java.io.FileInputStream; 056 import java.io.FileNotFoundException; 057 import java.io.FileOutputStream; 058 import java.security.KeyStore; 059 import java.security.KeyStoreException; 060 import java.security.cert.X509Certificate; 061 import java.util.Enumeration; 062 import java.util.logging.Level; 063 import java.util.logging.Logger; 064 065 /** 066 * Supports interacting with a user through the command line to 067 * prompt for information necessary to create an LDAP connection. 068 */ 069 public class LDAPConnectionConsoleInteraction { 070 071 private boolean useSSL; 072 private boolean useStartTLS; 073 private String hostName; 074 private int portNumber; 075 private String bindDN; 076 private String providedBindDN; 077 private String adminUID; 078 private String providedAdminUID; 079 private String bindPassword; 080 private KeyManager keyManager; 081 private ApplicationTrustManager trustManager; 082 // Boolean that tells if we ask for bind DN or admin UID in the same prompt. 083 private boolean useAdminOrBindDn = false; 084 // Boolean that tells if we must propose LDAP if it is available even if the 085 // user provided certificate parameters. 086 private boolean displayLdapIfSecureParameters = false; 087 088 // The SecureConnectionCliArgsList object. 089 private SecureConnectionCliArgs secureArgsList = null; 090 091 // Indicate if we need to display the heading 092 private boolean isHeadingDisplayed = false; 093 094 // the Console application 095 private ConsoleApplication app; 096 097 // Indicate if the truststore in in memory 098 private boolean trustStoreInMemory = false; 099 100 // Indicate that the trust manager was created with the parameters provided 101 private boolean trustManagerInitialized; 102 103 // The truststore to use for the SSL or STARTTLS connection 104 private KeyStore truststore; 105 106 private String keystorePath; 107 108 private String keystorePassword; 109 110 private String certifNickname; 111 112 private String truststorePath; 113 114 private String truststorePassword; 115 116 private Message heading = INFO_LDAP_CONN_HEADING_CONNECTION_PARAMETERS.get(); 117 118 // A copy of the secureArgList for convenience. 119 private SecureConnectionCliArgs copySecureArgsList = null; 120 121 // The command builder that we can return with the connection information. 122 private CommandBuilder commandBuilder; 123 124 /** 125 * Enumeration description protocols for interactive CLI choices. 126 */ 127 private enum Protocols 128 { 129 LDAP(1, INFO_LDAP_CONN_PROMPT_SECURITY_LDAP.get()), SSL(2, 130 INFO_LDAP_CONN_PROMPT_SECURITY_USE_SSL.get()), START_TLS(3, 131 INFO_LDAP_CONN_PROMPT_SECURITY_USE_START_TLS.get()); 132 133 private Integer choice; 134 135 private Message msg; 136 137 /** 138 * Private constructor. 139 * 140 * @param i 141 * the menu return value. 142 * @param msg 143 * the message message. 144 */ 145 private Protocols(int i, Message msg) 146 { 147 choice = i; 148 this.msg = msg; 149 } 150 151 /** 152 * Returns the choice number. 153 * 154 * @return the attribute name. 155 */ 156 public Integer getChoice() 157 { 158 return choice; 159 } 160 161 /** 162 * Return the menu message. 163 * 164 * @return the menu message. 165 */ 166 public Message getMenuMessage() 167 { 168 return msg; 169 } 170 } 171 172 /** 173 * Enumeration description protocols for interactive CLI choices. 174 */ 175 private enum TrustMethod 176 { 177 TRUSTALL(1, INFO_LDAP_CONN_PROMPT_SECURITY_USE_TRUST_ALL.get()), 178 179 TRUSTSTORE(2,INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE.get()), 180 181 DISPLAY_CERTIFICATE(3,INFO_LDAP_CONN_PROMPT_SECURITY_MANUAL_CHECK.get()); 182 183 private Integer choice; 184 185 private Message msg; 186 187 /** 188 * Private constructor. 189 * 190 * @param i 191 * the menu return value. 192 * @param msg 193 * the message message. 194 */ 195 private TrustMethod(int i, Message msg) 196 { 197 choice = new Integer(i); 198 this.msg = msg; 199 } 200 201 /** 202 * Returns the choice number. 203 * 204 * @return the attribute name. 205 */ 206 public Integer getChoice() 207 { 208 return choice; 209 } 210 211 /** 212 * Return the menu message. 213 * 214 * @return the menu message. 215 */ 216 public Message getMenuMessage() 217 { 218 return msg; 219 } 220 } 221 222 /** 223 * Enumeration description server certificate trust option. 224 */ 225 private enum TrustOption 226 { 227 UNTRUSTED(1, INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_NO.get()), 228 SESSION(2,INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_SESSION.get()), 229 PERMAMENT(3,INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_ALWAYS.get()), 230 CERTIFICATE_DETAILS(4, 231 INFO_LDAP_CONN_PROMPT_SECURITY_CERTIFICATE_DETAILS.get()); 232 233 private Integer choice; 234 235 private Message msg; 236 237 /** 238 * Private constructor. 239 * 240 * @param i 241 * the menu return value. 242 * @param msg 243 * the message message. 244 */ 245 private TrustOption(int i, Message msg) 246 { 247 choice = new Integer(i); 248 this.msg = msg; 249 } 250 251 /** 252 * Returns the choice number. 253 * 254 * @return the attribute name. 255 */ 256 public Integer getChoice() 257 { 258 return choice; 259 } 260 261 /** 262 * Return the menu message. 263 * 264 * @return the menu message. 265 */ 266 public Message getMenuMessage() 267 { 268 return msg; 269 } 270 } 271 /** 272 * Constructs a parameterized instance. 273 * 274 * @param app console application 275 * @param secureArgs existing set of arguments that have already 276 * been parsed and contain some potential command line specified 277 * LDAP arguments 278 */ 279 public LDAPConnectionConsoleInteraction(ConsoleApplication app, 280 SecureConnectionCliArgs secureArgs) { 281 this.app = app; 282 this.secureArgsList = secureArgs; 283 this.commandBuilder = new CommandBuilder(null); 284 copySecureArgsList = new SecureConnectionCliArgs(); 285 try 286 { 287 copySecureArgsList.createGlobalArguments(); 288 } 289 catch (Throwable t) 290 { 291 // This is a bug: we should always be able to create the global arguments 292 // no need to localize this one. 293 throw new RuntimeException("Unexpected error: "+t, t); 294 } 295 } 296 297 /** 298 * Interact with the user though the console to get information 299 * necessary to establish an LDAP connection. 300 * 301 * @throws ArgumentException if there is a problem with the arguments 302 */ 303 public void run() 304 throws ArgumentException 305 { 306 run(true, true); 307 } 308 309 310 /** 311 * Interact with the user though the console to get information 312 * necessary to establish an LDAP connection. 313 * @param canUseSSL whether we can propose to connect using SSL or not. 314 * @param canUseStartTLS whether we can propose to connect using Start TLS or 315 * not. 316 * 317 * @throws ArgumentException if there is a problem with the arguments 318 */ 319 public void run(boolean canUseSSL, boolean canUseStartTLS) 320 throws ArgumentException 321 { 322 // Reset everything 323 commandBuilder.clearArguments(); 324 copySecureArgsList.createGlobalArguments(); 325 boolean secureConnection = (canUseSSL || canUseStartTLS) && 326 ( 327 secureArgsList.useSSLArg.isPresent() 328 || 329 secureArgsList.useStartTLSArg.isPresent() 330 || 331 secureArgsList.trustAllArg.isPresent() 332 || 333 secureArgsList.trustStorePathArg.isPresent() 334 || 335 secureArgsList.trustStorePasswordArg.isPresent() 336 || 337 secureArgsList.trustStorePasswordFileArg.isPresent() 338 || 339 secureArgsList.keyStorePathArg.isPresent() 340 || 341 secureArgsList.keyStorePasswordArg.isPresent() 342 || 343 secureArgsList.keyStorePasswordFileArg.isPresent() 344 ); 345 346 // Get the LDAP host. 347 hostName = secureArgsList.hostNameArg.getValue(); 348 final String tmpHostName = hostName; 349 if (app.isInteractive() && !secureArgsList.hostNameArg.isPresent()) 350 { 351 checkHeadingDisplayed(); 352 353 ValidationCallback<String> callback = new ValidationCallback<String>() 354 { 355 356 public String validate(ConsoleApplication app, String input) 357 throws CLIException 358 { 359 String ninput = input.trim(); 360 if (ninput.length() == 0) 361 { 362 return tmpHostName; 363 } 364 else 365 { 366 try 367 { 368 InetAddress.getByName(ninput); 369 return ninput; 370 } 371 catch (UnknownHostException e) 372 { 373 // Try again... 374 app.println(); 375 app.println(ERR_LDAP_CONN_BAD_HOST_NAME.get(ninput)); 376 app.println(); 377 return null; 378 } 379 } 380 } 381 382 }; 383 384 try 385 { 386 app.println(); 387 hostName = app.readValidatedInput(INFO_LDAP_CONN_PROMPT_HOST_NAME 388 .get(hostName), callback); 389 } 390 catch (CLIException e) 391 { 392 throw ArgumentExceptionFactory.unableToReadConnectionParameters(e); 393 } 394 } 395 396 copySecureArgsList.hostNameArg.clearValues(); 397 copySecureArgsList.hostNameArg.addValue(hostName); 398 commandBuilder.addArgument(copySecureArgsList.hostNameArg); 399 400 useSSL = secureArgsList.useSSL(); 401 useStartTLS = secureArgsList.useStartTLS(); 402 boolean connectionTypeIsSet = 403 ( 404 secureArgsList.useSSLArg.isPresent() 405 || 406 secureArgsList.useStartTLSArg.isPresent() 407 || 408 ( 409 secureArgsList.useSSLArg.isValueSetByProperty() 410 && 411 secureArgsList.useStartTLSArg.isValueSetByProperty() 412 ) 413 ); 414 if (app.isInteractive() && !connectionTypeIsSet) 415 { 416 checkHeadingDisplayed(); 417 418 MenuBuilder<Integer> builder = new MenuBuilder<Integer>(app); 419 builder.setPrompt(INFO_LDAP_CONN_PROMPT_SECURITY_USE_SECURE_CTX.get()); 420 421 Protocols defaultProtocol ; 422 if (secureConnection) 423 { 424 defaultProtocol = Protocols.SSL; 425 } 426 else 427 { 428 defaultProtocol = Protocols.LDAP; 429 } 430 for (Protocols p : Protocols.values()) 431 { 432 if (secureConnection && p.equals(Protocols.LDAP) && 433 !displayLdapIfSecureParameters) 434 { 435 continue ; 436 } 437 if (!canUseSSL && p.equals(Protocols.SSL)) 438 { 439 continue; 440 } 441 if (!canUseStartTLS && p.equals(Protocols.START_TLS)) 442 { 443 continue; 444 } 445 int i = builder.addNumberedOption(p.getMenuMessage(), MenuResult 446 .success(p.getChoice())); 447 if (p.equals(defaultProtocol)) 448 { 449 builder.setDefault( 450 INFO_LDAP_CONN_PROMPT_SECURITY_PROTOCOL_DEFAULT_CHOICE 451 .get(i), MenuResult.success(p.getChoice())); 452 } 453 } 454 455 Menu<Integer> menu = builder.toMenu(); 456 try 457 { 458 MenuResult<Integer> result = menu.run(); 459 if (result.isSuccess()) 460 { 461 if (result.getValue().equals(Protocols.SSL.getChoice())) 462 { 463 useSSL = true; 464 } 465 else if (result.getValue() 466 .equals(Protocols.START_TLS.getChoice())) 467 { 468 useStartTLS = true; 469 } 470 } 471 else 472 { 473 // Should never happen. 474 throw new RuntimeException(); 475 } 476 } 477 catch (CLIException e) 478 { 479 throw new RuntimeException(e); 480 } 481 } 482 483 if (useSSL) 484 { 485 commandBuilder.addArgument(copySecureArgsList.useSSLArg); 486 } 487 else if (useStartTLS) 488 { 489 commandBuilder.addArgument(copySecureArgsList.useStartTLSArg); 490 } 491 492 if ((useSSL || useStartTLS) && (trustManager == null)) 493 { 494 initializeTrustManager(); 495 } 496 497 // Get the LDAP port. 498 if (!useSSL) 499 { 500 portNumber = secureArgsList.portArg.getIntValue(); 501 } 502 else 503 { 504 if (secureArgsList.portArg.isPresent()) 505 { 506 portNumber = secureArgsList.portArg.getIntValue(); 507 } 508 else 509 { 510 portNumber = 636; 511 } 512 } 513 final int tmpPortNumber = portNumber; 514 if (app.isInteractive() && !secureArgsList.portArg.isPresent()) 515 { 516 checkHeadingDisplayed(); 517 518 ValidationCallback<Integer> callback = new ValidationCallback<Integer>() 519 { 520 521 public Integer validate(ConsoleApplication app, String input) 522 throws CLIException 523 { 524 String ninput = input.trim(); 525 if (ninput.length() == 0) 526 { 527 return tmpPortNumber; 528 } 529 else 530 { 531 try 532 { 533 int i = Integer.parseInt(ninput); 534 if (i < 1 || i > 65535) 535 { 536 throw new NumberFormatException(); 537 } 538 return i; 539 } 540 catch (NumberFormatException e) 541 { 542 // Try again... 543 app.println(); 544 app.println(ERR_LDAP_CONN_BAD_PORT_NUMBER.get(ninput)); 545 app.println(); 546 return null; 547 } 548 } 549 } 550 551 }; 552 553 try 554 { 555 app.println(); 556 portNumber = app.readValidatedInput(INFO_LDAP_CONN_PROMPT_PORT_NUMBER 557 .get(portNumber), callback); 558 } 559 catch (CLIException e) 560 { 561 throw ArgumentExceptionFactory.unableToReadConnectionParameters(e); 562 } 563 } 564 565 copySecureArgsList.portArg.clearValues(); 566 copySecureArgsList.portArg.addValue(String.valueOf(portNumber)); 567 commandBuilder.addArgument(copySecureArgsList.portArg); 568 569 // Get the LDAP bind credentials. 570 bindDN = secureArgsList.bindDnArg.getValue(); 571 adminUID = secureArgsList.adminUidArg.getValue(); 572 final boolean useAdmin = secureArgsList.useAdminUID(); 573 if (useAdmin && secureArgsList.adminUidArg.isPresent()) 574 { 575 providedAdminUID = adminUID; 576 } 577 else 578 { 579 providedAdminUID = null; 580 } 581 if ((!useAdmin || useAdminOrBindDn) && 582 secureArgsList.bindDnArg.isPresent()) 583 { 584 providedBindDN = bindDN; 585 } 586 else 587 { 588 providedBindDN = null; 589 } 590 boolean argIsPresent = (providedAdminUID != null) || 591 (providedBindDN != null); 592 final String tmpBindDN = bindDN; 593 final String tmpAdminUID = adminUID; 594 if (keyManager == null) 595 { 596 if (app.isInteractive() && !argIsPresent) 597 { 598 checkHeadingDisplayed(); 599 600 ValidationCallback<String> callback = new ValidationCallback<String>() 601 { 602 603 public String validate(ConsoleApplication app, String input) 604 throws CLIException 605 { 606 String ninput = input.trim(); 607 if (ninput.length() == 0) 608 { 609 if (useAdmin) 610 { 611 return tmpAdminUID; 612 } 613 else 614 { 615 return tmpBindDN; 616 } 617 } 618 else 619 { 620 return ninput; 621 } 622 } 623 624 }; 625 626 try 627 { 628 app.println(); 629 if (useAdminOrBindDn) 630 { 631 String def = (adminUID != null) ? adminUID : bindDN; 632 String v = app.readValidatedInput( 633 INFO_LDAP_CONN_GLOBAL_ADMINISTRATOR_OR_BINDDN_PROMPT.get(def), 634 callback); 635 if (Utils.isDn(v)) 636 { 637 bindDN = v; 638 providedBindDN = v; 639 adminUID = null; 640 providedAdminUID = null; 641 } 642 else 643 { 644 bindDN = null; 645 providedBindDN = null; 646 adminUID = v; 647 providedAdminUID = v; 648 } 649 } 650 else if (useAdmin) 651 { 652 adminUID = app.readValidatedInput( 653 INFO_LDAP_CONN_PROMPT_ADMINISTRATOR_UID.get(adminUID), 654 callback); 655 providedAdminUID = adminUID; 656 } 657 else 658 { 659 bindDN = app.readValidatedInput(INFO_LDAP_CONN_PROMPT_BIND_DN 660 .get(bindDN), callback); 661 providedBindDN = bindDN; 662 } 663 } 664 catch (CLIException e) 665 { 666 throw ArgumentExceptionFactory 667 .unableToReadConnectionParameters(e); 668 } 669 } 670 if (useAdmin) 671 { 672 copySecureArgsList.adminUidArg.clearValues(); 673 copySecureArgsList.adminUidArg.addValue(getAdministratorUID()); 674 commandBuilder.addArgument(copySecureArgsList.adminUidArg); 675 } 676 else 677 { 678 copySecureArgsList.bindDnArg.clearValues(); 679 copySecureArgsList.bindDnArg.addValue(getBindDN()); 680 commandBuilder.addArgument(copySecureArgsList.bindDnArg); 681 } 682 } 683 else 684 { 685 bindDN = null; 686 adminUID = null; 687 } 688 689 bindPassword = secureArgsList.bindPasswordArg.getValue(); 690 if (keyManager == null) 691 { 692 if (secureArgsList.bindPasswordFileArg.isPresent()) 693 { 694 // Read from file if it exists. 695 bindPassword = secureArgsList.bindPasswordFileArg.getValue(); 696 697 if (bindPassword == null) 698 { 699 if (useAdmin) 700 { 701 throw ArgumentExceptionFactory.missingBindPassword(adminUID); 702 } 703 else 704 { 705 throw ArgumentExceptionFactory.missingBindPassword(bindDN); 706 } 707 } 708 copySecureArgsList.bindPasswordFileArg.clearValues(); 709 copySecureArgsList.bindPasswordFileArg.getNameToValueMap().putAll( 710 secureArgsList.bindPasswordFileArg.getNameToValueMap()); 711 commandBuilder.addArgument(secureArgsList.bindPasswordFileArg); 712 } 713 else if (bindPassword == null || bindPassword.equals("-")) 714 { 715 // Read the password from the stdin. 716 if (!app.isInteractive()) 717 { 718 throw ArgumentExceptionFactory 719 .unableToReadBindPasswordInteractively(); 720 } 721 722 checkHeadingDisplayed(); 723 724 try 725 { 726 app.println(); 727 Message prompt; 728 if (providedAdminUID != null) 729 { 730 prompt = INFO_LDAPAUTH_PASSWORD_PROMPT.get(providedAdminUID); 731 } 732 else if (providedBindDN != null) 733 { 734 prompt = INFO_LDAPAUTH_PASSWORD_PROMPT.get(providedBindDN); 735 } 736 else if (bindDN != null) 737 { 738 prompt = INFO_LDAPAUTH_PASSWORD_PROMPT.get(bindDN); 739 } 740 else 741 { 742 prompt = INFO_LDAPAUTH_PASSWORD_PROMPT.get(adminUID); 743 } 744 bindPassword = app.readPassword(prompt); 745 } 746 catch (Exception e) 747 { 748 throw ArgumentExceptionFactory 749 .unableToReadConnectionParameters(e); 750 } 751 } 752 copySecureArgsList.bindPasswordArg.clearValues(); 753 copySecureArgsList.bindPasswordArg.addValue(bindPassword); 754 commandBuilder.addObfuscatedArgument( 755 copySecureArgsList.bindPasswordArg); 756 } 757 } 758 759 /** 760 * Get the trust manager. 761 * 762 * @return The trust manager based on CLI args on interactive prompt. 763 * @throws ArgumentException If an error occurs when getting args values. 764 */ 765 private ApplicationTrustManager getTrustManagerInternal() 766 throws ArgumentException 767 { 768 // Remove these arguments since this method might be called several times. 769 commandBuilder.removeArgument(copySecureArgsList.trustAllArg); 770 commandBuilder.removeArgument(copySecureArgsList.trustStorePathArg); 771 commandBuilder.removeArgument(copySecureArgsList.trustStorePasswordArg); 772 commandBuilder.removeArgument(copySecureArgsList.trustStorePasswordFileArg); 773 774 // If we have the trustALL flag, don't do anything 775 // just return null 776 if (secureArgsList.trustAllArg.isPresent()) 777 { 778 commandBuilder.addArgument(copySecureArgsList.trustAllArg); 779 return null; 780 } 781 782 // Check if some trust manager info are set 783 boolean weDontKnowTheTrustMethod = 784 !( secureArgsList.trustAllArg.isPresent() 785 || 786 secureArgsList.trustStorePathArg.isPresent() 787 || 788 secureArgsList.trustStorePasswordArg.isPresent() 789 || 790 secureArgsList.trustStorePasswordFileArg.isPresent() 791 ); 792 boolean askForTrustStore = false; 793 if (app.isInteractive() && weDontKnowTheTrustMethod) 794 { 795 checkHeadingDisplayed(); 796 797 app.println(); 798 MenuBuilder<Integer> builder = new MenuBuilder<Integer>(app); 799 builder.setPrompt(INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_METHOD.get()); 800 801 TrustMethod defaultTrustMethod = TrustMethod.DISPLAY_CERTIFICATE; 802 for (TrustMethod t : TrustMethod.values()) 803 { 804 int i = builder.addNumberedOption(t.getMenuMessage(), MenuResult 805 .success(t.getChoice())); 806 if (t.equals(defaultTrustMethod)) 807 { 808 builder.setDefault( 809 INFO_LDAP_CONN_PROMPT_SECURITY_PROTOCOL_DEFAULT_CHOICE 810 .get(new Integer(i)), MenuResult.success(t.getChoice())); 811 } 812 } 813 814 Menu<Integer> menu = builder.toMenu(); 815 trustStoreInMemory = false; 816 try 817 { 818 MenuResult<Integer> result = menu.run(); 819 if (result.isSuccess()) 820 { 821 if (result.getValue().equals(TrustMethod.TRUSTALL.getChoice())) 822 { 823 commandBuilder.addArgument(copySecureArgsList.trustAllArg); 824 // If we have the trustALL flag, don't do anything 825 // just return null 826 return null; 827 } 828 else if (result.getValue().equals( 829 TrustMethod.TRUSTSTORE.getChoice())) 830 { 831 // We have to ask for truststore info 832 askForTrustStore = true; 833 } 834 else if (result.getValue().equals( 835 TrustMethod.DISPLAY_CERTIFICATE.getChoice())) 836 { 837 // The certificate will be displayed to the user 838 askForTrustStore = false; 839 trustStoreInMemory = true; 840 841 // There is no direct equivalent for this option, so propose the 842 // trust all option as command-line argument. 843 commandBuilder.addArgument(copySecureArgsList.trustAllArg); 844 } 845 else 846 { 847 // Should never happen. 848 throw new RuntimeException(); 849 } 850 } 851 else 852 { 853 // Should never happen. 854 throw new RuntimeException(); 855 } 856 } 857 catch (CLIException e) 858 { 859 throw new RuntimeException(e); 860 861 } 862 } 863 864 // If we do not trust all server certificates, we have to get info 865 // about truststore. First get the truststore path. 866 truststorePath = secureArgsList.trustStorePathArg.getValue(); 867 868 if (app.isInteractive() && !secureArgsList.trustStorePathArg.isPresent() 869 && askForTrustStore) 870 { 871 checkHeadingDisplayed(); 872 873 ValidationCallback<String> callback = new ValidationCallback<String>() 874 { 875 public String validate(ConsoleApplication app, String input) 876 throws CLIException 877 { 878 String ninput = input.trim(); 879 if (ninput.length() == 0) 880 { 881 app.println(); 882 app.println(ERR_LDAP_CONN_PROMPT_SECURITY_INVALID_FILE_PATH 883 .get()); 884 app.println(); 885 return null; 886 } 887 File f = new File(ninput); 888 if (f.exists() && f.canRead() && !f.isDirectory()) 889 { 890 return ninput; 891 } 892 else 893 { 894 app.println(); 895 app.println(ERR_LDAP_CONN_PROMPT_SECURITY_INVALID_FILE_PATH 896 .get()); 897 app.println(); 898 return null; 899 } 900 } 901 }; 902 903 try 904 { 905 app.println(); 906 truststorePath = app.readValidatedInput( 907 INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE_PATH.get(), callback); 908 } 909 catch (CLIException e) 910 { 911 throw ArgumentExceptionFactory.unableToReadConnectionParameters(e); 912 } 913 } 914 915 if (truststorePath != null) 916 { 917 copySecureArgsList.trustStorePathArg.clearValues(); 918 copySecureArgsList.trustStorePathArg.addValue(truststorePath); 919 commandBuilder.addArgument(copySecureArgsList.trustStorePathArg); 920 } 921 922 // Then the truststore password. 923 // As the most common case is to have no password for truststore, 924 // we don't ask it in the interactive mode. 925 truststorePassword = secureArgsList.trustStorePasswordArg 926 .getValue(); 927 928 if (secureArgsList.trustStorePasswordFileArg.isPresent()) 929 { 930 // Read from file if it exists. 931 truststorePassword = secureArgsList.trustStorePasswordFileArg 932 .getValue(); 933 } 934 if ((truststorePassword != null) && (truststorePassword.equals("-"))) 935 { 936 // Read the password from the stdin. 937 if (!app.isInteractive()) 938 { 939 truststorePassword = null; 940 } 941 else 942 { 943 checkHeadingDisplayed(); 944 945 try 946 { 947 app.println(); 948 Message prompt = INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE_PASSWORD 949 .get(truststorePath); 950 truststorePassword = app.readPassword(prompt); 951 } 952 catch (Exception e) 953 { 954 throw ArgumentExceptionFactory.unableToReadConnectionParameters(e); 955 } 956 } 957 } 958 959 // We've got all the information to get the truststore manager 960 try 961 { 962 truststore = KeyStore.getInstance(KeyStore.getDefaultType()); 963 if (truststorePath != null) 964 { 965 FileInputStream fos = new FileInputStream(truststorePath); 966 if (truststorePassword != null) 967 { 968 truststore.load(fos, truststorePassword.toCharArray()); 969 } 970 else 971 { 972 truststore.load(fos, null); 973 } 974 fos.close(); 975 } 976 else 977 { 978 truststore.load(null, null); 979 } 980 981 if (secureArgsList.trustStorePasswordFileArg.isPresent()) 982 { 983 copySecureArgsList.trustStorePasswordFileArg.clearValues(); 984 copySecureArgsList.trustStorePasswordFileArg.getNameToValueMap().putAll( 985 secureArgsList.trustStorePasswordFileArg.getNameToValueMap()); 986 commandBuilder.addArgument( 987 copySecureArgsList.trustStorePasswordFileArg); 988 } 989 else 990 { 991 copySecureArgsList.trustStorePasswordArg.clearValues(); 992 copySecureArgsList.trustStorePasswordArg.addValue(truststorePassword); 993 commandBuilder.addObfuscatedArgument( 994 copySecureArgsList.trustStorePasswordArg); 995 } 996 997 return new ApplicationTrustManager(truststore); 998 } 999 catch (Exception e) 1000 { 1001 throw ArgumentExceptionFactory.unableToReadConnectionParameters(e); 1002 } 1003 } 1004 1005 /** 1006 * Get the key manager. 1007 * 1008 * @return The key manager based on CLI args on interactive prompt. 1009 * @throws ArgumentException If an error occurs when getting args values. 1010 */ 1011 private KeyManager getKeyManagerInternal() 1012 throws ArgumentException 1013 { 1014 // Remove these arguments since this method might be called several times. 1015 commandBuilder.removeArgument(copySecureArgsList.certNicknameArg); 1016 commandBuilder.removeArgument(copySecureArgsList.keyStorePathArg); 1017 commandBuilder.removeArgument(copySecureArgsList.keyStorePasswordArg); 1018 commandBuilder.removeArgument(copySecureArgsList.keyStorePasswordFileArg); 1019 1020 // Do we need client side authentication ? 1021 // If one of the client side authentication args is set, we assume 1022 // that we 1023 // need client side authentication. 1024 boolean weDontKnowIfWeNeedKeystore = !(secureArgsList.keyStorePathArg 1025 .isPresent() 1026 || secureArgsList.keyStorePasswordArg.isPresent() 1027 || secureArgsList.keyStorePasswordFileArg.isPresent() 1028 || secureArgsList.certNicknameArg 1029 .isPresent()); 1030 1031 // We don't have specific key manager parameter. 1032 // We assume that no client side authentication is required 1033 // Client side authentication is not the common use case. As a 1034 // consequence, interactive mode doesn't add an extra question 1035 // which will be in most cases useless. 1036 if (weDontKnowIfWeNeedKeystore) 1037 { 1038 return null; 1039 } 1040 1041 // Get info about keystore. First get the keystore path. 1042 keystorePath = secureArgsList.keyStorePathArg.getValue(); 1043 if (app.isInteractive() && !secureArgsList.keyStorePathArg.isPresent()) 1044 { 1045 checkHeadingDisplayed(); 1046 1047 ValidationCallback<String> callback = new ValidationCallback<String>() 1048 { 1049 public String validate(ConsoleApplication app, String input) 1050 throws CLIException 1051 { 1052 String ninput = input.trim(); 1053 if (ninput.length() == 0) 1054 { 1055 return ninput; 1056 } 1057 File f = new File(ninput); 1058 if (f.exists() && f.canRead() && !f.isDirectory()) 1059 { 1060 return ninput; 1061 } 1062 else 1063 { 1064 app.println(); 1065 app.println(ERR_LDAP_CONN_PROMPT_SECURITY_INVALID_FILE_PATH 1066 .get()); 1067 app.println(); 1068 return null; 1069 } 1070 } 1071 }; 1072 1073 try 1074 { 1075 app.println(); 1076 keystorePath = app.readValidatedInput( 1077 INFO_LDAP_CONN_PROMPT_SECURITY_KEYSTORE_PATH.get(), callback); 1078 } 1079 catch (CLIException e) 1080 { 1081 throw ArgumentExceptionFactory.unableToReadConnectionParameters(e); 1082 } 1083 } 1084 1085 if (keystorePath != null) 1086 { 1087 copySecureArgsList.keyStorePathArg.clearValues(); 1088 copySecureArgsList.keyStorePathArg.addValue(keystorePath); 1089 commandBuilder.addArgument(copySecureArgsList.keyStorePathArg); 1090 } 1091 1092 1093 // Then the keystore password. 1094 keystorePassword = secureArgsList.keyStorePasswordArg.getValue(); 1095 1096 if (secureArgsList.keyStorePasswordFileArg.isPresent()) 1097 { 1098 // Read from file if it exists. 1099 keystorePassword = secureArgsList.keyStorePasswordFileArg.getValue(); 1100 1101 if (keystorePassword == null) 1102 { 1103 throw ArgumentExceptionFactory.missingBindPassword(keystorePassword); 1104 } 1105 } 1106 else if (keystorePassword == null || keystorePassword.equals("-")) 1107 { 1108 // Read the password from the stdin. 1109 if (!app.isInteractive()) 1110 { 1111 throw ArgumentExceptionFactory 1112 .unableToReadBindPasswordInteractively(); 1113 } 1114 1115 checkHeadingDisplayed(); 1116 1117 try 1118 { 1119 app.println(); 1120 Message prompt = INFO_LDAP_CONN_PROMPT_SECURITY_KEYSTORE_PASSWORD 1121 .get(keystorePath); 1122 keystorePassword = app.readPassword(prompt); 1123 } 1124 catch (Exception e) 1125 { 1126 throw ArgumentExceptionFactory.unableToReadConnectionParameters(e); 1127 } 1128 } 1129 1130 // finally the certificate name, if needed. 1131 KeyStore keystore = null; 1132 Enumeration<String> aliasesEnum = null; 1133 try 1134 { 1135 FileInputStream fos = new FileInputStream(keystorePath); 1136 keystore = KeyStore.getInstance(KeyStore.getDefaultType()); 1137 keystore.load(fos, keystorePassword.toCharArray()); 1138 fos.close(); 1139 aliasesEnum = keystore.aliases(); 1140 } 1141 catch (Exception e) 1142 { 1143 throw ArgumentExceptionFactory.unableToReadConnectionParameters(e); 1144 } 1145 1146 certifNickname = secureArgsList.certNicknameArg.getValue(); 1147 if (app.isInteractive() && !secureArgsList.certNicknameArg.isPresent() 1148 && aliasesEnum.hasMoreElements()) 1149 { 1150 checkHeadingDisplayed(); 1151 1152 try 1153 { 1154 MenuBuilder<String> builder = new MenuBuilder<String>(app); 1155 builder.setPrompt(INFO_LDAP_CONN_PROMPT_SECURITY_CERTIFICATE_ALIASES 1156 .get()); 1157 int certificateNumber = 0; 1158 for (; aliasesEnum.hasMoreElements();) 1159 { 1160 String alias = aliasesEnum.nextElement(); 1161 if (keystore.isKeyEntry(alias)) 1162 { 1163 X509Certificate certif = (X509Certificate) keystore 1164 .getCertificate(alias); 1165 certificateNumber++; 1166 builder.addNumberedOption( 1167 INFO_LDAP_CONN_PROMPT_SECURITY_CERTIFICATE_ALIAS.get(alias, 1168 certif.getSubjectDN().getName()), MenuResult 1169 .success(alias)); 1170 } 1171 } 1172 1173 if (certificateNumber > 1) 1174 { 1175 app.println(); 1176 Menu<String> menu = builder.toMenu(); 1177 MenuResult<String> result = menu.run(); 1178 if (result.isSuccess()) 1179 { 1180 certifNickname = result.getValue(); 1181 } 1182 else 1183 { 1184 // Should never happen. 1185 throw new RuntimeException(); 1186 } 1187 } 1188 else 1189 { 1190 certifNickname = null; 1191 } 1192 } 1193 catch (KeyStoreException e) 1194 { 1195 throw ArgumentExceptionFactory.unableToReadConnectionParameters(e); 1196 } 1197 catch (CLIException e) 1198 { 1199 throw ArgumentExceptionFactory.unableToReadConnectionParameters(e); 1200 } 1201 } 1202 1203 // We'we got all the information to get the keys manager 1204 ApplicationKeyManager akm = new ApplicationKeyManager(keystore, 1205 keystorePassword.toCharArray()); 1206 1207 1208 if (secureArgsList.keyStorePasswordFileArg.isPresent()) 1209 { 1210 copySecureArgsList.keyStorePasswordFileArg.clearValues(); 1211 copySecureArgsList.keyStorePasswordFileArg.getNameToValueMap().putAll( 1212 secureArgsList.keyStorePasswordFileArg.getNameToValueMap()); 1213 commandBuilder.addArgument( 1214 copySecureArgsList.keyStorePasswordFileArg); 1215 } 1216 else 1217 { 1218 copySecureArgsList.keyStorePasswordArg.clearValues(); 1219 copySecureArgsList.keyStorePasswordArg.addValue(keystorePassword); 1220 commandBuilder.addObfuscatedArgument( 1221 copySecureArgsList.keyStorePasswordArg); 1222 } 1223 1224 if (certifNickname != null) 1225 { 1226 copySecureArgsList.certNicknameArg.clearValues(); 1227 copySecureArgsList.certNicknameArg.addValue(certifNickname); 1228 } 1229 1230 if (certifNickname != null) 1231 { 1232 return new SelectableCertificateKeyManager(akm, certifNickname); 1233 } 1234 else 1235 { 1236 return akm; 1237 } 1238 } 1239 1240 /** 1241 * Indicates whether or not a connection should use SSL based on 1242 * this interaction. 1243 * 1244 * @return boolean where true means use SSL 1245 */ 1246 public boolean useSSL() { 1247 return useSSL; 1248 } 1249 1250 /** 1251 * Indicates whether or not a connection should use StartTLS based on 1252 * this interaction. 1253 * 1254 * @return boolean where true means use StartTLS 1255 */ 1256 public boolean useStartTLS() { 1257 return useStartTLS; 1258 } 1259 1260 /** 1261 * Gets the host name that should be used for connections based on 1262 * this interaction. 1263 * 1264 * @return host name for connections 1265 */ 1266 public String getHostName() { 1267 return hostName; 1268 } 1269 1270 /** 1271 * Gets the port number name that should be used for connections based on 1272 * this interaction. 1273 * 1274 * @return port number for connections 1275 */ 1276 public int getPortNumber() { 1277 return portNumber; 1278 } 1279 1280 /** 1281 * Sets the port number name that should be used for connections based on 1282 * this interaction. 1283 * 1284 * @param portNumber port number for connections 1285 */ 1286 public void setPortNumber(int portNumber) { 1287 this.portNumber = portNumber; 1288 } 1289 1290 /** 1291 * Gets the bind DN name that should be used for connections based on 1292 * this interaction. 1293 * 1294 * @return bind DN for connections 1295 */ 1296 public String getBindDN() { 1297 String dn; 1298 if (useAdminOrBindDn) 1299 { 1300 if (providedBindDN != null) 1301 { 1302 dn = providedBindDN; 1303 } 1304 else if (providedAdminUID != null) 1305 { 1306 dn = ADSContext.getAdministratorDN(providedAdminUID); 1307 } 1308 else if (this.bindDN != null) 1309 { 1310 dn = this.bindDN; 1311 } 1312 else if (this.adminUID != null) 1313 { 1314 dn = ADSContext.getAdministratorDN(this.adminUID); 1315 } 1316 else 1317 { 1318 dn = null; 1319 } 1320 } 1321 else if (secureArgsList.useAdminUID()) 1322 { 1323 dn = ADSContext.getAdministratorDN(this.adminUID); 1324 } 1325 else 1326 { 1327 dn = this.bindDN; 1328 } 1329 return dn; 1330 } 1331 1332 /** 1333 * Gets the administrator UID name that should be used for connections based 1334 * on this interaction. 1335 * 1336 * @return administrator UID for connections 1337 */ 1338 public String getAdministratorUID() { 1339 return this.adminUID; 1340 } 1341 1342 /** 1343 * Gets the bind password that should be used for connections based on 1344 * this interaction. 1345 * 1346 * @return bind password for connections 1347 */ 1348 public String getBindPassword() { 1349 return this.bindPassword; 1350 } 1351 1352 /** 1353 * Gets the trust manager that should be used for connections based on 1354 * this interaction. 1355 * 1356 * @return trust manager for connections 1357 */ 1358 public TrustManager getTrustManager() { 1359 return this.trustManager; 1360 } 1361 1362 /** 1363 * Gets the key store that should be used for connections based on 1364 * this interaction. 1365 * 1366 * @return key store for connections 1367 */ 1368 public KeyStore getKeyStore() { 1369 return this.truststore; 1370 } 1371 1372 /** 1373 * Gets the key manager that should be used for connections based on 1374 * this interaction. 1375 * 1376 * @return key manager for connections 1377 */ 1378 public KeyManager getKeyManager() { 1379 return this.keyManager; 1380 } 1381 1382 /** 1383 * Indicate if the truststore is in memory. 1384 * 1385 * @return true if the truststore is in memory. 1386 */ 1387 public boolean isTrustStoreInMemory() { 1388 return this.trustStoreInMemory; 1389 } 1390 1391 /** 1392 * Indicate if the certificate chain can be trusted. 1393 * 1394 * @param chain The certificate chain to validate 1395 * @return true if the server certificate is trusted. 1396 */ 1397 public boolean checkServerCertificate(X509Certificate[] chain) 1398 { 1399 return checkServerCertificate(chain, null, null); 1400 } 1401 1402 /** 1403 * Indicate if the certificate chain can be trusted. 1404 * 1405 * @param chain The certificate chain to validate 1406 * @param authType the authentication type. 1407 * @param host the host we tried to connect and that presented the 1408 * certificate. 1409 * @return true if the server certificate is trusted. 1410 */ 1411 public boolean checkServerCertificate(X509Certificate[] chain, 1412 String authType, String host) 1413 { 1414 if (trustManager == null) 1415 { 1416 try 1417 { 1418 initializeTrustManager(); 1419 } 1420 catch (ArgumentException ae) 1421 { 1422 // Should not occur 1423 throw new RuntimeException(ae); 1424 } 1425 } 1426 app.println(); 1427 app.println(INFO_LDAP_CONN_PROMPT_SECURITY_SERVER_CERTIFICATE.get()); 1428 app.println(); 1429 for (int i = 0; i < chain.length; i++) 1430 { 1431 // Certificate DN 1432 app.println(INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_USER_DN.get( 1433 chain[i].getSubjectDN().toString())); 1434 1435 // certificate validity 1436 app.println( 1437 INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_VALIDITY.get( 1438 chain[i].getNotBefore().toString(), 1439 chain[i].getNotAfter().toString())); 1440 1441 // certificate Issuer 1442 app.println( 1443 INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_ISSUER.get( 1444 chain[i].getIssuerDN().toString())); 1445 1446 if (i+1 <chain.length) 1447 { 1448 app.println(); 1449 app.println(); 1450 } 1451 } 1452 MenuBuilder<Integer> builder = new MenuBuilder<Integer>(app); 1453 builder.setPrompt(INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION.get()); 1454 1455 TrustOption defaultTrustMethod = TrustOption.SESSION ; 1456 for (TrustOption t : TrustOption.values()) 1457 { 1458 int i = builder.addNumberedOption(t.getMenuMessage(), MenuResult 1459 .success(t.getChoice())); 1460 if (t.equals(defaultTrustMethod)) 1461 { 1462 builder.setDefault( 1463 INFO_LDAP_CONN_PROMPT_SECURITY_PROTOCOL_DEFAULT_CHOICE 1464 .get(new Integer(i)), MenuResult.success(t.getChoice())); 1465 } 1466 } 1467 1468 app.println(); 1469 app.println(); 1470 1471 Menu<Integer> menu = builder.toMenu(); 1472 while (true) 1473 { 1474 try 1475 { 1476 MenuResult<Integer> result = menu.run(); 1477 if (result.isSuccess()) 1478 { 1479 if (result.getValue().equals(TrustOption.UNTRUSTED.getChoice())) 1480 { 1481 return false; 1482 } 1483 1484 if ((result.getValue().equals(TrustOption.CERTIFICATE_DETAILS 1485 .getChoice()))) 1486 { 1487 for (int i = 0; i < chain.length; i++) 1488 { 1489 app.println(); 1490 app.println(INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE 1491 .get(chain[i].toString())); 1492 } 1493 continue; 1494 } 1495 1496 // We should add it in the memory truststore 1497 for (int i = 0; i < chain.length; i++) 1498 { 1499 String alias = chain[i].getSubjectDN().getName(); 1500 try 1501 { 1502 truststore.setCertificateEntry(alias, chain[i]); 1503 } 1504 catch (KeyStoreException e1) 1505 { 1506 // What else should we do? 1507 return false; 1508 } 1509 } 1510 1511 // Update the trust manager 1512 if (trustManager == null) 1513 { 1514 trustManager = new ApplicationTrustManager(truststore); 1515 } 1516 if ((authType != null) && (host != null)) 1517 { 1518 // Update the trust manager with the new certificate 1519 trustManager.acceptCertificate(chain, authType, host); 1520 } 1521 else 1522 { 1523 // Do a full reset of the contents of the keystore. 1524 trustManager = new ApplicationTrustManager(truststore); 1525 } 1526 if (result.getValue().equals(TrustOption.PERMAMENT.getChoice())) 1527 { 1528 ValidationCallback<String> callback = 1529 new ValidationCallback<String>() 1530 { 1531 public String validate(ConsoleApplication app, String input) 1532 throws CLIException 1533 { 1534 String ninput = input.trim(); 1535 if (ninput.length() == 0) 1536 { 1537 app.println(); 1538 app.println(ERR_LDAP_CONN_PROMPT_SECURITY_INVALID_FILE_PATH 1539 .get()); 1540 app.println(); 1541 return null; 1542 } 1543 File f = new File(ninput); 1544 if (!f.isDirectory()) 1545 { 1546 return ninput; 1547 } 1548 else 1549 { 1550 app.println(); 1551 app.println(ERR_LDAP_CONN_PROMPT_SECURITY_INVALID_FILE_PATH 1552 .get()); 1553 app.println(); 1554 return null; 1555 } 1556 } 1557 }; 1558 1559 String truststorePath; 1560 try 1561 { 1562 app.println(); 1563 truststorePath = app.readValidatedInput( 1564 INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE_PATH.get(), 1565 callback); 1566 } 1567 catch (CLIException e) 1568 { 1569 return true; 1570 } 1571 1572 // Read the password from the stdin. 1573 String truststorePassword; 1574 try 1575 { 1576 app.println(); 1577 Message prompt = INFO_LDAP_CONN_PROMPT_SECURITY_KEYSTORE_PASSWORD 1578 .get(truststorePath); 1579 truststorePassword = app.readPassword(prompt); 1580 } 1581 catch (Exception e) 1582 { 1583 return true; 1584 } 1585 try 1586 { 1587 KeyStore ts = KeyStore.getInstance("JKS"); 1588 FileInputStream fis; 1589 try 1590 { 1591 fis = new FileInputStream(truststorePath); 1592 } 1593 catch (FileNotFoundException e) 1594 { 1595 fis = null; 1596 } 1597 ts.load(fis, truststorePassword.toCharArray()); 1598 if (fis != null) 1599 { 1600 fis.close(); 1601 } 1602 for (int i = 0; i < chain.length; i++) 1603 { 1604 String alias = chain[i].getSubjectDN().getName(); 1605 ts.setCertificateEntry(alias, chain[i]); 1606 } 1607 FileOutputStream fos = new FileOutputStream(truststorePath); 1608 ts.store(fos, truststorePassword.toCharArray()); 1609 if (fos != null) 1610 { 1611 fos.close(); 1612 } 1613 } 1614 catch (Exception e) 1615 { 1616 return true; 1617 } 1618 } 1619 return true; 1620 } 1621 else 1622 { 1623 // Should never happen. 1624 throw new RuntimeException(); 1625 } 1626 } 1627 catch (CLIException cliE) 1628 { 1629 throw new RuntimeException(cliE); 1630 } 1631 } 1632 } 1633 1634 /** 1635 * Populates a set of LDAP options with state from this interaction. 1636 * 1637 * @param options existing set of options; may be null in which case this 1638 * method will create a new set of <code>LDAPConnectionOptions</code> 1639 * to be returned 1640 * @return used during this interaction 1641 * @throws SSLConnectionException if this interaction has specified the use 1642 * of SSL and there is a problem initializing the SSL connection 1643 * factory 1644 */ 1645 public LDAPConnectionOptions populateLDAPOptions( 1646 LDAPConnectionOptions options) 1647 throws SSLConnectionException 1648 { 1649 if (options == null) { 1650 options = new LDAPConnectionOptions(); 1651 } 1652 if (this.useSSL) { 1653 options.setUseSSL(true); 1654 SSLConnectionFactory sslConnectionFactory = new SSLConnectionFactory(); 1655 sslConnectionFactory.init(getTrustManager() == null, keystorePath, 1656 keystorePassword, certifNickname, 1657 truststorePath, truststorePassword); 1658 options.setSSLConnectionFactory(sslConnectionFactory); 1659 } else { 1660 options.setUseSSL(false); 1661 } 1662 options.setStartTLS(this.useStartTLS); 1663 return options; 1664 } 1665 1666 /** 1667 * Prompts the user to accept the certificate. 1668 * @param t the throwable that was generated because the certificate was 1669 * not trusted. 1670 * @param usedTrustManager the trustManager used when trying to establish the 1671 * connection. 1672 * @param usedUrl the LDAP URL used to connect to the server. 1673 * @param displayErrorMessage whether to display an error message before 1674 * asking to accept the certificate or not. 1675 * @param logger the Logger used to log messages. 1676 * @return <CODE>true</CODE> if the user accepted the certificate and 1677 * <CODE>false</CODE> otherwise. 1678 */ 1679 public boolean promptForCertificateConfirmation(Throwable t, 1680 ApplicationTrustManager usedTrustManager, String usedUrl, 1681 boolean displayErrorMessage, Logger logger) 1682 { 1683 boolean returnValue = false; 1684 ApplicationTrustManager.Cause cause; 1685 if (usedTrustManager != null) 1686 { 1687 cause = usedTrustManager.getLastRefusedCause(); 1688 } 1689 else 1690 { 1691 cause = null; 1692 } 1693 if (logger != null) 1694 { 1695 logger.log(Level.INFO, "Certificate exception cause: "+cause); 1696 } 1697 UserDataCertificateException.Type excType = null; 1698 if (cause == ApplicationTrustManager.Cause.NOT_TRUSTED) 1699 { 1700 excType = UserDataCertificateException.Type.NOT_TRUSTED; 1701 } 1702 else if (cause == 1703 ApplicationTrustManager.Cause.HOST_NAME_MISMATCH) 1704 { 1705 excType = UserDataCertificateException.Type.HOST_NAME_MISMATCH; 1706 } 1707 else 1708 { 1709 Message msg = Utils.getThrowableMsg(INFO_ERROR_CONNECTING_TO_LOCAL.get(), 1710 t); 1711 app.println(msg); 1712 } 1713 1714 if (excType != null) 1715 { 1716 String h; 1717 int p; 1718 try 1719 { 1720 URI uri = new URI(usedUrl); 1721 h = uri.getHost(); 1722 p = uri.getPort(); 1723 } 1724 catch (Throwable t1) 1725 { 1726 if (logger != null) 1727 { 1728 logger.log(Level.WARNING, "Error parsing ldap url of ldap url.", t1); 1729 } 1730 h = INFO_NOT_AVAILABLE_LABEL.get().toString(); 1731 p = -1; 1732 } 1733 1734 1735 1736 UserDataCertificateException udce = 1737 new UserDataCertificateException(Step.REPLICATION_OPTIONS, 1738 INFO_CERTIFICATE_EXCEPTION.get(h, String.valueOf(p)), t, h, p, 1739 usedTrustManager.getLastRefusedChain(), 1740 usedTrustManager.getLastRefusedAuthType(), excType); 1741 1742 Message msg; 1743 if (udce.getType() == UserDataCertificateException.Type.NOT_TRUSTED) 1744 { 1745 msg = INFO_CERTIFICATE_NOT_TRUSTED_TEXT_CLI.get( 1746 udce.getHost(), String.valueOf(udce.getPort())); 1747 } 1748 else 1749 { 1750 msg = INFO_CERTIFICATE_NAME_MISMATCH_TEXT_CLI.get( 1751 udce.getHost(), String.valueOf(udce.getPort()), 1752 udce.getHost(), 1753 udce.getHost(), String.valueOf(udce.getPort())); 1754 } 1755 if (displayErrorMessage) 1756 { 1757 app.println(msg); 1758 } 1759 X509Certificate[] chain = udce.getChain(); 1760 String authType = udce.getAuthType(); 1761 String host = udce.getHost(); 1762 if (logger != null) 1763 { 1764 if (chain == null) 1765 { 1766 logger.log(Level.WARNING, 1767 "The chain is null for the UserDataCertificateException"); 1768 } 1769 if (authType == null) 1770 { 1771 logger.log(Level.WARNING, 1772 "The auth type is null for the UserDataCertificateException"); 1773 } 1774 if (host == null) 1775 { 1776 logger.log(Level.WARNING, 1777 "The host is null for the UserDataCertificateException"); 1778 } 1779 } 1780 if (chain != null) 1781 { 1782 returnValue = checkServerCertificate(chain, authType, host); 1783 } 1784 } 1785 return returnValue; 1786 } 1787 1788 /** 1789 * Sets the heading that is displayed in interactive mode. 1790 * @param heading the heading that is displayed in interactive mode. 1791 */ 1792 public void setHeadingMessage(Message heading) 1793 { 1794 this.heading = heading; 1795 } 1796 1797 /** 1798 * Returns the command builder with the equivalent arguments on the 1799 * non-interactive mode. 1800 * @return the command builder with the equivalent arguments on the 1801 * non-interactive mode. 1802 */ 1803 public CommandBuilder getCommandBuilder() 1804 { 1805 return commandBuilder; 1806 } 1807 1808 /** 1809 * Displays the heading if it was not displayed before. 1810 * 1811 */ 1812 private void checkHeadingDisplayed() 1813 { 1814 if (!isHeadingDisplayed) 1815 { 1816 app.println(); 1817 app.println(); 1818 app.println(heading); 1819 isHeadingDisplayed = true; 1820 } 1821 } 1822 1823 /** 1824 * Tells whether during interaction we can ask for both the DN or the admin 1825 * UID. 1826 * @return <CODE>true</CODE> if during interaction we can ask for both the DN 1827 * and the admin UID and <CODE>false</CODE> otherwise. 1828 */ 1829 public boolean isUseAdminOrBindDn() 1830 { 1831 return useAdminOrBindDn; 1832 } 1833 1834 /** 1835 * Tells whether we can ask during interaction for both the DN and the admin 1836 * UID or not. 1837 * @param useAdminOrBindDn whether we can ask for both the DN and the admin UID 1838 * during interaction or not. 1839 */ 1840 public void setUseAdminOrBindDn(boolean useAdminOrBindDn) 1841 { 1842 this.useAdminOrBindDn = useAdminOrBindDn; 1843 } 1844 1845 /** 1846 * Tells whether we propose LDAP as protocol even if the user provided security 1847 * parameters. This is required in command-lines that access multiple servers 1848 * (like dsreplication). 1849 * @param displayLdapIfSecureParameters whether propose LDAP as protocol even 1850 * if the user provided security parameters or not. 1851 */ 1852 public void setDisplayLdapIfSecureParameters( 1853 boolean displayLdapIfSecureParameters) 1854 { 1855 this.displayLdapIfSecureParameters = displayLdapIfSecureParameters; 1856 } 1857 1858 /** 1859 * Resets the heading displayed flag, so that next time we call run the heading 1860 * is displayed. 1861 */ 1862 public void resetHeadingDisplayed() 1863 { 1864 isHeadingDisplayed = false; 1865 } 1866 1867 /** 1868 * Forces the initialization of the trust manager with the arguments provided 1869 * by the user. 1870 * @throws ArgumentException if there is an error with the arguments provided 1871 * by the user. 1872 */ 1873 public void initializeTrustManagerIfRequired() throws ArgumentException 1874 { 1875 if (!trustManagerInitialized) 1876 { 1877 initializeTrustManager(); 1878 } 1879 } 1880 1881 private void initializeTrustManager() throws ArgumentException 1882 { 1883 // Get truststore info 1884 trustManager = getTrustManagerInternal(); 1885 1886 // Check if we need client side authentication 1887 keyManager = getKeyManagerInternal(); 1888 1889 trustManagerInitialized = true; 1890 } 1891 /** 1892 * Returns the explicitly provided Admin UID from the user (interactively 1893 * or through the argument). 1894 * @return the explicitly provided Admin UID from the user (interactively 1895 * or through the argument). 1896 */ 1897 public String getProvidedAdminUID() 1898 { 1899 return providedAdminUID; 1900 } 1901 1902 /** 1903 * Returns the explicitly provided bind DN from the user (interactively 1904 * or through the argument). 1905 * @return the explicitly provided bind DN from the user (interactively 1906 * or through the argument). 1907 */ 1908 public String getProvidedBindDN() 1909 { 1910 return providedBindDN; 1911 } 1912 }