From 61319d28a0a0129e3a81f4f9ca770d1b63e06233 Mon Sep 17 00:00:00 2001
From: jdemendi <jdemendi@localhost>
Date: Mon, 16 Jul 2007 08:02:35 +0000
Subject: [PATCH] This fix is the refactoring of the compare operation (issue #1886).
---
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java | 582 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 578 insertions(+), 4 deletions(-)
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
index e7919f2..5f95e28 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
@@ -74,6 +74,7 @@
import org.opends.server.core.AccessControlConfigManager;
import org.opends.server.core.AddOperation;
import org.opends.server.core.BindOperation;
+import org.opends.server.core.CompareOperation;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyOperation;
@@ -178,6 +179,9 @@
case MODIFY:
processModify((ModifyOperation) operation);
break;
+ case COMPARE:
+ processCompare((CompareOperation) operation);
+ break;
default:
// jdemendi - temporary code, just make sure that we don't fell into
// that incomplete code...
@@ -5860,9 +5864,9 @@
/**
- * Perform a delete operation against a local backend.
+ * Performs a delete operation against a local backend.
*
- * @param operation - The operation to perform
+ * @param operation the operation to perform
*/
public void processDelete(DeleteOperation operation){
LocalBackendDeleteOperation localOperation =
@@ -5871,9 +5875,9 @@
}
/**
- * Perform a local delete operation against a local backend.
+ * Performs a local delete operation against a local backend.
*
- * @param operation - The operation to perform
+ * @param operation the operation to perform
*/
private void processLocalDelete(LocalBackendDeleteOperation localOp)
{
@@ -6673,6 +6677,576 @@
/**
+ * Perform a compare operation against a local backend.
+ *
+ * @param operation - The operation to perform
+ */
+ public void processCompare(CompareOperation operation)
+ {
+ LocalBackendCompareOperation localOperation =
+ new LocalBackendCompareOperation(operation);
+ processLocalCompare(localOperation);
+ }
+
+
+ /**
+ * Perform a local compare operation against a local backend.
+ *
+ * @param operation - The operation to perform
+ */
+ private void processLocalCompare(LocalBackendCompareOperation localOp)
+ {
+ // Get the plugin config manager that will be used for invoking plugins.
+ PluginConfigManager pluginConfigManager =
+ DirectoryServer.getPluginConfigManager();
+ boolean skipPostOperation = false;
+
+
+ // Get a reference to the client connection
+ ClientConnection clientConnection = localOp.getClientConnection();
+
+
+ // Check for and handle a request to cancel this operation.
+ if (localOp.getCancelRequest() != null)
+ {
+ return;
+ }
+
+
+ // Create a labeled block of code that we can break out of if a problem is
+ // detected.
+compareProcessing:
+ {
+ // Process the entry DN to convert it from the raw form to the form
+ // required for the rest of the compare processing.
+ DN entryDN = localOp.getEntryDN();
+ if (entryDN == null)
+ {
+ skipPostOperation = true;
+ break compareProcessing;
+ }
+
+
+ // If the target entry is in the server configuration, then make sure the
+ // requester has the CONFIG_READ privilege.
+ if (DirectoryServer.getConfigHandler().handlesEntry(entryDN) &&
+ (! clientConnection.hasPrivilege(Privilege.CONFIG_READ, localOp)))
+ {
+ int msgID = MSGID_COMPARE_CONFIG_INSUFFICIENT_PRIVILEGES;
+ localOp.appendErrorMessage(getMessage(msgID));
+ localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ skipPostOperation = true;
+ break compareProcessing;
+ }
+
+
+ // Check for and handle a request to cancel this operation.
+ if (localOp.getCancelRequest() != null)
+ {
+ return;
+ }
+
+
+ // Grab a read lock on the entry.
+ Lock readLock = null;
+ for (int i=0; i < 3; i++)
+ {
+ readLock = LockManager.lockRead(entryDN);
+ if (readLock != null)
+ {
+ break;
+ }
+ }
+
+ if (readLock == null)
+ {
+ int msgID = MSGID_COMPARE_CANNOT_LOCK_ENTRY;
+ String message = getMessage(msgID, String.valueOf(entryDN));
+
+ localOp.setResultCode(DirectoryServer.getServerErrorResultCode());
+ localOp.appendErrorMessage(message);
+ skipPostOperation = true;
+ break compareProcessing;
+ }
+
+ Entry entry = null;
+ try
+ {
+ // Get the entry. If it does not exist, then fail.
+ try
+ {
+ entry = DirectoryServer.getEntry(entryDN);
+ localOp.setEntryToCompare(entry);
+
+ if (entry == null)
+ {
+ localOp.setResultCode(ResultCode.NO_SUCH_OBJECT);
+ localOp.appendErrorMessage(getMessage(MSGID_COMPARE_NO_SUCH_ENTRY,
+ String.valueOf(entryDN)));
+
+ // See if one of the entry's ancestors exists.
+ DN parentDN = entryDN.getParentDNInSuffix();
+ while (parentDN != null)
+ {
+ try
+ {
+ if (DirectoryServer.entryExists(parentDN))
+ {
+ localOp.setMatchedDN(parentDN);
+ break;
+ }
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+ break;
+ }
+
+ parentDN = parentDN.getParentDNInSuffix();
+ }
+
+ break compareProcessing;
+ }
+ }
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, de);
+ }
+
+ localOp.setResultCode(de.getResultCode());
+ localOp.appendErrorMessage(de.getErrorMessage());
+ break compareProcessing;
+ }
+
+ // Check to see if there are any controls in the request. If so, then
+ // see if there is any special processing required.
+ List<Control> requestControls = localOp.getRequestControls();
+ if ((requestControls != null) && (! requestControls.isEmpty()))
+ {
+ for (int i=0; i < requestControls.size(); i++)
+ {
+ Control c = requestControls.get(i);
+ String oid = c.getOID();
+
+ if (oid.equals(OID_LDAP_ASSERTION))
+ {
+ LDAPAssertionRequestControl assertControl;
+ if (c instanceof LDAPAssertionRequestControl)
+ {
+ assertControl = (LDAPAssertionRequestControl) c;
+ }
+ else
+ {
+ try
+ {
+ assertControl = LDAPAssertionRequestControl.decodeControl(c);
+ requestControls.set(i, assertControl);
+ }
+ catch (LDAPException le)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, le);
+ }
+
+ localOp.setResultCode(ResultCode.valueOf(le.getResultCode()));
+ localOp.appendErrorMessage(le.getMessage());
+
+ break compareProcessing;
+ }
+ }
+
+ try
+ {
+ // FIXME -- We need to determine whether the current user has
+ // permission to make this determination.
+ SearchFilter filter = assertControl.getSearchFilter();
+ if (! filter.matchesEntry(entry))
+ {
+ localOp.setResultCode(ResultCode.ASSERTION_FAILED);
+
+ localOp.appendErrorMessage(
+ getMessage(MSGID_COMPARE_ASSERTION_FAILED,
+ String.valueOf(entryDN)));
+
+ break compareProcessing;
+ }
+ }
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, de);
+ }
+
+ localOp.setResultCode(ResultCode.PROTOCOL_ERROR);
+
+ int msgID = MSGID_COMPARE_CANNOT_PROCESS_ASSERTION_FILTER;
+ localOp.appendErrorMessage(
+ getMessage(msgID, String.valueOf(entryDN),
+ de.getErrorMessage()));
+
+ break compareProcessing;
+ }
+ }
+ else if (oid.equals(OID_PROXIED_AUTH_V1))
+ {
+ // The requester must have the PROXIED_AUTH privilige in order to
+ // be able to use this control.
+ if (! clientConnection.hasPrivilege(
+ Privilege.PROXIED_AUTH, localOp))
+ {
+ int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
+ localOp.appendErrorMessage(getMessage(msgID));
+ localOp.setResultCode(ResultCode.AUTHORIZATION_DENIED);
+ break compareProcessing;
+ }
+
+
+ ProxiedAuthV1Control proxyControl;
+ if (c instanceof ProxiedAuthV1Control)
+ {
+ proxyControl = (ProxiedAuthV1Control) c;
+ }
+ else
+ {
+ try
+ {
+ proxyControl = ProxiedAuthV1Control.decodeControl(c);
+ }
+ catch (LDAPException le)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, le);
+ }
+
+ localOp.setResultCode(ResultCode.valueOf(le.getResultCode()));
+ localOp.appendErrorMessage(le.getMessage());
+
+ break compareProcessing;
+ }
+ }
+
+
+ Entry authorizationEntry;
+ try
+ {
+ authorizationEntry = proxyControl.getAuthorizationEntry();
+ }
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, de);
+ }
+
+ localOp.setResultCode(de.getResultCode());
+ localOp.appendErrorMessage(de.getErrorMessage());
+
+ break compareProcessing;
+ }
+
+ if (AccessControlConfigManager.getInstance()
+ .getAccessControlHandler().isProxiedAuthAllowed(localOp,
+ authorizationEntry) == false) {
+ localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+
+ int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+ localOp.appendErrorMessage(
+ getMessage(msgID, String.valueOf(entryDN)));
+
+ skipPostOperation = true;
+ break compareProcessing;
+ }
+ localOp.setAuthorizationEntry(authorizationEntry);
+ if (authorizationEntry == null)
+ {
+ localOp.setProxiedAuthorizationDN(DN.nullDN());
+ }
+ else
+ {
+ localOp.setProxiedAuthorizationDN(authorizationEntry.getDN());
+ }
+ }
+ else if (oid.equals(OID_PROXIED_AUTH_V2))
+ {
+ // The requester must have the PROXIED_AUTH privilige in order to
+ // be able to use this control.
+ if (! clientConnection.hasPrivilege(
+ Privilege.PROXIED_AUTH, localOp))
+ {
+ int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
+ localOp.appendErrorMessage(getMessage(msgID));
+ localOp.setResultCode(ResultCode.AUTHORIZATION_DENIED);
+ break compareProcessing;
+ }
+
+
+ ProxiedAuthV2Control proxyControl;
+ if (c instanceof ProxiedAuthV2Control)
+ {
+ proxyControl = (ProxiedAuthV2Control) c;
+ }
+ else
+ {
+ try
+ {
+ proxyControl = ProxiedAuthV2Control.decodeControl(c);
+ }
+ catch (LDAPException le)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, le);
+ }
+
+ localOp.setResultCode(ResultCode.valueOf(le.getResultCode()));
+ localOp.appendErrorMessage(le.getMessage());
+
+ break compareProcessing;
+ }
+ }
+
+
+ Entry authorizationEntry;
+ try
+ {
+ authorizationEntry = proxyControl.getAuthorizationEntry();
+ }
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, de);
+ }
+
+ localOp.setResultCode(de.getResultCode());
+ localOp.appendErrorMessage(de.getErrorMessage());
+
+ break compareProcessing;
+ }
+
+ if (AccessControlConfigManager.getInstance()
+ .getAccessControlHandler().isProxiedAuthAllowed(localOp,
+ authorizationEntry) == false) {
+ localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+
+ int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+ localOp.appendErrorMessage(
+ getMessage(msgID, String.valueOf(entryDN)));
+
+ skipPostOperation = true;
+ break compareProcessing;
+ }
+ localOp.setAuthorizationEntry(authorizationEntry);
+ if (authorizationEntry == null)
+ {
+ localOp.setProxiedAuthorizationDN(DN.nullDN());
+ }
+ else
+ {
+ localOp.setProxiedAuthorizationDN(authorizationEntry.getDN());
+ }
+ }
+
+ // NYI -- Add support for additional controls.
+ else if (c.isCritical())
+ {
+ Backend backend = DirectoryServer.getBackend(entryDN);
+ if ((backend == null) || (! backend.supportsControl(oid)))
+ {
+ localOp.setResultCode(
+ ResultCode.UNAVAILABLE_CRITICAL_EXTENSION);
+
+ int msgID = MSGID_COMPARE_UNSUPPORTED_CRITICAL_CONTROL;
+ localOp.appendErrorMessage(
+ getMessage(msgID, String.valueOf(entryDN), oid));
+
+ break compareProcessing;
+ }
+ }
+ }
+ }
+
+
+ // Check to see if the client has permission to perform the
+ // compare.
+
+ // FIXME: for now assume that this will check all permission
+ // pertinent to the operation. This includes proxy authorization
+ // and any other controls specified.
+
+ // FIXME: earlier checks to see if the entry already exists may
+ // have already exposed sensitive information to the client.
+ if (AccessControlConfigManager.getInstance()
+ .getAccessControlHandler().isAllowed(localOp) == false) {
+ localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+
+ int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
+ localOp.appendErrorMessage(
+ getMessage(msgID, String.valueOf(entryDN)));
+
+ skipPostOperation = true;
+ break compareProcessing;
+ }
+
+ // Check for and handle a request to cancel this operation.
+ if (localOp.getCancelRequest() != null)
+ {
+ return;
+ }
+
+
+ // Invoke the pre-operation compare plugins.
+ PreOperationPluginResult preOpResult =
+ pluginConfigManager.invokePreOperationComparePlugins(localOp);
+ if (preOpResult.connectionTerminated())
+ {
+ // There's no point in continuing with anything. Log the request and
+ // result and return.
+ localOp.setResultCode(ResultCode.CANCELED);
+
+ int msgID = MSGID_CANCELED_BY_PREOP_DISCONNECT;
+ localOp.appendErrorMessage(getMessage(msgID));
+
+ return;
+ }
+ else if (preOpResult.sendResponseImmediately())
+ {
+ skipPostOperation = true;
+ break compareProcessing;
+ }
+ else if (preOpResult.skipCoreProcessing())
+ {
+ skipPostOperation = false;
+ break compareProcessing;
+ }
+
+
+ // Get the base attribute type and set of options.
+ String baseName;
+ HashSet<String> options;
+ String rawAttributeType = localOp.getRawAttributeType();
+ int semicolonPos = rawAttributeType.indexOf(';');
+ if (semicolonPos > 0)
+ {
+ baseName = toLowerCase(rawAttributeType.substring(0, semicolonPos));
+
+ options = new HashSet<String>();
+ int nextPos = rawAttributeType.indexOf(';', semicolonPos+1);
+ while (nextPos > 0)
+ {
+ options.add(rawAttributeType.substring(semicolonPos+1, nextPos));
+ semicolonPos = nextPos;
+ nextPos = rawAttributeType.indexOf(';', semicolonPos+1);
+ }
+
+ options.add(rawAttributeType.substring(semicolonPos+1));
+ }
+ else
+ {
+ baseName = toLowerCase(rawAttributeType);
+ options = null;
+ }
+
+
+ // Actually perform the compare operation.
+ List<Attribute> attrList = null;
+ if (localOp.getAttributeType() == null)
+ {
+ localOp.setAttributeType(DirectoryServer.getAttributeType(baseName));
+ }
+ if (localOp.getAttributeType() == null)
+ {
+ attrList = entry.getAttribute(baseName, options);
+ localOp.setAttributeType(
+ DirectoryServer.getDefaultAttributeType(baseName));
+ }
+ else
+ {
+ attrList = entry.getAttribute(localOp.getAttributeType(), options);
+ }
+
+ if ((attrList == null) || attrList.isEmpty())
+ {
+ localOp.setResultCode(ResultCode.NO_SUCH_ATTRIBUTE);
+ if (options == null)
+ {
+ localOp.appendErrorMessage(getMessage(MSGID_COMPARE_OP_NO_SUCH_ATTR,
+ String.valueOf(entryDN), baseName));
+ }
+ else
+ {
+ localOp.appendErrorMessage(getMessage(
+ MSGID_COMPARE_OP_NO_SUCH_ATTR_WITH_OPTIONS,
+ String.valueOf(entryDN), baseName));
+ }
+ }
+ else
+ {
+ AttributeValue value = new AttributeValue(
+ localOp.getAttributeType(),
+ localOp.getAssertionValue());
+
+ boolean matchFound = false;
+ for (Attribute a : attrList)
+ {
+ if (a.hasValue(value))
+ {
+ matchFound = true;
+ break;
+ }
+ }
+
+ if (matchFound)
+ {
+ localOp.setResultCode(ResultCode.COMPARE_TRUE);
+ }
+ else
+ {
+ localOp.setResultCode(ResultCode.COMPARE_FALSE);
+ }
+ }
+ }
+ finally
+ {
+ LockManager.unlock(entryDN, readLock);
+ }
+ }
+
+
+ // Check for and handle a request to cancel this operation.
+ if (localOp.getCancelRequest() != null)
+ {
+ return;
+ }
+
+
+ // Invoke the post-operation compare plugins.
+ if (! skipPostOperation)
+ {
+ PostOperationPluginResult postOperationResult =
+ pluginConfigManager.invokePostOperationComparePlugins(localOp);
+ if (postOperationResult.connectionTerminated())
+ {
+ localOp.setResultCode(ResultCode.CANCELED);
+
+ int msgID = MSGID_CANCELED_BY_POSTOP_DISCONNECT;
+ localOp.appendErrorMessage(getMessage(msgID));
+
+ return;
+ }
+ }
+ }
+
+
+ /**
* Attaches the current local operation to the global operation so that
* operation runner can execute local operation post response later on.
*
--
Gitblit v1.10.0