From 7f207072519d5a4551dc943791cf23fef968cae7 Mon Sep 17 00:00:00 2001
From: jvergara <jvergara@localhost>
Date: Fri, 09 Jan 2009 17:47:45 +0000
Subject: [PATCH] Fix for issue 3698 (Cannot change Directory Manager password with the Control Panel)

---
 opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/task/ResetUserPasswordTask.java |  190 ++++++++++++++++++------------
 opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java      |   39 ++++++
 opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/task/ModifyEntryTask.java       |   72 +++++++++++
 opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/browser/LDAPConnectionPool.java |    2 
 opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/task/Task.java                  |   10 +
 5 files changed, 230 insertions(+), 83 deletions(-)

diff --git a/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/browser/LDAPConnectionPool.java b/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/browser/LDAPConnectionPool.java
index 11811e26..b39faa8 100644
--- a/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/browser/LDAPConnectionPool.java
+++ b/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/browser/LDAPConnectionPool.java
@@ -180,7 +180,7 @@
    * If authentication data available for this protocol/host/port,
    * getConnection() call bind() on the new connection.
    * If connect() or bind() failed, getConnection() forward the
-   * LDAPException.
+   * NamingException.
    * When getConnection() succeeds, the returned connection must
    * be passed to releaseConnection() after use.
    * @param ldapUrl the LDAP URL to which the connection must connect.
diff --git a/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/task/ModifyEntryTask.java b/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/task/ModifyEntryTask.java
index 0b135b2..e3d60ec 100644
--- a/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/task/ModifyEntryTask.java
+++ b/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/task/ModifyEntryTask.java
@@ -55,6 +55,7 @@
 import org.opends.guitools.controlpanel.datamodel.CustomSearchResult;
 import org.opends.guitools.controlpanel.ui.ColorAndFontConstants;
 import org.opends.guitools.controlpanel.ui.ProgressDialog;
+import org.opends.guitools.controlpanel.ui.StatusGenericPanel;
 import org.opends.guitools.controlpanel.ui.ViewEntryPanel;
 import org.opends.guitools.controlpanel.ui.nodes.BasicNode;
 import org.opends.guitools.controlpanel.util.Utilities;
@@ -84,6 +85,7 @@
   private CustomSearchResult oldEntry;
   private DN oldDn;
   private ArrayList<ModificationItem> modifications;
+  private ModificationItem passwordModification;
   private Entry newEntry;
   private BrowserController controller;
   private TreePath treePath;
@@ -132,8 +134,22 @@
           ode);
     }
     modifications = getModifications(newEntry, oldEntry, getInfo());
+    // Find password modifications
+    for (ModificationItem mod : modifications)
+    {
+      if (mod.getAttribute().getID().equalsIgnoreCase("userPassword"))
+      {
+        passwordModification = mod;
+        break;
+      }
+    }
+    if (passwordModification != null)
+    {
+      modifications.remove(passwordModification);
+    }
     hasModifications = modifications.size() > 0 ||
