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

neil_a_wilson
12.39.2007 4e806081638f22dade6802c2996295d263d3e377
opends/src/server/org/opends/server/core/AddOperation.java
@@ -1775,6 +1775,17 @@
            }
            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, this))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                appendErrorMessage(getMessage(msgID));
                setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break addProcessing;
              }
              ProxiedAuthV1Control proxyControl;
              if (c instanceof ProxiedAuthV1Control)
              {
@@ -1814,12 +1825,21 @@
              }
              // FIXME -- Should we specifically check permissions here, or let
              //          the earlier access control checks handle it?
              setAuthorizationEntry(authorizationEntry);
            }
            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, this))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                appendErrorMessage(getMessage(msgID));
                setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break addProcessing;
              }
              ProxiedAuthV2Control proxyControl;
              if (c instanceof ProxiedAuthV2Control)
              {
@@ -1859,8 +1879,6 @@
              }
              // FIXME -- Should we specifically check permissions here, or let
              //          the earlier access control checks handle it?
              setAuthorizationEntry(authorizationEntry);
            }
opends/src/server/org/opends/server/core/CompareOperation.java
@@ -829,6 +829,17 @@
            }
            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, this))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                appendErrorMessage(getMessage(msgID));
                setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break compareProcessing;
              }
              ProxiedAuthV1Control proxyControl;
              if (c instanceof ProxiedAuthV1Control)
              {
@@ -868,12 +879,21 @@
              }
              // FIXME -- Should we specifically check permissions here, or let
              //          the earlier access control checks handle it?
              setAuthorizationEntry(authorizationEntry);
            }
            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, this))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                appendErrorMessage(getMessage(msgID));
                setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break compareProcessing;
              }
              ProxiedAuthV2Control proxyControl;
              if (c instanceof ProxiedAuthV2Control)
              {
@@ -913,8 +933,6 @@
              }
              // FIXME -- Should we specifically check permissions here, or let
              //          the earlier access control checks handle it?
              setAuthorizationEntry(authorizationEntry);
            }
opends/src/server/org/opends/server/core/DeleteOperation.java
@@ -61,6 +61,7 @@
import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.LockManager;
import org.opends.server.types.OperationType;
import org.opends.server.types.Privilege;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.SearchResultEntry;
@@ -793,6 +794,17 @@
            }
            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, this))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                appendErrorMessage(getMessage(msgID));
                setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break deleteProcessing;
              }
              ProxiedAuthV1Control proxyControl;
              if (c instanceof ProxiedAuthV1Control)
              {
@@ -832,12 +844,21 @@
              }
              // FIXME -- Should we specifically check permissions here, or let
              //          the earlier access control checks handle it?
              setAuthorizationEntry(authorizationEntry);
            }
            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, this))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                appendErrorMessage(getMessage(msgID));
                setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break deleteProcessing;
              }
              ProxiedAuthV2Control proxyControl;
              if (c instanceof ProxiedAuthV2Control)
              {
@@ -877,8 +898,6 @@
              }
              // FIXME -- Should we specifically check permissions here, or let
              //          the earlier access control checks handle it?
              setAuthorizationEntry(authorizationEntry);
            }
opends/src/server/org/opends/server/core/ModifyDNOperation.java
@@ -69,6 +69,7 @@
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.OperationType;
import org.opends.server.types.Privilege;
import org.opends.server.types.RDN;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
@@ -1284,6 +1285,17 @@
            }
            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, this))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                appendErrorMessage(getMessage(msgID));
                setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break modifyDNProcessing;
              }
              ProxiedAuthV1Control proxyControl;
              if (c instanceof ProxiedAuthV1Control)
              {
@@ -1323,12 +1335,21 @@
              }
              // FIXME -- Should we specifically check permissions here, or let
              //          the earlier access control checks handle it?
              setAuthorizationEntry(authorizationEntry);
            }
            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, this))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                appendErrorMessage(getMessage(msgID));
                setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break modifyDNProcessing;
              }
              ProxiedAuthV2Control proxyControl;
              if (c instanceof ProxiedAuthV2Control)
              {
@@ -1368,8 +1389,6 @@
              }
              // FIXME -- Should we specifically check permissions here, or let
              //          the earlier access control checks handle it?
              setAuthorizationEntry(authorizationEntry);
            }
opends/src/server/org/opends/server/core/ModifyOperation.java
@@ -1087,6 +1087,17 @@
            }
            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, this))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                appendErrorMessage(getMessage(msgID));
                setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break modifyProcessing;
              }
              ProxiedAuthV1Control proxyControl;
              if (c instanceof ProxiedAuthV1Control)
              {
@@ -1126,12 +1137,21 @@
              }
              // FIXME -- Should we specifically check permissions here, or let
              //          the earlier access control checks handle it?
              setAuthorizationEntry(authorizationEntry);
            }
            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, this))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                appendErrorMessage(getMessage(msgID));
                setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break modifyProcessing;
              }
              ProxiedAuthV2Control proxyControl;
              if (c instanceof ProxiedAuthV2Control)
              {
@@ -1171,8 +1191,6 @@
              }
              // FIXME -- Should we specifically check permissions here, or let
              //          the earlier access control checks handle it?
              setAuthorizationEntry(authorizationEntry);
            }
