From 6e92eaa84cc7d2821334cb7f29bc56a9c4168102 Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Fri, 15 Sep 2006 00:44:34 +0000
Subject: [PATCH] Add a new test case that covers SASL PLAIN authentication.

---
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java |  491 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 491 insertions(+), 0 deletions(-)

diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java
new file mode 100644
index 0000000..705c820
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PlainSASLMechanismHandlerTestCase.java
@@ -0,0 +1,491 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.
+ */
+package org.opends.server.extensions;
+
+
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.api.SASLMechanismHandler;
+import org.opends.server.core.AddOperation;
+import org.opends.server.core.BindOperation;
+import org.opends.server.core.DirectoryServer;
+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.protocols.ldap.LDAPFilter;
+import org.opends.server.types.AuthenticationInfo;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.DN;
+import org.opends.server.types.Entry;
+import org.opends.server.types.ResultCode;
+import org.opends.server.types.SearchScope;
+import org.opends.server.types.SearchFilter;
+
+import static org.testng.Assert.*;
+
+
+
+/**
+ * A set of test cases for the PLAIN SASL mechanism handler.
+ */
+public class PlainSASLMechanismHandlerTestCase
+       extends ExtensionsTestCase
+{
+  /**
+   * Ensures that the Directory Server is running.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @BeforeClass()
+  public void startServer()
+         throws Exception
+  {
+    TestCaseUtils.startServer();
+  }
+
+
+
+  /**
+   * Tests to ensure that the SASL PLAIN mechanism is loaded and available in
+   * the server, and that it reports that it is password based and not secure.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testSASLPlainLoaded()
+  {
+    SASLMechanismHandler handler =
+         DirectoryServer.getSASLMechanismHandler("PLAIN");
+    assertNotNull(handler);
+
+    assertTrue(handler.isPasswordBased("PLAIN"));
+    assertFalse(handler.isSecure("PLAIN"));
+  }
+
+
+
+  /**
+   * Tests to ensure that PLAIN is advertised as a supported SASL mechanism.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testSASLPlainAdvertised()
+         throws Exception
+  {
+    InternalClientConnection conn =
+         InternalClientConnection.getRootConnection();
+    InternalSearchOperation op =
+         conn.processSearch(new ASN1OctetString(""), SearchScope.BASE_OBJECT,
+              LDAPFilter.decode("(supportedSASLMechanisms=PLAIN)"));
+    assertFalse(op.getSearchEntries().isEmpty());
+  }
+
+
+
+
+  /**
+   * Retrieves a set of passwords that may be used to test the password storage
+   * scheme.
+   *
+   * @return  A set of passwords that may be used to test the password storage
+   *          scheme.
+   */
+  @DataProvider(name = "testPasswords")
+  public Object[][] getTestPasswords()
+  {
+    return new Object[][]
+    {
+      new Object[] { new ASN1OctetString("a") },
+      new Object[] { new ASN1OctetString("ab") },
+      new Object[] { new ASN1OctetString("abc") },
+      new Object[] { new ASN1OctetString("abcd") },
+      new Object[] { new ASN1OctetString("abcde") },
+      new Object[] { new ASN1OctetString("abcdef") },
+      new Object[] { new ASN1OctetString("abcdefg") },
+      new Object[] { new ASN1OctetString("abcdefgh") },
+      new Object[] { new ASN1OctetString("The Quick Brown Fox Jumps Over " +
+                                         "The Lazy Dog") },
+    };
+  }
+
+
+
+  /**
+   * Creates a test user and authenticates to the server as that user with the
+   * SASL PLAIN mechanism using a raw authentication ID (i.e., not prefixed by
+   * either "u:" or "dn:").
+   *
+   * @param  password  The password for the user.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "testPasswords")
+  public void testSASLPlainRawAuthID(ByteString password)
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+
+    Entry e = TestCaseUtils.makeEntry(
+                   "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.stringValue());
+
+    InternalClientConnection conn =
+         InternalClientConnection.getRootConnection();
+    AddOperation addOperation = conn.processAdd(e.getDN(), e.getObjectClasses(),
+                                                e.getUserAttributes(),
+                                                e.getOperationalAttributes());
+    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+
+    byte[] saslCredBytes = new byte[11 + password.value().length];
+    System.arraycopy("test.user".getBytes("UTF-8"), 0, saslCredBytes, 1, 9);
+    System.arraycopy(password.value(), 0, saslCredBytes, 11,
+                     password.value().length);
+    InternalClientConnection anonymousConn =
+         new InternalClientConnection(new AuthenticationInfo());
+    BindOperation bindOperation =
+         anonymousConn.processSASLBind(new ASN1OctetString(), "PLAIN",
+                                       new ASN1OctetString(saslCredBytes));
+    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
+  }
+
+
+
+  /**
+   * Creates a test user and authenticates to the server as that user with the
+   * SASL PLAIN mechanism using the "u:" style authentication ID.
+   *
+   * @param  password  The password for the user.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "testPasswords")
+  public void testSASLPlainUColon(ByteString password)
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+
+    Entry e = TestCaseUtils.makeEntry(
+                   "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.stringValue());
+
+    InternalClientConnection conn =
+         InternalClientConnection.getRootConnection();
+    AddOperation addOperation = conn.processAdd(e.getDN(), e.getObjectClasses(),
+                                                e.getUserAttributes(),
+                                                e.getOperationalAttributes());
+    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+
+    byte[] saslCredBytes = new byte[13 + password.value().length];
+    System.arraycopy("u:test.user".getBytes("UTF-8"), 0, saslCredBytes, 1, 11);
+    System.arraycopy(password.value(), 0, saslCredBytes, 13,
+                     password.value().length);
+    InternalClientConnection anonymousConn =
+         new InternalClientConnection(new AuthenticationInfo());
+    BindOperation bindOperation =
+         anonymousConn.processSASLBind(new ASN1OctetString(), "PLAIN",
+                                       new ASN1OctetString(saslCredBytes));
+    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
+  }
+
+
+
+  /**
+   * Creates a test user and authenticates to the server as that user with the
+   * SASL PLAIN mechanism using the "u:" style authentication ID and
+   * authorization ID.
+   *
+   * @param  password  The password for the user.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "testPasswords")
+  public void testSASLPlainUColonWithAuthZID(ByteString password)
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+
+    Entry e = TestCaseUtils.makeEntry(
+                   "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.stringValue());
+
+    InternalClientConnection conn =
+         InternalClientConnection.getRootConnection();
+    AddOperation addOperation = conn.processAdd(e.getDN(), e.getObjectClasses(),
+                                                e.getUserAttributes(),
+                                                e.getOperationalAttributes());
+    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+
+    byte[] saslCredBytes = new byte[24 + password.value().length];
+    System.arraycopy("u:test.user".getBytes("UTF-8"), 0, saslCredBytes, 0, 11);
+    System.arraycopy("u:test.user".getBytes("UTF-8"), 0, saslCredBytes, 12, 11);
+    System.arraycopy(password.value(), 0, saslCredBytes, 24,
+                     password.value().length);
+    InternalClientConnection anonymousConn =
+         new InternalClientConnection(new AuthenticationInfo());
+    BindOperation bindOperation =
+         anonymousConn.processSASLBind(new ASN1OctetString(), "PLAIN",
+                                       new ASN1OctetString(saslCredBytes));
+    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
+  }
+
+
+
+  /**
+   * Creates a test user and authenticates to the server as that user with the
+   * SASL PLAIN mechanism using the "dn:" style authentication ID.
+   *
+   * @param  password  The password for the user.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "testPasswords")
+  public void testSASLPlainDNColon(ByteString password)
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+
+    Entry e = TestCaseUtils.makeEntry(
+                   "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.stringValue());
+
+    InternalClientConnection conn =
+         InternalClientConnection.getRootConnection();
+    AddOperation addOperation = conn.processAdd(e.getDN(), e.getObjectClasses(),
+                                                e.getUserAttributes(),
+                                                e.getOperationalAttributes());
+    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+
+    byte[] dnBytes = e.getDN().toString().getBytes("UTF-8");
+    byte[] saslCredBytes =
+         new byte[5 + dnBytes.length + password.value().length];
+    System.arraycopy("dn:".getBytes("UTF-8"), 0, saslCredBytes, 1, 3);
+    System.arraycopy(dnBytes, 0, saslCredBytes, 4, dnBytes.length);
+    System.arraycopy(password.value(), 0, saslCredBytes, 5 + dnBytes.length,
+                     password.value().length);
+    InternalClientConnection anonymousConn =
+         new InternalClientConnection(new AuthenticationInfo());
+    BindOperation bindOperation =
+         anonymousConn.processSASLBind(new ASN1OctetString(), "PLAIN",
+                                       new ASN1OctetString(saslCredBytes));
+    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
+  }
+
+
+
+  /**
+   * Creates a test user and authenticates to the server as that user with the
+   * SASL PLAIN mechanism using the "dn:" style authentication ID and an
+   * authorization ID.
+   *
+   * @param  password  The password for the user.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "testPasswords")
+  public void testSASLPlainDNColonWithAuthZID(ByteString password)
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+
+    Entry e = TestCaseUtils.makeEntry(
+                   "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.stringValue());
+
+    InternalClientConnection conn =
+         InternalClientConnection.getRootConnection();
+    AddOperation addOperation = conn.processAdd(e.getDN(), e.getObjectClasses(),
+                                                e.getUserAttributes(),
+                                                e.getOperationalAttributes());
+    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+
+    byte[] dnBytes = ("dn:" + e.getDN().toString()).getBytes("UTF-8");
+    byte[] saslCredBytes =
+         new byte[2 + (2*dnBytes.length) + password.value().length];
+    System.arraycopy(dnBytes, 0, saslCredBytes, 0, dnBytes.length);
+    System.arraycopy(dnBytes, 0, saslCredBytes, dnBytes.length+1,
+                     dnBytes.length);
+    System.arraycopy(password.value(), 0, saslCredBytes,
+                     (2*dnBytes.length + 2), password.value().length);
+    InternalClientConnection anonymousConn =
+         new InternalClientConnection(new AuthenticationInfo());
+    BindOperation bindOperation =
+         anonymousConn.processSASLBind(new ASN1OctetString(), "PLAIN",
+                                       new ASN1OctetString(saslCredBytes));
+    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
+  }
+
+
+
+  /**
+   * Ensures that SASL PLAIN authentication will work for root users.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testSASLPlainAsRoot()
+         throws Exception
+  {
+    ASN1OctetString rootCreds =
+         new ASN1OctetString("\u0000dn:cn=Directory Manager\u0000password");
+
+    InternalClientConnection anonymousConn =
+         new InternalClientConnection(new AuthenticationInfo());
+    BindOperation bindOperation =
+         anonymousConn.processSASLBind(new ASN1OctetString(), "PLAIN",
+                                    rootCreds);
+    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
+  }
+
+
+
+  /**
+   * Retrieves sets of invalid credentials that will not succeed when using
+   * SASL PLAIN.
+   *
+   * @return  Sets of invalid credentials that will not work when using SASL
+   * PLAIN.
+   */
+  @DataProvider(name = "invalidCredentials")
+  public Object[][] getInvalidCredentials()
+  {
+    return new Object[][]
+    {
+      new Object[] { null },
+      new Object[] { new ASN1OctetString() },
+      new Object[] { new ASN1OctetString("u:test.user") },
+      new Object[] { new ASN1OctetString("password") },
+      new Object[] { new ASN1OctetString("\u0000") },
+      new Object[] { new ASN1OctetString("\u0000\u0000") },
+      new Object[] { new ASN1OctetString("\u0000password") },
+      new Object[] { new ASN1OctetString("\u0000\u0000password") },
+      new Object[] { new ASN1OctetString("\u0000u:test.user\u0000") },
+      new Object[] { new ASN1OctetString("\u0000dn:\u0000password") },
+      new Object[] { new ASN1OctetString("\u0000dn:bogus\u0000password") },
+      new Object[] { new ASN1OctetString("\u0000dn:cn=no such user" +
+                                         "\u0000password") },
+      new Object[] { new ASN1OctetString("\u0000u:\u0000password") },
+      new Object[] { new ASN1OctetString("\u0000u:nosuchuser\u0000password") },
+      new Object[] { new ASN1OctetString("\u0000u:test.user\u0000" +
+                                         "wrongpassword") },
+    };
+  }
+
+
+
+  /**
+   * Creates a test user and authenticates to the server as that user with the
+   * SASL PLAIN mechanism using the "dn:" style authentication ID.
+   *
+   * @param  saslCredentials  The (invalid) SASL credentials to use.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "invalidCredentials")
+  public void testInvalidCredentials(ASN1OctetString saslCredentials)
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+
+    Entry e = TestCaseUtils.makeEntry(
+                   "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");
+
+    InternalClientConnection conn =
+         InternalClientConnection.getRootConnection();
+    AddOperation addOperation = conn.processAdd(e.getDN(), e.getObjectClasses(),
+                                                e.getUserAttributes(),
+                                                e.getOperationalAttributes());
+    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+
+    InternalClientConnection anonymousConn =
+         new InternalClientConnection(new AuthenticationInfo());
+    BindOperation bindOperation =
+         anonymousConn.processSASLBind(new ASN1OctetString(), "PLAIN",
+                                       saslCredentials);
+    assertEquals(bindOperation.getResultCode(), ResultCode.INVALID_CREDENTIALS);
+  }
+}
+

--
Gitblit v1.10.0