-    !oldDn.equals(newEntry.getDN());
+    !oldDn.equals(newEntry.getDN()) ||
+    (passwordModification != null);
   }
 
   /**
@@ -287,6 +303,60 @@
   }
 
   /**
+   * {@inheritDoc}
+   */
+  public void postOperation()
+  {
+    if ((lastException == null) && (state == State.FINISHED_SUCCESSFULLY) &&
+        (passwordModification != null))
+    {
+      try
+      {
+        Object o = passwordModification.getAttribute().get();
+        String sPwd;
+        if (o instanceof byte[])
+        {
+          try
+          {
+            sPwd = new String((byte[])o, "UTF-8");
+          }
+          catch (Throwable t)
+          {
+            throw new IllegalStateException("Unexpected error: "+t, t);
+          }
+        }
+        else
+        {
+          sPwd = String.valueOf(o);
+        }
+        ResetUserPasswordTask newTask = new ResetUserPasswordTask(getInfo(),
+            getProgressDialog(), (BasicNode)treePath.getLastPathComponent(),
+            controller, sPwd.toCharArray());
+        if ((modifications.size() > 0) || mustRename)
+        {
+          getProgressDialog().appendProgressHtml("<br><br>");
+        }
+        StatusGenericPanel.launchOperation(newTask,
+            INFO_CTRL_PANEL_RESETTING_USER_PASSWORD_SUMMARY.get(),
+            INFO_CTRL_PANEL_RESETTING_USER_PASSWORD_SUCCESSFUL_SUMMARY.get(),
+            INFO_CTRL_PANEL_RESETTING_USER_PASSWORD_SUCCESSFUL_DETAILS.get(),
+            ERR_CTRL_PANEL_RESETTING_USER_PASSWORD_ERROR_SUMMARY.get(),
+            ERR_CTRL_PANEL_RESETTING_USER_PASSWORD_ERROR_DETAILS.get(),
+            null,
+            getProgressDialog(),
+            false,
+            getInfo());
+        getProgressDialog().setVisible(true);
+      }
+      catch (NamingException ne)
+      {
+        // This should not happen
+        throw new IllegalStateException("Unexpected exception: "+ne, ne);
+      }
+    }
+  }
+
+  /**
    * Modifies and renames the entry.
    * @param ctx the connection to the server.
    * @param oldDN the oldDN of the entry.
diff --git a/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/task/ResetUserPasswordTask.java b/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/task/ResetUserPasswordTask.java
index 4714edd..bb060f9 100644
--- a/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/task/ResetUserPasswordTask.java
+++ b/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/task/ResetUserPasswordTask.java
@@ -35,27 +35,25 @@
 import java.util.Set;
 import java.util.TreeSet;
 
-import javax.naming.directory.BasicAttribute;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.ModificationItem;
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
 import javax.naming.ldap.InitialLdapContext;
-import javax.swing.SwingUtilities;
-import javax.swing.tree.TreePath;
 
+import org.opends.admin.ads.util.ConnectionUtils;
 import org.opends.guitools.controlpanel.browser.BrowserController;
 import org.opends.guitools.controlpanel.datamodel.BackendDescriptor;
 import org.opends.guitools.controlpanel.datamodel.BaseDNDescriptor;
 import org.opends.guitools.controlpanel.datamodel.ControlPanelInfo;
-import org.opends.guitools.controlpanel.ui.ColorAndFontConstants;
 import org.opends.guitools.controlpanel.ui.ProgressDialog;
 import org.opends.guitools.controlpanel.ui.nodes.BasicNode;
-import org.opends.guitools.controlpanel.ui.nodes.BrowserNodeInfo;
 import org.opends.guitools.controlpanel.util.Utilities;
 import org.opends.messages.Message;
+import org.opends.server.config.ConfigConstants;
+import org.opends.server.tools.LDAPPasswordModify;
 import org.opends.server.types.DN;
 import org.opends.server.types.OpenDsException;
-import org.opends.server.util.ServerConstants;
-import org.opends.server.util.cli.CommandBuilder;
 
 /**
  * The task called when we want to reset the password of the user.
@@ -65,8 +63,8 @@
 {
   private Set<String> backendSet;
   private BasicNode node;
+  private char[] currentPassword;
   private char[] newPassword;
-  private BrowserController controller;
   private DN dn;
   private boolean useAdminCtx;
 
@@ -86,7 +84,6 @@
     backendSet = new HashSet<String>();
     this.node = node;
     this.newPassword = pwd;
-    this.controller = controller;
     try
     {
       dn = DN.decode(node.getDN());
@@ -105,6 +102,19 @@
     {
       throw new IllegalStateException("Could not parse DN: "+node.getDN(), ode);
     }
+    try
+    {
+      InitialLdapContext ctx =
+        controller.findConnectionForDisplayedEntry(node);
+      if ((ctx != null) && isBoundAs(dn, ctx))
+      {
+        currentPassword = ConnectionUtils.getBindPassword(ctx).toCharArray();
+      }
+    }
+    catch (Throwable t)
+    {
+    }
+    useAdminCtx = controller.isConfigurationNode(node);
   }
 
   /**
@@ -145,7 +155,7 @@
    */
   protected String getCommandLinePath()
   {
-    return null;
+    return getCommandLinePath("ldappasswordmodify");
   }
 
   /**
@@ -153,7 +163,22 @@
    */
   protected ArrayList<String> getCommandLineArguments()
   {
-    return new ArrayList<String>();
+    ArrayList<String> args = new ArrayList<String>();
+    if (currentPassword == null)
+    {
+      args.add("--authzID");
+      args.add("dn:"+dn);
+    }
+    else
+    {
+      args.add("--currentPassword");
+      args.add(String.valueOf(currentPassword));
+    }
+    args.add("--newPassword");
+    args.add(String.valueOf(newPassword));
+    args.addAll(getConnectionCommandLineArguments(useAdminCtx, true));
+    args.add(getNoPropertiesFileArgument());
+    return args;
   }
 
   /**
@@ -191,57 +216,40 @@
   {
     state = State.RUNNING;
     lastException = null;
-
     try
     {
-      useAdminCtx = controller.isConfigurationNode(node);
-      InitialLdapContext ctx =
-        controller.findConnectionForDisplayedEntry(node);
-      BasicAttribute attr =
-        new BasicAttribute(ServerConstants.ATTR_USER_PASSWORD);
-      attr.add(new String(newPassword));
-      ModificationItem mod =
-        new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr);
-      ModificationItem[] mods = {mod};
-      final ArrayList<ModificationItem> modifications =
-        new ArrayList<ModificationItem>();
-      modifications.add(mod);
+      ArrayList<String> arguments = getCommandLineArguments();
 
-      SwingUtilities.invokeLater(new Runnable()
+      String[] args = new String[arguments.size()];
+
+      arguments.toArray(args);
+
+      returnCode = LDAPPasswordModify.mainPasswordModify(args, false,
+            outPrintStream, errorPrintStream);
+
+      if (returnCode != 0)
       {
-        public void run()
-        {
-          printEquivalentCommand(dn, newPassword, useAdminCtx);
-          getProgressDialog().appendProgressHtml(
-              Utilities.getProgressWithPoints(
-                  INFO_CTRL_PANEL_RESETTING_USER_PASSWORD.get(node.getDN()),
-                  ColorAndFontConstants.progressFont));
-        }
-      });
-
-      ctx.modifyAttributes(Utilities.getJNDIName(node.getDN()), mods);
-
-      SwingUtilities.invokeLater(new Runnable()
+        state = State.FINISHED_WITH_ERROR;
+      }
+      else
       {
-        public void run()
+        if ((lastException == null) && (currentPassword != null))
         {
-          getProgressDialog().appendProgressHtml(
-              Utilities.getProgressDone(ColorAndFontConstants.progressFont));
-          TreePath treePath =
-            new TreePath(controller.getTreeModel().getPathToRoot(node));
-          if (treePath != null)
+          // The connections must be updated, just update the environment, which
+          // is what we use to clone connections and to launch scripts.
+          // The environment will also be used if we want to reconnect.
+          getInfo().getDirContext().addToEnvironment(
+              Context.SECURITY_CREDENTIALS,
+              String.valueOf(newPassword));
+          if (getInfo().getUserDataDirContext() != null)
           {
-            BrowserNodeInfo nodeInfo = controller.getNodeInfoFromPath(treePath);
-            if (nodeInfo != null)
-            {
-              controller.notifyEntryChanged(nodeInfo);
-            }
-            controller.getTree().removeSelectionPath(treePath);
-            controller.getTree().setSelectionPath(treePath);
+            getInfo().getUserDataDirContext().addToEnvironment(
+                Context.SECURITY_CREDENTIALS,
+                String.valueOf(newPassword));
           }
         }
-      });
-      state = State.FINISHED_SUCCESSFULLY;
+        state = State.FINISHED_SUCCESSFULLY;
+      }
     }
     catch (Throwable t)
     {
@@ -251,31 +259,59 @@
   }
 
   /**
-   * Prints the equivalent modify command line in the progress dialog.
-   * @param dn the dn of the modified entry.
-   * @param newPassword the new password.
-   * @param useAdminCtx use the administration connector.
+   * Returns <CODE>true</CODE> if we are bound using the provided entry.  In
+   * the case of root entries this is not necessarily the same as using that
+   * particular DN (we might be binding using a value specified in
+   * ds-cfg-alternate-bind-dn).
+   * @param dn the DN.
+   * @param ctx the connection that we are using to modify the password.
+   * @return <CODE>true</CODE> if we are bound using the provided entry.
    */