opends/src/server/org/opends/server/core/SearchOperation.java
@@ -66,6 +66,7 @@
import org.opends.server.types.Entry;
import org.opends.server.types.FilterType;
import org.opends.server.types.OperationType;
import org.opends.server.types.Privilege;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.SearchResultEntry;
@@ -1760,6 +1761,17 @@
          }
          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, this))
            {
              int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
              appendErrorMessage(getMessage(msgID));
              setResultCode(ResultCode.AUTHORIZATION_DENIED);
              break searchProcessing;
            }
            ProxiedAuthV1Control proxyControl;
            if (c instanceof ProxiedAuthV1Control)
            {
@@ -1783,28 +1795,37 @@
            }
              Entry authorizationEntry;
              try
              {
                authorizationEntry = proxyControl.getAuthorizationEntry();
              }
              catch (DirectoryException de)
              {
                assert debugException(CLASS_NAME, "run", de);
            Entry authorizationEntry;
            try
            {
              authorizationEntry = proxyControl.getAuthorizationEntry();
            }
            catch (DirectoryException de)
            {
              assert debugException(CLASS_NAME, "run", de);
                setResultCode(de.getResultCode());
                appendErrorMessage(de.getErrorMessage());
              setResultCode(de.getResultCode());
              appendErrorMessage(de.getErrorMessage());
                break searchProcessing;
              }
              break searchProcessing;
            }
              // FIXME -- Should we specifically check permissions here, or let
              //          the earlier access control checks handle it?
              setAuthorizationEntry(authorizationEntry);
            setAuthorizationEntry(authorizationEntry);
          }
          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, this))
            {
              int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
              appendErrorMessage(getMessage(msgID));
              setResultCode(ResultCode.AUTHORIZATION_DENIED);
              break searchProcessing;
            }
            ProxiedAuthV2Control proxyControl;
            if (c instanceof ProxiedAuthV2Control)
            {
@@ -1828,25 +1849,23 @@
            }
              Entry authorizationEntry;
              try
              {
                authorizationEntry = proxyControl.getAuthorizationEntry();
              }
              catch (DirectoryException de)
              {
                assert debugException(CLASS_NAME, "run", de);
            Entry authorizationEntry;
            try
            {
              authorizationEntry = proxyControl.getAuthorizationEntry();
            }
            catch (DirectoryException de)
            {
              assert debugException(CLASS_NAME, "run", de);
                setResultCode(de.getResultCode());
                appendErrorMessage(de.getErrorMessage());
              setResultCode(de.getResultCode());
              appendErrorMessage(de.getErrorMessage());
                break searchProcessing;
              }
              break searchProcessing;
            }
              // FIXME -- Should we specifically check permissions here, or let
              //          the earlier access control checks handle it?
              setAuthorizationEntry(authorizationEntry);
            setAuthorizationEntry(authorizationEntry);
          }
          else if (oid.equals(OID_PERSISTENT_SEARCH))
          {
opends/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandler.java
@@ -55,6 +55,7 @@
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.PasswordPolicyState;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.types.AuthenticationInfo;
import org.opends.server.types.ByteString;
import org.opends.server.types.ConfigChangeResult;
@@ -66,6 +67,7 @@
import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.InitializationException;
import org.opends.server.types.LockManager;
import org.opends.server.types.Privilege;
import org.opends.server.types.ResultCode;
import org.opends.server.util.Base64;
@@ -893,6 +895,170 @@
    }
    Entry authZEntry = userEntry;
    if (responseAuthzID != null)
    {
      if (responseAuthzID.length() == 0)
      {
        // The authorization ID must not be an empty string.
        bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
        int    msgID   = MSGID_SASLDIGESTMD5_EMPTY_AUTHZID;
        String message = getMessage(msgID);
        bindOperation.setAuthFailureReason(msgID, message);
        return;
      }
      else if (! responseAuthzID.equals(responseUserName))
      {
        String lowerAuthzID = toLowerCase(responseAuthzID);
        if (lowerAuthzID.startsWith("dn:"))
        {
          DN authzDN;
          try
          {
            authzDN = DN.decode(responseAuthzID.substring(3));
          }
          catch (DirectoryException de)
          {
            assert debugException(CLASS_NAME, "processSASLBind", de);
            bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
            int    msgID   = MSGID_SASLDIGESTMD5_AUTHZID_INVALID_DN;
            String message = getMessage(msgID, responseAuthzID,
                                        de.getErrorMessage());
            bindOperation.setAuthFailureReason(msgID, message);
            return;
          }
          DN actualAuthzDN = DirectoryServer.getActualRootBindDN(authzDN);
          if (actualAuthzDN != null)
          {
            authzDN = actualAuthzDN;
          }
          if (! authzDN.equals(userEntry.getDN()))
          {
            AuthenticationInfo tempAuthInfo =
              new AuthenticationInfo(userEntry,
                       DirectoryServer.isRootDN(userEntry.getDN()));
            InternalClientConnection tempConn =
                 new InternalClientConnection(tempAuthInfo);
            if (! tempConn.hasPrivilege(Privilege.PROXIED_AUTH, bindOperation))
            {
              bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
              int msgID = MSGID_SASLDIGESTMD5_AUTHZID_INSUFFICIENT_PRIVILEGES;
              String message = getMessage(msgID,
                                          String.valueOf(userEntry.getDN()));
              bindOperation.setAuthFailureReason(msgID, message);
              return;
            }
            if (authzDN.isNullDN())
            {
              authZEntry = null;
            }
            else
            {
              try
              {
                authZEntry = DirectoryServer.getEntry(authzDN);
                if (authZEntry == null)
                {
                  bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
                  int msgID = MSGID_SASLDIGESTMD5_AUTHZID_NO_SUCH_ENTRY;
                  String message = getMessage(msgID, String.valueOf(authzDN));
                  bindOperation.setAuthFailureReason(msgID, message);
                  return;
                }
              }
              catch (DirectoryException de)
              {
                assert debugException(CLASS_NAME, "processSASLBind", de);
                bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
                int msgID = MSGID_SASLDIGESTMD5_AUTHZID_CANNOT_GET_ENTRY;
                String message = getMessage(msgID, String.valueOf(authzDN),
                                            de.getErrorMessage());
                bindOperation.setAuthFailureReason(msgID, message);
                return;
              }
            }
          }
        }
        else
        {
          String idStr;
          if (lowerAuthzID.startsWith("u:"))
          {
            idStr = responseAuthzID.substring(2);
          }
          else
          {
            idStr = responseAuthzID;
          }
          if (idStr.length() == 0)
          {
            authZEntry = null;
          }
          else
          {
            try
            {
              authZEntry = identityMapper.getEntryForID(idStr);
              if (authZEntry == null)
              {
                bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
                int    msgID   = MSGID_SASLDIGESTMD5_AUTHZID_NO_MAPPED_ENTRY;
                String message = getMessage(msgID, responseAuthzID);
                bindOperation.setAuthFailureReason(msgID, message);
                return;
              }
            }
            catch (DirectoryException de)
            {
              assert debugException(CLASS_NAME, "processSASLBind", de);
              bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
              int    msgID   = MSGID_SASLDIGESTMD5_CANNOT_MAP_AUTHZID;
              String message = getMessage(msgID, responseAuthzID,
                                          de.getErrorMessage());
              bindOperation.setAuthFailureReason(msgID, message);
              return;
            }
          }
          if ((authZEntry == null) ||
              (! authZEntry.getDN().equals(userEntry.getDN())))
          {
            AuthenticationInfo tempAuthInfo =
              new AuthenticationInfo(userEntry,
                       DirectoryServer.isRootDN(userEntry.getDN()));
            InternalClientConnection tempConn =
                 new InternalClientConnection(tempAuthInfo);
            if (! tempConn.hasPrivilege(Privilege.PROXIED_AUTH, bindOperation))
            {
              bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
              int msgID = MSGID_SASLDIGESTMD5_AUTHZID_INSUFFICIENT_PRIVILEGES;
              String message = getMessage(msgID,
                                          String.valueOf(userEntry.getDN()));
              bindOperation.setAuthFailureReason(msgID, message);
              return;
            }
          }
        }
      }
    }
    // Get the clear-text passwords from the user entry, if there are any.
    List<ByteString> clearPasswords;
    try
@@ -968,9 +1134,6 @@
    }
    // FIXME -- Need to do something with the authzid.
    // Generate the response auth element to include in the response to the
    // client.
    byte[] responseAuth;
