mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

lutoff
31.54.2009 9de916fbb0e9a77e02d87c08a57df18944653136
 fixed for issue #3818 (encode-password should support accepting clear text password on STDIN)
A new argument (--i, interactivePassword) is added to prompt password
2 files modified
290 ■■■■■ changed files
opends/src/messages/messages/tools.properties 8 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/tools/EncodePassword.java 282 ●●●●● patch | view | raw | blame | history
opends/src/messages/messages/tools.properties
@@ -80,7 +80,7 @@
SEVERE_ERR_ERROR_PARSING_ARGS_17=An error occurred while parsing the \
 command-line arguments:  %s
SEVERE_ERR_ENCPW_NO_CLEAR_PW_18=No clear-text password was specified.  Use \
 --%s or --%s to specify the password to encode
 --%s, --%s or --%s to specify the password to encode
SEVERE_ERR_ENCPW_NO_SCHEME_19=No password storage scheme was specified.  Use \
 the --%s argument to specify the storage scheme
SEVERE_ERR_SERVER_BOOTSTRAP_ERROR_20=An unexpected error occurred while \
@@ -2519,3 +2519,9 @@
INFO_LDAPSEARCH_PUBLIC_CHANGELOG_COOKIE_EXC_1689=# Public \
 changelog exchange control(%s): %s
INFO_ENCPW_DESCRIPTION_INPUT_PW_1690=The password to encode or to compare \
 against an encoded password is interactively asked to the user
INFO_ENCPW_INPUT_PWD_1_1691=Please enter the password :
INFO_ENCPW_INPUT_PWD_2_1692=Please renter the password:
SEVERE_ERR_ENCPW_NOT_SAME_PW_1693=Provided passwords don't matched
SEVERE_ERR_ENCPW_CANNOT_READ_PW_1694=Cannot read password from the input: %s
opends/src/server/org/opends/server/tools/EncodePassword.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Copyright 2006-2009 Sun Microsystems, Inc.
 */
package org.opends.server.tools;
@@ -36,8 +36,10 @@
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -170,6 +172,7 @@
    BooleanArgument   useCompareResultCode = null;
    BooleanArgument   listSchemes          = null;
    BooleanArgument   showUsage            = null;
    BooleanArgument   interactivePassword  = null;
    StringArgument    clearPassword        = null;
    FileBasedArgument clearPasswordFile    = null;
    StringArgument    encodedPassword      = null;
