From 9de916fbb0e9a77e02d87c08a57df18944653136 Mon Sep 17 00:00:00 2001
From: lutoff <lutoff@localhost>
Date: Mon, 31 Aug 2009 09:54:15 +0000
Subject: [PATCH]  fixed for issue #3818 (encode-password should support accepting clear text password on STDIN) A new argument (--i, interactivePassword) is added to prompt password

---
 opends/src/server/org/opends/server/tools/EncodePassword.java |  282 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 263 insertions(+), 19 deletions(-)

diff --git a/opends/src/server/org/opends/server/tools/EncodePassword.java b/opends/src/server/org/opends/server/tools/EncodePassword.java
index 69a21e6..07a0d47 100644
--- a/opends/src/server/org/opends/server/tools/EncodePassword.java
+++ b/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;
+    }
+
+  }
+
 }
 

--
Gitblit v1.10.0