-  private void printEquivalentCommand(DN dn, char[] newPassword,
-      boolean useAdminCtx)
+  private boolean isBoundAs(DN dn, InitialLdapContext ctx)
   {
-    ArrayList<String> args = new ArrayList<String>();
-    args.add(getCommandLinePath("ldappasswordmodify"));
-    args.add("--authzID");
-    args.add("dn:"+dn);
-    args.add("--newPassword");
-    args.add(Utilities.OBFUSCATED_VALUE);
-    args.addAll(getObfuscatedCommandLineArguments(
-        getConnectionCommandLineArguments(useAdminCtx, true)));
-    args.add(getNoPropertiesFileArgument());
-    StringBuilder sb = new StringBuilder();
-    for (String arg : args)
+    boolean isBoundAs = false;
+    DN bindDN = DN.nullDN();
+    try
     {
-      sb.append(" "+CommandBuilder.escapeValue(arg));
+      String b = ConnectionUtils.getBindDN(ctx);
+      bindDN = DN.decode(b);
+      isBoundAs = dn.equals(bindDN);
     }
-    getProgressDialog().appendProgressHtml(Utilities.applyFont(
-        INFO_CTRL_PANEL_EQUIVALENT_CMD_TO_RESET_PASSWORD.get().toString()+
-        "<br><b>"+sb.toString()+"</b><br><br>",
-        ColorAndFontConstants.progressFont));
+    catch (Throwable t)
+    {
+      // Ignore
+    }
+    if (!isBoundAs)
+    {
+      try
+      {
+        SearchControls ctls = new SearchControls();
+        ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
+        String filter =
+          "(|(objectClass=*)(objectclass=ldapsubentry))";
+        String attrName = ConfigConstants.ATTR_ROOTDN_ALTERNATE_BIND_DN;
+        ctls.setReturningAttributes(new String[] {attrName});
+        NamingEnumeration<SearchResult> entries =
+          ctx.search(Utilities.getJNDIName(dn.toString()), filter, ctls);
+
+        while (entries.hasMore())
+        {
+          SearchResult sr = entries.next();
+          Set<String> dns = ConnectionUtils.getValues(sr, attrName);
+          for (String sDn : dns)
+          {
+            if (bindDN.equals(DN.decode(sDn)))
+            {
+              isBoundAs = true;
+              break;
+            }
+          }
+        }
+      }
+      catch (Throwable t)
+      {
+      }
+    }
+    return isBoundAs;
   }
 }