@@ -195,6 +198,11 @@
              INFO_ENCPW_DESCRIPTION_LISTSCHEMES.get());
      argParser.addArgument(listSchemes);
      interactivePassword = new BooleanArgument(
              "interactivePassword", 'i',
              "interactivePassword",
              INFO_ENCPW_DESCRIPTION_INPUT_PW.get());
      argParser.addArgument(interactivePassword);
      clearPassword = new StringArgument("clearpw", 'c', "clearPassword", false,
                                         false, true, INFO_CLEAR_PWD.get(),
@@ -315,6 +323,25 @@
      return 1;
    }
    if (clearPassword.isPresent() && interactivePassword.isPresent())
    {
      Message message =
              ERR_TOOL_CONFLICTING_ARGS.get(clearPassword.getLongIdentifier(),
                  interactivePassword.getLongIdentifier());
      err.println(wrapText(message, MAX_LINE_WIDTH));
      return 1;
    }
    if (clearPasswordFile.isPresent() && interactivePassword.isPresent())
    {
      Message message =
              ERR_TOOL_CONFLICTING_ARGS.get(
                  clearPasswordFile.getLongIdentifier(),
                  interactivePassword.getLongIdentifier());
      err.println(wrapText(message, MAX_LINE_WIDTH));
      return 1;
    }
    if (encodedPassword.isPresent() && encodedPasswordFile.isPresent())
    {
      Message message =
@@ -331,24 +358,6 @@
    ByteString clearPW = null;
    if (! listSchemes.isPresent())
    {
      if (clearPassword.hasValue())
      {
        clearPW = ByteString.valueOf(clearPassword.getValue());
      }
      else if (clearPasswordFile.hasValue())
      {
        clearPW = ByteString.valueOf(clearPasswordFile.getValue());
      }
      else
      {
        Message message =
                ERR_ENCPW_NO_CLEAR_PW.get(clearPassword.getLongIdentifier(),
                clearPasswordFile.getLongIdentifier());
        err.println(wrapText(message, MAX_LINE_WIDTH));
        err.println(argParser.getUsage());
        return 1;
      }
      if ((! encodedPassword.isPresent()) && (! encodedPasswordFile.isPresent())
           && (! schemeName.isPresent()))
      {
@@ -623,6 +632,15 @@
          return 1;
        }
        if (clearPW == null)
        {
          clearPW = getClearPW(out, err, argParser, clearPassword,
              clearPasswordFile, interactivePassword);
          if (clearPW == null)
          {
            return 1;
          }
        }
        if (storageScheme.authPasswordMatches(clearPW, authInfo, authValue))
        {
          Message message = INFO_ENCPW_PASSWORDS_MATCH.get();
@@ -711,6 +729,15 @@
          }
        }
        if (clearPW == null)
        {
          clearPW = getClearPW(out, err, argParser, clearPassword,
              clearPasswordFile, interactivePassword);
          if (clearPW == null)
          {
            return 1;
          }
        }
        if (storageScheme.passwordMatches(clearPW,
            ByteString.valueOf(encodedPWString)))
        {
@@ -773,6 +800,15 @@
      {
        try
        {
          if (clearPW == null)
          {
            clearPW = getClearPW(out, err, argParser, clearPassword,
                clearPasswordFile, interactivePassword);
            if (clearPW == null)
            {
              return 1;
            }
          }
          encodedPW = storageScheme.encodeAuthPassword(clearPW);
          Message message = ERR_ENCPW_ENCODED_PASSWORD.get(
@@ -796,6 +832,15 @@
      {
        try
        {
          if (clearPW == null)
          {
            clearPW = getClearPW(out, err, argParser, clearPassword,
                clearPasswordFile, interactivePassword);
            if (clearPW == null)
            {
              return 1;
            }
          }
          encodedPW = storageScheme.encodePasswordWithScheme(clearPW);
          Message message =
@@ -961,5 +1006,204 @@
      }
    }
  }
  /**
   * Get the clear password.
   * @param out The output to ask password.
   * @param err The error output.
   * @param argParser The argument parser.
   * @param clearPassword the clear password
   * @param clearPasswordFile the fil in which the password in stored
   * @param interactivePassword indicate if the password should be asked
   *        interactively.
   * @return the password or null if an error occurs.
   */
  private static ByteString getClearPW(PrintStream out, PrintStream err,
      ArgumentParser argParser, StringArgument clearPassword,
      FileBasedArgument clearPasswordFile, BooleanArgument interactivePassword)
  {
    ByteString clearPW = null;
    if (clearPassword.hasValue())
    {
      clearPW = ByteString.valueOf(clearPassword.getValue());
    }
    else if (clearPasswordFile.hasValue())
    {
      clearPW = ByteString.valueOf(clearPasswordFile.getValue());
    }
    else if (interactivePassword.isPresent())
    {
      EncodePassword encodePassword = new EncodePassword() ;
      try
      {
        String pwd1, pwd2;
        Message msg = INFO_ENCPW_INPUT_PWD_1.get();
        pwd1 = encodePassword.getPassword(out, msg.toString());
        msg = INFO_ENCPW_INPUT_PWD_2.get();
        pwd2 = encodePassword.getPassword(out,msg.toString());
        if (pwd1.equals(pwd2))
        {
          clearPW = ByteString.valueOf(pwd1);
        }
        else
        {
          Message message = ERR_ENCPW_NOT_SAME_PW.get();
          err.println(wrapText(message, MAX_LINE_WIDTH));
          return null;
        }
      }
      catch (IOException e)
      {
        Message message = ERR_ENCPW_CANNOT_READ_PW.get(e.getMessage());
        err.println(wrapText(message, MAX_LINE_WIDTH));
        return null;
      }
    }
    else
    {
      Message message = ERR_ENCPW_NO_CLEAR_PW.get(clearPassword
          .getLongIdentifier(), clearPasswordFile.getLongIdentifier(),
          interactivePassword.getLongIdentifier());
      err.println(wrapText(message, MAX_LINE_WIDTH));
      err.println(argParser.getUsage());
      return null;
    }
    return clearPW;
  }
  /**
   * Get the password from JDK6 console or from masked password.
   * @param out The output
   * @param prompt The message to print out.
   * @return the password
   * @throws IOException if an issue occurs when reading the password
   *         from the input
   */
  private String getPassword(PrintStream out, String prompt)
      throws IOException
  {
    String password;
    try // JDK 6 console
    {
      // get the Console (class the constructor)
      Method constructor =
        System.class.getDeclaredMethod("console",new Class[0]);
      Object console = constructor.invoke(null, new Object[0]);
      if (console != null)
      {
        // class to method
        Class<?> c = Class.forName("java.io.Console");
        Object[] args = new Object[] { prompt, new Object[0] };
        Method m = c.getDeclaredMethod("readPassword",
            new Class[] { String.class, args.getClass() });
        password = new String((char[]) m.invoke(console, args));
      }
      else
      {
        throw new IOException("No console");
      }
    }
    catch (Exception e)
    {
      // Try the fallback to the old trick method.
      // Create the thread that will erase chars
      ErasingThread erasingThread = new ErasingThread(out, prompt);
      erasingThread.start();
      password = "";
      // block until enter is pressed
      while (true)
      {
        char c = (char) System.in.read();
        // assume enter pressed, stop masking
        erasingThread.stopMasking();
        if (c == '\r')
        {
          c = (char) System.in.read();
          if (c == '\n')
          {
            break;
          }
          else
          {
            continue;
          }
        }
        else if (c == '\n')
        {
          break;
        }
        else
        {
          // store the password
          password += c;
        }
      }
    }
    return password;
  }
  /**
   * Thread that mask user input.
   *
   */
  private class ErasingThread extends Thread
  {
    private boolean stop = false;
    private String prompt;
    /**
     * The class will mask the user input.
     * @param out
     *          the output
     * @param prompt
     *          The prompt displayed to the user
     */
    public ErasingThread(PrintStream out, String prompt)
    {
      this.prompt = prompt;
    }
    /**
     * Begin masking until asked to stop.
     */
    public void run()
    {
      while (!stop)
      {
        try
        {
          // attempt masking at this rate
          this.sleep(1);
        }
        catch (InterruptedException iex)
        {
          iex.printStackTrace();
        }
        if (!stop)
        {
          System.out.print("\r" + prompt + " \r" + prompt);
        }
        System.out.flush();
      }
    }
    /**
     * Instruct the thread to stop masking.
     */
    public void stopMasking()
    {
      this.stop = true;
    }
  }
}