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

neil_a_wilson
18.41.2007 00f5eee9ce02ed3e3d0b3c1f2658951b8f37acef
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
opends/src/server/org/opends/server/api/ClientConnection.java 16 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/AuthenticatedUsers.java 21 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/core/BindOperationTestCase.java 62 ●●●●● patch | view | raw | blame | history
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();
  }
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.
   *
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();
  }
}