@@ -1011,7 +1174,8 @@
    AuthenticationInfo authInfo =
         new AuthenticationInfo(userEntry, SASL_MECHANISM_DIGEST_MD5,
         new AuthenticationInfo(userEntry, authZEntry,
                                SASL_MECHANISM_DIGEST_MD5,
                                DirectoryServer.isRootDN(userEntry.getDN()));
    bindOperation.setAuthenticationInfo(authInfo);
    return;
opends/src/server/org/opends/server/extensions/PlainSASLMechanismHandler.java
@@ -44,6 +44,7 @@
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.PasswordPolicyState;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.types.AuthenticationInfo;
import org.opends.server.types.ByteString;
import org.opends.server.types.ConfigChangeResult;
@@ -52,6 +53,7 @@
import org.opends.server.types.Entry;
import org.opends.server.types.InitializationException;
import org.opends.server.types.LockManager;
import org.opends.server.types.Privilege;
import org.opends.server.types.ResultCode;
import static org.opends.server.config.ConfigConstants.*;
@@ -398,6 +400,156 @@
    }
    // If an authorization ID was provided, then make sure that it is
    // acceptable.
    Entry authZEntry = userEntry;
    if (authzID != null)
    {
      String lowerAuthzID = toLowerCase(authzID);
      if (lowerAuthzID.startsWith("dn:"))
      {
        DN authzDN;
        try
        {
          authzDN = DN.decode(authzID.substring(3));
        }
        catch (DirectoryException de)
        {
          assert debugException(CLASS_NAME, "processSASLBind", de);
          bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
          int    msgID   = MSGID_SASLPLAIN_AUTHZID_INVALID_DN;
          String message = getMessage(msgID, authzID, de.getErrorMessage());
          bindOperation.setAuthFailureReason(msgID, message);
          return;
        }
        DN actualAuthzDN = DirectoryServer.getActualRootBindDN(authzDN);
        if (actualAuthzDN != null)
        {
          authzDN = actualAuthzDN;
        }
        if (! authzDN.equals(userEntry.getDN()))
        {
          AuthenticationInfo tempAuthInfo =
            new AuthenticationInfo(userEntry,
                     DirectoryServer.isRootDN(userEntry.getDN()));
          InternalClientConnection tempConn =
               new InternalClientConnection(tempAuthInfo);
          if (! tempConn.hasPrivilege(Privilege.PROXIED_AUTH, bindOperation))
          {
            bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
            int msgID = MSGID_SASLPLAIN_AUTHZID_INSUFFICIENT_PRIVILEGES;
            String message = getMessage(msgID,
                                        String.valueOf(userEntry.getDN()));
            bindOperation.setAuthFailureReason(msgID, message);
            return;
          }
          if (authzDN.isNullDN())
          {
            authZEntry = null;
          }
          else
          {
            try
            {
              authZEntry = DirectoryServer.getEntry(authzDN);
              if (authZEntry == null)
              {
                bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
                int msgID = MSGID_SASLPLAIN_AUTHZID_NO_SUCH_ENTRY;
                String message = getMessage(msgID, String.valueOf(authzDN));
                bindOperation.setAuthFailureReason(msgID, message);
                return;
              }
            }
            catch (DirectoryException de)
            {
              assert debugException(CLASS_NAME, "processSASLBind", de);
              bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
              int msgID = MSGID_SASLPLAIN_AUTHZID_CANNOT_GET_ENTRY;
              String message = getMessage(msgID, String.valueOf(authzDN),
                                          de.getErrorMessage());
              bindOperation.setAuthFailureReason(msgID, message);
              return;
            }
          }
        }
      }
      else
      {
        String idStr;
        if (lowerAuthzID.startsWith("u:"))
        {
          idStr = authzID.substring(2);
        }
        else
        {
          idStr = authzID;
        }
        if (idStr.length() == 0)
        {
          authZEntry = null;
        }
        else
        {
          try
          {
            authZEntry = identityMapper.getEntryForID(idStr);
            if (authZEntry == null)
            {
              bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
              int    msgID   = MSGID_SASLPLAIN_AUTHZID_NO_MAPPED_ENTRY;
              String message = getMessage(msgID, authzID);
              bindOperation.setAuthFailureReason(msgID, message);
              return;
            }
          }
          catch (DirectoryException de)
          {
            assert debugException(CLASS_NAME, "processSASLBind", de);
            bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
            int    msgID   = MSGID_SASLPLAIN_AUTHZID_CANNOT_MAP_AUTHZID;
            String message = getMessage(msgID, authzID, de.getErrorMessage());
            bindOperation.setAuthFailureReason(msgID, message);
            return;
          }
        }
        if ((authZEntry == null) ||
            (! authZEntry.getDN().equals(userEntry.getDN())))
        {
          AuthenticationInfo tempAuthInfo =
            new AuthenticationInfo(userEntry,
                     DirectoryServer.isRootDN(userEntry.getDN()));
          InternalClientConnection tempConn =
               new InternalClientConnection(tempAuthInfo);
          if (! tempConn.hasPrivilege(Privilege.PROXIED_AUTH, bindOperation))
          {
            bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
            int msgID = MSGID_SASLPLAIN_AUTHZID_INSUFFICIENT_PRIVILEGES;
            String message = getMessage(msgID,
                                        String.valueOf(userEntry.getDN()));
            bindOperation.setAuthFailureReason(msgID, message);
            return;
          }
        }
      }
    }
    // Get the password policy for the user and use it to determine if the
    // provided password was correct.
    try
@@ -428,14 +580,11 @@
    }
    // FIXME -- Figure out what to do with the authzID if one was provided.
    // If we've gotten here, then the authentication was successful.
    bindOperation.setResultCode(ResultCode.SUCCESS);
    AuthenticationInfo authInfo =
         new AuthenticationInfo(userEntry, SASL_MECHANISM_PLAIN,
         new AuthenticationInfo(userEntry, authZEntry, SASL_MECHANISM_PLAIN,
                                DirectoryServer.isRootDN(userEntry.getDN()));
    bindOperation.setAuthenticationInfo(authInfo);
    return;
opends/src/server/org/opends/server/messages/CoreMessages.java
@@ -6229,6 +6229,16 @@
  /**
   * The message ID for the message that will be used when a client attempts to
   * use the proxied authorization control without sufficient privileges.  This
   * does not take any arguments.
   */
  public static final int MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES =
       CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 595;
  /**
   * Associates a set of generic messages with the message IDs defined
   * in this class.
   */
@@ -8423,6 +8433,9 @@
    registerMessage(MSGID_CLIENTCONNECTION_AUDIT_HASPRIVILEGES,
                    "hasPrivilege determination for connID=%d opID=%d " +
                    "requesterDN=\"%s\" privilegeSet=\"%s\" result=%b");
    registerMessage(MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES,
                    "You do not have sufficient privileges to use the " +
                    "proxied authorization control.");
  }
}
opends/src/server/org/opends/server/messages/ExtensionsMessages.java
@@ -4150,6 +4150,141 @@
  /**
   * The message ID for the message that will be used if the DIGEST-MD5 authzid
   * is the empty string.  This does not take any arguments.
   */
  public static final int MSGID_SASLDIGESTMD5_EMPTY_AUTHZID =
       CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 393;
  /**
   * The message ID for the message that will be used if the DIGEST-MD5 authzid
   * contained an invalid DN.  This takes two arguments, which are the authzid
   * and the reason that it was invalid.
   */
  public static final int MSGID_SASLDIGESTMD5_AUTHZID_INVALID_DN =
       CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 394;
  /**
   * The message ID for the message that will be used if the authenticating user
   * does not have sufficient privilege to specify an authorization identity
   * that is different from the authentication identity.  This takes a single
   * argument, which is the DN of the authentication identity.
   */
  public static final int MSGID_SASLDIGESTMD5_AUTHZID_INSUFFICIENT_PRIVILEGES =
       CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 395;
  /**
   * The message ID for the message that will be used if the DIGEST-MD5 authzid
   * references an entry that does not exist.  This takes a single argument,
   * which is the DN of the target entry.
   */
  public static final int MSGID_SASLDIGESTMD5_AUTHZID_NO_SUCH_ENTRY =
       CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 396;
  /**
   * The message ID for the message that will be used if an error occurs while
   * attempting to get the entry for the authorization identity.  This takes two
   * arguments, which are the authorization DN and a message explaining the
   * problem that occurred.
   */
  public static final int MSGID_SASLDIGESTMD5_AUTHZID_CANNOT_GET_ENTRY =
       CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 397;
  /**
   * The message ID for the message that will be used if the "u:"-form
   * authorization ID cannot be mapped to a user entry.  This takes a single
   * argument, which is the authzID string.
   */
  public static final int MSGID_SASLDIGESTMD5_AUTHZID_NO_MAPPED_ENTRY =
       CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 398;
  /**
   * The message ID for the message that will be used if an error occurs while
   * attempting to map the "u:"-form authorization ID to a user entry.  This
   * takes two arguments, which are the authzID string and a message explaining
   * the problem that occurred.
   */
  public static final int MSGID_SASLDIGESTMD5_CANNOT_MAP_AUTHZID =
       CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 399;
  /**
   * The message ID for the message that will be used if the authorization ID is
   * a malformed DN.  This takes two arguments, which are the authorization ID
   * string and a message explaining the problem that occurred.
   */
  public static final int MSGID_SASLPLAIN_AUTHZID_INVALID_DN =
       CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 400;
  /**
   * The message ID for the message that will be used if the authenticating user
   * attempts to provide an alternate authorization ID but does not have
   * sufficient privileges to do so.  This takes a single argument, which is the
   * DN of the authenticating user.
   */
  public static final int MSGID_SASLPLAIN_AUTHZID_INSUFFICIENT_PRIVILEGES =
       CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 401;
  /**
   * The message ID for the message that will be used if the authorization ID
   * contains the DN of an entry that does not exist.  This takes a single
   * argument, which is the authorization DN.
   */
  public static final int MSGID_SASLPLAIN_AUTHZID_NO_SUCH_ENTRY =
       CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 402;
  /**
   * The message ID for the message that will be used if a problem occurs while
   * trying to get the entry for the authorization DN.  This takes two
   * arguments, which are the authorization DN and a message explaining the
   * problem that occurred.
   */
  public static final int MSGID_SASLPLAIN_AUTHZID_CANNOT_GET_ENTRY =
       CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 403;
  /**
   * The message ID for the message that will be used if the authorization ID
   * specifies a username that does not map to an entry.  This takes a single
   * argument, which is the authorization ID string.
   */
  public static final int MSGID_SASLPLAIN_AUTHZID_NO_MAPPED_ENTRY =
       CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 404;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to map the authorization ID username to an entry.  This takes two
   * arguments, which are the authorization ID string and a message explaining
   * the problem that occurred.
   */
  public static final int MSGID_SASLPLAIN_AUTHZID_CANNOT_MAP_AUTHZID =
       CATEGORY_MASK_EXTENSIONS | SEVERITY_MASK_MILD_ERROR | 405;
  /**
   * Associates a set of generic messages with the message IDs defined in this
   * class.
   */
