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 legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2011-2015 ForgeRock AS.
026 */
027package org.opends.server.tools;
028
029import static com.forgerock.opendj.cli.ArgumentConstants.*;
030import static com.forgerock.opendj.cli.Utils.*;
031
032import static org.opends.messages.ConfigMessages.*;
033import static org.opends.messages.ToolMessages.*;
034import static org.opends.server.protocols.ldap.LDAPResultCode.*;
035import static org.opends.server.util.StaticUtils.*;
036
037import java.io.Console;
038import java.io.IOException;
039import java.io.OutputStream;
040import java.io.PrintStream;
041import java.util.ArrayList;
042import java.util.Collections;
043import java.util.concurrent.ConcurrentHashMap;
044
045import org.forgerock.i18n.LocalizableMessage;
046import org.forgerock.opendj.config.server.ConfigException;
047import org.forgerock.opendj.ldap.ByteString;
048import org.opends.server.admin.server.ServerManagementContext;
049import org.opends.server.admin.std.server.BackendCfg;
050import org.opends.server.admin.std.server.LDIFBackendCfg;
051import org.opends.server.admin.std.server.RootCfg;
052import org.opends.server.admin.std.server.TrustStoreBackendCfg;
053import org.opends.server.api.Backend;
054import org.opends.server.api.PasswordStorageScheme;
055import org.opends.server.config.ConfigConstants;
056import org.opends.server.config.ConfigEntry;
057import org.opends.server.core.CoreConfigManager;
058import org.opends.server.core.DirectoryServer;
059import org.opends.server.core.DirectoryServer.DirectoryServerVersionHandler;
060import org.opends.server.core.PasswordStorageSchemeConfigManager;
061import org.opends.server.crypto.CryptoManagerSync;
062import org.opends.server.extensions.ConfigFileHandler;
063import org.opends.server.loggers.JDKLogging;
064import org.opends.server.schema.AuthPasswordSyntax;
065import org.opends.server.schema.UserPasswordSyntax;
066import org.opends.server.types.*;
067import org.opends.server.util.BuildVersion;
068
069import com.forgerock.opendj.cli.ArgumentException;
070import com.forgerock.opendj.cli.ArgumentParser;
071import com.forgerock.opendj.cli.BooleanArgument;
072import com.forgerock.opendj.cli.CommonArguments;
073import com.forgerock.opendj.cli.FileBasedArgument;
074import com.forgerock.opendj.cli.StringArgument;
075
076/**
077 * This program provides a utility that may be used to interact with the
078 * password storage schemes defined in the Directory Server.  In particular,
079 * it can encode a clear-text password using a specified scheme, and it can also
080 * determine whether a given encoded password is the encoded representation of a
081 * given clear-text password.  Alternately, it can be used to obtain a list of
082 * the available password storage scheme names.
083 */
084public class EncodePassword
085{
086  /**
087   * Processes the command-line arguments and performs the requested action.
088   *
089   * @param  args  The command-line arguments provided to this program.
090   */
091  public static void main(String[] args)
092  {
093    int returnCode = encodePassword(args, true, System.out, System.err);
094    if (returnCode != 0)
095    {
096      System.exit(filterExitCode(returnCode));
097    }
098  }
099
100
101
102  /**
103   * Processes the command-line arguments and performs the requested action.
104   *
105   * @param  args  The command-line arguments provided to this program.
106   *
107   * @return  An integer value that indicates whether processing was successful.
108   */
109  public static int encodePassword(String[] args)
110  {
111    return encodePassword(args, true, System.out, System.err);
112  }
113
114
115
116  /**
117   * Processes the command-line arguments and performs the requested action.
118   *
119   * @param  args              The command-line arguments provided to this
120   *                           program.
121   * @param  initializeServer  Indicates whether to initialize the server.
122   * @param  outStream         The output stream to use for standard output, or
123   *                           <CODE>null</CODE> if standard output is not
124   *                           needed.
125   * @param  errStream         The output stream to use for standard error, or
126   *                           <CODE>null</CODE> if standard error is not
127   *                           needed.
128   *
129   * @return  An integer value that indicates whether processing was successful.
130   */
131  public static int encodePassword(String[] args, boolean initializeServer,
132                                   OutputStream outStream,
133                                   OutputStream errStream)
134  {
135    PrintStream out = NullOutputStream.wrapOrNullStream(outStream);
136    PrintStream err = NullOutputStream.wrapOrNullStream(errStream);
137    JDKLogging.disableLogging();
138
139    // Define the command-line arguments that may be used with this program.
140    BooleanArgument   authPasswordSyntax   = null;
141    BooleanArgument   useCompareResultCode = null;
142    BooleanArgument   listSchemes          = null;
143    BooleanArgument   showUsage            = null;
144    BooleanArgument   interactivePassword  = null;
145    StringArgument    clearPassword        = null;
146    FileBasedArgument clearPasswordFile    = null;
147    StringArgument    encodedPassword      = null;
148    FileBasedArgument encodedPasswordFile  = null;
149    StringArgument    configClass          = null;
150    StringArgument    configFile           = null;
151    StringArgument    schemeName           = null;
152
153
154    // Create the command-line argument parser for use with this program.
155    LocalizableMessage toolDescription = INFO_ENCPW_TOOL_DESCRIPTION.get();
156    ArgumentParser argParser =
157         new ArgumentParser("org.opends.server.tools.EncodePassword",
158                            toolDescription, false);
159    argParser.setShortToolDescription(REF_SHORT_DESC_ENCODE_PASSWORD.get());
160    argParser.setVersionHandler(new DirectoryServerVersionHandler());
161
162    // Initialize all the command-line argument types and register them with the
163    // parser.
164    try
165    {
166      listSchemes = new BooleanArgument(
167              "listschemes", 'l', "listSchemes",
168              INFO_ENCPW_DESCRIPTION_LISTSCHEMES.get());
169      argParser.addArgument(listSchemes);
170
171      interactivePassword = new BooleanArgument(
172              "interactivePassword", 'i',
173              "interactivePassword",
174              INFO_ENCPW_DESCRIPTION_INPUT_PW.get());
175      argParser.addArgument(interactivePassword);
176
177      clearPassword = new StringArgument("clearpw", 'c', "clearPassword", false,
178                                         false, true, INFO_CLEAR_PWD.get(),
179                                         null, null,
180                                         INFO_ENCPW_DESCRIPTION_CLEAR_PW.get());
181      argParser.addArgument(clearPassword);
182
183
184      clearPasswordFile =
185           new FileBasedArgument("clearpwfile", 'f', "clearPasswordFile", false,
186                                 false, INFO_FILE_PLACEHOLDER.get(), null, null,
187                                 INFO_ENCPW_DESCRIPTION_CLEAR_PW_FILE.get());
188      argParser.addArgument(clearPasswordFile);
189
190
191      encodedPassword = new StringArgument(
192              "encodedpw", 'e', "encodedPassword",
193              false, false, true, INFO_ENCODED_PWD_PLACEHOLDER.get(),
194              null, null,
195              INFO_ENCPW_DESCRIPTION_ENCODED_PW.get());
196      argParser.addArgument(encodedPassword);
197
198
199      encodedPasswordFile =
200           new FileBasedArgument("encodedpwfile", 'E', "encodedPasswordFile",
201                                 false, false, INFO_FILE_PLACEHOLDER.get(),
202                                 null, null,
203                                 INFO_ENCPW_DESCRIPTION_ENCODED_PW_FILE.get());
204      argParser.addArgument(encodedPasswordFile);
205
206
207      configClass = new StringArgument("configclass", OPTION_SHORT_CONFIG_CLASS,
208                                       OPTION_LONG_CONFIG_CLASS,
209                                       true, false, true,
210                                       INFO_CONFIGCLASS_PLACEHOLDER.get(),
211                                       ConfigFileHandler.class.getName(), null,
212                                       INFO_DESCRIPTION_CONFIG_CLASS.get());
213      configClass.setHidden(true);
214      argParser.addArgument(configClass);
215
216
217      configFile = new StringArgument("configfile", 'F', "configFile",
218                                      true, false, true,
219                                      INFO_CONFIGFILE_PLACEHOLDER.get(), null,
220                                      null,
221                                      INFO_DESCRIPTION_CONFIG_FILE.get());
222      configFile.setHidden(true);
223      argParser.addArgument(configFile);
224
225
226      schemeName = new StringArgument("scheme", 's', "storageScheme", false,
227                                      false, true,
228                                      INFO_STORAGE_SCHEME_PLACEHOLDER.get(),
229                                      null, null,
230                                      INFO_ENCPW_DESCRIPTION_SCHEME.get());
231      argParser.addArgument(schemeName);
232
233
234      authPasswordSyntax = new BooleanArgument(
235              "authpasswordsyntax", 'a',
236              "authPasswordSyntax",
237              INFO_ENCPW_DESCRIPTION_AUTHPW.get());
238      argParser.addArgument(authPasswordSyntax);
239
240
241      useCompareResultCode =
242           new BooleanArgument("usecompareresultcode", 'r',
243                               "useCompareResultCode",
244                               INFO_ENCPW_DESCRIPTION_USE_COMPARE_RESULT.get());
245      argParser.addArgument(useCompareResultCode);
246
247
248      showUsage = CommonArguments.getShowUsage();
249      argParser.addArgument(showUsage);
250      argParser.setUsageArgument(showUsage, out);
251    }
252    catch (ArgumentException ae)
253    {
254      printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage()));
255      return OPERATIONS_ERROR;
256    }
257
258
259    // Parse the command-line arguments provided to this program.
260    try
261    {
262      argParser.parseArguments(args);
263    }
264    catch (ArgumentException ae)
265    {
266      argParser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage()));
267      return OPERATIONS_ERROR;
268    }
269
270
271    // If we should just display usage or version information,
272    // then we've already done it so just return without doing anything else.
273    if (argParser.usageOrVersionDisplayed())
274    {
275      return SUCCESS;
276    }
277
278    // Checks the version - if upgrade required, the tool is unusable
279    try
280    {
281      BuildVersion.checkVersionMismatch();
282    }
283    catch (InitializationException e)
284    {
285      printWrappedText(err, e.getMessage());
286      return 1;
287    }
288
289    // Check for conflicting arguments.
290    if (clearPassword.isPresent() && clearPasswordFile.isPresent())
291    {
292      printWrappedText(err,
293          ERR_TOOL_CONFLICTING_ARGS.get(clearPassword.getLongIdentifier(), clearPasswordFile.getLongIdentifier()));
294      return OPERATIONS_ERROR;
295    }
296
297    if (clearPassword.isPresent() && interactivePassword.isPresent())
298    {
299      printWrappedText(err,
300          ERR_TOOL_CONFLICTING_ARGS.get(clearPassword.getLongIdentifier(), interactivePassword.getLongIdentifier()));
301      return OPERATIONS_ERROR;
302    }
303
304    if (clearPasswordFile.isPresent() && interactivePassword.isPresent())
305    {
306      printWrappedText(err, ERR_TOOL_CONFLICTING_ARGS.get(clearPasswordFile.getLongIdentifier(),
307                                                          interactivePassword.getLongIdentifier()));
308      return OPERATIONS_ERROR;
309    }
310
311    if (encodedPassword.isPresent() && encodedPasswordFile.isPresent())
312    {
313      printWrappedText(err,
314          ERR_TOOL_CONFLICTING_ARGS.get(encodedPassword.getLongIdentifier(), encodedPasswordFile.getLongIdentifier()));
315      return OPERATIONS_ERROR;
316    }
317
318
319    // If we are not going to just list the storage schemes, then the clear-text
320    // password must have been provided.  If we're going to encode a password,
321    // then the scheme must have also been provided.
322    if (!listSchemes.isPresent()
323        && !encodedPassword.isPresent()
324        && !encodedPasswordFile.isPresent()
325        && !schemeName.isPresent())
326    {
327      argParser.displayMessageAndUsageReference(err, ERR_ENCPW_NO_SCHEME.get(schemeName.getLongIdentifier()));
328      return OPERATIONS_ERROR;
329    }
330
331
332    // Determine whether we're encoding the clear-text password or comparing it
333    // against an already-encoded password.
334    boolean compareMode;
335    ByteString encodedPW = null;
336    if (encodedPassword.hasValue())
337    {
338      compareMode = true;
339      encodedPW = ByteString.valueOf(encodedPassword.getValue());
340    }
341    else if (encodedPasswordFile.hasValue())
342    {
343      compareMode = true;
344      encodedPW = ByteString.valueOf(encodedPasswordFile.getValue());
345    }
346    else
347    {
348      compareMode = false;
349    }
350
351
352    // Perform the initial bootstrap of the Directory Server and process the
353    // configuration.
354    DirectoryServer directoryServer = DirectoryServer.getInstance();
355
356    if (initializeServer)
357    {
358      try
359      {
360        DirectoryServer.bootstrapClient();
361        DirectoryServer.initializeJMX();
362      }
363      catch (Exception e)
364      {
365        printWrappedText(err, ERR_SERVER_BOOTSTRAP_ERROR.get(getExceptionMessage(e)));
366        return OPERATIONS_ERROR;
367      }
368
369      try
370      {
371        directoryServer.initializeConfiguration(configClass.getValue(),
372                                                configFile.getValue());
373      }
374      catch (InitializationException ie)
375      {
376        printWrappedText(err, ERR_CANNOT_LOAD_CONFIG.get(ie.getMessage()));
377        return OPERATIONS_ERROR;
378      }
379      catch (Exception e)
380      {
381        printWrappedText(err, ERR_CANNOT_LOAD_CONFIG.get(getExceptionMessage(e)));
382        return OPERATIONS_ERROR;
383      }
384
385
386
387      // Initialize the Directory Server schema elements.
388      try
389      {
390        directoryServer.initializeSchema();
391      }
392      catch (ConfigException | InitializationException e)
393      {
394        printWrappedText(err, ERR_CANNOT_LOAD_SCHEMA.get(e.getMessage()));
395        return OPERATIONS_ERROR;
396      }
397      catch (Exception e)
398      {
399        printWrappedText(err, ERR_CANNOT_LOAD_SCHEMA.get(getExceptionMessage(e)));
400        return OPERATIONS_ERROR;
401      }
402
403
404      // Initialize the Directory Server core configuration.
405      try
406      {
407        CoreConfigManager coreConfigManager = new CoreConfigManager(directoryServer.getServerContext());
408        coreConfigManager.initializeCoreConfig();
409      }
410      catch (ConfigException | InitializationException e)
411      {
412        printWrappedText(err, ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(e.getMessage()));
413        return OPERATIONS_ERROR;
414      }
415      catch (Exception e)
416      {
417        printWrappedText(err, ERR_CANNOT_INITIALIZE_CORE_CONFIG.get(getExceptionMessage(e)));
418        return OPERATIONS_ERROR;
419      }
420
421
422      if(!initializeServerComponents(directoryServer, err))
423      {
424        return -1;
425      }
426
427      // Initialize the password storage schemes.
428      try
429      {
430        PasswordStorageSchemeConfigManager storageSchemeConfigManager =
431             new PasswordStorageSchemeConfigManager(directoryServer.getServerContext());
432        storageSchemeConfigManager.initializePasswordStorageSchemes();
433      }
434      catch (ConfigException | InitializationException e)
435      {
436        printWrappedText(err, ERR_ENCPW_CANNOT_INITIALIZE_STORAGE_SCHEMES.get(e.getMessage()));
437        return OPERATIONS_ERROR;
438      }
439      catch (Exception e)
440      {
441        printWrappedText(err, ERR_ENCPW_CANNOT_INITIALIZE_STORAGE_SCHEMES.get(getExceptionMessage(e)));
442        return OPERATIONS_ERROR;
443      }
444    }
445
446
447    // If we are only trying to list the available schemes, then do so and exit.
448    if (listSchemes.isPresent())
449    {
450      if (authPasswordSyntax.isPresent())
451      {
452        listPasswordStorageSchemes(out, err, DirectoryServer.getAuthPasswordStorageSchemes(), true);
453      }
454      else
455      {
456        listPasswordStorageSchemes(out, err, DirectoryServer.getPasswordStorageSchemes(), false);
457      }
458      return SUCCESS;
459    }
460
461
462    // Either encode the clear-text password using the provided scheme, or
463    // compare the clear-text password against the encoded password.
464    ByteString clearPW = null;
465    if (compareMode)
466    {
467      // Check to see if the provided password value was encoded.  If so, then
468      // break it down into its component parts and use that to perform the
469      // comparison.  Otherwise, the user must have provided the storage scheme.
470      if (authPasswordSyntax.isPresent())
471      {
472        String scheme;
473        String authInfo;
474        String authValue;
475
476        try
477        {
478          StringBuilder[] authPWElements =
479               AuthPasswordSyntax.decodeAuthPassword(encodedPW.toString());
480          scheme    = authPWElements[0].toString();
481          authInfo  = authPWElements[1].toString();
482          authValue = authPWElements[2].toString();
483        }
484        catch (DirectoryException de)
485        {
486          printWrappedText(err, ERR_ENCPW_INVALID_ENCODED_AUTHPW.get(de.getMessageObject()));
487          return OPERATIONS_ERROR;
488        }
489        catch (Exception e)
490        {
491          printWrappedText(err, ERR_ENCPW_INVALID_ENCODED_AUTHPW.get(e));
492          return OPERATIONS_ERROR;
493        }
494
495        PasswordStorageScheme storageScheme =
496             DirectoryServer.getAuthPasswordStorageScheme(scheme);
497        if (storageScheme == null)
498        {
499          printWrappedText(err, ERR_ENCPW_NO_SUCH_AUTH_SCHEME.get(scheme));
500          return OPERATIONS_ERROR;
501        }
502
503        if (clearPW == null)
504        {
505          clearPW = getClearPW(out, err, argParser, clearPassword,
506              clearPasswordFile, interactivePassword);
507          if (clearPW == null)
508          {
509            return OPERATIONS_ERROR;
510          }
511        }
512        final boolean authPasswordMatches =
513            storageScheme.authPasswordMatches(clearPW, authInfo, authValue);
514        out.println(getOutputMessage(authPasswordMatches));
515        if (useCompareResultCode.isPresent())
516        {
517          return authPasswordMatches ? COMPARE_TRUE : COMPARE_FALSE;
518        }
519        return SUCCESS;
520      }
521      else
522      {
523        PasswordStorageScheme storageScheme;
524        String                encodedPWString;
525
526        if (UserPasswordSyntax.isEncoded(encodedPW))
527        {
528          try
529          {
530            String[] userPWElements =
531                 UserPasswordSyntax.decodeUserPassword(encodedPW.toString());
532            encodedPWString = userPWElements[1];
533
534            storageScheme =
535                 DirectoryServer.getPasswordStorageScheme(userPWElements[0]);
536            if (storageScheme == null)
537            {
538              printWrappedText(err, ERR_ENCPW_NO_SUCH_SCHEME.get(userPWElements[0]));
539              return OPERATIONS_ERROR;
540            }
541          }
542          catch (DirectoryException de)
543          {
544            printWrappedText(err, ERR_ENCPW_INVALID_ENCODED_USERPW.get(de.getMessageObject()));
545            return OPERATIONS_ERROR;
546          }
547          catch (Exception e)
548          {
549            printWrappedText(err, ERR_ENCPW_INVALID_ENCODED_USERPW.get(e));
550            return OPERATIONS_ERROR;
551          }
552        }
553        else
554        {
555          if (! schemeName.isPresent())
556          {
557            printWrappedText(err, ERR_ENCPW_NO_SCHEME.get(schemeName.getLongIdentifier()));
558            return OPERATIONS_ERROR;
559          }
560
561          encodedPWString = encodedPW.toString();
562
563          String scheme = toLowerCase(schemeName.getValue());
564          storageScheme = DirectoryServer.getPasswordStorageScheme(scheme);
565          if (storageScheme == null)
566          {
567            printWrappedText(err, ERR_ENCPW_NO_SUCH_SCHEME.get(scheme));
568            return OPERATIONS_ERROR;
569          }
570        }
571
572        if (clearPW == null)
573        {
574          clearPW = getClearPW(out, err, argParser, clearPassword,
575              clearPasswordFile, interactivePassword);
576          if (clearPW == null)
577          {
578            return OPERATIONS_ERROR;
579          }
580        }
581        boolean passwordMatches =
582            storageScheme.passwordMatches(clearPW, ByteString
583                .valueOf(encodedPWString));
584        out.println(getOutputMessage(passwordMatches));
585        if (useCompareResultCode.isPresent())
586        {
587          return passwordMatches ? COMPARE_TRUE : COMPARE_FALSE;
588        }
589        return SUCCESS;
590      }
591    }
592    else
593    {
594      // Try to get a reference to the requested password storage scheme.
595      PasswordStorageScheme storageScheme;
596      if (authPasswordSyntax.isPresent())
597      {
598        String scheme = schemeName.getValue();
599        storageScheme = DirectoryServer.getAuthPasswordStorageScheme(scheme);
600        if (storageScheme == null)
601        {
602          printWrappedText(err, ERR_ENCPW_NO_SUCH_AUTH_SCHEME.get(scheme));
603          return OPERATIONS_ERROR;
604        }
605      }
606      else
607      {
608        String scheme = toLowerCase(schemeName.getValue());
609        storageScheme = DirectoryServer.getPasswordStorageScheme(scheme);
610        if (storageScheme == null)
611        {
612          printWrappedText(err, ERR_ENCPW_NO_SUCH_SCHEME.get(scheme));
613          return OPERATIONS_ERROR;
614        }
615      }
616
617      if (authPasswordSyntax.isPresent())
618      {
619        try
620        {
621          if (clearPW == null)
622          {
623            clearPW = getClearPW(out, err, argParser, clearPassword,
624                clearPasswordFile, interactivePassword);
625            if (clearPW == null)
626            {
627              return OPERATIONS_ERROR;
628            }
629          }
630          encodedPW = storageScheme.encodeAuthPassword(clearPW);
631
632          LocalizableMessage message = ERR_ENCPW_ENCODED_PASSWORD.get(encodedPW);
633          out.println(message);
634        }
635        catch (DirectoryException de)
636        {
637          printWrappedText(err, ERR_ENCPW_CANNOT_ENCODE.get(de.getMessageObject()));
638          return OPERATIONS_ERROR;
639        }
640        catch (Exception e)
641        {
642          printWrappedText(err, ERR_ENCPW_CANNOT_ENCODE.get(getExceptionMessage(e)));
643          return OPERATIONS_ERROR;
644        }
645      }
646      else
647      {
648        try
649        {
650          if (clearPW == null)
651          {
652            clearPW = getClearPW(out, err, argParser, clearPassword,
653                clearPasswordFile, interactivePassword);
654            if (clearPW == null)
655            {
656              return OPERATIONS_ERROR;
657            }
658          }
659          encodedPW = storageScheme.encodePasswordWithScheme(clearPW);
660
661          out.println(ERR_ENCPW_ENCODED_PASSWORD.get(encodedPW));
662        }
663        catch (DirectoryException de)
664        {
665          printWrappedText(err, ERR_ENCPW_CANNOT_ENCODE.get(de.getMessageObject()));
666          return OPERATIONS_ERROR;
667        }
668        catch (Exception e)
669        {
670          printWrappedText(err, ERR_ENCPW_CANNOT_ENCODE.get(getExceptionMessage(e)));
671          return OPERATIONS_ERROR;
672        }
673      }
674    }
675
676    // If we've gotten here, then all processing completed successfully.
677    return SUCCESS;
678  }
679
680  private static void listPasswordStorageSchemes(PrintStream out, PrintStream err,
681      ConcurrentHashMap<String, PasswordStorageScheme> storageSchemes, boolean authPasswordSchemeName)
682  {
683    if (storageSchemes.isEmpty())
684    {
685      printWrappedText(err, ERR_ENCPW_NO_STORAGE_SCHEMES.get());
686    }
687    else
688    {
689      ArrayList<String> nameList = new ArrayList<>(storageSchemes.size());
690      for (PasswordStorageScheme<?> s : storageSchemes.values())
691      {
692        if (authPasswordSchemeName)
693        {
694          nameList.add(s.getAuthPasswordSchemeName());
695        }
696        else
697        {
698          nameList.add(s.getStorageSchemeName());
699        }
700      }
701      Collections.sort(nameList);
702
703      for (String storageSchemeName : nameList)
704      {
705        out.println(storageSchemeName);
706      }
707    }
708  }
709
710  private static LocalizableMessage getOutputMessage(boolean passwordMatches)
711  {
712    if (passwordMatches)
713    {
714      return INFO_ENCPW_PASSWORDS_MATCH.get();
715    }
716    return INFO_ENCPW_PASSWORDS_DO_NOT_MATCH.get();
717  }
718
719
720
721  private static boolean initializeServerComponents(DirectoryServer directoryServer, PrintStream err)
722  {
723      // Initialize the Directory Server crypto manager.
724      try
725      {
726        directoryServer.initializeCryptoManager();
727      }
728      catch (ConfigException | InitializationException e)
729      {
730        printWrappedText(err, ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(e.getMessage()));
731        return false;
732      }
733      catch (Exception e)
734      {
735        printWrappedText(err, ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(getExceptionMessage(e)));
736        return false;
737      }
738      //Attempt to bring up enough of the server to process schemes requiring
739      //secret keys from the trust store backend (3DES, BLOWFISH, AES, RC4) via
740      //the crypto-manager.
741      try {
742          directoryServer.initializeRootDNConfigManager();
743          directoryServer.initializePlugins(Collections.EMPTY_SET);
744          initializeServerBackends(directoryServer, err);
745          directoryServer.initializeSubentryManager();
746          directoryServer.initializeAuthenticationPolicyComponents();
747          directoryServer.initializeAuthenticatedUsers();
748          new CryptoManagerSync();
749    } catch (InitializationException | ConfigException e) {
750        printWrappedText(err, ERR_ENCPW_CANNOT_INITIALIZE_SERVER_COMPONENTS.get(getExceptionMessage(e)));
751        return false;
752    }
753    return true;
754  }
755
756  private static void initializeServerBackends(DirectoryServer directoryServer, PrintStream err)
757  throws InitializationException, ConfigException {
758    directoryServer.initializeRootDSE();
759    ServerManagementContext context = ServerManagementContext.getInstance();
760    RootCfg root = context.getRootConfiguration();
761    ConfigEntry backendRoot;
762    try {
763      DN configEntryDN = DN.valueOf(ConfigConstants.DN_BACKEND_BASE);
764      backendRoot   = DirectoryServer.getConfigEntry(configEntryDN);
765    } catch (Exception e) {
766      LocalizableMessage message = ERR_CONFIG_BACKEND_CANNOT_GET_CONFIG_BASE.get(
767          getExceptionMessage(e));
768      throw new ConfigException(message, e);
769    }
770    if (backendRoot == null) {
771      LocalizableMessage message = ERR_CONFIG_BACKEND_BASE_DOES_NOT_EXIST.get();
772      throw new ConfigException(message);
773    }
774    for (String name : root.listBackends()) {
775      BackendCfg backendCfg = root.getBackend(name);
776      String backendID = backendCfg.getBackendId();
777      if((backendCfg instanceof TrustStoreBackendCfg
778          || backendCfg instanceof LDIFBackendCfg)
779          && backendCfg.isEnabled())
780      {
781        String className = backendCfg.getJavaClass();
782        Class<?> backendClass;
783        Backend<BackendCfg> backend;
784        try {
785          backendClass = DirectoryServer.loadClass(className);
786          backend = (Backend<BackendCfg>) backendClass.newInstance();
787        } catch (Exception e) {
788          printWrappedText(err,
789              ERR_CONFIG_BACKEND_CANNOT_INSTANTIATE.get(className, backendCfg.dn(), stackTraceToSingleLineString(e)));
790          continue;
791        }
792        backend.setBackendID(backendID);
793        backend.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
794        try {
795          backend.configureBackend(backendCfg, directoryServer.getServerContext());
796          backend.openBackend();
797        } catch (Exception e) {
798          printWrappedText(err,
799              ERR_CONFIG_BACKEND_CANNOT_INITIALIZE.get(className, backendCfg.dn(), stackTraceToSingleLineString(e)));
800        }
801        try {
802          DirectoryServer.registerBackend(backend);
803        } catch (Exception e)
804        {
805          printWrappedText(
806              err, WARN_CONFIG_BACKEND_CANNOT_REGISTER_BACKEND.get(backendCfg.getBackendId(), getExceptionMessage(e)));
807        }
808      }
809    }
810  }
811
812  /**
813   * Get the clear password.
814   * @param out The output to ask password.
815   * @param err The error output.
816   * @param argParser The argument parser.
817   * @param clearPassword the clear password
818   * @param clearPasswordFile the file in which the password in stored
819   * @param interactivePassword indicate if the password should be asked
820   *        interactively.
821   * @return the password or null if an error occurs.
822   */
823  private static ByteString getClearPW(PrintStream out, PrintStream err,
824      ArgumentParser argParser, StringArgument clearPassword,
825      FileBasedArgument clearPasswordFile, BooleanArgument interactivePassword)
826  {
827    if (clearPassword.hasValue())
828    {
829      return ByteString.valueOf(clearPassword.getValue());
830    }
831    else if (clearPasswordFile.hasValue())
832    {
833      return ByteString.valueOf(clearPasswordFile.getValue());
834    }
835    else if (interactivePassword.isPresent())
836    {
837      try
838      {
839        EncodePassword encodePassword = new EncodePassword();
840        String pwd1 = encodePassword.getPassword(INFO_ENCPW_INPUT_PWD_1.get().toString());
841        String pwd2 = encodePassword.getPassword(INFO_ENCPW_INPUT_PWD_2.get().toString());
842        if (pwd1.equals(pwd2))
843        {
844          return ByteString.valueOf(pwd1);
845        }
846        else
847        {
848          printWrappedText(err, ERR_ENCPW_NOT_SAME_PW.get());
849          return null;
850        }
851      }
852      catch (IOException e)
853      {
854        printWrappedText(err, ERR_ENCPW_CANNOT_READ_PW.get(e.getMessage()));
855        return null;
856      }
857    }
858    else
859    {
860      argParser.displayMessageAndUsageReference(err, ERR_ENCPW_NO_CLEAR_PW.get(clearPassword.getLongIdentifier(),
861                                      clearPasswordFile.getLongIdentifier(), interactivePassword.getLongIdentifier()));
862      return null;
863    }
864  }
865
866  /**
867   * Get the password from JDK6 console or from masked password.
868   * @param prompt The message to print out.
869   * @return the password
870   * @throws IOException if an issue occurs when reading the password
871   *         from the input
872   */
873  private String getPassword(String prompt) throws IOException
874  {
875    String password;
876    try
877    {
878      Console console = System.console();
879      if (console == null)
880      {
881        throw new IOException("No console");
882      }
883      password = new String(console.readPassword(prompt));
884    }
885    catch (Exception e)
886    {
887      // Try the fallback to the old trick method.
888      // Create the thread that will erase chars
889      ErasingThread erasingThread = new ErasingThread(prompt);
890      erasingThread.start();
891
892      password = "";
893
894      // block until enter is pressed
895      while (true)
896      {
897        char c = (char) System.in.read();
898        // assume enter pressed, stop masking
899        erasingThread.stopMasking();
900        if (c == '\r')
901        {
902          c = (char) System.in.read();
903          if (c == '\n')
904          {
905            break;
906          }
907        }
908        else if (c == '\n')
909        {
910          break;
911        }
912        else
913        {
914          // store the password
915          password += c;
916        }
917      }
918    }
919    return password;
920  }
921
922
923  /**
924   * Thread that mask user input.
925   */
926  private class ErasingThread extends Thread
927  {
928
929    private boolean stop;
930    private String prompt;
931
932    /**
933     * The class will mask the user input.
934     * @param prompt
935     *          The prompt displayed to the user
936     */
937    public ErasingThread(String prompt)
938    {
939      this.prompt = prompt;
940    }
941
942    /**
943     * Begin masking until asked to stop.
944     */
945    @Override
946    public void run()
947    {
948      while (!stop)
949      {
950        try
951        {
952          // attempt masking at this rate
953          Thread.sleep(1);
954        }
955        catch (InterruptedException iex)
956        {
957          iex.printStackTrace();
958        }
959        if (!stop)
960        {
961          System.out.print("\r" + prompt + " \r" + prompt);
962        }
963        System.out.flush();
964      }
965    }
966
967    /**
968     * Instruct the thread to stop masking.
969     */
970    public void stopMasking()
971    {
972      this.stop = true;
973    }
974  }
975
976}
977