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

neil_a_wilson
18.41.2007 7269ae01fdc8953b1b568c06b1dd6b80f94d8e83
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.

OpenDS Issue Number: 1392
3 files modified
99 ■■■■ changed files
opendj-sdk/opends/src/server/org/opends/server/api/ClientConnection.java 16 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/core/AuthenticatedUsers.java 21 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java 62 ●●●●● patch | view | raw | blame | history
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();
  }
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.
   *
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();
  }
}