001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2011-2016 ForgeRock AS. 016 */ 017package org.opends.quicksetup.util; 018 019import static com.forgerock.opendj.cli.Utils.*; 020import static com.forgerock.opendj.util.OperatingSystem.*; 021 022import static org.forgerock.util.Utils.*; 023import static org.opends.admin.ads.util.ConnectionUtils.*; 024import static org.opends.messages.QuickSetupMessages.*; 025import static org.opends.quicksetup.Installation.*; 026import static org.opends.server.util.DynamicConstants.*; 027 028import java.io.BufferedOutputStream; 029import java.io.BufferedReader; 030import java.io.ByteArrayOutputStream; 031import java.io.File; 032import java.io.FileOutputStream; 033import java.io.FileReader; 034import java.io.FileWriter; 035import java.io.IOException; 036import java.io.InputStream; 037import java.io.InputStreamReader; 038import java.io.PrintStream; 039import java.io.PrintWriter; 040import java.io.RandomAccessFile; 041import java.net.InetAddress; 042import java.text.SimpleDateFormat; 043import java.util.ArrayList; 044import java.util.Collection; 045import java.util.HashMap; 046import java.util.Hashtable; 047import java.util.LinkedHashSet; 048import java.util.List; 049import java.util.Locale; 050import java.util.Map; 051import java.util.Set; 052import java.util.TimeZone; 053 054import javax.naming.AuthenticationException; 055import javax.naming.CommunicationException; 056import javax.naming.NamingEnumeration; 057import javax.naming.NamingException; 058import javax.naming.NamingSecurityException; 059import javax.naming.NoPermissionException; 060import javax.naming.directory.SearchControls; 061import javax.naming.directory.SearchResult; 062import javax.naming.ldap.InitialLdapContext; 063import javax.naming.ldap.LdapName; 064import javax.net.ssl.HostnameVerifier; 065import javax.net.ssl.TrustManager; 066 067import org.forgerock.i18n.LocalizableMessage; 068import org.forgerock.i18n.LocalizableMessageBuilder; 069import org.forgerock.i18n.slf4j.LocalizedLogger; 070import org.forgerock.opendj.config.ManagedObjectDefinition; 071import org.forgerock.opendj.server.config.client.BackendCfgClient; 072import org.forgerock.opendj.server.config.server.BackendCfg; 073import org.opends.admin.ads.ADSContext; 074import org.opends.admin.ads.ReplicaDescriptor; 075import org.opends.admin.ads.ServerDescriptor; 076import org.opends.admin.ads.SuffixDescriptor; 077import org.opends.admin.ads.TopologyCacheException; 078import org.opends.admin.ads.util.ConnectionUtils; 079import org.opends.quicksetup.Constants; 080import org.opends.quicksetup.Installation; 081import org.opends.quicksetup.SecurityOptions; 082import org.opends.quicksetup.UserData; 083import org.opends.quicksetup.installer.AuthenticationData; 084import org.opends.quicksetup.installer.DataReplicationOptions; 085import org.opends.quicksetup.installer.NewSuffixOptions; 086import org.opends.quicksetup.installer.SuffixesToReplicateOptions; 087import org.opends.quicksetup.ui.UIFactory; 088import org.opends.server.tools.BackendTypeHelper; 089import org.opends.server.util.SetupUtils; 090import org.opends.server.util.StaticUtils; 091 092import com.forgerock.opendj.cli.ArgumentConstants; 093import com.forgerock.opendj.cli.ClientException; 094 095/** This class provides some static convenience methods of different nature. */ 096public class Utils 097{ 098 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 099 100 private Utils() {} 101 102 private static final int BUFFER_SIZE = 1024; 103 private static final int MAX_LINE_WIDTH = 80; 104 105 /** Chars that require special treatment when passing them to command-line. */ 106 private static final char[] CHARS_TO_ESCAPE = 107 { ' ', '\t', '\n', '|', ';', '<', '>', '(', ')', '$', '`', '\\', '"', '\'' }; 108 109 /** The class name that contains the control panel customizations for products. */ 110 private static final String CUSTOMIZATION_CLASS_NAME = "org.opends.server.util.ReleaseDefinition"; 111 112 /** 113 * Returns <CODE>true</CODE> if the provided port is free and we can use it, 114 * <CODE>false</CODE> otherwise. 115 * 116 * @param port 117 * the port we are analyzing. 118 * @return <CODE>true</CODE> if the provided port is free and we can use it, 119 * <CODE>false</CODE> otherwise. 120 */ 121 public static boolean canUseAsPort(int port) 122 { 123 return SetupUtils.canUseAsPort(port); 124 } 125 126 /** 127 * Returns <CODE>true</CODE> if the provided port is a privileged port, 128 * <CODE>false</CODE> otherwise. 129 * 130 * @param port 131 * the port we are analyzing. 132 * @return <CODE>true</CODE> if the provided port is a privileged port, 133 * <CODE>false</CODE> otherwise. 134 */ 135 public static boolean isPrivilegedPort(int port) 136 { 137 return SetupUtils.isPrivilegedPort(port); 138 } 139 140 /** 141 * Tells whether the provided java installation supports a given option or 142 * not. 143 * 144 * @param javaHome 145 * the java installation path. 146 * @param option 147 * the java option that we want to check. 148 * @param installPath 149 * the install path of the server. 150 * @return <CODE>true</CODE> if the provided java installation supports a 151 * given option and <CODE>false</CODE> otherwise. 152 */ 153 public static boolean supportsOption(String option, String javaHome, String installPath) 154 { 155 boolean supported = false; 156 logger.info(LocalizableMessage.raw("Checking if options " + option + " are supported with java home: " + javaHome)); 157 try 158 { 159 List<String> args = new ArrayList<>(); 160 args.add(getScript(installPath)); 161 162 ProcessBuilder pb = new ProcessBuilder(args); 163 Map<String, String> env = pb.environment(); 164 env.put(SetupUtils.OPENDJ_JAVA_HOME, javaHome); 165 env.put("OPENDJ_JAVA_ARGS", option); 166 env.put("SCRIPT_UTIL_CMD", "set-full-environment-and-test-java"); 167 env.remove("OPENDJ_JAVA_BIN"); 168 // In windows by default the scripts ask the user to click on enter when 169 // they fail. Set this environment variable to avoid it. 170 if (isWindows()) 171 { 172 env.put("DO_NOT_PAUSE", "true"); 173 } 174 final Process process = pb.start(); 175 logger.info(LocalizableMessage.raw("launching " + args + " with env: " + env)); 176 InputStream is = process.getInputStream(); 177 BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 178 String line; 179 boolean errorDetected = false; 180 while (null != (line = reader.readLine())) 181 { 182 logger.info(LocalizableMessage.raw("The output: " + line)); 183 if (line.contains("ERROR: The detected Java version")) 184 { 185 if (isWindows()) 186 { 187 // If we are running windows, the process get blocked waiting for 188 // user input. Just wait for a certain time to print the output 189 // in the logger and then kill the process. 190 Thread t = new Thread(new Runnable() 191 { 192 @Override 193 public void run() 194 { 195 try 196 { 197 Thread.sleep(3000); 198 // To see if the process is over, call the exitValue method. 199 // If it is not over, a IllegalThreadStateException. 200 process.exitValue(); 201 } 202 catch (Throwable t) 203 { 204 process.destroy(); 205 } 206 } 207 }); 208 t.start(); 209 } 210 errorDetected = true; 211 } 212 } 213 process.waitFor(); 214 int returnCode = process.exitValue(); 215 logger.info(LocalizableMessage.raw("returnCode: " + returnCode)); 216 supported = returnCode == 0 && !errorDetected; 217 logger.info(LocalizableMessage.raw("supported: " + supported)); 218 } 219 catch (Throwable t) 220 { 221 logger.warn(LocalizableMessage.raw("Error testing option " + option + " on " + javaHome, t)); 222 } 223 return supported; 224 } 225 226 private static String getScript(String installPath) 227 { 228 String libPath = Utils.getPath(installPath, Installation.LIBRARIES_PATH_RELATIVE); 229 String scriptUtilFileUnix = isWindows() ? SCRIPT_UTIL_FILE_WINDOWS : SCRIPT_UTIL_FILE_UNIX; 230 return Utils.getScriptPath(Utils.getPath(libPath, scriptUtilFileUnix)); 231 } 232 233 /** 234 * Creates a new file attempting to create the parent directories if necessary. 235 * 236 * @param f 237 * File to create 238 * @return boolean indicating whether the file was created; false otherwise 239 * @throws IOException 240 * if something goes wrong 241 */ 242 public static boolean createFile(File f) throws IOException 243 { 244 if (f != null) 245 { 246 File parent = f.getParentFile(); 247 if (!parent.exists()) 248 { 249 parent.mkdirs(); 250 } 251 return f.createNewFile(); 252 } 253 return false; 254 } 255 256 /** 257 * Returns the absolute path for the given parentPath and relativePath. 258 * 259 * @param parentPath 260 * the parent path. 261 * @param relativePath 262 * the relative path. 263 * @return the absolute path for the given parentPath and relativePath. 264 */ 265 public static String getPath(String parentPath, String relativePath) 266 { 267 return getPath(new File(new File(parentPath), relativePath)); 268 } 269 270 /** 271 * Returns the String that can be used to launch an script using Runtime.exec. 272 * This method is required because in Windows the script that contain a "=" in 273 * their path must be quoted. 274 * 275 * @param script 276 * the script name 277 * @return the absolute path for the given parentPath and relativePath. 278 */ 279 public static String getScriptPath(String script) 280 { 281 return SetupUtils.getScriptPath(script); 282 } 283 284 /** 285 * Returns the absolute path for the given file. It tries to get the canonical 286 * file path. If it fails it returns the string representation. 287 * 288 * @param f 289 * File to get the path 290 * @return the absolute path for the given file. 291 */ 292 public static String getPath(File f) 293 { 294 if (f != null) 295 { 296 try 297 { 298 /* 299 * Do a best effort to avoid having a relative representation (for 300 * instance to avoid having ../../../). 301 */ 302 f = f.getCanonicalFile(); 303 } 304 catch (IOException ioe) 305 { 306 /* 307 * This is a best effort to get the best possible representation of the 308 * file: reporting the error is not necessary. 309 */ 310 } 311 return f.toString(); 312 } 313 return null; 314 } 315 316 /** 317 * Returns <CODE>true</CODE> if the first provided path is under the second 318 * path in the file system. 319 * 320 * @param descendant 321 * the descendant candidate path. 322 * @param path 323 * the path. 324 * @return <CODE>true</CODE> if the first provided path is under the second 325 * path in the file system; <code>false</code> otherwise or if either 326 * of the files are null 327 */ 328 public static boolean isDescendant(File descendant, File path) 329 { 330 boolean isDescendant = false; 331 if (descendant != null && path != null) 332 { 333 File parent = descendant.getParentFile(); 334 while (parent != null && !isDescendant) 335 { 336 isDescendant = path.equals(parent); 337 if (!isDescendant) 338 { 339 parent = parent.getParentFile(); 340 } 341 } 342 } 343 return isDescendant; 344 } 345 346 /** 347 * Returns <CODE>true</CODE> if the parent directory for the provided path 348 * exists and <CODE>false</CODE> otherwise. 349 * 350 * @param path 351 * the path that we are analyzing. 352 * @return <CODE>true</CODE> if the parent directory for the provided path 353 * exists and <CODE>false</CODE> otherwise. 354 */ 355 public static boolean parentDirectoryExists(String path) 356 { 357 File f = new File(path); 358 File parentFile = f.getParentFile(); 359 return parentFile != null && parentFile.isDirectory(); 360 } 361 362 /** 363 * Returns <CODE>true</CODE> if the the provided path is a file and exists and 364 * <CODE>false</CODE> otherwise. 365 * 366 * @param path 367 * the path that we are analyzing. 368 * @return <CODE>true</CODE> if the the provided path is a file and exists and 369 * <CODE>false</CODE> otherwise. 370 */ 371 public static boolean fileExists(String path) 372 { 373 return new File(path).isFile(); 374 } 375 376 /** 377 * Returns <CODE>true</CODE> if the the provided path is a directory, exists 378 * and is not empty <CODE>false</CODE> otherwise. 379 * 380 * @param path 381 * the path that we are analyzing. 382 * @return <CODE>true</CODE> if the the provided path is a directory, exists 383 * and is not empty <CODE>false</CODE> otherwise. 384 */ 385 public static boolean directoryExistsAndIsNotEmpty(String path) 386 { 387 final File f = new File(path); 388 if (f.isDirectory()) 389 { 390 final String[] ch = f.list(); 391 return ch != null && ch.length > 0; 392 } 393 return false; 394 } 395 396 /** 397 * Returns <CODE>true</CODE> if the the provided string is a configuration DN 398 * and <CODE>false</CODE> otherwise. 399 * 400 * @param dn 401 * the String we are analyzing. 402 * @return <CODE>true</CODE> if the the provided string is a configuration DN 403 * and <CODE>false</CODE> otherwise. 404 */ 405 public static boolean isConfigurationDn(String dn) 406 { 407 boolean isConfigurationDn = false; 408 String[] configDns = { "cn=config", Constants.SCHEMA_DN }; 409 for (int i = 0; i < configDns.length && !isConfigurationDn; i++) 410 { 411 isConfigurationDn = areDnsEqual(dn, configDns[i]); 412 } 413 return isConfigurationDn; 414 } 415 416 /** 417 * Returns <CODE>true</CODE> if the the provided strings represent the same DN 418 * and <CODE>false</CODE> otherwise. 419 * 420 * @param dn1 421 * the first dn to compare. 422 * @param dn2 423 * the second dn to compare. 424 * @return <CODE>true</CODE> if the the provided strings represent the same DN 425 * and <CODE>false</CODE> otherwise. 426 */ 427 public static boolean areDnsEqual(String dn1, String dn2) 428 { 429 try 430 { 431 LdapName name1 = new LdapName(dn1); 432 LdapName name2 = new LdapName(dn2); 433 return name1.equals(name2); 434 } 435 catch (Exception ex) 436 { 437 return false; 438 } 439 } 440 441 /** 442 * Creates the parent directory if it does not already exist. 443 * 444 * @param f 445 * File for which parentage will be insured 446 * @return boolean indicating whether or not the input <code>f</code> has a 447 * parent after this method is invoked. 448 */ 449 public static boolean ensureParentsExist(File f) 450 { 451 final File parent = f.getParentFile(); 452 return parent.exists() || parent.mkdirs(); 453 } 454 455 /** 456 * Creates the a directory in the provided path. 457 * 458 * @param path 459 * the path. 460 * @return <CODE>true</CODE> if the path was created or already existed (and 461 * was a directory) and <CODE>false</CODE> otherwise. 462 * @throws IOException 463 * if something goes wrong. 464 */ 465 public static boolean createDirectory(String path) throws IOException 466 { 467 return createDirectory(new File(path)); 468 } 469 470 /** 471 * Creates the a directory in the provided path. 472 * 473 * @param f 474 * the path. 475 * @return <CODE>true</CODE> if the path was created or already existed (and 476 * was a directory) and <CODE>false</CODE> otherwise. 477 * @throws IOException 478 * if something goes wrong. 479 */ 480 public static boolean createDirectory(File f) throws IOException 481 { 482 if (f.exists()) 483 { 484 return f.isDirectory(); 485 } 486 return f.mkdirs(); 487 } 488 489 /** 490 * Creates a file on the specified path with the contents of the provided 491 * stream. 492 * 493 * @param path 494 * the path where the file will be created. 495 * @param is 496 * the InputStream with the contents of the file. 497 * @throws IOException 498 * if something goes wrong. 499 */ 500 public static void createFile(File path, InputStream is) throws IOException 501 { 502 FileOutputStream out; 503 BufferedOutputStream dest; 504 byte[] data = new byte[BUFFER_SIZE]; 505 int count; 506 507 out = new FileOutputStream(path); 508 509 dest = new BufferedOutputStream(out); 510 511 while ((count = is.read(data, 0, BUFFER_SIZE)) != -1) 512 { 513 dest.write(data, 0, count); 514 } 515 dest.flush(); 516 dest.close(); 517 } 518 519 /** 520 * Creates a file on the specified path with the contents of the provided 521 * String. The file is protected, so that 'others' have no access to it. 522 * 523 * @param path 524 * the path where the file will be created. 525 * @param content 526 * the String with the contents of the file. 527 * @throws IOException 528 * if something goes wrong. 529 * @throws InterruptedException 530 * if there is a problem changing the permissions of the file. 531 */ 532 public static void createProtectedFile(String path, String content) throws IOException, InterruptedException 533 { 534 FileWriter file = new FileWriter(path); 535 PrintWriter out = new PrintWriter(file); 536 537 out.println(content); 538 539 out.flush(); 540 out.close(); 541 542 if (!isWindows()) 543 { 544 setPermissionsUnix(path, "600"); 545 } 546 } 547 548 /** 549 * This is a helper method that gets a LocalizableMessage representation of 550 * the elements in the Collection of Messages. The LocalizableMessage will 551 * display the different elements separated by the separator String. 552 * 553 * @param col 554 * the collection containing the messages. 555 * @param separator 556 * the separator String to be used. 557 * @return the message representation for the collection; null if 558 * <code>col</code> is null 559 */ 560 public static LocalizableMessage getMessageFromCollection(Collection<LocalizableMessage> col, String separator) 561 { 562 if (col != null) 563 { 564 final LocalizableMessageBuilder mb = new LocalizableMessageBuilder(); 565 for (LocalizableMessage m : col) 566 { 567 mb.append(separator).append(m); 568 } 569 return mb.toMessage(); 570 } 571 return null; 572 } 573 574 /** 575 * Returns the default server location that will be proposed to the user in 576 * the installation. 577 * 578 * @return the default server location that will be proposed to the user in 579 * the installation. 580 */ 581 public static String getDefaultServerLocation() 582 { 583 String userDir = System.getProperty("user.home"); 584 String firstLocation = userDir + File.separator + SHORT_NAME.toLowerCase(Locale.ENGLISH); 585 String serverLocation = firstLocation; 586 int i = 1; 587 while (fileExists(serverLocation) || directoryExistsAndIsNotEmpty(serverLocation)) 588 { 589 serverLocation = firstLocation + "-" + i; 590 i++; 591 } 592 return serverLocation; 593 } 594 595 /** 596 * Returns <CODE>true</CODE> if there is more disk space in the provided path 597 * than what is specified with the bytes parameter. 598 * 599 * @param directoryPath 600 * the path. 601 * @param bytes 602 * the disk space. 603 * @return <CODE>true</CODE> if there is more disk space in the provided path 604 * than what is specified with the bytes parameter. 605 */ 606 public static synchronized boolean hasEnoughSpace(String directoryPath, long bytes) 607 { 608 // TODO This does not work with quotas etc. but at least it seems that 609 // we do not write all data on disk if it fails. 610 boolean hasEnoughSpace = false; 611 File file = null; 612 RandomAccessFile raf = null; 613 File directory = new File(directoryPath); 614 boolean deleteDirectory = false; 615 if (!directory.exists()) 616 { 617 deleteDirectory = directory.mkdir(); 618 } 619 620 try 621 { 622 file = File.createTempFile("temp" + System.nanoTime(), ".tmp", directory); 623 raf = new RandomAccessFile(file, "rw"); 624 raf.setLength(bytes); 625 hasEnoughSpace = true; 626 } 627 catch (IOException ex) 628 { /* do nothing */ 629 } 630 finally 631 { 632 StaticUtils.close(raf); 633 if (file != null) 634 { 635 file.delete(); 636 } 637 } 638 639 if (deleteDirectory) 640 { 641 directory.delete(); 642 } 643 644 return hasEnoughSpace; 645 } 646 647 /** 648 * Gets a localized representation of the provide TopologyCacheException. 649 * 650 * @param te 651 * the exception. 652 * @return a localized representation of the provide TopologyCacheException. 653 */ 654 public static LocalizableMessage getMessage(TopologyCacheException te) 655 { 656 LocalizableMessageBuilder buf = new LocalizableMessageBuilder(); 657 658 String ldapUrl = te.getLdapUrl(); 659 if (ldapUrl != null) 660 { 661 String hostName = ldapUrl.substring(ldapUrl.indexOf("://") + 3); 662 buf.append(INFO_SERVER_ERROR.get(hostName)); 663 buf.append(" "); 664 } 665 if (te.getType() == TopologyCacheException.Type.TIMEOUT) 666 { 667 buf.append(INFO_ERROR_CONNECTING_TIMEOUT.get()); 668 } 669 else if (te.getCause() instanceof NamingException) 670 { 671 buf.append(getThrowableMsg(INFO_ERROR_CONNECTING_TO_LOCAL.get(), te.getCause())); 672 } 673 else 674 { 675 logger.warn(LocalizableMessage.raw("Unexpected error: " + te, te)); 676 // This is unexpected. 677 if (te.getCause() != null) 678 { 679 buf.append(getThrowableMsg(INFO_BUG_MSG.get(), te.getCause())); 680 } 681 else 682 { 683 buf.append(getThrowableMsg(INFO_BUG_MSG.get(), te)); 684 } 685 } 686 return buf.toMessage(); 687 } 688 689 /** 690 * Sets the permissions of the provided paths with the provided permission 691 * String. 692 * 693 * @param paths 694 * the paths to set permissions on. 695 * @param permissions 696 * the UNIX-mode file system permission representation (for example 697 * "644" or "755") 698 * @return the return code of the chmod command. 699 * @throws IOException 700 * if something goes wrong. 701 * @throws InterruptedException 702 * if the Runtime.exec method is interrupted. 703 */ 704 public static int setPermissionsUnix(List<String> paths, String permissions) throws IOException, 705 InterruptedException 706 { 707 String[] args = new String[paths.size() + 2]; 708 args[0] = "chmod"; 709 args[1] = permissions; 710 for (int i = 2; i < args.length; i++) 711 { 712 args[i] = paths.get(i - 2); 713 } 714 Process p = Runtime.getRuntime().exec(args); 715 return p.waitFor(); 716 } 717 718 /** 719 * Sets the permissions of the provided paths with the provided permission 720 * String. 721 * 722 * @param path 723 * to set permissions on. 724 * @param permissions 725 * the UNIX-mode file system permission representation (for example 726 * "644" or "755") 727 * @return the return code of the chmod command. 728 * @throws IOException 729 * if something goes wrong. 730 * @throws InterruptedException 731 * if the Runtime.exec method is interrupted. 732 */ 733 public static int setPermissionsUnix(String path, String permissions) throws IOException, InterruptedException 734 { 735 String[] args = new String[] { "chmod", permissions, path }; 736 Process p = Runtime.getRuntime().exec(args); 737 return p.waitFor(); 738 } 739 740 /** 741 * Returns <CODE>true</CODE> if this is executed from command line and 742 * <CODE>false</CODE> otherwise. 743 * 744 * @return <CODE>true</CODE> if this is executed from command line and 745 * <CODE>false</CODE> otherwise. 746 */ 747 public static boolean isCli() 748 { 749 return "true".equals(System.getProperty(Constants.CLI_JAVA_PROPERTY)); 750 } 751 752 /** 753 * Creates an LDAP+StartTLS connection and returns the corresponding 754 * LdapContext. This method first creates an LdapContext with anonymous bind. 755 * Then it requests a StartTlsRequest extended operation. The StartTlsResponse 756 * is setup with the specified hostname verifier. Negotiation is done using a 757 * TrustSocketFactory so that the specified TrustManager gets called during 758 * the SSL handshake. If trust manager is null, certificates are not checked 759 * during SSL handshake. 760 * 761 * @param ldapsURL 762 * the target *LDAPS* URL. 763 * @param dn 764 * passed as Context.SECURITY_PRINCIPAL if not null. 765 * @param pwd 766 * passed as Context.SECURITY_CREDENTIALS if not null. 767 * @param timeout 768 * passed as com.sun.jndi.ldap.connect.timeout if > 0. 769 * @param env 770 * null or additional environment properties. 771 * @param trustManager 772 * null or the trust manager to be invoked during SSL. negociation. 773 * @param verifier 774 * null or the hostname verifier to be setup in the StartTlsResponse. 775 * @return the established connection with the given parameters. 776 * @throws NamingException 777 * the exception thrown when instantiating InitialLdapContext. 778 * @see javax.naming.Context 779 * @see javax.naming.ldap.InitialLdapContext 780 * @see javax.naming.ldap.StartTlsRequest 781 * @see javax.naming.ldap.StartTlsResponse 782 * @see org.opends.admin.ads.util.TrustedSocketFactory 783 */ 784 785 public static InitialLdapContext createStartTLSContext(String ldapsURL, String dn, String pwd, int timeout, 786 Hashtable<String, String> env, TrustManager trustManager, HostnameVerifier verifier) throws NamingException 787 { 788 return ConnectionUtils.createStartTLSContext(ldapsURL, dn, pwd, timeout, env, trustManager, null, verifier); 789 } 790 791 /** 792 * Returns a message object for the given NamingException. The code assume 793 * that we are trying to connect to the local server. 794 * 795 * @param ne 796 * the NamingException. 797 * @return a message object for the given NamingException. 798 */ 799 public static LocalizableMessage getMessageForException(NamingException ne) 800 { 801 final String detailedException = ne.toString(true); 802 if (isCertificateException(ne)) 803 { 804 return INFO_ERROR_READING_CONFIG_LDAP_CERTIFICATE.get(detailedException); 805 } 806 else if (ne instanceof AuthenticationException) 807 { 808 return ERR_CANNOT_CONNECT_TO_LOCAL_AUTHENTICATION.get(detailedException); 809 } 810 else if (ne instanceof NoPermissionException) 811 { 812 return ERR_CANNOT_CONNECT_TO_LOCAL_PERMISSIONS.get(detailedException); 813 } 814 else if (ne instanceof NamingSecurityException) 815 { 816 return ERR_CANNOT_CONNECT_TO_LOCAL_PERMISSIONS.get(detailedException); 817 } 818 else if (ne instanceof CommunicationException) 819 { 820 return ERR_CANNOT_CONNECT_TO_LOCAL_COMMUNICATION.get(detailedException); 821 } 822 else 823 { 824 return ERR_CANNOT_CONNECT_TO_LOCAL_GENERIC.get(detailedException); 825 } 826 } 827 828 /** 829 * Returns the path of the installation of the directory server. Note that 830 * this method assumes that this code is being run locally. 831 * 832 * @return the path of the installation of the directory server. 833 */ 834 public static String getInstallPathFromClasspath() 835 { 836 String installPath = System.getProperty("org.opends.quicksetup.Root"); 837 if (installPath != null) 838 { 839 return installPath; 840 } 841 842 /* Get the install path from the Class Path */ 843 String sep = System.getProperty("path.separator"); 844 String[] classPaths = System.getProperty("java.class.path").split(sep); 845 String path = getInstallPath(classPaths); 846 if (path != null) 847 { 848 File f = new File(path).getAbsoluteFile(); 849 File librariesDir = f.getParentFile(); 850 851 /* 852 * Do a best effort to avoid having a relative representation (for 853 * instance to avoid having ../../../). 854 */ 855 try 856 { 857 installPath = librariesDir.getParentFile().getCanonicalPath(); 858 } 859 catch (IOException ioe) 860 { 861 // Best effort 862 installPath = librariesDir.getParent(); 863 } 864 } 865 return installPath; 866 } 867 868 private static String getInstallPath(final String[] classPaths) 869 { 870 for (String classPath : classPaths) 871 { 872 final String normPath = classPath.replace(File.separatorChar, '/'); 873 if (normPath.endsWith(OPENDJ_BOOTSTRAP_CLIENT_JAR_RELATIVE_PATH) 874 || normPath.endsWith(OPENDJ_BOOTSTRAP_JAR_RELATIVE_PATH)) 875 { 876 return classPath; 877 } 878 } 879 return null; 880 } 881 882 /** 883 * Returns the path of the installation of the directory server. Note that 884 * this method assumes that this code is being run locally. 885 * 886 * @param installPath 887 * The installation path 888 * @return the path of the installation of the directory server. 889 */ 890 public static String getInstancePathFromInstallPath(String installPath) 891 { 892 String instancePathFileName = Installation.INSTANCE_LOCATION_PATH; 893 File _svcScriptPathName = new File( 894 installPath + File.separator + Installation.LIBRARIES_PATH_RELATIVE + File.separator + "_svc-opendj.sh"); 895 896 // look for /etc/opt/opendj/instance.loc 897 File f = new File(instancePathFileName); 898 if (!_svcScriptPathName.exists() || !f.exists()) 899 { 900 // look for <installPath>/instance.loc 901 instancePathFileName = installPath + File.separator + Installation.INSTANCE_LOCATION_PATH_RELATIVE; 902 f = new File(instancePathFileName); 903 if (!f.exists()) 904 { 905 return installPath; 906 } 907 } 908 909 // Read the first line and close the file. 910 try (BufferedReader reader = new BufferedReader(new FileReader(instancePathFileName))) 911 { 912 String line = reader.readLine(); 913 File instanceLoc = new File(line.trim()); 914 if (instanceLoc.isAbsolute()) 915 { 916 return getCanonicalPath(instanceLoc); 917 } 918 else 919 { 920 return getCanonicalPath(new File(installPath + File.separator + instanceLoc.getPath())); 921 } 922 } 923 catch (Exception e) 924 { 925 return installPath; 926 } 927 } 928 929 /** 930 * Returns the max size in character of a line to be displayed in the command 931 * line. 932 * 933 * @return the max size in character of a line to be displayed in the command 934 * line. 935 */ 936 public static int getCommandLineMaxLineWidth() 937 { 938 return MAX_LINE_WIDTH; 939 } 940 941 /** 942 * Puts Swing menus in the Mac OS menu bar, if using the Aqua look and feel, 943 * and sets the application name that is displayed in the application menu and 944 * in the dock. 945 * 946 * @param appName 947 * application name to display in the menu bar and the dock. 948 */ 949 public static void setMacOSXMenuBar(LocalizableMessage appName) 950 { 951 System.setProperty("apple.laf.useScreenMenuBar", "true"); 952 System.setProperty("com.apple.mrj.application.apple.menu.about.name", String.valueOf(appName)); 953 } 954 955 /** 956 * Returns the number of entries contained in the zip file. This is used to 957 * update properly the progress bar ratio. 958 * 959 * @return the number of entries contained in the zip file. 960 */ 961 public static int getNumberZipEntries() 962 { 963 // TODO we should get this dynamically during build 964 return 165; 965 } 966 967 /** 968 * Creates a string consisting of the string representation of the elements in 969 * the <code>list</code> separated by <code>separator</code>. 970 * 971 * @param list 972 * the list to print 973 * @param separator 974 * to use in separating elements 975 * @param prefix 976 * prepended to each individual element in the list before adding to 977 * the returned string. 978 * @param suffix 979 * appended to each individual element in the list before adding to 980 * the returned string. 981 * @return String representing the list 982 */ 983 public static String listToString(List<?> list, String separator, String prefix, String suffix) 984 { 985 StringBuilder sb = new StringBuilder(); 986 for (int i = 0; i < list.size(); i++) 987 { 988 if (prefix != null) 989 { 990 sb.append(prefix); 991 } 992 sb.append(list.get(i)); 993 if (suffix != null) 994 { 995 sb.append(suffix); 996 } 997 if (i < list.size() - 1) 998 { 999 sb.append(separator); 1000 } 1001 } 1002 return sb.toString(); 1003 } 1004 1005 /** 1006 * Returns the file system permissions for a file. 1007 * 1008 * @param file 1009 * the file for which we want the file permissions. 1010 * @return the file system permissions for the file. 1011 */ 1012 public static String getFileSystemPermissions(File file) 1013 { 1014 String name = file.getName(); 1015 if (file.getParent().endsWith(File.separator + Installation.WINDOWS_BINARIES_PATH_RELATIVE) 1016 || file.getParent().endsWith(File.separator + Installation.UNIX_BINARIES_PATH_RELATIVE)) 1017 { 1018 return name.endsWith(".bat") ? "644" : "755"; 1019 } 1020 else if (name.endsWith(".sh") 1021 || name.endsWith(Installation.UNIX_SETUP_FILE_NAME) 1022 || name.endsWith(Installation.UNIX_UNINSTALL_FILE_NAME) 1023 || name.endsWith(Installation.UNIX_UPGRADE_FILE_NAME) 1024 || name.endsWith(Installation.MAC_JAVA_APP_STUB_NAME)) 1025 { 1026 return "755"; 1027 } 1028 else 1029 { 1030 return "644"; 1031 } 1032 } 1033 1034 /** 1035 * Inserts HTML break tags into <code>d</code> breaking it up so that ideally 1036 * no line is longer than <code>maxll</code> assuming no single word is longer 1037 * then <code>maxll</code>. If the string already contains HTML tags that 1038 * cause a line break (e.g break and closing list item tags) they are 1039 * respected by this method when calculating where to place new breaks to 1040 * control the maximum line length. 1041 * 1042 * @param cs 1043 * String to break 1044 * @param maxll 1045 * int maximum line length 1046 * @return String representing <code>d</code> with HTML break tags inserted 1047 */ 1048 public static String breakHtmlString(CharSequence cs, int maxll) 1049 { 1050 if (cs != null) 1051 { 1052 String d = cs.toString(); 1053 int len = d.length(); 1054 if (len <= 0) 1055 { 1056 return d; 1057 } 1058 if (len > maxll) 1059 { 1060 // First see if there are any tags that would cause a 1061 // natural break in the line. If so start line break 1062 // point evaluation from that point. 1063 for (String tag : Constants.BREAKING_TAGS) 1064 { 1065 int p = d.lastIndexOf(tag, maxll); 1066 if (p > 0 && p < len) 1067 { 1068 return d.substring(0, p + tag.length()) + breakHtmlString(d.substring(p + tag.length()), maxll); 1069 } 1070 } 1071 1072 // Now look for spaces in which to insert a break. 1073 // First see if there are any spaces counting backward 1074 // from the max line length. If there aren't any, then 1075 // use the first space encountered after the max line 1076 // length. 1077 int p = d.lastIndexOf(' ', maxll); 1078 if (p <= 0) 1079 { 1080 p = d.indexOf(' ', maxll); 1081 } 1082 if (p > 0 && p < len) 1083 { 1084 return d.substring(0, p) + Constants.HTML_LINE_BREAK + breakHtmlString(d.substring(p + 1), maxll); 1085 } 1086 else 1087 { 1088 return d; 1089 } 1090 } 1091 else 1092 { 1093 return d; 1094 } 1095 } 1096 else 1097 { 1098 return null; 1099 } 1100 } 1101 1102 /** 1103 * Converts existing HTML break tags to native line separators. 1104 * 1105 * @param s 1106 * string to convert 1107 * @return converted string 1108 */ 1109 public static String convertHtmlBreakToLineSeparator(String s) 1110 { 1111 return s.replaceAll("<br>", Constants.LINE_SEPARATOR); 1112 } 1113 1114 /** 1115 * Strips any potential HTML markup from a given string. 1116 * 1117 * @param s 1118 * string to strip 1119 * @return resulting string 1120 */ 1121 public static String stripHtml(String s) 1122 { 1123 if (s != null) 1124 { 1125 // This is not a comprehensive solution but addresses the few tags 1126 // that we have in Resources.properties at the moment. 1127 // Note that the following might strip out more than is intended for non-tags 1128 // like '<your name here>' or for funky tags like '<tag attr="1 > 0">'. 1129 // See test class for cases that might cause problems. 1130 return s.replaceAll("<.*?>", ""); 1131 } 1132 return null; 1133 } 1134 1135 /** 1136 * Tests a text string to see if it contains HTML. 1137 * 1138 * @param text 1139 * String to test 1140 * @return true if the string contains HTML 1141 */ 1142 public static boolean containsHtml(String text) 1143 { 1144 return text != null && text.indexOf('<') != -1 && text.indexOf('>') != -1; 1145 } 1146 1147 private static EmptyPrintStream emptyStream = new EmptyPrintStream(); 1148 1149 /** 1150 * Returns a printstream that does not write anything to standard output. 1151 * 1152 * @return a printstream that does not write anything to standard output. 1153 */ 1154 public static EmptyPrintStream getEmptyPrintStream() 1155 { 1156 if (emptyStream == null) 1157 { 1158 emptyStream = new EmptyPrintStream(); 1159 } 1160 return emptyStream; 1161 } 1162 1163 /** 1164 * Returns the current time of a server in milliseconds. 1165 * 1166 * @param ctx 1167 * the connection to the server. 1168 * @return the current time of a server in milliseconds. 1169 */ 1170 public static long getServerClock(InitialLdapContext ctx) 1171 { 1172 long time = -1; 1173 SearchControls ctls = new SearchControls(); 1174 ctls.setSearchScope(SearchControls.OBJECT_SCOPE); 1175 ctls.setReturningAttributes(new String[] { "currentTime" }); 1176 String filter = "(objectclass=*)"; 1177 1178 try 1179 { 1180 LdapName jndiName = new LdapName("cn=monitor"); 1181 NamingEnumeration<?> listeners = ctx.search(jndiName, filter, ctls); 1182 1183 try 1184 { 1185 while (listeners.hasMore()) 1186 { 1187 SearchResult sr = (SearchResult) listeners.next(); 1188 1189 String v = getFirstValue(sr, "currentTime"); 1190 1191 TimeZone utcTimeZone = TimeZone.getTimeZone("UTC"); 1192 1193 SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); 1194 formatter.setTimeZone(utcTimeZone); 1195 1196 time = formatter.parse(v).getTime(); 1197 } 1198 } 1199 finally 1200 { 1201 listeners.close(); 1202 } 1203 } 1204 catch (Throwable t) 1205 { 1206 logger.warn(LocalizableMessage.raw("Error retrieving server current time: " + t, t)); 1207 } 1208 return time; 1209 } 1210 1211 /** 1212 * Checks that the java version we are running is compatible with OpenDS. 1213 * 1214 * @throws IncompatibleVersionException 1215 * if the java version we are running is not compatible with OpenDS. 1216 */ 1217 public static void checkJavaVersion() throws IncompatibleVersionException 1218 { 1219 try 1220 { 1221 com.forgerock.opendj.cli.Utils.checkJavaVersion(); 1222 } 1223 catch (ClientException e) 1224 { 1225 throw new IncompatibleVersionException(e.getMessageObject(), e); 1226 } 1227 } 1228 1229 /** 1230 * Basic method to know if the host is local or not. This is only used to know 1231 * if we can perform a port check or not. 1232 * 1233 * @param host 1234 * the host to analyze. 1235 * @return <CODE>true</CODE> if it is the local host and <CODE>false</CODE> 1236 * otherwise. 1237 */ 1238 public static boolean isLocalHost(String host) 1239 { 1240 if ("localhost".equalsIgnoreCase(host)) 1241 { 1242 return true; 1243 } 1244 1245 try 1246 { 1247 InetAddress localAddress = InetAddress.getLocalHost(); 1248 InetAddress[] addresses = InetAddress.getAllByName(host); 1249 for (InetAddress address : addresses) 1250 { 1251 if (localAddress.equals(address)) 1252 { 1253 return true; 1254 } 1255 } 1256 } 1257 catch (Throwable t) 1258 { 1259 logger.warn(LocalizableMessage.raw("Failing checking host names: " + t, t)); 1260 } 1261 return false; 1262 } 1263 1264 /** 1265 * Returns the HTML representation of a plain text string which is obtained 1266 * by converting some special characters (like '<') into its equivalent 1267 * escaped HTML representation. 1268 * 1269 * @param rawString the String from which we want to obtain the HTML 1270 * representation. 1271 * @return the HTML representation of the plain text string. 1272 */ 1273 private static String escapeHtml(String rawString) 1274 { 1275 StringBuilder buffer = new StringBuilder(); 1276 for (int i = 0; i < rawString.length(); i++) 1277 { 1278 escapeChar(buffer, rawString.charAt(i)); 1279 } 1280 return buffer.toString(); 1281 } 1282 1283 private static StringBuilder escapeChar(StringBuilder buffer, char c) 1284 { 1285 switch (c) 1286 { 1287 case '<': 1288 return buffer.append("<"); 1289 case '>': 1290 return buffer.append(">"); 1291 case '&': 1292 return buffer.append("&"); 1293 case '"': 1294 return buffer.append("""); 1295 default: 1296 return buffer.append(c); 1297 } 1298 } 1299 1300 /** 1301 * Returns the HTML representation for a given text. without adding any kind 1302 * of font or style elements. Just escapes the problematic characters 1303 * (like '<') and transform the break lines into '\n' characters. 1304 * 1305 * @param text the source text from which we want to get the HTML 1306 * representation 1307 * @return the HTML representation for the given text. 1308 */ 1309 public static String getHtml(String text) 1310 { 1311 if (text == null) 1312 { 1313 return ""; 1314 } 1315 1316 text = text.replaceAll("\r\n", "\n"); 1317 1318 StringBuilder buffer = new StringBuilder(); 1319 String[] lines = text.split("[\n\r\u0085\u2028\u2029]"); 1320 for (int i = 0; i < lines.length; i++) 1321 { 1322 if (i != 0) 1323 { 1324 buffer.append(Constants.HTML_LINE_BREAK); 1325 } 1326 buffer.append(escapeHtml(lines[i])); 1327 } 1328 return buffer.toString(); 1329 } 1330 1331 /** 1332 * Tries to find a customized object in the customization class. If the 1333 * customization class does not exist or it does not contain the field as the 1334 * specified type of the object, returns the default value. 1335 * 1336 * @param <T> 1337 * the type of the customized object. 1338 * @param fieldName 1339 * the name of the field representing an object in the customization 1340 * class. 1341 * @param defaultValue 1342 * the default value. 1343 * @param valueClass 1344 * the class of the parameterized value. 1345 * @return the customized object. 1346 */ 1347 public static <T> T getCustomizedObject(String fieldName, T defaultValue, Class<T> valueClass) 1348 { 1349 try 1350 { 1351 Class<?> c = Class.forName(Utils.CUSTOMIZATION_CLASS_NAME); 1352 Object obj = c.newInstance(); 1353 1354 return valueClass.cast(c.getField(fieldName).get(obj)); 1355 } 1356 catch (Exception ex) 1357 { 1358 //do nothing. 1359 } 1360 return defaultValue; 1361 } 1362 1363 /** 1364 * Adds word break tags to the provided html string. 1365 * 1366 * @param htmlString 1367 * the string. 1368 * @param from 1369 * the first index to start the spacing from. 1370 * @param spacing 1371 * the minimal spacing between word breaks. 1372 * @return a string containing word breaks. 1373 */ 1374 public static String addWordBreaks(String htmlString, int from, int spacing) 1375 { 1376 StringBuilder sb = new StringBuilder(); 1377 boolean insideTag = false; 1378 int totalAddedChars = 0; 1379 int addedChars = 0; 1380 for (int i = 0; i < htmlString.length(); i++) 1381 { 1382 char c = htmlString.charAt(i); 1383 sb.append(c); 1384 if (c == '<') 1385 { 1386 insideTag = true; 1387 } 1388 else if (c == '>' && insideTag) 1389 { 1390 insideTag = false; 1391 } 1392 if (!insideTag && c != '>') 1393 { 1394 addedChars++; 1395 totalAddedChars++; 1396 } 1397 if (addedChars > spacing && totalAddedChars > from && !insideTag) 1398 { 1399 sb.append("<wbr>"); 1400 addedChars = 0; 1401 } 1402 } 1403 return sb.toString(); 1404 } 1405 1406 /** 1407 * Returns the localized string describing the DataOptions chosen by the user. 1408 * 1409 * @param userInstallData 1410 * the DataOptions of the user. 1411 * @return the localized string describing the DataOptions chosen by the user. 1412 */ 1413 public static String getDataDisplayString(final UserData userInstallData) 1414 { 1415 LocalizableMessage msg; 1416 1417 final DataReplicationOptions repl = userInstallData.getReplicationOptions(); 1418 final SuffixesToReplicateOptions suf = userInstallData.getSuffixesToReplicateOptions(); 1419 1420 boolean createSuffix = repl.getType() == DataReplicationOptions.Type.FIRST_IN_TOPOLOGY 1421 || repl.getType() == DataReplicationOptions.Type.STANDALONE 1422 || suf.getType() == SuffixesToReplicateOptions.Type.NEW_SUFFIX_IN_TOPOLOGY; 1423 1424 if (createSuffix) 1425 { 1426 NewSuffixOptions options = userInstallData.getNewSuffixOptions(); 1427 LocalizableMessage arg2 = toArg2(options); 1428 1429 if (options.getBaseDns().isEmpty()) 1430 { 1431 msg = INFO_REVIEW_CREATE_NO_SUFFIX.get(); 1432 } 1433 else 1434 { 1435 final String backendType = userInstallData.getBackendType().getUserFriendlyName().toString(); 1436 if (options.getBaseDns().size() > 1) 1437 { 1438 msg = INFO_REVIEW_CREATE_SUFFIX.get( 1439 backendType, joinAsString(Constants.LINE_SEPARATOR, options.getBaseDns()), arg2); 1440 } 1441 else 1442 { 1443 msg = INFO_REVIEW_CREATE_SUFFIX.get(backendType, options.getBaseDns().getFirst(), arg2); 1444 } 1445 } 1446 } 1447 else 1448 { 1449 final StringBuilder buf = new StringBuilder(); 1450 for (final SuffixDescriptor suffix : suf.getSuffixes()) 1451 { 1452 if (buf.length() > 0) 1453 { 1454 buf.append(Constants.LINE_SEPARATOR); 1455 } 1456 buf.append(suffix.getDN()); 1457 } 1458 msg = INFO_REVIEW_REPLICATE_SUFFIX.get(buf); 1459 } 1460 1461 return msg.toString(); 1462 } 1463 1464 private static LocalizableMessage toArg2(NewSuffixOptions options) 1465 { 1466 switch (options.getType()) 1467 { 1468 case CREATE_BASE_ENTRY: 1469 return INFO_REVIEW_CREATE_BASE_ENTRY_LABEL.get(options.getBaseDns().getFirst()); 1470 case LEAVE_DATABASE_EMPTY: 1471 return INFO_REVIEW_LEAVE_DATABASE_EMPTY_LABEL.get(); 1472 case IMPORT_FROM_LDIF_FILE: 1473 return INFO_REVIEW_IMPORT_LDIF.get(options.getLDIFPaths().getFirst()); 1474 case IMPORT_AUTOMATICALLY_GENERATED_DATA: 1475 return INFO_REVIEW_IMPORT_AUTOMATICALLY_GENERATED.get(options.getNumberEntries()); 1476 default: 1477 throw new IllegalArgumentException("Unknown type: " + options.getType()); 1478 } 1479 } 1480 1481 /** 1482 * Returns a localized String representation of the provided SecurityOptions 1483 * object. 1484 * 1485 * @param ops 1486 * the SecurityOptions object from which we want to obtain the String 1487 * representation. 1488 * @param html 1489 * whether the resulting String must be in HTML or not. 1490 * @return a localized String representation of the provided SecurityOptions 1491 * object. 1492 */ 1493 public static String getSecurityOptionsString(SecurityOptions ops, boolean html) 1494 { 1495 StringBuilder buf = new StringBuilder(); 1496 1497 if (ops.getCertificateType() == SecurityOptions.CertificateType.NO_CERTIFICATE) 1498 { 1499 buf.append(INFO_NO_SECURITY.get()); 1500 } 1501 else 1502 { 1503 if (ops.getEnableStartTLS()) 1504 { 1505 buf.append(INFO_ENABLE_STARTTLS.get()); 1506 } 1507 if (ops.getEnableSSL()) 1508 { 1509 if (buf.length() > 0) 1510 { 1511 if (html) 1512 { 1513 buf.append(Constants.HTML_LINE_BREAK); 1514 } 1515 else 1516 { 1517 buf.append("\n"); 1518 } 1519 } 1520 buf.append(INFO_ENABLE_SSL.get(ops.getSslPort())); 1521 } 1522 if (html) 1523 { 1524 buf.append(Constants.HTML_LINE_BREAK); 1525 } 1526 else 1527 { 1528 buf.append("\n"); 1529 } 1530 buf.append(toCertMsg(ops)); 1531 } 1532 1533 if (html) 1534 { 1535 return "<html>" + UIFactory.applyFontToHtml(buf.toString(), UIFactory.SECONDARY_FIELD_VALID_FONT); 1536 } 1537 else 1538 { 1539 return buf.toString(); 1540 } 1541 } 1542 1543 private static LocalizableMessage toCertMsg(SecurityOptions ops) 1544 { 1545 switch (ops.getCertificateType()) 1546 { 1547 case SELF_SIGNED_CERTIFICATE: 1548 return INFO_SELF_SIGNED_CERTIFICATE.get(); 1549 case JKS: 1550 return INFO_JKS_CERTIFICATE.get(); 1551 case JCEKS: 1552 return INFO_JCEKS_CERTIFICATE.get(); 1553 case PKCS11: 1554 return INFO_PKCS11_CERTIFICATE.get(); 1555 case PKCS12: 1556 return INFO_PKCS12_CERTIFICATE.get(); 1557 default: 1558 throw new IllegalStateException("Unknown certificate options type: " + ops.getCertificateType()); 1559 } 1560 } 1561 1562 /** 1563 * Returns a String representation of the provided command-line. 1564 * 1565 * @param cmd 1566 * the command-line arguments. 1567 * @param formatter 1568 * the formatted to be used to create the String representation. 1569 * @return a String representation of the provided command-line. 1570 */ 1571 public static String getFormattedEquivalentCommandLine(List<String> cmd, ProgressMessageFormatter formatter) 1572 { 1573 StringBuilder builder = new StringBuilder(); 1574 builder.append(formatter.getFormattedProgress(LocalizableMessage.raw(cmd.get(0)))); 1575 int initialIndex = 1; 1576 StringBuilder sbSeparator = new StringBuilder(); 1577 sbSeparator.append(formatter.getSpace()); 1578 if (!isWindows()) 1579 { 1580 sbSeparator.append("\\"); 1581 sbSeparator.append(formatter.getLineBreak()); 1582 for (int i = 0; i < 10; i++) 1583 { 1584 sbSeparator.append(formatter.getSpace()); 1585 } 1586 } 1587 1588 String lineSeparator = sbSeparator.toString(); 1589 for (int i = initialIndex; i < cmd.size(); i++) 1590 { 1591 String s = cmd.get(i); 1592 if (s.startsWith("-")) 1593 { 1594 builder.append(lineSeparator); 1595 builder.append(formatter.getFormattedProgress(LocalizableMessage.raw(s))); 1596 } 1597 else 1598 { 1599 builder.append(formatter.getSpace()); 1600 builder.append(formatter.getFormattedProgress(LocalizableMessage.raw(escapeCommandLineValue(s)))); 1601 } 1602 } 1603 return builder.toString(); 1604 } 1605 1606 /** 1607 * This method simply takes a value and tries to transform it (with escape or 1608 * '"') characters so that it can be used in a command line. 1609 * 1610 * @param value 1611 * the String to be treated. 1612 * @return the transformed value. 1613 */ 1614 public static String escapeCommandLineValue(String value) 1615 { 1616 StringBuilder b = new StringBuilder(); 1617 if (isUnix()) 1618 { 1619 for (int i = 0; i < value.length(); i++) 1620 { 1621 char c = value.charAt(i); 1622 boolean charToEscapeFound = false; 1623 for (int j = 0; j < CHARS_TO_ESCAPE.length && !charToEscapeFound; j++) 1624 { 1625 charToEscapeFound = c == CHARS_TO_ESCAPE[j]; 1626 } 1627 if (charToEscapeFound) 1628 { 1629 b.append('\\'); 1630 } 1631 b.append(c); 1632 } 1633 } 1634 else 1635 { 1636 b.append('"').append(value).append('"'); 1637 } 1638 1639 return b.toString(); 1640 } 1641 1642 /** 1643 * Returns the equivalent setup CLI command-line. Note that this command-line 1644 * does not cover all the replication part of the GUI install. 1645 * 1646 * @param userData 1647 * the user data. 1648 * @return the equivalent setup command-line. 1649 */ 1650 public static List<String> getSetupEquivalentCommandLine(final UserData userData) 1651 { 1652 List<String> cmdLine = new ArrayList<>(); 1653 cmdLine.add(getInstallDir(userData) + getSetupFileName()); 1654 cmdLine.add("--cli"); 1655 1656 final ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backendType = 1657 userData.getBackendType(); 1658 if (backendType != null) 1659 { 1660 cmdLine.add("--" + ArgumentConstants.OPTION_LONG_BACKEND_TYPE); 1661 cmdLine.add(BackendTypeHelper.filterSchemaBackendName(backendType.getName())); 1662 } 1663 1664 for (final String baseDN : getBaseDNs(userData)) 1665 { 1666 cmdLine.add("--baseDN"); 1667 cmdLine.add(baseDN); 1668 } 1669 1670 switch (userData.getNewSuffixOptions().getType()) 1671 { 1672 case CREATE_BASE_ENTRY: 1673 cmdLine.add("--addBaseEntry"); 1674 break; 1675 1676 case IMPORT_AUTOMATICALLY_GENERATED_DATA: 1677 cmdLine.add("--sampleData"); 1678 cmdLine.add(Integer.toString(userData.getNewSuffixOptions().getNumberEntries())); 1679 break; 1680 1681 case IMPORT_FROM_LDIF_FILE: 1682 for (final String ldifFile : userData.getNewSuffixOptions().getLDIFPaths()) 1683 { 1684 cmdLine.add("--ldifFile"); 1685 cmdLine.add(ldifFile); 1686 } 1687 1688 final String rejectFile = userData.getNewSuffixOptions().getRejectedFile(); 1689 if (rejectFile != null) 1690 { 1691 cmdLine.add("--rejectFile"); 1692 cmdLine.add(rejectFile); 1693 } 1694 1695 final String skipFile = userData.getNewSuffixOptions().getSkippedFile(); 1696 if (skipFile != null) 1697 { 1698 cmdLine.add("--skipFile"); 1699 cmdLine.add(skipFile); 1700 } 1701 break; 1702 1703 default: 1704 break; 1705 } 1706 1707 cmdLine.add("--ldapPort"); 1708 cmdLine.add(Integer.toString(userData.getServerPort())); 1709 1710 cmdLine.add("--adminConnectorPort"); 1711 cmdLine.add(Integer.toString(userData.getAdminConnectorPort())); 1712 1713 if (userData.getServerJMXPort() != -1) 1714 { 1715 cmdLine.add("--jmxPort"); 1716 cmdLine.add(Integer.toString(userData.getServerJMXPort())); 1717 } 1718 1719 cmdLine.add("--rootUserDN"); 1720 cmdLine.add(userData.getDirectoryManagerDn()); 1721 1722 cmdLine.add("--rootUserPassword"); 1723 cmdLine.add(OBFUSCATED_VALUE); 1724 1725 if (isWindows() && userData.getEnableWindowsService()) 1726 { 1727 cmdLine.add("--enableWindowsService"); 1728 } 1729 1730 if (userData.getReplicationOptions().getType() == DataReplicationOptions.Type.STANDALONE 1731 && !userData.getStartServer()) 1732 { 1733 cmdLine.add("--doNotStart"); 1734 } 1735 1736 if (userData.getSecurityOptions().getEnableStartTLS()) 1737 { 1738 cmdLine.add("--enableStartTLS"); 1739 } 1740 1741 if (userData.getSecurityOptions().getEnableSSL()) 1742 { 1743 cmdLine.add("--ldapsPort"); 1744 cmdLine.add(Integer.toString(userData.getSecurityOptions().getSslPort())); 1745 } 1746 1747 cmdLine.addAll(getSecurityOptionSetupEquivalentCmdLine(userData)); 1748 cmdLine.add("--no-prompt"); 1749 cmdLine.add("--noPropertiesFile"); 1750 1751 return cmdLine; 1752 } 1753 1754 private static List<String> getSecurityOptionSetupEquivalentCmdLine(final UserData userData) 1755 { 1756 final List<String> cmdLine = new ArrayList<>(); 1757 1758 switch (userData.getSecurityOptions().getCertificateType()) 1759 { 1760 case SELF_SIGNED_CERTIFICATE: 1761 cmdLine.add("--generateSelfSignedCertificate"); 1762 cmdLine.add("--hostName"); 1763 cmdLine.add(userData.getHostName()); 1764 break; 1765 1766 case JKS: 1767 cmdLine.add("--useJavaKeystore"); 1768 cmdLine.add(userData.getSecurityOptions().getKeystorePath()); 1769 addKeyStoreAndCert(userData.getSecurityOptions(), cmdLine); 1770 break; 1771 1772 case JCEKS: 1773 cmdLine.add("--useJCEKS"); 1774 cmdLine.add(userData.getSecurityOptions().getKeystorePath()); 1775 1776 addKeyStoreAndCert(userData.getSecurityOptions(), cmdLine); 1777 break; 1778 1779 case PKCS12: 1780 cmdLine.add("--usePkcs12keyStore"); 1781 cmdLine.add(userData.getSecurityOptions().getKeystorePath()); 1782 1783 addKeyStoreAndCert(userData.getSecurityOptions(), cmdLine); 1784 break; 1785 1786 case PKCS11: 1787 cmdLine.add("--usePkcs11Keystore"); 1788 1789 addKeyStoreAndCert(userData.getSecurityOptions(), cmdLine); 1790 break; 1791 1792 default: 1793 break; 1794 } 1795 1796 return cmdLine; 1797 } 1798 1799 private static void addKeyStoreAndCert(final SecurityOptions securityOptions, final List<String> cmdLine) 1800 { 1801 if (securityOptions.getKeystorePassword() != null) 1802 { 1803 cmdLine.add("--keyStorePassword"); 1804 cmdLine.add(OBFUSCATED_VALUE); 1805 } 1806 1807 for(String alias : securityOptions.getAliasesToUse()) 1808 { 1809 cmdLine.add("--certNickname"); 1810 cmdLine.add(alias); 1811 } 1812 } 1813 1814 /** 1815 * Returns the list of equivalent command-lines that must be executed to 1816 * enable or initialize replication as the setup does. 1817 * 1818 * @param subcommand 1819 * either {@code "enable"} or {@code "initialize"} 1820 * @param userData 1821 * the user data. 1822 * @return the list of equivalent command-lines that must be executed to 1823 * enable or initialize replication as the setup does. 1824 */ 1825 public static List<List<String>> getDsReplicationEquivalentCommandLines(String subcommand, UserData userData) 1826 { 1827 final List<List<String>> cmdLines = new ArrayList<>(); 1828 final Map<ServerDescriptor, Set<String>> hmServerBaseDNs = getServerDescriptorBaseDNMap(userData); 1829 for (ServerDescriptor server : hmServerBaseDNs.keySet()) 1830 { 1831 cmdLines.add(getDsReplicationEquivalentCommandLine(subcommand, userData, hmServerBaseDNs.get(server), server)); 1832 } 1833 return cmdLines; 1834 } 1835 1836 private static void addEnableCommandOptions(UserData userData, ServerDescriptor server, List<String> cmdLine) 1837 { 1838 DataReplicationOptions replOptions = userData.getReplicationOptions(); 1839 cmdLine.add("--host1"); 1840 cmdLine.add(server.getHostName()); 1841 cmdLine.add("--port1"); 1842 cmdLine.add(String.valueOf(server.getEnabledAdministrationPorts().get(0))); 1843 1844 AuthenticationData authData = userData.getReplicationOptions().getAuthenticationData(); 1845 if (!Utils.areDnsEqual(authData.getDn(), ADSContext.getAdministratorDN(userData.getGlobalAdministratorUID()))) 1846 { 1847 cmdLine.add("--bindDN1"); 1848 cmdLine.add(authData.getDn()); 1849 cmdLine.add("--bindPassword1"); 1850 cmdLine.add(OBFUSCATED_VALUE); 1851 } 1852 for (ServerDescriptor s : userData.getRemoteWithNoReplicationPort().keySet()) 1853 { 1854 if (s.getAdminConnectorURL().equals(server.getAdminConnectorURL())) 1855 { 1856 AuthenticationData remoteRepl = userData.getRemoteWithNoReplicationPort().get(server); 1857 int remoteReplicationPort = remoteRepl.getPort(); 1858 1859 cmdLine.add("--replicationPort1"); 1860 cmdLine.add(String.valueOf(remoteReplicationPort)); 1861 if (remoteRepl.useSecureConnection()) 1862 { 1863 cmdLine.add("--secureReplication1"); 1864 } 1865 } 1866 } 1867 cmdLine.add("--host2"); 1868 cmdLine.add(userData.getHostName()); 1869 cmdLine.add("--port2"); 1870 cmdLine.add(String.valueOf(userData.getAdminConnectorPort())); 1871 cmdLine.add("--bindDN2"); 1872 cmdLine.add(userData.getDirectoryManagerDn()); 1873 cmdLine.add("--bindPassword2"); 1874 cmdLine.add(OBFUSCATED_VALUE); 1875 if (replOptions.getReplicationPort() != -1) 1876 { 1877 cmdLine.add("--replicationPort2"); 1878 cmdLine.add(String.valueOf(replOptions.getReplicationPort())); 1879 if (replOptions.useSecureReplication()) 1880 { 1881 cmdLine.add("--secureReplication2"); 1882 } 1883 } 1884 } 1885 1886 /** 1887 * Returns the full path of the command-line for a given script name. 1888 * 1889 * @param userData 1890 * the user data. 1891 * @param scriptBasicName 1892 * the script basic name (with no extension). 1893 * @return the full path of the command-line for a given script name. 1894 */ 1895 private static String getCommandLinePath(UserData userData, String scriptBasicName) 1896 { 1897 String installDir = getInstallDir(userData); 1898 if (isWindows()) 1899 { 1900 return installDir + WINDOWS_BINARIES_PATH_RELATIVE + File.separatorChar + scriptBasicName + ".bat"; 1901 } 1902 else 1903 { 1904 return installDir + UNIX_BINARIES_PATH_RELATIVE + File.separatorChar + scriptBasicName; 1905 } 1906 } 1907 1908 private static String installDir; 1909 1910 /** 1911 * Returns the installation directory. 1912 * 1913 * @return the installation directory. 1914 */ 1915 private static String getInstallDir(UserData userData) 1916 { 1917 if (installDir == null) 1918 { 1919 File f = org.opends.quicksetup.Installation.getLocal().getRootDirectory(); 1920 installDir = getCanonicalPath(f); 1921 if (installDir.lastIndexOf(File.separatorChar) != installDir.length() - 1) 1922 { 1923 installDir += File.separatorChar; 1924 } 1925 } 1926 1927 return installDir; 1928 } 1929 1930 private static String getCanonicalPath(File f) 1931 { 1932 try 1933 { 1934 return f.getCanonicalPath(); 1935 } 1936 catch (IOException t) 1937 { 1938 return f.getAbsolutePath(); 1939 } 1940 } 1941 1942 private static List<String> getDsReplicationEquivalentCommandLine(String subcommand, UserData userData, 1943 Set<String> baseDNs, ServerDescriptor server) 1944 { 1945 List<String> cmdLine = new ArrayList<>(); 1946 String cmdName = getCommandLinePath(userData, "dsreplication"); 1947 cmdLine.add(cmdName); 1948 cmdLine.add(subcommand); 1949 1950 if ("enable".equals(subcommand)) 1951 { 1952 addEnableCommandOptions(userData, server, cmdLine); 1953 } 1954 else if ("initialize".equals(subcommand)) 1955 { 1956 addInitializeCommandOptions(userData, server, cmdLine); 1957 } 1958 else 1959 { 1960 throw new IllegalArgumentException("Code is not implemented for subcommand " + subcommand); 1961 } 1962 1963 addCommonOptions(userData, baseDNs, cmdLine); 1964 return cmdLine; 1965 } 1966 1967 private static void addInitializeCommandOptions(UserData userData, ServerDescriptor server, List<String> cmdLine) 1968 { 1969 cmdLine.add("--hostSource"); 1970 cmdLine.add(server.getHostName()); 1971 cmdLine.add("--portSource"); 1972 cmdLine.add(String.valueOf(server.getEnabledAdministrationPorts().get(0))); 1973 1974 cmdLine.add("--hostDestination"); 1975 cmdLine.add(userData.getHostName()); 1976 cmdLine.add("--portDestination"); 1977 cmdLine.add(String.valueOf(userData.getAdminConnectorPort())); 1978 } 1979 1980 private static void addCommonOptions(UserData userData, Set<String> baseDNs, List<String> cmdLine) 1981 { 1982 for (String baseDN : baseDNs) 1983 { 1984 cmdLine.add("--baseDN"); 1985 cmdLine.add(baseDN); 1986 } 1987 1988 cmdLine.add("--adminUID"); 1989 cmdLine.add(userData.getGlobalAdministratorUID()); 1990 cmdLine.add("--adminPassword"); 1991 cmdLine.add(OBFUSCATED_VALUE); 1992 1993 cmdLine.add("--trustAll"); 1994 cmdLine.add("--no-prompt"); 1995 cmdLine.add("--noPropertiesFile"); 1996 } 1997 1998 private static List<String> getBaseDNs(UserData userData) 1999 { 2000 List<String> baseDNs = new ArrayList<>(); 2001 2002 DataReplicationOptions repl = userData.getReplicationOptions(); 2003 SuffixesToReplicateOptions suf = userData.getSuffixesToReplicateOptions(); 2004 2005 boolean createSuffix = 2006 repl.getType() == DataReplicationOptions.Type.FIRST_IN_TOPOLOGY 2007 || repl.getType() == DataReplicationOptions.Type.STANDALONE 2008 || suf.getType() == SuffixesToReplicateOptions.Type.NEW_SUFFIX_IN_TOPOLOGY; 2009 2010 if (createSuffix) 2011 { 2012 NewSuffixOptions options = userData.getNewSuffixOptions(); 2013 baseDNs.addAll(options.getBaseDns()); 2014 } 2015 else 2016 { 2017 Set<SuffixDescriptor> suffixes = suf.getSuffixes(); 2018 for (SuffixDescriptor suffix : suffixes) 2019 { 2020 baseDNs.add(suffix.getDN()); 2021 } 2022 } 2023 return baseDNs; 2024 } 2025 2026 private static Map<ServerDescriptor, Set<String>> getServerDescriptorBaseDNMap(UserData userData) 2027 { 2028 Map<ServerDescriptor, Set<String>> hm = new HashMap<>(); 2029 2030 Set<SuffixDescriptor> suffixes = userData.getSuffixesToReplicateOptions().getSuffixes(); 2031 AuthenticationData authData = userData.getReplicationOptions().getAuthenticationData(); 2032 String ldapURL = 2033 ConnectionUtils.getLDAPUrl(authData.getHostName(), authData.getPort(), authData.useSecureConnection()); 2034 for (SuffixDescriptor suffix : suffixes) 2035 { 2036 boolean found = false; 2037 for (ReplicaDescriptor replica : suffix.getReplicas()) 2038 { 2039 if (ldapURL.equalsIgnoreCase(replica.getServer().getAdminConnectorURL())) 2040 { 2041 // This is the server we're configuring 2042 found = true; 2043 Set<String> baseDNs = hm.get(replica.getServer()); 2044 if (baseDNs == null) 2045 { 2046 baseDNs = new LinkedHashSet<>(); 2047 hm.put(replica.getServer(), baseDNs); 2048 } 2049 baseDNs.add(suffix.getDN()); 2050 break; 2051 } 2052 } 2053 if (!found) 2054 { 2055 for (ReplicaDescriptor replica : suffix.getReplicas()) 2056 { 2057 if (hm.keySet().contains(replica.getServer())) 2058 { 2059 hm.get(replica.getServer()).add(suffix.getDN()); 2060 found = true; 2061 break; 2062 } 2063 } 2064 } 2065 if (!found) 2066 { 2067 // We haven't found the server yet, just take the first one 2068 ReplicaDescriptor replica = suffix.getReplicas().iterator().next(); 2069 if (replica != null) 2070 { 2071 Set<String> baseDNs = new LinkedHashSet<>(); 2072 hm.put(replica.getServer(), baseDNs); 2073 baseDNs.add(suffix.getDN()); 2074 } 2075 } 2076 } 2077 return hm; 2078 } 2079 2080 /** 2081 * Returns the equivalent dsconfig command-line required to configure the 2082 * first replicated server in the topology. 2083 * 2084 * @param userData 2085 * the user data. 2086 * @return the equivalent dsconfig command-line required to configure the 2087 * first replicated server in the topology. 2088 */ 2089 public static List<List<String>> getDsConfigReplicationEnableEquivalentCommandLines(UserData userData) 2090 { 2091 final List<List<String>> cmdLines = new ArrayList<>(); 2092 final String cmdName = getCommandLinePath(userData, "dsconfig"); 2093 2094 List<String> connectionArgs = new ArrayList<>(); 2095 connectionArgs.add("--hostName"); 2096 connectionArgs.add(userData.getHostName()); 2097 connectionArgs.add("--port"); 2098 connectionArgs.add(String.valueOf(userData.getAdminConnectorPort())); 2099 connectionArgs.add("--bindDN"); 2100 connectionArgs.add(userData.getDirectoryManagerDn()); 2101 connectionArgs.add("--bindPassword"); 2102 connectionArgs.add(OBFUSCATED_VALUE); 2103 connectionArgs.add("--trustAll"); 2104 connectionArgs.add("--no-prompt"); 2105 connectionArgs.add("--noPropertiesFile"); 2106 2107 List<String> cmdReplicationServer = new ArrayList<>(); 2108 cmdReplicationServer.add(cmdName); 2109 cmdReplicationServer.add("create-replication-server"); 2110 cmdReplicationServer.add("--provider-name"); 2111 cmdReplicationServer.add("Multimaster Synchronization"); 2112 cmdReplicationServer.add("--set"); 2113 cmdReplicationServer.add("replication-port:" + userData.getReplicationOptions().getReplicationPort()); 2114 cmdReplicationServer.add("--set"); 2115 cmdReplicationServer.add("replication-server-id:1"); 2116 cmdReplicationServer.add("--type"); 2117 cmdReplicationServer.add("generic"); 2118 cmdReplicationServer.addAll(connectionArgs); 2119 2120 cmdLines.add(cmdReplicationServer); 2121 return cmdLines; 2122 } 2123} 2124 2125/** 2126 * This class is used to avoid displaying the error message related to display 2127 * problems that we might have when trying to display the SplashWindow. 2128 */ 2129class EmptyPrintStream extends PrintStream 2130{ 2131 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 2132 2133 /** Default constructor. */ 2134 public EmptyPrintStream() 2135 { 2136 super(new ByteArrayOutputStream(), true); 2137 } 2138 2139 @Override 2140 public void println(String msg) 2141 { 2142 logger.info(LocalizableMessage.raw("EmptyStream msg: " + msg)); 2143 } 2144}