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 }