diff --git a/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/task/Task.java b/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/task/Task.java
index 2f147e5..6b33397 100644
--- a/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/task/Task.java
+++ b/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/task/Task.java
@@ -657,12 +657,18 @@
   protected List<String> getObfuscatedCommandLineArguments(
       List<String> clearArgs)
   {
+    String[] toObfuscate = {"--bindPassword", "--currentPassword",
+        "--newPassword"};
     ArrayList<String> args = new ArrayList<String>(clearArgs);
     for (int i=1; i<args.size(); i++)
     {
-      if (args.get(i-1).equalsIgnoreCase("--bindPassword"))
+      for (String argName : toObfuscate)
       {
-        args.set(i, Utilities.OBFUSCATED_VALUE);
+        if (args.get(i-1).equalsIgnoreCase(argName))
+        {
+          args.set(i, Utilities.OBFUSCATED_VALUE);
+          break;
+        }
       }
     }
     return args;
diff --git a/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java b/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java
index 11d70ad..78480e4 100644
--- a/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java
+++ b/opendj-sdk/opends/src/guitools/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java
@@ -1561,6 +1561,41 @@
       final MessageDescriptor.Arg1<Number> errorDetailCode,
       final ProgressDialog dialog, boolean resetLogs)
   {
+    launchOperation(task, initialSummary, successSummary, successDetail,
+        errorSummary, errorDetail, errorDetailCode, dialog, resetLogs,
+        getInfo());
+  }
+
+  /**
+   * Launch an task.
+   * @param task the task to be launched.
+   * @param initialSummary the initial summary to be displayed in the progress
+   * dialog.
+   * @param successSummary the success summary to be displayed in the progress
+   * dialog if the task is successful.
+   * @param successDetail the success details to be displayed in the progress
+   * dialog if the task is successful.
+   * @param errorSummary the error summary to be displayed in the progress
+   * dialog if the task ended with error.
+   * @param errorDetail error details to be displayed in the progress
+   * dialog if the task ended with error.
+   * @param errorDetailCode error detail message to be displayed in the progress
+   * dialog if the task ended with error and we have an exit error code (for
+   * instance if the error occurred when launching a script we will have an
+   * error code).
+   * @param dialog the progress dialog.
+   * @param resetLogs whether the contents of the progress dialog should be
+   * reset or not.
+   * @param info the ControlPanelInfo.
+   */
+  public static void launchOperation(final Task task, Message initialSummary,
+      final Message successSummary, final Message successDetail,
+      final Message errorSummary,
+      final Message errorDetail,
+      final MessageDescriptor.Arg1<Number> errorDetailCode,
+      final ProgressDialog dialog, boolean resetLogs,
+      final ControlPanelInfo info)
+  {
     dialog.setTaskIsOver(false);
     dialog.getProgressBar().setIndeterminate(true);
     dialog.addPrintStreamListeners(task.getOutPrintStream(),
@@ -1592,7 +1627,7 @@
         task.runTask();
         if (task.regenerateDescriptor())
         {
-          getInfo().regenerateDescriptor();
+          info.regenerateDescriptor();
         }
         return task;
       }
@@ -1676,7 +1711,7 @@
         task.postOperation();
       }
     };
-    getInfo().registerTask(task);
+    info.registerTask(task);
     worker.startBackgroundTask();
   }
 

--
Gitblit v1.10.0