@@ -5084,6 +5219,24 @@
    registerMessage(MSGID_SASLPLAIN_NO_MATCHING_ENTRIES,
                    "The server was not able to find any user entries for " +
                    "the provided authentication ID of %s.");
    registerMessage(MSGID_SASLPLAIN_AUTHZID_INVALID_DN,
                    "The provided authorization ID %s contained an invalid " +
                    "DN:  %s.");
    registerMessage(MSGID_SASLPLAIN_AUTHZID_INSUFFICIENT_PRIVILEGES,
                    "The authenticating user %s does not have sufficient " +
                    "privileges to specify an alternate authorization ID.");
    registerMessage(MSGID_SASLPLAIN_AUTHZID_NO_SUCH_ENTRY,
                    "The entry corresponding to authorization DN %s does not " +
                    "exist in the Directory Server.");
    registerMessage(MSGID_SASLPLAIN_AUTHZID_CANNOT_GET_ENTRY,
                    "An error occurred while attempting to retrieve entry %s " +
                    "specified as the authorization ID:  %s.");
    registerMessage(MSGID_SASLPLAIN_AUTHZID_NO_MAPPED_ENTRY,
                    "No entry corresponding to authorization ID %s was found " +
                    "in the server.");
    registerMessage(MSGID_SASLPLAIN_AUTHZID_CANNOT_MAP_AUTHZID,
                    "An error occurred while attempting to map authorization " +
                    "ID %s to a user entry:  %s.");
    registerMessage(MSGID_SASLPLAIN_NO_PW_ATTR,
                    "The SASL PLAIN authentication failed because the mapped " +
                    "user entry did not contain any values for the %s " +
@@ -5469,6 +5622,27 @@
    registerMessage(MSGID_SASLDIGESTMD5_NO_MATCHING_ENTRIES,
                    "The server was not able to find any user entries for " +
                    "the provided username of %s.");
    registerMessage(MSGID_SASLDIGESTMD5_EMPTY_AUTHZID,
                    "The provided authorization ID was empty, which is not " +
                    "allowed for DIGEST-MD5 authentication.");
    registerMessage(MSGID_SASLDIGESTMD5_AUTHZID_INVALID_DN,
                    "The provided authorization ID %s contained an invalid " +
                    "DN:  %s.");
    registerMessage(MSGID_SASLDIGESTMD5_AUTHZID_INSUFFICIENT_PRIVILEGES,
                    "The authenticating user %s does not have sufficient " +
                    "privileges to assume a different authorization identity.");
    registerMessage(MSGID_SASLDIGESTMD5_AUTHZID_NO_SUCH_ENTRY,
                    "The entry %s specified as the authorization identity " +
                    "does not exist.");
    registerMessage(MSGID_SASLDIGESTMD5_AUTHZID_CANNOT_GET_ENTRY,
                    "The entry %s specified as the authorization identity " +
                    "could not be retrieved:  %s.");
    registerMessage(MSGID_SASLDIGESTMD5_AUTHZID_NO_MAPPED_ENTRY,
                    "The server was unable to find any entry corresponding " +
                    "to authorization ID %s.");
    registerMessage(MSGID_SASLDIGESTMD5_CANNOT_MAP_AUTHZID,
                    "An error occurred while attempting to map authorization " +
                    "ID %s to a user entry:  %s.");
    registerMessage(MSGID_SASLDIGESTMD5_NO_PW_ATTR,
                    "The SASL DIGEST-MD5 authentication failed because the " +
                    "mapped user entry did not contain any values for the %s " +
opends/src/server/org/opends/server/types/AuthenticationInfo.java
@@ -224,8 +224,9 @@
   * @param  authorizationEntry   The entry of the user that will be
   *                              used as the default authorization
   *                              identity, or {@code null} to
   *                              indicate that it should be the same
   *                              as the authentication entry.
   *                              indicate that the authorization
   *                              identity should be the
   *                              unauthenticated user.
   * @param  saslMechanism        The SASL mechanism used to
   *                              authenticate.  This must be provided
   *                              in all-uppercase characters and must
@@ -246,17 +247,9 @@
    ensureNotNull(authenticationEntry, saslMechanism);
    this.authenticationEntry = authenticationEntry;
    this.authorizationEntry  = authorizationEntry;
    this.isRoot              = isRoot;
    if (authorizationEntry == null)
    {
      this.authorizationEntry = authenticationEntry;
    }
    else
    {
      this.authorizationEntry = authorizationEntry;
    }
    isAuthenticated    = true;
    mustChangePassword = false;
    simplePassword     = null;
opends/tests/unit-tests-testng/src/server/org/opends/server/core/CompareOperationTestCase.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.core;
@@ -32,8 +32,10 @@
import org.opends.server.protocols.asn1.ASN1Reader;
import org.opends.server.protocols.asn1.ASN1Writer;
import org.opends.server.protocols.ldap.*;
import org.opends.server.types.AuthenticationInfo;
import org.opends.server.types.Control;
import org.opends.server.types.ResultCode;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.LockManager;
import org.opends.server.TestCaseUtils;
@@ -54,6 +56,7 @@
public class CompareOperationTestCase extends OperationTestCase
{
  private Entry entry;
  private InternalClientConnection proxyUserConn;
  @BeforeClass
@@ -101,6 +104,25 @@
                               entry.getOperationalAttributes());
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    assertNotNull(DirectoryServer.getEntry(entry.getDN()));
    // Add a user capable of using the proxied authorization control.
    TestCaseUtils.addEntry(
         "dn: uid=proxy.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: proxy.user",
         "givenName: Proxy",
         "sn: User",
         "cn: Proxy User",
         "userPassword: password",
         "ds-privilege-name: proxied-auth");
    Entry proxyUserEntry =
               DirectoryServer.getEntry(DN.decode("uid=proxy.user,o=test"));
    AuthenticationInfo authInfo = new AuthenticationInfo(proxyUserEntry, false);
    proxyUserConn = new InternalClientConnection(authInfo);
  }
@@ -435,16 +457,14 @@
  {
    InvocationCounterPlugin.resetAllCounters();
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ProxiedAuthV1Control authV1Control =
         new ProxiedAuthV1Control(new ASN1OctetString());
    List<Control> controls = new ArrayList<Control>();
    controls.add(authV1Control);
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
         new CompareOperation(proxyUserConn,
                              InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              controls,
                              new ASN1OctetString(entry.getDN().toString()),
@@ -461,10 +481,9 @@
  @Test
  public void testCompareProxiedAuthV1Denied() throws Exception
  {
    InvocationCounterPlugin.resetAllCounters();
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InvocationCounterPlugin.resetAllCounters();
    ProxiedAuthV1Control authV1Control =
         new ProxiedAuthV1Control(new ASN1OctetString("cn=nonexistent,o=test"));
@@ -472,7 +491,8 @@
    controls.add(authV1Control);
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
         new CompareOperation(proxyUserConn,
                              InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              controls,
                              new ASN1OctetString(entry.getDN().toString()),
@@ -490,16 +510,14 @@
  {
    InvocationCounterPlugin.resetAllCounters();
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ProxiedAuthV2Control authV2Control =
         new ProxiedAuthV2Control(new ASN1OctetString("dn:"));
    List<Control> controls = new ArrayList<Control>();
    controls.add(authV2Control);
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
         new CompareOperation(proxyUserConn,
                              InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              controls,
                              new ASN1OctetString(entry.getDN().toString()),
@@ -518,16 +536,14 @@
  {
    InvocationCounterPlugin.resetAllCounters();
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ProxiedAuthV2Control authV2Control = new ProxiedAuthV2Control(
         new ASN1OctetString("dn:cn=nonexistent,o=test"));
    List<Control> controls = new ArrayList<Control>();
    controls.add(authV2Control);
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
         new CompareOperation(proxyUserConn,
                              InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              controls,
                              new ASN1OctetString(entry.getDN().toString()),
@@ -545,9 +561,6 @@
  {
    InvocationCounterPlugin.resetAllCounters();
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ProxiedAuthV2Control authV2Control =
         new ProxiedAuthV2Control(new ASN1OctetString());
    authV2Control.setCritical(false);
@@ -555,7 +568,8 @@
    controls.add(authV2Control);
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
         new CompareOperation(proxyUserConn,
                              InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              controls,
                              new ASN1OctetString(entry.getDN().toString()),
opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java
@@ -56,6 +56,7 @@
{
  private Entry entry;
  private InternalClientConnection proxyUserConn;
  @BeforeClass
  public void setUp() throws Exception
@@ -132,6 +133,25 @@
                               entry.getOperationalAttributes());
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    assertNotNull(DirectoryServer.getEntry(entry.getDN()));
    // Add a user capable of using the proxied authorization control.
    TestCaseUtils.addEntry(
         "dn: uid=proxy.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: proxy.user",
         "givenName: Proxy",
         "sn: User",
         "cn: Proxy User",
         "userPassword: password",
         "ds-privilege-name: proxied-auth");
    Entry proxyUserEntry =
               DirectoryServer.getEntry(DN.decode("uid=proxy.user,o=test"));
    AuthenticationInfo authInfo = new AuthenticationInfo(proxyUserEntry, false);
    proxyUserConn = new InternalClientConnection(authInfo);
  }
  /**
@@ -806,12 +826,9 @@
    controls.add(authV1Control);
    InvocationCounterPlugin.resetAllCounters();
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                               controls,
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               new ASN1OctetString("uid=user.0,ou=People,dc=example,dc=com"),
                               new ASN1OctetString("uid=user.test0"), false,
                               null);
@@ -835,8 +852,8 @@
    InvocationCounterPlugin.resetAllCounters();
    modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                               controls,
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               new ASN1OctetString("uid=user.test0,ou=People,dc=example,dc=com"),
                               new ASN1OctetString("uid=user.0"), true,
                               null);
@@ -868,12 +885,9 @@
    controls.add(authV1Control);
    InvocationCounterPlugin.resetAllCounters();
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                               controls,
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), false,
                               null);
@@ -897,7 +911,8 @@
    InvocationCounterPlugin.resetAllCounters();
    modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(),
                               controls,
                               DN.decode("uid=user.test0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.0"), true,
@@ -930,12 +945,9 @@
    controls.add(authV1Control);
    InvocationCounterPlugin.resetAllCounters();
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                               controls,
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), false,
                               null);
@@ -957,12 +969,9 @@
    controls.add(authV2Control);
    InvocationCounterPlugin.resetAllCounters();
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                               controls,
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), false,
                               null);
@@ -986,8 +995,8 @@
    InvocationCounterPlugin.resetAllCounters();
    modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                               controls,
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               DN.decode("uid=user.test0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.0"), true,
                               null);
@@ -1019,12 +1028,9 @@
    controls.add(authV2Control);
    InvocationCounterPlugin.resetAllCounters();
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                               controls,
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), false,
                               null);
@@ -1047,12 +1053,9 @@
    controls.add(authV2Control);
    InvocationCounterPlugin.resetAllCounters();
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                               controls,
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), false,
                               null);
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DigestMD5SASLMechanismHandlerTestCase.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
@@ -727,6 +727,50 @@
  /**
   * Performs a failed LDAP bind using DIGEST-MD5 using an empty authorization
   * ID.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testLDAPBindFailEmptyAuthzID()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
      "dn: uid=test.user,o=test",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "uid: test.user",
      "givenName: Test",
      "sn: User",
      "cn: Test User",
      "userPassword: password",
      "ds-privilege-name: proxied-auth",
      "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
           "cn=Password Policies,cn=config");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=dn:uid=test.user,o=test",
      "-o", "authzid=",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
  /**
   * Performs a failed LDAP bind using DIGEST-MD5 using the dn: form of the
   * authentication ID with the root DN (which has a stored password that's not
   * reversible).
@@ -811,6 +855,138 @@
  /**
   * Performs a failed LDAP bind using DIGEST-MD5 using an authorization ID that
   * contains the DN of an entry that doesn't exist.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testLDAPBindFailNonexistentAuthzDN()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
      "dn: uid=test.user,o=test",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "uid: test.user",
      "givenName: Test",
      "sn: User",
      "cn: Test User",
      "userPassword: password",
      "ds-privilege-name: proxied-auth",
      "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
           "cn=Password Policies,cn=config");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=dn:uid=test.user,o=test",
      "-o", "authzid=dn:uid=nonexistent,o=test",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
  /**
   * Performs a failed LDAP bind using DIGEST-MD5 using an authorization ID that
   * contains a username for an entry that doesn't exist.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testLDAPBindFailNonexistentAuthzUsername()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
      "dn: uid=test.user,o=test",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "uid: test.user",
      "givenName: Test",
      "sn: User",
      "cn: Test User",
      "userPassword: password",
      "ds-privilege-name: proxied-auth",
      "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
           "cn=Password Policies,cn=config");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=dn:uid=test.user,o=test",
      "-o", "authzid=u:nonexistent",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
  /**
   * Performs a failed LDAP bind using DIGEST-MD5 using an authorization ID that
   * contains a malformed DN.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testLDAPBindFailMalformedAuthzDN()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
      "dn: uid=test.user,o=test",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "uid: test.user",
      "givenName: Test",
      "sn: User",
      "cn: Test User",
      "userPassword: password",
      "ds-privilege-name: proxied-auth",
      "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
           "cn=Password Policies,cn=config");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=dn:uid=test.user,o=test",
      "-o", "authzid=dn:malformed",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
  /**
   * Verifies that the server will reject a DIGEST-MD5 bind in which the first
   * message contains SASL credentials (which isn't allowed).
   *
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006 Sun Microsystems, Inc.
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
@@ -516,5 +516,128 @@
                                       saslCredentials);
    assertEquals(bindOperation.getResultCode(), ResultCode.INVALID_CREDENTIALS);
  }
  /**
   * Performs a failed LDAP bind using PLAIN with an authorization ID that
   * contains the DN of an entry that doesn't exist.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testLDAPBindFailNonexistentAuthzDN()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
      "dn: uid=test.user,o=test",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "uid: test.user",
      "givenName: Test",
      "sn: User",
      "cn: Test User",
      "userPassword: password",
      "ds-privilege-name: proxied-auth");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=dn:uid=test.user,o=test",
      "-o", "authzid=dn:uid=nonexistent,o=test",
      "-w", "password",
      "-b", "",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
  /**
   * Performs a failed LDAP bind using PLAIN with an authorization ID that
   * contains a username for an entry that doesn't exist.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testLDAPBindFailNonexistentAuthzUsername()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
      "dn: uid=test.user,o=test",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "uid: test.user",
      "givenName: Test",
      "sn: User",
      "cn: Test User",
      "userPassword: password",
      "ds-privilege-name: proxied-auth");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=dn:uid=test.user,o=test",
      "-o", "authzid=u:nonexistent",
      "-w", "password",
      "-b", "",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
  /**
   * Performs a failed LDAP bind using PLAIN with an authorization ID that
   * contains a malformed DN.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testLDAPBindFailMalformedAuthzDN()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
      "dn: uid=test.user,o=test",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "uid: test.user",
      "givenName: Test",
      "sn: User",
      "cn: Test User",
      "userPassword: password",
      "ds-privilege-name: proxied-auth");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=dn:uid=test.user,o=test",
      "-o", "authzid=dn:malformed",
      "-w", "password",
      "-b", "",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
@@ -43,6 +43,8 @@
import org.opends.server.backends.task.Task;
import org.opends.server.backends.task.TaskBackend;
import org.opends.server.backends.task.TaskState;
import org.opends.server.controls.ProxiedAuthV1Control;
import org.opends.server.controls.ProxiedAuthV2Control;
import org.opends.server.core.AddOperation;
import org.opends.server.core.CompareOperation;
import org.opends.server.core.DeleteOperation;
@@ -50,10 +52,12 @@
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.SchemaConfigManager;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.tools.LDAPModify;
import org.opends.server.tools.LDAPPasswordModify;
import org.opends.server.tools.LDAPSearch;
import org.opends.server.types.Attribute;
import org.opends.server.types.AuthenticationInfo;
import org.opends.server.types.DN;
@@ -120,6 +124,7 @@
      "cn: Unprivileged Root",
      "givenName: Unprivileged",
      "sn: Root",
      "uid: unprivileged.root",
      "userPassword: password",
      "ds-privilege-name: -config-read",
      "ds-privilege-name: -config-write",
@@ -130,6 +135,19 @@
      "ds-privilege-name: -backend-backup",
      "ds-privilege-name: -backend-restore",
      "",
      "dn: cn=Proxy Root,cn=Root DNs,cn=config",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "objectClass: ds-cfg-root-dn",
      "cn: Proxy Root",
      "givenName: Proxy",
      "sn: Root",
      "uid: proxy.root",
      "userPassword: password",
      "ds-privilege-name: proxied-auth",
      "",
      "dn: cn=Privileged User,o=test",
      "objectClass: top",
      "objectClass: person",
@@ -138,6 +156,7 @@
      "cn: Privileged User",
      "givenName: Privileged",
      "sn: User",
      "uid: privileged.user",
      "userPassword: password",
      "ds-privilege-name: config-read",
      "ds-privilege-name: config-write",
@@ -147,6 +166,9 @@
      "ds-privilege-name: ldif-export",
      "ds-privilege-name: backend-backup",
      "ds-privilege-name: backend-restore",
      "ds-privilege-name: proxied-auth",
      "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
           "cn=Password Policies,cn=config",
      "",
      "dn: cn=Unprivileged User,o=test",
      "objectClass: top",
@@ -156,7 +178,10 @@
      "cn: Unprivileged User",
      "givenName: Unprivileged",
      "sn: User",
      "uid: unprivileged.user",
      "userPassword: password",
      "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
           "cn=Password Policies,cn=config",
      "",
      "dn: cn=PWReset Target,o=test",
      "objectClass: top",
@@ -166,6 +191,7 @@
      "cn: PWReset Target",
      "givenName: PWReset",
      "sn: Target",
      "uid: pwreset.target",
      "userPassword: password");
// FIXME -- It will likely be necessary to also have access control rules in
@@ -196,6 +222,12 @@
    connList.add(new InternalClientConnection(authInfo));
    successList.add(false);
    userDN    = "cn=Proxy Root,cn=Root DNs,cn=config";
    userEntry = DirectoryServer.getEntry(DN.decode(userDN));
    authInfo  = new AuthenticationInfo(userEntry, true);
    connList.add(new InternalClientConnection(authInfo));
    successList.add(true);
    userDN    = "cn=Unprivileged User,o=test";
    userEntry = DirectoryServer.getEntry(DN.decode(userDN));
    authInfo  = new AuthenticationInfo(userEntry, false);
@@ -985,6 +1017,1129 @@
  /**
   * Tests to ensure that the use of the Directory Server will properly respect
   * the PROXIED_AUTH privilege for add, delete, modify and modify DN requests
   * that contain the proxied auth v1 control.
   *
   * @param  conn          The client connection to use to perform the
   *                       operation.
   * @param  hasPrivilege  Indicates whether the authenticated user is expected
   *                       to have the PROXIED_AUTH privilege and therefore
   *                       the operation should succeed.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata")
  public void testProxyAuthV1Write(InternalClientConnection conn,
                                   boolean hasPrivilege)
         throws Exception
  {
    // We can't trust the value of hasPrivilege because root users don't get
    // proxy privileges by default.  So make the determination based on the
    // privileges the user actually has.
    boolean hasProxyPrivilege = conn.hasPrivilege(Privilege.PROXIED_AUTH, null);
    Entry e = TestCaseUtils.makeEntry(
      "dn: cn=ProxyV1 Test,o=test",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "cn: ProxyV1 Test",
      "givenName: ProxyV1",
      "sn: Test");
    ArrayList<Control> controls = new ArrayList<Control>(1);
    controls.add(new ProxiedAuthV1Control(
                          DN.decode("cn=PWReset Target,o=test")));
    // Try to add the entry.  If this fails with the proxy control, then add it
    // with a root connection so we can do other things with it.
    AddOperation addOperation =
         new AddOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                          controls, e.getDN(), e.getObjectClasses(),
                          e.getUserAttributes(), e.getOperationalAttributes());
    addOperation.run();
    if (hasProxyPrivilege)
    {
      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    }
    else
    {
      assertEquals(addOperation.getResultCode(),
                   ResultCode.AUTHORIZATION_DENIED);
      TestCaseUtils.addEntry(e);
    }
    // Try to modify the entry to add a description.
    ArrayList<Modification> mods = new ArrayList<Modification>(1);
    mods.add(new Modification(ModificationType.REPLACE,
                              new Attribute("description", "foo")));
    ModifyOperation modifyOperation =
         new ModifyOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                             controls, e.getDN(), mods);
    modifyOperation.run();
    if (hasProxyPrivilege)
    {
      assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    }
    else
    {
      assertEquals(modifyOperation.getResultCode(),
                   ResultCode.AUTHORIZATION_DENIED);
    }
    // Try to rename the entry.
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(),
                               conn.nextMessageID(), controls, e.getDN(),
                               RDN.decode("cn=Proxy V1 Test"), true, null);
    modifyDNOperation.run();
    DN newEntryDN;
    if (hasProxyPrivilege)
    {
      assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS);
      newEntryDN = modifyDNOperation.getUpdatedEntry().getDN();
    }
    else
    {
      assertEquals(modifyDNOperation.getResultCode(),
                   ResultCode.AUTHORIZATION_DENIED);
      newEntryDN = e.getDN();
    }
    // Try to delete the operation.  If this fails, then delete it with a root
    // connection so it gets cleaned up.
    DeleteOperation deleteOperation =
         new DeleteOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                             controls, newEntryDN);
    deleteOperation.run();
    if (hasProxyPrivilege)
    {
      assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
    }
    else
    {
      assertEquals(deleteOperation.getResultCode(),
                   ResultCode.AUTHORIZATION_DENIED);
      InternalClientConnection rootConnection =
           InternalClientConnection.getRootConnection();
      deleteOperation = rootConnection.processDelete(newEntryDN);
      assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
    }
  }
  /**
   * Tests to ensure that the use of the Directory Server will properly respect
   * the PROXIED_AUTH privilege for search and compare requests that contain the
   * proxied auth v1 control.
   *
   * @param  conn          The client connection to use to perform the
   *                       operation.
   * @param  hasPrivilege  Indicates whether the authenticated user is expected
   *                       to have the PROXIED_AUTH privilege and therefore
   *                       the operation should succeed.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata")
  public void testProxyAuthV1Read(InternalClientConnection conn,
                                  boolean hasPrivilege)
         throws Exception
  {
    // We can't trust the value of hasPrivilege because root users don't get
    // proxy privileges by default.  So make the determination based on the
    // privileges the user actually has.
    boolean hasProxyPrivilege = conn.hasPrivilege(Privilege.PROXIED_AUTH, null);
    DN targetDN = DN.decode("cn=PWReset Target,o=test");
    ArrayList<Control> controls = new ArrayList<Control>(1);
    controls.add(new ProxiedAuthV1Control(targetDN));
    // Test a compare operation against the PWReset Target user.
    CompareOperation compareOperation =
         new CompareOperation(conn, conn.nextOperationID(),
                              conn.nextMessageID(), controls, targetDN,
                              DirectoryServer.getAttributeType("cn", true),
                              ByteStringFactory.create("PWReset Target"));
    compareOperation.run();
    if (hasProxyPrivilege)
    {
      assertEquals(compareOperation.getResultCode(), ResultCode.COMPARE_TRUE);
    }
    else
    {
      assertEquals(compareOperation.getResultCode(),
                   ResultCode.AUTHORIZATION_DENIED);
    }
    // Test a search operation against the PWReset Target user.
    InternalSearchOperation searchOperation =
         new InternalSearchOperation(conn, conn.nextOperationID(),
                  conn.nextMessageID(), controls, targetDN,
                  SearchScope.BASE_OBJECT,
                  DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                  SearchFilter.createFilterFromString("(objectClass=*)"), null,
                  null);
    searchOperation.run();
    if (hasProxyPrivilege)
    {
      assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
    }
    else
    {
      assertEquals(searchOperation.getResultCode(),
                   ResultCode.AUTHORIZATION_DENIED);
    }
  }
  /**
   * Tests to ensure that the use of the Directory Server will properly respect
   * the PROXIED_AUTH privilege for add, delete, modify and modify DN requests
   * that contain the proxied auth v2 control.
   *
   * @param  conn          The client connection to use to perform the
   *                       operation.
   * @param  hasPrivilege  Indicates whether the authenticated user is expected
   *                       to have the PROXIED_AUTH privilege and therefore
   *                       the operation should succeed.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata")
  public void testProxyAuthV2Write(InternalClientConnection conn,
                                   boolean hasPrivilege)
         throws Exception
  {
    // We can't trust the value of hasPrivilege because root users don't get
    // proxy privileges by default.  So make the determination based on the
    // privileges the user actually has.
    boolean hasProxyPrivilege = conn.hasPrivilege(Privilege.PROXIED_AUTH, null);
    Entry e = TestCaseUtils.makeEntry(
      "dn: cn=ProxyV2 Test,o=test",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "cn: ProxyV2 Test",
      "givenName: ProxyV2",
      "sn: Test");
    ArrayList<Control> controls = new ArrayList<Control>(1);
    controls.add(new ProxiedAuthV2Control(
                          new ASN1OctetString("dn:cn=PWReset Target,o=test")));
    // Try to add the entry.  If this fails with the proxy control, then add it
    // with a root connection so we can do other things with it.
    AddOperation addOperation =
         new AddOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                          controls, e.getDN(), e.getObjectClasses(),
                          e.getUserAttributes(), e.getOperationalAttributes());
    addOperation.run();
    if (hasProxyPrivilege)
    {
      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    }
    else
    {
      assertEquals(addOperation.getResultCode(),
                   ResultCode.AUTHORIZATION_DENIED);
      TestCaseUtils.addEntry(e);
    }
    // Try to modify the entry to add a description.
    ArrayList<Modification> mods = new ArrayList<Modification>(1);
    mods.add(new Modification(ModificationType.REPLACE,
                              new Attribute("description", "foo")));
    ModifyOperation modifyOperation =
         new ModifyOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                             controls, e.getDN(), mods);
    modifyOperation.run();
    if (hasProxyPrivilege)
    {
      assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    }
    else
    {
      assertEquals(modifyOperation.getResultCode(),
                   ResultCode.AUTHORIZATION_DENIED);
    }
    // Try to rename the entry.
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(),
                               conn.nextMessageID(), controls, e.getDN(),
                               RDN.decode("cn=Proxy V2 Test"), true, null);
    modifyDNOperation.run();
    DN newEntryDN;
    if (hasProxyPrivilege)
    {
      assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS);
      newEntryDN = modifyDNOperation.getUpdatedEntry().getDN();
    }
    else
    {
      assertEquals(modifyDNOperation.getResultCode(),
                   ResultCode.AUTHORIZATION_DENIED);
      newEntryDN = e.getDN();
    }
    // Try to delete the operation.  If this fails, then delete it with a root
    // connection so it gets cleaned up.
    DeleteOperation deleteOperation =
         new DeleteOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
                             controls, newEntryDN);
    deleteOperation.run();
    if (hasProxyPrivilege)
    {
      assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
    }
    else
    {
      assertEquals(deleteOperation.getResultCode(),
                   ResultCode.AUTHORIZATION_DENIED);
      InternalClientConnection rootConnection =
           InternalClientConnection.getRootConnection();
      deleteOperation = rootConnection.processDelete(newEntryDN);
      assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
    }
  }
  /**
   * Tests to ensure that the use of the Directory Server will properly respect
   * the PROXIED_AUTH privilege for search and compare requests that contain the
   * proxied auth v2 control.
   *
   * @param  conn          The client connection to use to perform the
   *                       operation.
   * @param  hasPrivilege  Indicates whether the authenticated user is expected
   *                       to have the PROXIED_AUTH privilege and therefore
   *                       the operation should succeed.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata")
  public void testProxyAuthV2Read(InternalClientConnection conn,
                                  boolean hasPrivilege)
         throws Exception
  {
    // We can't trust the value of hasPrivilege because root users don't get
    // proxy privileges by default.  So make the determination based on the
    // privileges the user actually has.
    boolean hasProxyPrivilege = conn.hasPrivilege(Privilege.PROXIED_AUTH, null);
    DN targetDN = DN.decode("cn=PWReset Target,o=test");
    ArrayList<Control> controls = new ArrayList<Control>(1);
    controls.add(new ProxiedAuthV2Control(
                          new ASN1OctetString("dn:" + targetDN.toString())));
    // Test a compare operation against the PWReset Target user.
    CompareOperation compareOperation =
         new CompareOperation(conn, conn.nextOperationID(),
                              conn.nextMessageID(), controls, targetDN,
                              DirectoryServer.getAttributeType("cn", true),
                              ByteStringFactory.create("PWReset Target"));
    compareOperation.run();
    if (hasProxyPrivilege)
    {
      assertEquals(compareOperation.getResultCode(), ResultCode.COMPARE_TRUE);
    }
    else
    {
      assertEquals(compareOperation.getResultCode(),
                   ResultCode.AUTHORIZATION_DENIED);
    }
    // Test a search operation against the PWReset Target user.
    InternalSearchOperation searchOperation =
         new InternalSearchOperation(conn, conn.nextOperationID(),
                  conn.nextMessageID(), controls, targetDN,
                  SearchScope.BASE_OBJECT,
                  DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                  SearchFilter.createFilterFromString("(objectClass=*)"), null,
                  null);
    searchOperation.run();
    if (hasProxyPrivilege)
    {
      assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
    }
    else
    {
      assertEquals(searchOperation.getResultCode(),
                   ResultCode.AUTHORIZATION_DENIED);
    }
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform DIGEST-MD5 authentication when an
   * anonymous authorization ID is specified with an authentication identity
   * that has sufficient privileges and using the "dn:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDIGESTMD5AnonymousAuthzIDSuccessfulDNColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=dn:cn=Privileged User,o=test",
      "-o", "authzid=dn:",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will behave properly when attempting to
   * perform DIGEST-MD5 authentication when an authorization ID equaling the
   * authentication ID is specified with an authentication identity that has
   * sufficient privileges and using the "dn:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDIGESTMD5SameAuthzIDSuccessfulDNColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=dn:cn=Privileged User,o=test",
      "-o", "authzid=dn:cn=Privileged User,o=test",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform DIGEST-MD5 authentication when an
   * alternate authorization ID is specified with an authentication identity
   * that has sufficient privileges and using the "dn:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDIGESTMD5DifferentAuthzIDSuccessfulDNColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=dn:cn=Privileged User,o=test",
      "-o", "authzid=dn:cn=Unprivileged User,o=test",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform DIGEST-MD5 authentication when an
   * anonymous authorization ID is specified with an authentication identity
   * that has sufficient privileges and using the "u:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDIGESTMD5AnonymousAuthzIDSuccessfulUColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=u:privileged.user",
      "-o", "authzid=u:",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will behave properly when attempting to
   * perform DIGEST-MD5 authentication when an authorization ID equaling the
   * authentication ID is specified with an authentication identity that has
   * sufficient privileges and using the "u:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDIGESTMD5SameAuthzIDSuccessfulUColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=u:privileged.user",
      "-o", "authzid=u:privileged.user",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform DIGEST-MD5 authentication when an
   * alternate authorization ID is specified with an authentication identity
   * that has sufficient privileges and using the "u:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDIGESTMD5DifferentAuthzIDSuccessfulUColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=u:privileged.user",
      "-o", "authzid=u:unprivileged.user",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform DIGEST-MD5 authentication when an
   * anonymous authorization ID is specified with an authentication identity
   * that does not have sufficient privileges and using the "dn:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDIGESTMD5AnonymousAuthzIDFailedDNColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=dn:cn=Unprivileged User,o=test",
      "-o", "authzid=dn:",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
  /**
   * Tests to ensure that the server will behave properly when attempting to
   * perform DIGEST-MD5 authentication when an authorization ID equaling the
   * authentication ID is specified with an authentication identity that does
   * not have sufficient privileges and using the "dn:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDIGESTMD5SameUnprivAuthzIDSuccessfulDNColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=dn:cn=Unprivileged User,o=test",
      "-o", "authzid=dn:cn=Unprivileged User,o=test",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform DIGEST-MD5 authentication when an
   * alternate authorization ID is specified with an authentication identity
   * that does not have sufficient privileges and using the "dn:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDIGESTMD5DifferentAuthzIDFailedDNColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=dn:cn=Unprivileged User,o=test",
      "-o", "authzid=dn:cn=Privileged User,o=test",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform DIGEST-MD5 authentication when an
   * anonymous authorization ID is specified with an authentication identity
   * that does not have sufficient privileges and using the "u:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDIGESTMD5AnonymousAuthzIDFailedUColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=u:unprivileged.user",
      "-o", "authzid=u:",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
  /**
   * Tests to ensure that the server will behave properly when attempting to
   * perform DIGEST-MD5 authentication when an authorization ID equaling the
   * authentication ID is specified with an authentication identity that does
   * not have sufficient privileges and using the "u:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDIGESTMD5SameUnprivAuthzIDSuccessfulUColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=u:unprivileged.user",
      "-o", "authzid=u:unprivileged.user",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform DIGEST-MD5 authentication when an
   * alternate authorization ID is specified with an authentication identity
   * that does not have sufficient privileges and using the "u:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDIGESTMD5DifferentAuthzIDFailedUColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=DIGEST-MD5",
      "-o", "authid=u:unprivileged.user",
      "-o", "authzid=u:privileged.user",
      "-o", "realm=o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform PLAIN authentication when an
   * anonymous authorization ID is specified with an authentication identity
   * that has sufficient privileges and using the "dn:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testPLAINAnonymousAuthzIDSuccessfulDNColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=dn:cn=Privileged User,o=test",
      "-o", "authzid=dn:",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will behave properly when attempting to
   * perform PLAIN authentication when an authorization ID equaling the
   * authentication ID is specified with an authentication identity that has
   * sufficient privileges and using the "dn:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testPLAINSameAuthzIDSuccessfulDNColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=dn:cn=Privileged User,o=test",
      "-o", "authzid=dn:cn=Privileged User,o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform PLAIN authentication when an
   * alternate authorization ID is specified with an authentication identity
   * that has sufficient privileges and using the "dn:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testPLAINDifferentAuthzIDSuccessfulDNColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=dn:cn=Privileged User,o=test",
      "-o", "authzid=dn:cn=Unprivileged User,o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform PLAIN authentication when an
   * anonymous authorization ID is specified with an authentication identity
   * that has sufficient privileges and using the "u:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testPLAINAnonymousAuthzIDSuccessfulUColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=u:privileged.user",
      "-o", "authzid=u:",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will behave properly when attempting to
   * perform PLAIN authentication when an authorization ID equaling the
   * authentication ID is specified with an authentication identity that has
   * sufficient privileges and using the "u:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testPLAINSameAuthzIDSuccessfulUColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=u:privileged.user",
      "-o", "authzid=u:privileged.user",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform PLAIN authentication when an
   * alternate authorization ID is specified with an authentication identity
   * that has sufficient privileges and using the "u:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testPLAINDifferentAuthzIDSuccessfulUColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=u:privileged.user",
      "-o", "authzid=u:unprivileged.user",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform PLAIN authentication when an
   * anonymous authorization ID is specified with an authentication identity
   * that does not have sufficient privileges and using the "dn:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testPLAINAnonymousAuthzIDFailedDNColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=dn:cn=Unprivileged User,o=test",
      "-o", "authzid=dn:",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
  /**
   * Tests to ensure that the server will behave properly when attempting to
   * perform PLAIN authentication when an authorization ID equaling the
   * authentication ID is specified with an authentication identity that does
   * not have sufficient privileges and using the "dn:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testPLAINSameUnprivAuthzIDSuccessfulDNColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=dn:cn=Unprivileged User,o=test",
      "-o", "authzid=dn:cn=Unprivileged User,o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform PLAIN authentication when an
   * alternate authorization ID is specified with an authentication identity
   * that does not have sufficient privileges and using the "dn:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testPLAINDifferentAuthzIDFailedDNColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=dn:cn=Unprivileged User,o=test",
      "-o", "authzid=dn:cn=Privileged User,o=test",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform PLAIN authentication when an
   * anonymous authorization ID is specified with an authentication identity
   * that does not have sufficient privileges and using the "u:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testPLAINAnonymousAuthzIDFailedUColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=u:unprivileged.user",
      "-o", "authzid=u:",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
  /**
   * Tests to ensure that the server will behave properly when attempting to
   * perform PLAIN authentication when an authorization ID equaling the
   * authentication ID is specified with an authentication identity that does
   * not have sufficient privileges and using the "u:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testPLAINSameUnprivAuthzIDSuccessfulUColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=u:unprivileged.user",
      "-o", "authzid=u:unprivileged.user",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0);
  }
  /**
   * Tests to ensure that the server will properly respect the PROXIED_AUTH
   * privilege when attempting to perform PLAIN authentication when an
   * alternate authorization ID is specified with an authentication identity
   * that does not have sufficient privileges and using the "u:" syntax.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testPLAINDifferentAuthzIDFailedUColon()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-o", "mech=PLAIN",
      "-o", "authid=u:unprivileged.user",
      "-o", "authzid=u:privileged.user",
      "-w", "password",
      "-b", "o=test",
      "-s", "base",
      "(objectClass=*)"
    };
    assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0);
  }
  /**
   * Tests the ability to update the set of privileges for a user on the fly
   * and have them take effect immediately.
   *