From 938eec61d6c1bf9f62c9c3dad50086d02340f006 Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Sat, 03 Feb 2007 00:30:16 +0000
Subject: [PATCH] Update the proxied authorization control code to require that the controls have a criticality of "true" as per the specification in RFC 4370.

---
 opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.java                                 |   29 +
 opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV1ControlTestCase.java |  528 ++++++++++++++++++++++++++
 opends/src/server/org/opends/server/messages/ProtocolMessages.java                                     |   30 +
 opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV2ControlTestCase.java |  547 +++++++++++++++++++++++++++
 opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.java                                 |   44 -
 5 files changed, 1,144 insertions(+), 34 deletions(-)

diff --git a/opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.java b/opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.java
index 27cfb52..518d547 100644
--- a/opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.java
+++ b/opends/src/server/org/opends/server/controls/ProxiedAuthV1Control.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.controls;
 
@@ -50,6 +50,7 @@
 import static org.opends.server.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
+import static org.opends.server.util.Validator.*;
 
 
 
@@ -86,7 +87,7 @@
    * provided information.
    *
    * @param  rawAuthorizationDN  The raw, unprocessed authorization DN from the
-   *                             control value.
+   *                             control value.  It must not be {@code null}.
    */
   public ProxiedAuthV1Control(ASN1OctetString rawAuthorizationDN)
   {
@@ -105,7 +106,8 @@
    * Creates a new instance of the proxied authorization v1 control with the
    * provided information.
    *
-   * @param  authorizationDN  The authorization DN from the control value.
+   * @param  authorizationDN  The authorization DN from the control value.  It
+   *                          must not be {@code null}.
    */
   public ProxiedAuthV1Control(DN authorizationDN)
   {
@@ -156,7 +158,8 @@
    * authorization DN.
    *
    * @param  rawAuthorizationDN  The raw, unprocessed authorization DN to use in
-   *                             the control value.
+   *                             the control value.  It must not be
+   *                             {@code null}.
    *
    * @return  The encoded control value.
    */
@@ -165,6 +168,8 @@
     assert debugEnter(CLASS_NAME, "encodeValue",
                       String.valueOf(rawAuthorizationDN));
 
+    ensureNotNull(rawAuthorizationDN);
+
     ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(1);
     elements.add(rawAuthorizationDN);
 
@@ -178,7 +183,8 @@
    * provided control.
    *
    * @param  control  The generic control containing the information to use to
-   *                  create this proxied authorization v1 control.
+   *                  create this proxied authorization v1 control.  It must not
+   *                  be {@code null}.
    *
    * @return  The proxied authorization v1 control decoded from the provided
    *          control.
@@ -191,6 +197,16 @@
   {
     assert debugEnter(CLASS_NAME, "decodeControl", String.valueOf(control));
 
+    ensureNotNull(control);
+
+    if (! control.isCritical())
+    {
+      int    msgID   = MSGID_PROXYAUTH1_CONTROL_NOT_CRITICAL;
+      String message = getMessage(msgID);
+      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID,
+                              message);
+    }
+
     if (! control.hasValue())
     {
       int    msgID   = MSGID_PROXYAUTH1_NO_CONTROL_VALUE;
@@ -293,12 +309,15 @@
    * Specifies the authorization DN for this proxied auth control.
    *
    * @param  authorizationDN  The authorizationDN for this proxied auth control.
+   *                          It must not be {@code null}.
    */
   public void setAuthorizationDN(DN authorizationDN)
   {
     assert debugEnter(CLASS_NAME, "setAuthorizationDN",
                       String.valueOf(authorizationDN));
 
+    ensureNotNull(authorizationDN);
+
     this.authorizationDN = authorizationDN;
 
     rawAuthorizationDN = new ASN1OctetString(authorizationDN.toString());
diff --git a/opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.java b/opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.java
index 02b2912..07f993d 100644
--- a/opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.java
+++ b/opends/src/server/org/opends/server/controls/ProxiedAuthV2Control.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.controls;
 
@@ -49,6 +49,7 @@
 import static org.opends.server.messages.ProtocolMessages.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
+import static org.opends.server.util.Validator.*;
 
 
 
@@ -84,10 +85,11 @@
    */
   public ProxiedAuthV2Control(ASN1OctetString authorizationID)
   {
-    super(OID_PROXIED_AUTH_V2, true, encodeValue(authorizationID));
+    super(OID_PROXIED_AUTH_V2, true, authorizationID);
 
     assert debugConstructor(CLASS_NAME, String.valueOf(authorizationID));
 
+    ensureNotNull(authorizationID);
     this.authorizationID = authorizationID;
   }
 
@@ -118,36 +120,12 @@
 
 
   /**
-   * Generates an encoded value for this control containing the provided
-   * authorization ID.
-   *
-   * @param  authorizationID  The authorization ID to be encoded.
-   *
-   * @return  The encoded control value.
-   */
-  private static ASN1OctetString encodeValue(ASN1OctetString authorizationID)
-  {
-    assert debugEnter(CLASS_NAME, "encodeValue",
-                      String.valueOf(authorizationID));
-
-    if (authorizationID == null)
-    {
-      return new ASN1OctetString();
-    }
-    else
-    {
-      return authorizationID;
-    }
-  }
-
-
-
-  /**
    * Creates a new proxied authorization v2 control from the contents of the
    * provided control.
    *
    * @param  control  The generic control containing the information to use to
-   *                  create this proxied authorization v2 control.
+   *                  create this proxied authorization v2 control.  It must not
+   *                  be {@code null}.
    *
    * @return  The proxied authorization v2 control decoded from the provided
    *          control.
@@ -160,6 +138,16 @@
   {
     assert debugEnter(CLASS_NAME, "decodeControl", String.valueOf(control));
 
+    ensureNotNull(control);
+
+    if (! control.isCritical())
+    {
+      int    msgID   = MSGID_PROXYAUTH2_CONTROL_NOT_CRITICAL;
+      String message = getMessage(msgID);
+      throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID,
+                              message);
+    }
+
     if (! control.hasValue())
     {
       int    msgID   = MSGID_PROXYAUTH2_NO_CONTROL_VALUE;
diff --git a/opends/src/server/org/opends/server/messages/ProtocolMessages.java b/opends/src/server/org/opends/server/messages/ProtocolMessages.java
index e8f2593..969de8d 100644
--- a/opends/src/server/org/opends/server/messages/ProtocolMessages.java
+++ b/opends/src/server/org/opends/server/messages/ProtocolMessages.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.messages;
 
@@ -4210,6 +4210,24 @@
 
 
   /**
+   * The message ID for the message that will be used if a proxied auth V1
+   * control is not marked critical.  This does not take any arguments.
+   */
+  public static final int MSGID_PROXYAUTH1_CONTROL_NOT_CRITICAL =
+       CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_MILD_ERROR | 388;
+
+
+
+  /**
+   * The message ID for the message that will be used if a proxied auth V2
+   * control is not marked critical.  This does not take any arguments.
+   */
+  public static final int MSGID_PROXYAUTH2_CONTROL_NOT_CRITICAL =
+       CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_MILD_ERROR | 389;
+
+
+
+  /**
    * Associates a set of generic messages with the message IDs defined in this
    * class.
    */
@@ -5654,6 +5672,11 @@
                     "decode the control value:  %s.");
 
 
+    registerMessage(MSGID_PROXYAUTH1_CONTROL_NOT_CRITICAL,
+                    "Unwilling to process the request because it contains a " +
+                    "proxied authorization V1 control which is not marked " +
+                    "critical.  The proxied authorization control must " +
+                    "always have a criticality of \"true\".");
     registerMessage(MSGID_PROXYAUTH1_NO_CONTROL_VALUE,
                     "Cannot decode the provided proxied authorization V1 " +
                     "control because it does not have a value.");
@@ -5677,6 +5700,11 @@
                     "is not allowed by the password policy configuration.");
 
 
+    registerMessage(MSGID_PROXYAUTH2_CONTROL_NOT_CRITICAL,
+                    "Unwilling to process the request because it contains a " +
+                    "proxied authorization V2 control which is not marked " +
+                    "critical.  The proxied authorization control must " +
+                    "always have a criticality of \"true\".");
     registerMessage(MSGID_PROXYAUTH2_NO_CONTROL_VALUE,
                     "Cannot decode the provided proxied authorization V2 " +
                     "control because it does not have a value.");
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV1ControlTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV1ControlTestCase.java
new file mode 100644
index 0000000..b0b6a7c
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV1ControlTestCase.java
@@ -0,0 +1,528 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying * information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.controls;
+
+
+
+import java.util.ArrayList;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.protocols.asn1.ASN1Element;
+import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.protocols.asn1.ASN1Sequence;
+import org.opends.server.protocols.ldap.LDAPException;
+import org.opends.server.types.Control;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.DN;
+
+import static org.testng.Assert.*;
+
+import static org.opends.server.util.ServerConstants.*;
+
+
+
+/**
+ * This class contains a number of test cases for the proxied authorization v1
+ * control.
+ */
+public class ProxiedAuthV1ControlTestCase
+    extends ControlsTestCase
+{
+  /**
+   * Make sure that the server is running.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @BeforeClass()
+  public void startServer()
+         throws Exception
+  {
+    TestCaseUtils.startServer();
+  }
+
+
+
+  /**
+   * Tests the first constructor, which creates an instance of the control using
+   * a raw, unprocessed DN.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testConstructor1()
+         throws Exception
+  {
+    // Try a DN of "null", which is not valid and will fail on the attempt to
+    // create the control
+    ProxiedAuthV1Control proxyControl;
+    try
+    {
+      proxyControl = new ProxiedAuthV1Control((ASN1OctetString) null);
+      throw new AssertionError("Expected a failure when creating a proxied " +
+                               "auth V1 control with a null octet string.");
+    } catch (Throwable t) {}
+
+
+    // Try an empty DN, which is acceptable.
+    proxyControl = new ProxiedAuthV1Control(new ASN1OctetString(""));
+    assertTrue(proxyControl.getOID().equals(OID_PROXIED_AUTH_V1));
+    assertTrue(proxyControl.isCritical());
+    assertTrue(proxyControl.hasValue());
+    assertTrue(proxyControl.getAuthorizationDN().isNullDN());
+
+
+    // Try a valid DN, which is acceptable.
+    proxyControl =
+         new ProxiedAuthV1Control(new ASN1OctetString("uid=test,o=test"));
+    assertTrue(proxyControl.getOID().equals(OID_PROXIED_AUTH_V1));
+    assertTrue(proxyControl.isCritical());
+    assertTrue(proxyControl.hasValue());
+    assertEquals(proxyControl.getAuthorizationDN(),
+                 DN.decode("uid=test,o=test"));
+
+
+    // Try an invalid DN, which will be initally accepted but will fail when
+    // attempting to get the authorization DN.
+    proxyControl = new ProxiedAuthV1Control(new ASN1OctetString("invalid"));
+    assertTrue(proxyControl.getOID().equals(OID_PROXIED_AUTH_V1));
+    assertTrue(proxyControl.isCritical());
+    assertTrue(proxyControl.hasValue());
+    try
+    {
+      proxyControl.getAuthorizationDN();
+      throw new AssertionError("Expected a failure when creating a proxied " +
+                               "auth V1 control with an invalid DN string.");
+    } catch (Exception e) {}
+  }
+
+
+
+  /**
+   * Tests the second constructor, which creates an instance of the control
+   * using a processed DN.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testConstructor2()
+         throws Exception
+  {
+    // Try a DN of "null", which is not valid and will fail on the attempt to
+    // create the control
+    ProxiedAuthV1Control proxyControl;
+    try
+    {
+      proxyControl = new ProxiedAuthV1Control((DN) null);
+      throw new AssertionError("Expected a failure when creating a proxied " +
+                               "auth V1 control with a null octet string.");
+    } catch (Throwable t) {}
+
+
+    // Try an empty DN, which is acceptable.
+    proxyControl = new ProxiedAuthV1Control(DN.nullDN());
+    assertTrue(proxyControl.getOID().equals(OID_PROXIED_AUTH_V1));
+    assertTrue(proxyControl.isCritical());
+    assertTrue(proxyControl.hasValue());
+    assertTrue(proxyControl.getAuthorizationDN().isNullDN());
+
+
+    // Try a valid DN, which is acceptable.
+    proxyControl =
+         new ProxiedAuthV1Control(DN.decode("uid=test,o=test"));
+    assertTrue(proxyControl.getOID().equals(OID_PROXIED_AUTH_V1));
+    assertTrue(proxyControl.isCritical());
+    assertTrue(proxyControl.hasValue());
+    assertEquals(proxyControl.getAuthorizationDN(),
+                 DN.decode("uid=test,o=test"));
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method when the provided control is
+   * {@code null}.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { AssertionError.class })
+  public void testDecodeControlNull()
+         throws Exception
+  {
+    ProxiedAuthV1Control.decodeControl(null);
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method when the provided control has a
+   * criticality of "false".
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { LDAPException.class })
+  public void testDecodeControlNotCritical()
+         throws Exception
+  {
+    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(1);
+    elements.add(new ASN1OctetString("uid=test,o=test"));
+    ASN1Sequence valueSequence = new ASN1Sequence(elements);
+    ASN1OctetString value = new ASN1OctetString(valueSequence.encode());
+    Control c = new Control(OID_PROXIED_AUTH_V1, false, value);
+
+    ProxiedAuthV1Control.decodeControl(c);
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method when the provided control does not
+   * have a value.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { LDAPException.class })
+  public void testDecodeControlNoValue()
+         throws Exception
+  {
+    Control c = new Control(OID_PROXIED_AUTH_V1, true, null);
+
+    ProxiedAuthV1Control.decodeControl(c);
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method when the control value is not a
+   * sequence.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { LDAPException.class })
+  public void testDecodeControlValueNotSequence()
+         throws Exception
+  {
+    ASN1OctetString value = new ASN1OctetString("uid=test,o=test");
+    Control c = new Control(OID_PROXIED_AUTH_V1, true, value);
+
+    ProxiedAuthV1Control.decodeControl(c);
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method when the control value is a sequence
+   * with zero elements.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { LDAPException.class })
+  public void testDecodeControlValueEmptySequence()
+         throws Exception
+  {
+    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(0);
+    ASN1Sequence valueSequence = new ASN1Sequence(elements);
+    ASN1OctetString value = new ASN1OctetString(valueSequence.encode());
+    Control c = new Control(OID_PROXIED_AUTH_V1, true, value);
+
+    ProxiedAuthV1Control.decodeControl(c);
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method when the control value is a sequence
+   * with multiple elements.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { LDAPException.class })
+  public void testDecodeControlValueMultiElementSequence()
+         throws Exception
+  {
+    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
+    elements.add(new ASN1OctetString("uid=element1,o=test"));
+    elements.add(new ASN1OctetString("uid=element2,o=test"));
+    ASN1Sequence valueSequence = new ASN1Sequence(elements);
+    ASN1OctetString value = new ASN1OctetString(valueSequence.encode());
+    Control c = new Control(OID_PROXIED_AUTH_V1, true, value);
+
+    ProxiedAuthV1Control.decodeControl(c);
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method when the control value is a valid
+   * octet string that contains an invalid DN.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DirectoryException.class })
+  public void testDecodeControlValueInvalidDN()
+         throws Exception
+  {
+    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(1);
+    elements.add(new ASN1OctetString("invaliddn"));
+    ASN1Sequence valueSequence = new ASN1Sequence(elements);
+    ASN1OctetString value = new ASN1OctetString(valueSequence.encode());
+    Control c = new Control(OID_PROXIED_AUTH_V1, true, value);
+
+    ProxiedAuthV1Control proxyControl = ProxiedAuthV1Control.decodeControl(c);
+    proxyControl.getAuthorizationDN();
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method when the control value is a valid
+   * octet string that contains an valid empty DN.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testDecodeControlValueEmptyDN()
+         throws Exception
+  {
+    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(1);
+    elements.add(new ASN1OctetString(""));
+    ASN1Sequence valueSequence = new ASN1Sequence(elements);
+    ASN1OctetString value = new ASN1OctetString(valueSequence.encode());
+    Control c = new Control(OID_PROXIED_AUTH_V1, true, value);
+
+    ProxiedAuthV1Control proxyControl = ProxiedAuthV1Control.decodeControl(c);
+    assertTrue(proxyControl.getAuthorizationDN().isNullDN());
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method when the control value is a valid
+   * octet string that contains an valid non-empty DN.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testDecodeControlValueNonEmptyDN()
+         throws Exception
+  {
+    ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(1);
+    elements.add(new ASN1OctetString("uid=test,o=test"));
+    ASN1Sequence valueSequence = new ASN1Sequence(elements);
+    ASN1OctetString value = new ASN1OctetString(valueSequence.encode());
+    Control c = new Control(OID_PROXIED_AUTH_V1, true, value);
+
+    ProxiedAuthV1Control proxyControl = ProxiedAuthV1Control.decodeControl(c);
+    assertEquals(proxyControl.getAuthorizationDN(),
+                 DN.decode("uid=test,o=test"));
+  }
+
+
+
+  /**
+   * Tests the {@code getRawAuthorizationDN} and {@code setRawAuthorizationDN}
+   * methods.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testGetAndSetRawAuthorizationDN()
+         throws Exception
+  {
+    ProxiedAuthV1Control proxyControl =
+         new ProxiedAuthV1Control(new ASN1OctetString(""));
+    assertEquals(proxyControl.getRawAuthorizationDN(), new ASN1OctetString(""));
+
+    proxyControl.setRawAuthorizationDN(new ASN1OctetString("uid=test,o=test"));
+    assertEquals(proxyControl.getRawAuthorizationDN(),
+                 new ASN1OctetString("uid=test,o=test"));
+  }
+
+
+
+  /**
+   * Tests the {@code getAuthorizationDN} and {@code setRawAuthorizationDN}
+   * methods.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testGetAndSetAuthorizationDN()
+         throws Exception
+  {
+    ProxiedAuthV1Control proxyControl =
+         new ProxiedAuthV1Control(DN.nullDN());
+    assertEquals(proxyControl.getRawAuthorizationDN(), new ASN1OctetString(""));
+    assertEquals(proxyControl.getAuthorizationDN(), DN.nullDN());
+
+    proxyControl.setAuthorizationDN(DN.decode("uid=test,o=test"));
+    assertEquals(proxyControl.getRawAuthorizationDN(),
+                 new ASN1OctetString("uid=test,o=test"));
+    assertEquals(proxyControl.getAuthorizationDN(),
+                 DN.decode("uid=test,o=test"));
+  }
+
+
+
+  /**
+   * Tests the {@code setRawAuthorizationDN} method when providing an
+   * authorization DN that is {@code null}.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { AssertionError.class })
+  public void testSetNullAuthorizationDN()
+         throws Exception
+  {
+    ProxiedAuthV1Control proxyControl =
+         new ProxiedAuthV1Control(DN.nullDN());
+    proxyControl.setAuthorizationDN(null);
+  }
+
+
+
+  /**
+   * Tests the {@code getValidatedAuthorizationDN} method for the null DN.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testGetValidatedAuthorizationDNNullDN()
+         throws Exception
+  {
+    ProxiedAuthV1Control proxyControl =
+         new ProxiedAuthV1Control(DN.nullDN());
+
+    assertTrue(proxyControl.getValidatedAuthorizationDN().isNullDN());
+  }
+
+
+
+  /**
+   * Tests the {@code getValidatedAuthorizationDN} method for a normal user
+   * that exists in the directory data and doesn't have any restrictions on its
+   * use.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testGetValidatedAuthorizationExistingNormalUser()
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+    TestCaseUtils.addEntry(
+      "dn: uid=test,o=test",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "uid: test",
+      "givenName: Test",
+      "sn: User",
+      "cn: Test User");
+
+    ProxiedAuthV1Control proxyControl =
+         new ProxiedAuthV1Control(DN.decode("uid=test,o=test"));
+
+    assertEquals(proxyControl.getValidatedAuthorizationDN(),
+                 DN.decode("uid=test,o=test"));
+  }
+
+
+
+  /**
+   * Tests the {@code getValidatedAuthorizationDN} method for a user that
+   * doesn't exist in the directory data.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DirectoryException.class })
+  public void testGetValidatedAuthorizationNonExistingNormalUser()
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+
+    ProxiedAuthV1Control proxyControl =
+         new ProxiedAuthV1Control(DN.decode("uid=test,o=test"));
+
+    proxyControl.getValidatedAuthorizationDN();
+  }
+
+
+
+  /**
+   * Tests the {@code getValidatedAuthorizationDN} method for a disabled user.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DirectoryException.class })
+  public void testGetValidatedAuthorizationDisabledUser()
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+    TestCaseUtils.addEntry(
+      "dn: uid=test,o=test",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "uid: test",
+      "givenName: Test",
+      "sn: User",
+      "cn: Test User",
+      "ds-pwp-account-disabled: true");
+
+    ProxiedAuthV1Control proxyControl =
+         new ProxiedAuthV1Control(DN.decode("uid=test,o=test"));
+
+    proxyControl.getValidatedAuthorizationDN();
+  }
+
+
+
+  /**
+   * Tests the {@code toString} methods.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testToString()
+         throws Exception
+  {
+    // The default toString() calls the version that takes a string builder
+    // argument, so we only need to use the default version to cover both cases.
+    ProxiedAuthV1Control proxyControl =
+         new ProxiedAuthV1Control(new ASN1OctetString("uid=test,o=test"));
+    proxyControl.toString();
+
+    proxyControl = new ProxiedAuthV1Control(DN.decode("uid=test,o=test"));
+    proxyControl.toString();
+  }
+}
+
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV2ControlTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV2ControlTestCase.java
new file mode 100644
index 0000000..79fea63
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/controls/ProxiedAuthV2ControlTestCase.java
@@ -0,0 +1,547 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying * information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.controls;
+
+
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.protocols.ldap.LDAPException;
+import org.opends.server.types.Control;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.DN;
+
+import static org.testng.Assert.*;
+
+import static org.opends.server.util.ServerConstants.*;
+
+
+
+/**
+ * This class contains a number of test cases for the proxied authorization v2
+ * control.
+ */
+public class ProxiedAuthV2ControlTestCase
+    extends ControlsTestCase
+{
+  /**
+   * Make sure that the server is running.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @BeforeClass()
+  public void startServer()
+         throws Exception
+  {
+    TestCaseUtils.startServer();
+  }
+
+
+
+  /**
+   * Tests the constructor with a {@code null} authorization ID.
+   */
+  @Test(expectedExceptions = { AssertionError.class })
+  public void testConstructorNullAuthzID()
+  {
+    ProxiedAuthV2Control proxyControl = new ProxiedAuthV2Control(null);
+  }
+
+
+
+  /**
+   * Tests the constructor with an empty authorization ID.
+   */
+  @Test()
+  public void testConstructorEmptyAuthzID()
+  {
+    ProxiedAuthV2Control proxyControl =
+         new ProxiedAuthV2Control(new ASN1OctetString(""));
+    assertEquals(proxyControl.getAuthorizationID(), new ASN1OctetString(""));
+  }
+
+
+
+  /**
+   * Tests the constructor with a non-empty authorization ID using the "dn:"
+   * form.
+   */
+  @Test()
+  public void testConstructorNonEmptyAuthzIDDN()
+  {
+    ProxiedAuthV2Control proxyControl =
+         new ProxiedAuthV2Control(new ASN1OctetString("dn:uid=test,o=test"));
+    assertEquals(proxyControl.getAuthorizationID(),
+                 new ASN1OctetString("dn:uid=test,o=test"));
+  }
+
+
+
+  /**
+   * Tests the constructor with a non-empty authorization ID using the "u:"
+   * form.
+   */
+  @Test()
+  public void testConstructorNonEmptyAuthzIDUsername()
+  {
+    ProxiedAuthV2Control proxyControl =
+         new ProxiedAuthV2Control(new ASN1OctetString("u:test"));
+    assertEquals(proxyControl.getAuthorizationID(),
+                 new ASN1OctetString("u:test"));
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method with a {@code null} argument.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { AssertionError.class })
+  public void testDecodeControlNull()
+         throws Exception
+  {
+    ProxiedAuthV2Control.decodeControl(null);
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method with a control that is not marked
+   * critical.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { LDAPException.class })
+  public void testDecodeControlNotCritical()
+         throws Exception
+  {
+    Control c = new Control(OID_PROXIED_AUTH_V2, false,
+                            new ASN1OctetString("u:test"));
+    ProxiedAuthV2Control.decodeControl(c);
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method with a control that does not have a
+   * value.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { LDAPException.class })
+  public void testDecodeControlNoValue()
+         throws Exception
+  {
+    Control c = new Control(OID_PROXIED_AUTH_V2, true);
+    ProxiedAuthV2Control.decodeControl(c);
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method with a control encoded in the
+   * standard from with the "dn:"-style value.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testDecodeControlDNValue()
+         throws Exception
+  {
+    ASN1OctetString authzID = new ASN1OctetString("dn:uid=test,o=test");
+
+    Control c = new Control(OID_PROXIED_AUTH_V2, true, authzID);
+    ProxiedAuthV2Control proxyControl = ProxiedAuthV2Control.decodeControl(c);
+    assertEquals(proxyControl.getAuthorizationID(), authzID);
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method with a control encoded in the
+   * standard from with the "u:"-style value.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testDecodeControlUsernameValue()
+         throws Exception
+  {
+    ASN1OctetString authzID = new ASN1OctetString("u:test");
+
+    Control c = new Control(OID_PROXIED_AUTH_V2, true, authzID);
+    ProxiedAuthV2Control proxyControl = ProxiedAuthV2Control.decodeControl(c);
+    assertEquals(proxyControl.getAuthorizationID(), authzID);
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method with an invalid value (which doesn't
+   * start with either "dn:" or "u:").
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { LDAPException.class })
+  public void testDecodeControlInvalidValue()
+         throws Exception
+  {
+    ASN1OctetString authzID = new ASN1OctetString("invalid");
+
+    Control c = new Control(OID_PROXIED_AUTH_V2, true, authzID);
+    ProxiedAuthV2Control proxyControl = ProxiedAuthV2Control.decodeControl(c);
+    assertEquals(proxyControl.getAuthorizationID(), authzID);
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method with a control encoded in the legacy
+   * form (in which the value is wrapped by an extra octet string) with the
+   * "dn:"-style value.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testDecodeControlLegacyDNValue()
+         throws Exception
+  {
+    ASN1OctetString innerValue = new ASN1OctetString("dn:uid=test,o=test");
+    ASN1OctetString outerValue = new ASN1OctetString(innerValue.encode());
+
+    Control c = new Control(OID_PROXIED_AUTH_V2, true, outerValue);
+    ProxiedAuthV2Control proxyControl = ProxiedAuthV2Control.decodeControl(c);
+    assertEquals(proxyControl.getAuthorizationID(), innerValue);
+  }
+
+
+
+  /**
+   * Tests the {@code decodeControl} method with a control encoded in the legacy
+   * form (in which the value is wrapped by an extra octet string) with the
+   * "u:"-style value.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testDecodeControlLegacyUsernameValue()
+         throws Exception
+  {
+    ASN1OctetString innerValue = new ASN1OctetString("u:test");
+    ASN1OctetString outerValue = new ASN1OctetString(innerValue.encode());
+
+    Control c = new Control(OID_PROXIED_AUTH_V2, true, outerValue);
+    ProxiedAuthV2Control proxyControl = ProxiedAuthV2Control.decodeControl(c);
+    assertEquals(proxyControl.getAuthorizationID(), innerValue);
+  }
+
+
+
+  /**
+   * Tests the {@code getAuthorizationID} and {@code setAuthorizationID}
+   * methods.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testGetAndSetAuthorizationID()
+         throws Exception
+  {
+    ProxiedAuthV2Control proxyControl =
+         new ProxiedAuthV2Control(new ASN1OctetString("dn:uid=test,o=test"));
+    assertEquals(proxyControl.getAuthorizationID(),
+                 new ASN1OctetString("dn:uid=test,o=test"));
+
+    proxyControl.setAuthorizationID(null);
+    assertEquals(proxyControl.getAuthorizationID(), new ASN1OctetString(""));
+
+    proxyControl.setAuthorizationID(new ASN1OctetString(""));
+    assertEquals(proxyControl.getAuthorizationID(), new ASN1OctetString(""));
+
+    proxyControl.setAuthorizationID(new ASN1OctetString("u:test"));
+    assertEquals(proxyControl.getAuthorizationID(),
+                 new ASN1OctetString("u:test"));
+
+    proxyControl.setAuthorizationID(new ASN1OctetString("dn:uid=test,o=test"));
+    assertEquals(proxyControl.getAuthorizationID(),
+                 new ASN1OctetString("dn:uid=test,o=test"));
+  }
+
+
+
+  /**
+   * Tests the {@code getValidatedAuthorizationDN} method with an empty
+   * authorization ID string.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testGetValidatedAuthorizationDNEmptyAuthzID()
+         throws Exception
+  {
+    ProxiedAuthV2Control proxyControl =
+         new ProxiedAuthV2Control(new ASN1OctetString(""));
+    assertEquals(proxyControl.getValidatedAuthorizationDN(), DN.nullDN());
+  }
+
+
+
+  /**
+   * Tests the {@code getValidatedAuthorizationDN} method with an authorization
+   * ID of "dn:".
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testGetValidatedAuthorizationDNEmptyAuthzIDDN()
+         throws Exception
+  {
+    ProxiedAuthV2Control proxyControl =
+         new ProxiedAuthV2Control(new ASN1OctetString("dn:"));
+    assertEquals(proxyControl.getValidatedAuthorizationDN(), DN.nullDN());
+  }
+
+
+
+  /**
+   * Tests the {@code getValidatedAuthorizationDN} method with an authorization
+   * ID in the "dn:" form that points to a valid user.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testGetValidatedAuthorizationDNExistingUserDN()
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+    TestCaseUtils.addEntry(
+      "dn: uid=test,o=test",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "uid: test",
+      "givenName: Test",
+      "sn: User",
+      "cn: Test User");
+
+    ProxiedAuthV2Control proxyControl =
+         new ProxiedAuthV2Control(new ASN1OctetString("dn:uid=test,o=test"));
+    assertEquals(proxyControl.getValidatedAuthorizationDN(),
+                 DN.decode("uid=test,o=test"));
+  }
+
+
+
+  /**
+   * Tests the {@code getValidatedAuthorizationDN} method with an authorization
+   * ID in the "dn:" form that points to a user that doesn't exist.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DirectoryException.class })
+  public void testGetValidatedAuthorizationDNNonExistingUserDN()
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+
+    ProxiedAuthV2Control proxyControl =
+         new ProxiedAuthV2Control(new ASN1OctetString("dn:uid=test,o=test"));
+    proxyControl.getValidatedAuthorizationDN();
+  }
+
+
+
+  /**
+   * Tests the {@code getValidatedAuthorizationDN} method with an authorization
+   * ID in the "dn:" form that points to a valid user but whose account is
+   * disabled.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DirectoryException.class })
+  public void testGetValidatedAuthorizationDNExistingDisabledUserDN()
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+    TestCaseUtils.addEntry(
+      "dn: uid=test,o=test",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "uid: test",
+      "givenName: Test",
+      "sn: User",
+      "cn: Test User",
+      "ds-pwp-account-disabled: true");
+
+    ProxiedAuthV2Control proxyControl =
+         new ProxiedAuthV2Control(new ASN1OctetString("dn:uid=test,o=test"));
+    proxyControl.getValidatedAuthorizationDN();
+  }
+
+
+
+  /**
+   * Tests the {@code getValidatedAuthorizationDN} method with an authorization
+   * ID of "u:".
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testGetValidatedAuthorizationDNEmptyAuthzIDUsername()
+         throws Exception
+  {
+    ProxiedAuthV2Control proxyControl =
+         new ProxiedAuthV2Control(new ASN1OctetString("u:"));
+    assertEquals(proxyControl.getValidatedAuthorizationDN(), DN.nullDN());
+  }
+
+
+
+  /**
+   * Tests the {@code getValidatedAuthorizationDN} method with an authorization
+   * ID in the "u:" form that points to a valid user.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testGetValidatedAuthorizationDNExistingUserUsername()
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+    TestCaseUtils.addEntry(
+      "dn: uid=test,o=test",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "uid: test",
+      "givenName: Test",
+      "sn: User",
+      "cn: Test User");
+
+    ProxiedAuthV2Control proxyControl =
+         new ProxiedAuthV2Control(new ASN1OctetString("u:test"));
+    assertEquals(proxyControl.getValidatedAuthorizationDN(),
+                 DN.decode("uid=test,o=test"));
+  }
+
+
+
+  /**
+   * Tests the {@code getValidatedAuthorizationDN} method with an authorization
+   * ID in the "u:" form that points to a user that doesn't exist.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DirectoryException.class })
+  public void testGetValidatedAuthorizationDNNonExistingUserUsername()
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+
+    ProxiedAuthV2Control proxyControl =
+         new ProxiedAuthV2Control(new ASN1OctetString("u:test"));
+    proxyControl.getValidatedAuthorizationDN();
+  }
+
+
+
+  /**
+   * Tests the {@code getValidatedAuthorizationDN} method with an authorization
+   * ID in the "u:" form that points to a valid user but whose account is
+   * disabled.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DirectoryException.class })
+  public void testGetValidatedAuthorizationDNExistingDisabledUserUsername()
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+    TestCaseUtils.addEntry(
+      "dn: uid=test,o=test",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "uid: test",
+      "givenName: Test",
+      "sn: User",
+      "cn: Test User",
+      "ds-pwp-account-disabled: true");
+
+    ProxiedAuthV2Control proxyControl =
+         new ProxiedAuthV2Control(new ASN1OctetString("u:test"));
+    proxyControl.getValidatedAuthorizationDN();
+  }
+
+
+
+  /**
+   * Tests the {@code getValidatedAuthorizationDN} method with an invalid
+   * authorization ID.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(expectedExceptions = { DirectoryException.class })
+  public void testGetValidatedAuthorizationDNInvalidAuthzID()
+         throws Exception
+  {
+    ProxiedAuthV2Control proxyControl =
+         new ProxiedAuthV2Control(new ASN1OctetString("invalid"));
+    proxyControl.getValidatedAuthorizationDN();
+  }
+
+
+
+  /**
+   * Tests the {@code toString} methods.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testToString()
+         throws Exception
+  {
+    // The default toString() calls the version that takes a string builder
+    // argument, so we only need to use the default version to cover both cases.
+    ProxiedAuthV2Control proxyControl =
+         new ProxiedAuthV2Control(new ASN1OctetString("dn:uid=test,o=test"));
+    proxyControl.toString();
+
+    proxyControl = new ProxiedAuthV2Control(new ASN1OctetString("u:test"));
+    proxyControl.toString();
+  }
+}
+

--
Gitblit v1.10.0