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