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.valueOfUtf8(encodedPassword.getValue());
340    }
341    else if (encodedPasswordFile.hasValue())
342    {
343      compareMode = true;
344      encodedPW = ByteString.valueOfUtf8(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[] authPWElements;
473        try
474        {
475          authPWElements = AuthPasswordSyntax.decodeAuthPassword(encodedPW.toString());
476        }
477        catch (DirectoryException de)
478        {
479          printWrappedText(err, ERR_ENCPW_INVALID_ENCODED_AUTHPW.get(de.getMessageObject()));
480          return OPERATIONS_ERROR;
481        }
482        catch (Exception e)
483        {
484          printWrappedText(err, ERR_ENCPW_INVALID_ENCODED_AUTHPW.get(e));
485          return OPERATIONS_ERROR;
486        }
487
488        String scheme = authPWElements[0];
489        String authInfo = authPWElements[1];
490        String authValue = authPWElements[2];
491
492        PasswordStorageScheme storageScheme =
493             DirectoryServer.getAuthPasswordStorageScheme(scheme);
494        if (storageScheme == null)
495        {
496          printWrappedText(err, ERR_ENCPW_NO_SUCH_AUTH_SCHEME.get(scheme));
497          return OPERATIONS_ERROR;
498        }
499
500        if (clearPW == null)
501        {
502          clearPW = getClearPW(out, err, argParser, clearPassword,
503              clearPasswordFile, interactivePassword);
504          if (clearPW == null)
505          {
506            return OPERATIONS_ERROR;
507          }
508        }
509        final boolean authPasswordMatches =
510            storageScheme.authPasswordMatches(clearPW, authInfo, authValue);
511        out.println(getOutputMessage(authPasswordMatches));
512        if (useCompareResultCode.isPresent())
513        {
514          return authPasswordMatches ? COMPARE_TRUE : COMPARE_FALSE;
515        }
516        return SUCCESS;
517      }
518      else
519      {
520        PasswordStorageScheme storageScheme;
521        String                encodedPWString;
522
523        if (UserPasswordSyntax.isEncoded(encodedPW))
524        {
525          try
526          {
527            String[] userPWElements =
528                 UserPasswordSyntax.decodeUserPassword(encodedPW.toString());
529            encodedPWString = userPWElements[1];
530
531            storageScheme =
532                 DirectoryServer.getPasswordStorageScheme(userPWElements[0]);
533            if (storageScheme == null)
534            {
535              printWrappedText(err, ERR_ENCPW_NO_SUCH_SCHEME.get(userPWElements[0]));
536              return OPERATIONS_ERROR;
537            }
538          }
539          catch (DirectoryException de)
540          {
541            printWrappedText(err, ERR_ENCPW_INVALID_ENCODED_USERPW.get(de.getMessageObject()));
542            return OPERATIONS_ERROR;
543          }
544          catch (Exception e)
545          {
546            printWrappedText(err, ERR_ENCPW_INVALID_ENCODED_USERPW.get(e));
547            return OPERATIONS_ERROR;
548          }
549        }
550        else
551        {
552          if (! schemeName.isPresent())
553          {
554            printWrappedText(err, ERR_ENCPW_NO_SCHEME.get(schemeName.getLongIdentifier()));
555            return OPERATIONS_ERROR;
556          }
557
558          encodedPWString = encodedPW.toString();
559
560          String scheme = toLowerCase(schemeName.getValue());
561          storageScheme = DirectoryServer.getPasswordStorageScheme(scheme);
562          if (storageScheme == null)
563          {
564            printWrappedText(err, ERR_ENCPW_NO_SUCH_SCHEME.get(scheme));
565            return OPERATIONS_ERROR;
566          }
567        }
568
569        if (clearPW == null)
570        {
571          clearPW = getClearPW(out, err, argParser, clearPassword,
572              clearPasswordFile, interactivePassword);
573          if (clearPW == null)
574          {
575            return OPERATIONS_ERROR;
576          }
577        }
578        boolean passwordMatches =
579            storageScheme.passwordMatches(clearPW, ByteString
580                .valueOfUtf8(encodedPWString));
581        out.println(getOutputMessage(passwordMatches));
582        if (useCompareResultCode.isPresent())
583        {
584          return passwordMatches ? COMPARE_TRUE : COMPARE_FALSE;
585        }
586        return SUCCESS;
587      }
588    }
589    else
590    {
591      // Try to get a reference to the requested password storage scheme.
592      PasswordStorageScheme storageScheme;
593      if (authPasswordSyntax.isPresent())
594      {
595        String scheme = schemeName.getValue();
596        storageScheme = DirectoryServer.getAuthPasswordStorageScheme(scheme);
597        if (storageScheme == null)
598        {
599          printWrappedText(err, ERR_ENCPW_NO_SUCH_AUTH_SCHEME.get(scheme));
600          return OPERATIONS_ERROR;
601        }
602      }
603      else
604      {
605        String scheme = toLowerCase(schemeName.getValue());
606        storageScheme = DirectoryServer.getPasswordStorageScheme(scheme);
607        if (storageScheme == null)
608        {
609          printWrappedText(err, ERR_ENCPW_NO_SUCH_SCHEME.get(scheme));
610          return OPERATIONS_ERROR;
611        }
612      }
613
614      if (authPasswordSyntax.isPresent())
615      {
616        try
617        {
618          if (clearPW == null)
619          {
620            clearPW = getClearPW(out, err, argParser, clearPassword,
621                clearPasswordFile, interactivePassword);
622            if (clearPW == null)
623            {
624              return OPERATIONS_ERROR;
625            }
626          }
627          encodedPW = storageScheme.encodeAuthPassword(clearPW);
628
629          LocalizableMessage message = ERR_ENCPW_ENCODED_PASSWORD.get(encodedPW);
630          out.println(message);
631        }
632        catch (DirectoryException de)
633        {
634          printWrappedText(err, ERR_ENCPW_CANNOT_ENCODE.get(de.getMessageObject()));
635          return OPERATIONS_ERROR;
636        }
637        catch (Exception e)
638        {
639          printWrappedText(err, ERR_ENCPW_CANNOT_ENCODE.get(getExceptionMessage(e)));
640          return OPERATIONS_ERROR;
641        }
642      }
643      else
644      {
645        try
646        {
647          if (clearPW == null)
648          {
649            clearPW = getClearPW(out, err, argParser, clearPassword,
650                clearPasswordFile, interactivePassword);
651            if (clearPW == null)
652            {
653              return OPERATIONS_ERROR;
654            }
655          }
656          encodedPW = storageScheme.encodePasswordWithScheme(clearPW);
657
658          out.println(ERR_ENCPW_ENCODED_PASSWORD.get(encodedPW));
659        }
660        catch (DirectoryException de)
661        {
662          printWrappedText(err, ERR_ENCPW_CANNOT_ENCODE.get(de.getMessageObject()));
663          return OPERATIONS_ERROR;
664        }
665        catch (Exception e)
666        {
667          printWrappedText(err, ERR_ENCPW_CANNOT_ENCODE.get(getExceptionMessage(e)));
668          return OPERATIONS_ERROR;
669        }
670      }
671    }
672
673    // If we've gotten here, then all processing completed successfully.
674    return SUCCESS;
675  }
676
677  private static void listPasswordStorageSchemes(PrintStream out, PrintStream err,
678      ConcurrentHashMap<String, PasswordStorageScheme> storageSchemes, boolean authPasswordSchemeName)
679  {
680    if (storageSchemes.isEmpty())
681    {
682      printWrappedText(err, ERR_ENCPW_NO_STORAGE_SCHEMES.get());
683    }
684    else
685    {
686      ArrayList<String> nameList = new ArrayList<>(storageSchemes.size());
687      for (PasswordStorageScheme<?> s : storageSchemes.values())
688      {
689        if (authPasswordSchemeName)
690        {
691          nameList.add(s.getAuthPasswordSchemeName());
692        }
693        else
694        {
695          nameList.add(s.getStorageSchemeName());
696        }
697      }
698      Collections.sort(nameList);
699
700      for (String storageSchemeName : nameList)
701      {
702        out.println(storageSchemeName);
703      }
704    }
705  }
706
707  private static LocalizableMessage getOutputMessage(boolean passwordMatches)
708  {
709    if (passwordMatches)
710    {
711      return INFO_ENCPW_PASSWORDS_MATCH.get();
712    }
713    return INFO_ENCPW_PASSWORDS_DO_NOT_MATCH.get();
714  }
715
716
717
718  private static boolean initializeServerComponents(DirectoryServer directoryServer, PrintStream err)
719  {
720      // Initialize the Directory Server crypto manager.
721      try
722      {
723        directoryServer.initializeCryptoManager();
724      }
725      catch (ConfigException | InitializationException e)
726      {
727        printWrappedText(err, ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(e.getMessage()));
728        return false;
729      }
730      catch (Exception e)
731      {
732        printWrappedText(err, ERR_CANNOT_INITIALIZE_CRYPTO_MANAGER.get(getExceptionMessage(e)));
733        return false;
734      }
735      //Attempt to bring up enough of the server to process schemes requiring
736      //secret keys from the trust store backend (3DES, BLOWFISH, AES, RC4) via
737      //the crypto-manager.
738      try {
739          directoryServer.initializeRootDNConfigManager();
740          directoryServer.initializePlugins(Collections.EMPTY_SET);
741          initializeServerBackends(directoryServer, err);
742          directoryServer.initializeSubentryManager();
743          directoryServer.initializeAuthenticationPolicyComponents();
744          directoryServer.initializeAuthenticatedUsers();
745          new CryptoManagerSync();
746    } catch (InitializationException | ConfigException e) {
747        printWrappedText(err, ERR_ENCPW_CANNOT_INITIALIZE_SERVER_COMPONENTS.get(getExceptionMessage(e)));
748        return false;
749    }
750    return true;
751  }
752
753  private static void initializeServerBackends(DirectoryServer directoryServer, PrintStream err)
754  throws InitializationException, ConfigException {
755    directoryServer.initializeRootDSE();
756    ServerManagementContext context = ServerManagementContext.getInstance();
757    RootCfg root = context.getRootConfiguration();
758    ConfigEntry backendRoot;
759    try {
760      DN configEntryDN = DN.valueOf(ConfigConstants.DN_BACKEND_BASE);
761      backendRoot   = DirectoryServer.getConfigEntry(configEntryDN);
762    } catch (Exception e) {
763      LocalizableMessage message = ERR_CONFIG_BACKEND_CANNOT_GET_CONFIG_BASE.get(
764          getExceptionMessage(e));
765      throw new ConfigException(message, e);
766    }
767    if (backendRoot == null) {
768      LocalizableMessage message = ERR_CONFIG_BACKEND_BASE_DOES_NOT_EXIST.get();
769      throw new ConfigException(message);
770    }
771    for (String name : root.listBackends()) {
772      BackendCfg backendCfg = root.getBackend(name);
773      String backendID = backendCfg.getBackendId();
774      if((backendCfg instanceof TrustStoreBackendCfg
775          || backendCfg instanceof LDIFBackendCfg)
776          && backendCfg.isEnabled())
777      {
778        String className = backendCfg.getJavaClass();
779        Class<?> backendClass;
780        Backend<BackendCfg> backend;
781        try {
782          backendClass = DirectoryServer.loadClass(className);
783          backend = (Backend<BackendCfg>) backendClass.newInstance();
784        } catch (Exception e) {
785          printWrappedText(err,
786              ERR_CONFIG_BACKEND_CANNOT_INSTANTIATE.get(className, backendCfg.dn(), stackTraceToSingleLineString(e)));
787          continue;
788        }
789        backend.setBackendID(backendID);
790        backend.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
791        try {
792          backend.configureBackend(backendCfg, directoryServer.getServerContext());
793          backend.openBackend();
794        } catch (Exception e) {
795          printWrappedText(err,
796              ERR_CONFIG_BACKEND_CANNOT_INITIALIZE.get(className, backendCfg.dn(), stackTraceToSingleLineString(e)));
797        }
798        try {
799          DirectoryServer.registerBackend(backend);
800        } catch (Exception e)
801        {
802          printWrappedText(
803              err, WARN_CONFIG_BACKEND_CANNOT_REGISTER_BACKEND.get(backendCfg.getBackendId(), getExceptionMessage(e)));
804        }
805      }
806    }
807  }
808
809  /**
810   * Get the clear password.
811   * @param out The output to ask password.
812   * @param err The error output.
813   * @param argParser The argument parser.
814   * @param clearPassword the clear password
815   * @param clearPasswordFile the file in which the password in stored
816   * @param interactivePassword indicate if the password should be asked
817   *        interactively.
818   * @return the password or null if an error occurs.
819   */
820  private static ByteString getClearPW(PrintStream out, PrintStream err,
821      ArgumentParser argParser, StringArgument clearPassword,
822      FileBasedArgument clearPasswordFile, BooleanArgument interactivePassword)
823  {
824    if (clearPassword.hasValue())
825    {
826      return ByteString.valueOfUtf8(clearPassword.getValue());
827    }
828    else if (clearPasswordFile.hasValue())
829    {
830      return ByteString.valueOfUtf8(clearPasswordFile.getValue());
831    }
832    else if (interactivePassword.isPresent())
833    {
834      try
835      {
836        EncodePassword encodePassword = new EncodePassword();
837        String pwd1 = encodePassword.getPassword(INFO_ENCPW_INPUT_PWD_1.get().toString());
838        String pwd2 = encodePassword.getPassword(INFO_ENCPW_INPUT_PWD_2.get().toString());
839        if (pwd1.equals(pwd2))
840        {
841          return ByteString.valueOfUtf8(pwd1);
842        }
843        else
844        {
845          printWrappedText(err, ERR_ENCPW_NOT_SAME_PW.get());
846          return null;
847        }
848      }
849      catch (IOException e)
850      {
851        printWrappedText(err, ERR_ENCPW_CANNOT_READ_PW.get(e.getMessage()));
852        return null;
853      }
854    }
855    else
856    {
857      argParser.displayMessageAndUsageReference(err, ERR_ENCPW_NO_CLEAR_PW.get(clearPassword.getLongIdentifier(),
858                                      clearPasswordFile.getLongIdentifier(), interactivePassword.getLongIdentifier()));
859      return null;
860    }
861  }
862
863  /**
864   * Get the password from JDK6 console or from masked password.
865   * @param prompt The message to print out.
866   * @return the password
867   * @throws IOException if an issue occurs when reading the password
868   *         from the input
869   */
870  private String getPassword(String prompt) throws IOException
871  {
872    String password;
873    try
874    {
875      Console console = System.console();
876      if (console == null)
877      {
878        throw new IOException("No console");
879      }
880      password = new String(console.readPassword(prompt));
881    }
882    catch (Exception e)
883    {
884      // Try the fallback to the old trick method.
885      // Create the thread that will erase chars
886      ErasingThread erasingThread = new ErasingThread(prompt);
887      erasingThread.start();
888
889      password = "";
890
891      // block until enter is pressed
892      while (true)
893      {
894        char c = (char) System.in.read();
895        // assume enter pressed, stop masking
896        erasingThread.stopMasking();
897        if (c == '\r')
898        {
899          c = (char) System.in.read();
900          if (c == '\n')
901          {
902            break;
903          }
904        }
905        else if (c == '\n')
906        {
907          break;
908        }
909        else
910        {
911          // store the password
912          password += c;
913        }
914      }
915    }
916    return password;
917  }
918
919
920  /**
921   * Thread that mask user input.
922   */
923  private class ErasingThread extends Thread
924  {
925
926    private boolean stop;
927    private String prompt;
928
929    /**
930     * The class will mask the user input.
931     * @param prompt
932     *          The prompt displayed to the user
933     */
934    public ErasingThread(String prompt)
935    {
936      this.prompt = prompt;
937    }
938
939    /**
940     * Begin masking until asked to stop.
941     */
942    @Override
943    public void run()
944    {
945      while (!stop)
946      {
947        try
948        {
949          // attempt masking at this rate
950          Thread.sleep(1);
951        }
952        catch (InterruptedException iex)
953        {
954          iex.printStackTrace();
955        }
956        if (!stop)
957        {
958          System.out.print("\r" + prompt + " \r" + prompt);
959        }
960        System.out.flush();
961      }
962    }
963
964    /**
965     * Instruct the thread to stop masking.
966     */
967    public void stopMasking()
968    {
969      this.stop = true;
970    }
971  }
972
973}
974