From 7269ae01fdc8953b1b568c06b1dd6b80f94d8e83 Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Sun, 18 Mar 2007 00:41:40 +0000
Subject: [PATCH] Update the client connection code to ensure that any attempt to change the authentication info structure goes through the setAuthenticationInfo() method. This will ensure that all proper cleanup is done.  Without doing this, there may be problems if a client connection is used to authenticate multiple times and the entry for one of the previous users is modified or deleted, since that could cause an attempt to update the client connection which is now authenticated as another user.

---
 opendj-sdk/opends/src/server/org/opends/server/api/ClientConnection.java                               |   16 ++++----
 opendj-sdk/opends/src/server/org/opends/server/core/AuthenticatedUsers.java                            |   21 +++++++++-
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java |   62 +++++++++++++++++++++++++++++++
 3 files changed, 88 insertions(+), 11 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/api/ClientConnection.java b/opendj-sdk/opends/src/server/org/opends/server/api/ClientConnection.java
index 0d6e09f..d1ca3a3 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/api/ClientConnection.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/api/ClientConnection.java
@@ -618,7 +618,7 @@
   {
     if (authenticationInfo == null)
     {
-      authenticationInfo = new AuthenticationInfo();
+      setAuthenticationInfo(new AuthenticationInfo());
     }
 
     authenticationInfo.setMustChangePassword(mustChangePassword);
@@ -881,22 +881,22 @@
       if ((authZEntry == null) ||
           (! authZEntry.getDN().equals(authNEntry.getDN())))
       {
-        authenticationInfo =
-             authenticationInfo.duplicate(newEntry, authZEntry);
+        setAuthenticationInfo(
+             authenticationInfo.duplicate(newEntry, authZEntry));
         updatePrivileges(newEntry, authenticationInfo.isRoot());
       }
       else
       {
-        authenticationInfo =
-             authenticationInfo.duplicate(newEntry, newEntry);
+        setAuthenticationInfo(
+             authenticationInfo.duplicate(newEntry, newEntry));
         updatePrivileges(newEntry, authenticationInfo.isRoot());
       }
     }
     else if ((authZEntry != null) &&
              (authZEntry.getDN().equals(oldEntry.getDN())))
     {
-      authenticationInfo =
-           authenticationInfo.duplicate(authNEntry, newEntry);
+      setAuthenticationInfo(
+           authenticationInfo.duplicate(authNEntry, newEntry));
     }
   }
 
@@ -910,7 +910,7 @@
    */
   public void setUnauthenticated()
   {
-    this.authenticationInfo = new AuthenticationInfo();
+    setAuthenticationInfo(new AuthenticationInfo());
     this.sizeLimit          = DirectoryServer.getSizeLimit();
     this.timeLimit          = DirectoryServer.getTimeLimit();
   }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/AuthenticatedUsers.java b/opendj-sdk/opends/src/server/org/opends/server/core/AuthenticatedUsers.java
index cd47191..bf00081 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/AuthenticatedUsers.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/AuthenticatedUsers.java
@@ -59,9 +59,6 @@
 public class AuthenticatedUsers
        implements ChangeNotificationListener
 {
-
-
-
   // The mapping between authenticated user DNs and the associated client
   // connection objects.
   private ConcurrentHashMap<DN,CopyOnWriteArraySet<ClientConnection>>
@@ -130,6 +127,24 @@
 
 
   /**
+   * Retrieves the set of client connections authenticated as the specified
+   * user.  This method is only intended for internal testing use and should not
+   * be called for any other purpose.
+   *
+   * @param  userDN  The DN of the user for which to retrieve the corresponding
+   *                 set of client connections.
+   *
+   * @return  The set of client connections authenticated as the specified user,
+   *          or {@code null} if there are none.
+   */
+  synchronized CopyOnWriteArraySet<ClientConnection> get(DN userDN)
+  {
+    return userMap.get(userDN);
+  }
+
+
+
+  /**
    * Performs any processing that may be required after an add
    * operation.
    *
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java
index 2ea76ab..c225fd2 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java
@@ -1857,5 +1857,67 @@
                                 new ASN1OctetString("wrongpassword"));
     assertEquals(bindOperation.getResultCode(), ResultCode.INVALID_CREDENTIALS);
   }
+
+
+
+  /**
+   * Tests to ensure that performing multiple binds on a client connection will
+   * cause the connection to no longer be associated with the previous identity.
+   * This helps provide coverage for issue #1392.
+   *
+   * @throws  Exception
+   */
+  @Test()
+  public void testRebindClearsAuthInfo()
+         throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+    TestCaseUtils.addEntry(
+      "dn: uid=rebind.test,o=test",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "uid: rebind.test",
+      "givenName: Rebind",
+      "sn: Test",
+      "cn: Rebind Test",
+      "userPassword: password");
+    String dnString = "uid=rebind.test,o=test";
+    DN userDN = DN.decode(dnString);
+
+    Socket s = new Socket("127.0.0.1", (int) TestCaseUtils.getServerLdapPort());
+    ASN1Reader r = new ASN1Reader(s);
+    ASN1Writer w = new ASN1Writer(s);
+    r.setIOTimeout(6000);
+
+    BindRequestProtocolOp bindRequest =
+         new BindRequestProtocolOp(new ASN1OctetString(dnString),
+                                   3, new ASN1OctetString("password"));
+    LDAPMessage message = new LDAPMessage(1, bindRequest);
+    w.writeElement(message.encode());
+
+    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
+    assertEquals(bindResponse.getResultCode(), 0);
+
+    assertNotNull(DirectoryServer.getAuthenticatedUsers().get(userDN));
+    assertEquals(DirectoryServer.getAuthenticatedUsers().get(userDN).size(),
+                 1);
+
+    bindRequest = new BindRequestProtocolOp(
+                           new ASN1OctetString("cn=Directory Manager"), 3,
+                           new ASN1OctetString("password"));
+    message = new LDAPMessage(1, bindRequest);
+    w.writeElement(message.encode());
+
+    message = LDAPMessage.decode(r.readElement().decodeAsSequence());
+    bindResponse = message.getBindResponseProtocolOp();
+    assertEquals(bindResponse.getResultCode(), 0);
+
+    assertNull(DirectoryServer.getAuthenticatedUsers().get(userDN));
+
+    s.close();
+  }
 }
 

--
Gitblit v1.10.0