From deb5cb32b58a5e4ddf67d263e0e565fd5b068472 Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Fri, 04 Aug 2006 13:38:56 +0000
Subject: [PATCH] Update the password modify extended operation to use the identity mapping API to identify users based on an authorization ID in the "u:" form. This was previously based on a hard-coded mapping.
---
opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java | 333 ++++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 278 insertions(+), 55 deletions(-)
diff --git a/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java b/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
index 4ff6127..eedeaa2 100644
--- a/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
+++ b/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
@@ -35,10 +35,14 @@
import java.util.concurrent.locks.Lock;
import org.opends.server.api.ClientConnection;
+import org.opends.server.api.ConfigurableComponent;
import org.opends.server.api.ExtendedOperationHandler;
+import org.opends.server.api.IdentityMapper;
import org.opends.server.api.PasswordStorageScheme;
+import org.opends.server.config.ConfigAttribute;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
+import org.opends.server.config.DNConfigAttribute;
import org.opends.server.core.DirectoryException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ExtendedOperation;
@@ -51,8 +55,6 @@
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.asn1.ASN1Sequence;
import org.opends.server.protocols.internal.InternalClientConnection;
-import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.protocols.ldap.LDAPFilter;
import org.opends.server.schema.AuthPasswordSyntax;
import org.opends.server.schema.UserPasswordSyntax;
import org.opends.server.types.Attribute;
@@ -60,13 +62,12 @@
import org.opends.server.types.AttributeValue;
import org.opends.server.types.AuthenticationInfo;
import org.opends.server.types.ByteString;
+import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchScope;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.extensions.ExtensionsConstants.*;
@@ -85,6 +86,7 @@
*/
public class PasswordModifyExtendedOperation
extends ExtendedOperationHandler
+ implements ConfigurableComponent
{
/**
* The fully-qualified name of this class for debugging purposes.
@@ -94,6 +96,17 @@
+ // The DN of the configuration entry.
+ private DN configEntryDN;
+
+ // The DN of the identity mapper.
+ private DN identityMapperDN;
+
+ // The reference to the identity mapper.
+ private IdentityMapper identityMapper;
+
+
+
/**
* Create an instance of this password modify extended operation. All
* initialization should be performed in the
@@ -131,6 +144,47 @@
assert debugEnter(CLASS_NAME, "initializeExtendedOperationHandler",
String.valueOf(configEntry));
+ configEntryDN = configEntry.getDN();
+
+ int msgID = MSGID_EXTOP_PASSMOD_DESCRIPTION_ID_MAPPER;
+ DNConfigAttribute mapperStub =
+ new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID), true, false,
+ false);
+ try
+ {
+ DNConfigAttribute mapperAttr =
+ (DNConfigAttribute) configEntry.getConfigAttribute(mapperStub);
+ if (mapperAttr == null)
+ {
+ msgID = MSGID_EXTOP_PASSMOD_NO_ID_MAPPER;
+ String message = getMessage(msgID, String.valueOf(configEntryDN));
+ throw new ConfigException(msgID, message);
+ }
+ else
+ {
+ identityMapperDN = mapperAttr.activeValue();
+ identityMapper = DirectoryServer.getIdentityMapper(identityMapperDN);
+ if (identityMapper == null)
+ {
+ msgID = MSGID_EXTOP_PASSMOD_NO_SUCH_ID_MAPPER;
+ String message = getMessage(msgID, String.valueOf(identityMapperDN),
+ String.valueOf(configEntryDN));
+ throw new ConfigException(msgID, message);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ assert debugException(CLASS_NAME, "initializeExtendedOperationHandler",
+ e);
+ msgID = MSGID_EXTOP_PASSMOD_CANNOT_DETERMINE_ID_MAPPER;
+ String message = getMessage(msgID, String.valueOf(configEntryDN),
+ stackTraceToSingleLineString(e));
+ throw new InitializationException(msgID, message, e);
+ }
+
+ DirectoryServer.registerConfigurableComponent(this);
+
DirectoryServer.registerSupportedExtension(OID_PASSWORD_MODIFY_REQUEST,
this);
}
@@ -145,6 +199,8 @@
{
assert debugEnter(CLASS_NAME, "finalizeExtendedOperationHandler");
+ DirectoryServer.deregisterConfigurableComponent(this);
+
DirectoryServer.deregisterSupportedExtension(OID_PASSWORD_MODIFY_REQUEST);
}
@@ -309,15 +365,55 @@
}
else if (lowerAuthzIDStr.startsWith("u:"))
{
- userDN = getDNByUserID(operation, authzIDStr.substring(2));
- if (userDN == null)
+ try
{
- return;
- }
+ userEntry = identityMapper.getEntryForID(authzIDStr.substring(2));
+ if (userEntry == null)
+ {
+ if (oldPassword == null)
+ {
+ operation.setResultCode(ResultCode.NO_SUCH_OBJECT);
- userEntry = getEntryByDN(operation, userDN);
- if (userEntry == null)
+ int msgID = MSGID_EXTOP_PASSMOD_CANNOT_MAP_USER;
+ operation.appendErrorMessage(getMessage(msgID, authzIDStr));
+ }
+ else
+ {
+ operation.setResultCode(ResultCode.INVALID_CREDENTIALS);
+
+ int msgID = MSGID_EXTOP_PASSMOD_CANNOT_MAP_USER;
+ operation.appendAdditionalLogMessage(getMessage(msgID,
+ authzIDStr));
+ }
+
+ return;
+ }
+ else
+ {
+ userDN = userEntry.getDN();
+ }
+ }
+ catch (DirectoryException de)
{
+ assert debugException(CLASS_NAME, "processExtendedOperation", de);
+
+ if (oldPassword == null)
+ {
+ operation.setResultCode(de.getResultCode());
+
+ int msgID = MSGID_EXTOP_PASSMOD_ERROR_MAPPING_USER;
+ operation.appendErrorMessage(getMessage(msgID, authzIDStr,
+ de.getErrorMessage()));
+ }
+ else
+ {
+ operation.setResultCode(ResultCode.INVALID_CREDENTIALS);
+
+ int msgID = MSGID_EXTOP_PASSMOD_ERROR_MAPPING_USER;
+ operation.appendAdditionalLogMessage(getMessage(msgID, authzIDStr,
+ de.getErrorMessage()));
+ }
+
return;
}
}
@@ -918,65 +1014,192 @@
/**
- * Retrieves the DN of the user with the provided user ID. The DN will be
- * obtained by performing a subtree search with a base of the null DN (i.e.,
- * the root DSE) and therefore potentially searching across multiple backends.
- * If any problem is encountered or the requested entry does not exist, then
- * the provided operation will be updated with appropriate result information
- * and this method will return <CODE>null</CODE>. The caller is not required
- * to hold any locks.
+ * Retrieves the DN of the configuration entry with which this component is
+ * associated.
*
- * @param operation The extended operation being processed.
- * @param userID The user ID for which to retrieve the DN.
- *
- * @return The requested DN, or <CODE>null</CODE> if there was no such entry
- * or if a problem was encountered.
+ * @return The DN of the configuration entry with which this component is
+ * associated.
*/
- private DN getDNByUserID(ExtendedOperation operation, String userID)
+ public DN getConfigurableComponentEntryDN()
{
- assert debugEnter(CLASS_NAME, "getDNByUserID", String.valueOf(operation),
- String.valueOf(userID));
+ assert debugEnter(CLASS_NAME, "getConfigurableComponentEntryDN");
- InternalClientConnection internalConnection =
- InternalClientConnection.getRootConnection();
+ return configEntryDN;
+ }
- LDAPFilter rawFilter =
- LDAPFilter.createEqualityFilter("uid", new ASN1OctetString(userID));
- InternalSearchOperation internalSearch =
- internalConnection.processSearch(new ASN1OctetString(),
- SearchScope.WHOLE_SUBTREE, rawFilter);
- ResultCode resultCode = internalSearch.getResultCode();
- if (resultCode != ResultCode.SUCCESS)
+ /**
+ * Retrieves the set of configuration attributes that are associated with this
+ * configurable component.
+ *
+ * @return The set of configuration attributes that are associated with this
+ * configurable component.
+ */
+ public List<ConfigAttribute> getConfigurationAttributes()
+ {
+ assert debugEnter(CLASS_NAME, "getConfigurationAttributes");
+
+ List<ConfigAttribute> attrList = new LinkedList<ConfigAttribute>();
+
+ int msgID = MSGID_EXTOP_PASSMOD_DESCRIPTION_ID_MAPPER;
+ attrList.add(new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID),
+ true, false, false, identityMapperDN));
+
+ return attrList;
+ }
+
+
+
+ /**
+ * Indicates whether the provided configuration entry has an acceptable
+ * configuration for this component. If it does not, then detailed
+ * information about the problem(s) should be added to the provided list.
+ *
+ * @param configEntry The configuration entry for which to make the
+ * determination.
+ * @param unacceptableReasons A list that can be used to hold messages about
+ * why the provided entry does not have an
+ * acceptable configuration.
+ *
+ * @return <CODE>true</CODE> if the provided entry has an acceptable
+ * configuration for this component, or <CODE>false</CODE> if not.
+ */
+ public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
+ List<String> unacceptableReasons)
+ {
+ assert debugEnter(CLASS_NAME, "hasAcceptableConfiguration",
+ String.valueOf(configEntry), "List<String>");
+
+
+ // Make sure that the specified identity mapper is OK.
+ int msgID = MSGID_EXTOP_PASSMOD_DESCRIPTION_ID_MAPPER;
+ DNConfigAttribute mapperStub =
+ new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID), true, false,
+ false);
+ try
{
- operation.setResultCode(resultCode);
- operation.setErrorMessage(internalSearch.getErrorMessage());
- operation.setMatchedDN(internalSearch.getMatchedDN());
- return null;
+ DNConfigAttribute mapperAttr =
+ (DNConfigAttribute) configEntry.getConfigAttribute(mapperStub);
+ if (mapperAttr == null)
+ {
+ msgID = MSGID_EXTOP_PASSMOD_NO_ID_MAPPER;
+ String message = getMessage(msgID, String.valueOf(configEntry.getDN()));
+ unacceptableReasons.add(message);
+ return false;
+ }
+ else
+ {
+ DN mapperDN = mapperAttr.pendingValue();
+ IdentityMapper mapper = DirectoryServer.getIdentityMapper(mapperDN);
+ if (mapper == null)
+ {
+ msgID = MSGID_EXTOP_PASSMOD_NO_SUCH_ID_MAPPER;
+ String message = getMessage(msgID, String.valueOf(mapperDN),
+ String.valueOf(configEntry.getDN()));
+ unacceptableReasons.add(message);
+ return false;
+ }
+ }
}
-
- LinkedList<SearchResultEntry> entryList = internalSearch.getSearchEntries();
- if ((entryList == null) || entryList.isEmpty())
+ catch (Exception e)
{
- operation.setResultCode(ResultCode.NO_SUCH_OBJECT);
+ assert debugException(CLASS_NAME, "hasAcceptableConfiguration", e);
- int msgID = MSGID_EXTOP_PASSMOD_NO_DN_BY_AUTHZID;
- operation.appendErrorMessage(getMessage(msgID, String.valueOf(userID)));
- return null;
- }
-
- if (entryList.size() > 1)
- {
- operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-
- int msgID = MSGID_EXTOP_PASSMOD_MULTIPLE_ENTRIES_BY_AUTHZID;
- operation.appendErrorMessage(getMessage(msgID, String.valueOf(userID)));
- return null;
+ msgID = MSGID_EXTOP_PASSMOD_CANNOT_DETERMINE_ID_MAPPER;
+ String message = getMessage(msgID, String.valueOf(configEntry.getDN()),
+ stackTraceToSingleLineString(e));
+ unacceptableReasons.add(message);
+ return false;
}
- return entryList.get(0).getDN();
+ // If we've gotten here, then everything is OK.
+ return true;
+ }
+
+
+
+ /**
+ * Makes a best-effort attempt to apply the configuration contained in the
+ * provided entry. Information about the result of this processing should be
+ * added to the provided message list. Information should always be added to
+ * this list if a configuration change could not be applied. If detailed
+ * results are requested, then information about the changes applied
+ * successfully (and optionally about parameters that were not changed) should
+ * also be included.
+ *
+ * @param configEntry The entry containing the new configuration to
+ * apply for this component.
+ * @param detailedResults Indicates whether detailed information about the
+ * processing should be added to the list.
+ *
+ * @return Information about the result of the configuration update.
+ */
+ public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
+ boolean detailedResults)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+
+ // Make sure that the specified identity mapper is OK.
+ DN mapperDN = null;
+ IdentityMapper mapper = null;
+ int msgID = MSGID_EXTOP_PASSMOD_DESCRIPTION_ID_MAPPER;
+ DNConfigAttribute mapperStub =
+ new DNConfigAttribute(ATTR_IDMAPPER_DN, getMessage(msgID), true, false,
+ false);
+ try
+ {
+ DNConfigAttribute mapperAttr =
+ (DNConfigAttribute) configEntry.getConfigAttribute(mapperStub);
+ if (mapperAttr == null)
+ {
+ resultCode = ResultCode.OBJECTCLASS_VIOLATION;
+
+ msgID = MSGID_EXTOP_PASSMOD_NO_ID_MAPPER;
+ messages.add(getMessage(msgID, String.valueOf(configEntry.getDN())));
+ }
+ else
+ {
+ mapperDN = mapperAttr.pendingValue();
+ mapper = DirectoryServer.getIdentityMapper(mapperDN);
+ if (mapper == null)
+ {
+ resultCode = ResultCode.CONSTRAINT_VIOLATION;
+
+ msgID = MSGID_EXTOP_PASSMOD_NO_SUCH_ID_MAPPER;
+ messages.add(getMessage(msgID, String.valueOf(mapperDN),
+ String.valueOf(configEntry.getDN())));
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ assert debugException(CLASS_NAME, "applyNewConfiguration", e);
+
+ resultCode = DirectoryServer.getServerErrorResultCode();
+
+ msgID = MSGID_EXTOP_PASSMOD_CANNOT_DETERMINE_ID_MAPPER;
+ messages.add(getMessage(msgID, String.valueOf(configEntry.getDN()),
+ stackTraceToSingleLineString(e)));
+ }
+
+
+ // If all of the changes were acceptable, then apply them.
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ if (! identityMapperDN.equals(mapperDN))
+ {
+ identityMapper = mapper;
+ identityMapperDN = mapperDN;
+ }
+ }
+
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
}
}
--
Gitblit v1.10.0