ResetUserPasswordTask.java revision 6638c2755466ca601450700d5a39f390f23d4781
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2014-2015 ForgeRock AS
*/
package org.opends.guitools.controlpanel.task;
import static org.opends.messages.AdminToolMessages.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
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.ProgressDialog;
import org.opends.guitools.controlpanel.ui.nodes.BasicNode;
import org.opends.guitools.controlpanel.util.Utilities;
import org.forgerock.i18n.LocalizableMessage;
import org.opends.server.config.ConfigConstants;
import org.opends.server.tools.LDAPPasswordModify;
import org.opends.server.types.DN;
import org.opends.server.types.OpenDsException;
/**
* The task called when we want to reset the password of the user.
*
*/
public class ResetUserPasswordTask extends Task
{
private Set<String> backendSet;
private BasicNode node;
private char[] currentPassword;
private char[] newPassword;
private DN dn;
private boolean useAdminCtx;
/**
* Constructor of the task.
* @param info the control panel information.
* @param dlg the progress dialog where the task progress will be displayed.
* @param node the node corresponding to the entry whose password is going
* to be reset.
* @param controller the BrowserController.
* @param pwd the new password.
*/
public ResetUserPasswordTask(ControlPanelInfo info, ProgressDialog dlg,
BasicNode node, BrowserController controller, char[] pwd)
{
super(info, dlg);
backendSet = new HashSet<String>();
this.node = node;
this.newPassword = pwd;
try
{
dn = DN.valueOf(node.getDN());
for (BackendDescriptor backend : info.getServerDescriptor().getBackends())
{
for (BaseDNDescriptor baseDN : backend.getBaseDns())
{
if (dn.isDescendantOf(baseDN.getDn()))
{
backendSet.add(backend.getBackendID());
}
}
}
}
catch (OpenDsException ode)
{
throw new RuntimeException("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);
}
/** {@inheritDoc} */
public Type getType()
{
return Type.MODIFY_ENTRY;
}
/** {@inheritDoc} */
public Set<String> getBackends()
{
return backendSet;
}
/** {@inheritDoc} */
public LocalizableMessage getTaskDescription()
{
return INFO_CTRL_PANEL_RESET_USER_PASSWORD_TASK_DESCRIPTION.get(
node.getDN());
}
/** {@inheritDoc} */
public boolean regenerateDescriptor()
{
return false;
}
/** {@inheritDoc} */
protected String getCommandLinePath()
{
return getCommandLinePath("ldappasswordmodify");
}
/** {@inheritDoc} */
protected ArrayList<String> getCommandLineArguments()
{
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;
}
/** {@inheritDoc} */
public boolean canLaunch(Task taskToBeLaunched,
Collection<LocalizableMessage> incompatibilityReasons)
{
if (!isServerRunning()
&& state == State.RUNNING
&& runningOnSameServer(taskToBeLaunched))
{
// All the operations are incompatible if they apply to this
// backend for safety. This is a short operation so the limitation
// has not a lot of impact.
Set<String> backends =
new TreeSet<String>(taskToBeLaunched.getBackends());
backends.retainAll(getBackends());
if (backends.size() > 0)
{
incompatibilityReasons.add(getIncompatibilityMessage(this,
taskToBeLaunched));
return false;
}
}
return true;
}
/** {@inheritDoc} */
public void runTask()
{
state = State.RUNNING;
lastException = null;
try
{
ArrayList<String> arguments = getCommandLineArguments();
String[] args = new String[arguments.size()];
arguments.toArray(args);
returnCode = LDAPPasswordModify.mainPasswordModify(args, false,
outPrintStream, errorPrintStream);
if (returnCode != 0)
{
state = State.FINISHED_WITH_ERROR;
}
else
{
if ((lastException == null) && (currentPassword != 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)
{
getInfo().getUserDataDirContext().addToEnvironment(
Context.SECURITY_CREDENTIALS,
String.valueOf(newPassword));
}
}
state = State.FINISHED_SUCCESSFULLY;
}
}
catch (Throwable t)
{
lastException = t;
state = State.FINISHED_WITH_ERROR;
}
}
/**
* 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 boolean isBoundAs(DN dn, InitialLdapContext ctx)
{
boolean isBoundAs = false;
DN bindDN = DN.rootDN();
try
{
String b = ConnectionUtils.getBindDN(ctx);
bindDN = DN.valueOf(b);
isBoundAs = dn.equals(bindDN);
}
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);
try
{
while (entries.hasMore())
{
SearchResult sr = entries.next();
Set<String> dns = ConnectionUtils.getValues(sr, attrName);
for (String sDn : dns)
{
if (bindDN.equals(DN.valueOf(sDn)))
{
isBoundAs = true;
break;
}
}
}
}
finally
{
entries.close();
}
}
catch (Throwable t)
{
}
}
return isBoundAs;
}
}