mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

jdemendi
16.02.2007 61319d28a0a0129e3a81f4f9ca770d1b63e06233
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.
   *