From 439a48e88a9891e3e3e813ca06bfbcbf54bcb140 Mon Sep 17 00:00:00 2001
From: Ludovic Poitou <ludovic.poitou@forgerock.com>
Date: Wed, 20 Jul 2011 09:37:34 +0000
Subject: [PATCH] Fix issue OPENDJ-237: Password modification by deleting the value and adding a new one fails with unwilling to perform (would result in multiple password in the entry). Make sure we update the passwords counters when deleting values. Unit-tests added to make sure we do not have regressions in the future
---
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java | 32 +++++++
opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java | 191 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 222 insertions(+), 1 deletions(-)
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
index e37efe2..858bd6a 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
@@ -1323,6 +1323,12 @@
// encoded forms.
Attribute pwAttr = m.getAttribute();
AttributeBuilder builder = new AttributeBuilder(pwAttr, true);
+ if (pwAttr.isEmpty())
+ {
+ // Removing all current password values.
+ numPasswords = 0;
+ }
+
for (AttributeValue v : pwAttr)
{
if (pwPolicyState.passwordIsPreEncoded(v.getValue()))
@@ -1335,7 +1341,31 @@
}
else
{
- builder.add(v);
+ // We still need to check if the pre-encoded password matches
+ // an existing value, to decrease the number of passwords.
+ List<Attribute> attrList = currentEntry.getAttribute(pwAttr
+ .getAttributeType());
+ if ((attrList == null) || (attrList.isEmpty()))
+ {
+ throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
+ ERR_MODIFY_NO_EXISTING_VALUES.get());
+ }
+ boolean found = false;
+ for (Attribute attr : attrList)
+ {
+ for (AttributeValue av : attr)
+ {
+ if (av.equals(v))
+ {
+ builder.add(v);
+ found = true;
+ }
+ }
+ }
+ if (found)
+ {
+ numPasswords--;
+ }
}
}
else
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java
index e80ba20..a99dff8 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java
@@ -23,6 +23,7 @@
*
*
* Copyright 2006-2011 Sun Microsystems, Inc.
+ * Portions Copyright 2011 ForgeRock AS
*/
package org.opends.server.core;
@@ -4776,6 +4777,196 @@
assertTrue(modifyOperation.getResultCode() == ResultCode.SUCCESS);
retrieveSuccessfulOperationElements(modifyOperation);
}
+
+ /**
+ * Tests a modify operation that attempts change the user password doing
+ * a delete of all values followed of an add of a new value.
+ *
+ * @param baseDN The base DN for the test backend.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "baseDNs")
+ public void testModifyDelAddPasswordAttribute(String baseDN)
+ throws Exception
+ {
+ TestCaseUtils.clearJEBackend(true,"userRoot",baseDN);
+
+ Entry entry = TestCaseUtils.makeEntry(
+ "dn: uid=testPassword01.user," + baseDN,
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalPerson",
+ "objectClass: inetOrgPerson",
+ "uid: test.user",
+ "givenName: Test",
+ "sn: User",
+ "cn: Test User",
+ "displayName: Test User",
+ "userPassword: password");
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ AddOperation addOperation =
+ conn.processAdd(entry.getDN(), entry.getObjectClasses(),
+ entry.getUserAttributes(),
+ entry.getOperationalAttributes());
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+
+ String path = TestCaseUtils.createTempFile(
+ "dn: uid=testPassword01.user," + baseDN,
+ "changetype: modify",
+ "delete: userPassword",
+ "-",
+ "add: userPassword",
+ "userPassword: aNewPassword");
+
+ String[] args =
+ {
+ "-h", "127.0.0.1",
+ "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
+ "-D", "cn=Directory Manager",
+ "-w", "password",
+ "-f", path
+ };
+
+ assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
+ }
+
+ /**
+ * Tests a modify operation that attempts change the user password doing
+ * a delete of a clear text value followed of an add of a new value.
+ *
+ * @param baseDN The base DN for the test backend.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "baseDNs")
+ public void testModifyDelOneAddOnePasswordAttribute(String baseDN)
+ throws Exception
+ {
+ TestCaseUtils.clearJEBackend(true,"userRoot",baseDN);
+
+ Entry entry = TestCaseUtils.makeEntry(
+ "dn: uid=testPassword02.user," + baseDN,
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalPerson",
+ "objectClass: inetOrgPerson",
+ "uid: test.user",
+ "givenName: Test",
+ "sn: User",
+ "cn: Test User",
+ "displayName: Test User",
+ "userPassword: password");
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ AddOperation addOperation =
+ conn.processAdd(entry.getDN(), entry.getObjectClasses(),
+ entry.getUserAttributes(),
+ entry.getOperationalAttributes());
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+
+ String path = TestCaseUtils.createTempFile(
+ "dn: uid=testPassword02.user," + baseDN,
+ "changetype: modify",
+ "delete: userPassword",
+ "userPassword: password",
+ "-",
+ "add: userPassword",
+ "userPassword: aNewPassword");
+
+ String[] args =
+ {
+ "-h", "127.0.0.1",
+ "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
+ "-D", "cn=Directory Manager",
+ "-w", "password",
+ "-f", path
+ };
+
+ assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
+ }
+
+ /**
+ * Tests a modify operation that attempts change the user password doing
+ * a delete of an encrypted value followed of an add of a new value.
+ *
+ * @param baseDN The base DN for the test backend.
+ *
+ * @throws Exception If an unexpected problem occurs.
+ */
+ @Test(dataProvider = "baseDNs")
+ public void testModifyDelEncryptedAddOnePasswordAttribute(String baseDN)
+ throws Exception
+ {
+ TestCaseUtils.clearJEBackend(true,"userRoot",baseDN);
+
+ Entry entry = TestCaseUtils.makeEntry(
+ "dn: uid=testPassword03.user," + baseDN,
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalPerson",
+ "objectClass: inetOrgPerson",
+ "uid: test.user",
+ "givenName: Test",
+ "sn: User",
+ "cn: Test User",
+ "displayName: Test User",
+ "userPassword: password");
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ AddOperation addOperation =
+ conn.processAdd(entry.getDN(), entry.getObjectClasses(),
+ entry.getUserAttributes(),
+ entry.getOperationalAttributes());
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+ Entry e = DirectoryServer.getEntry(
+ DN.decode("uid=testPassword03.user," + baseDN));
+ List<Attribute> attrList =
+ e.getAttribute(DirectoryServer.getAttributeType("userpassword", true));
+
+ assertNotNull(attrList);
+
+ String passwd = null;
+ for (Attribute a : attrList)
+ {
+ for (AttributeValue v : a)
+ {
+ passwd = v.toString();
+ }
+ }
+
+ assertNotNull(passwd);
+
+ String path = TestCaseUtils.createTempFile(
+ "dn: uid=testPassword03.user," + baseDN,
+ "changetype: modify",
+ "delete: userPassword",
+ "userPassword: " + passwd,
+ "-",
+ "add: userPassword",
+ "userPassword: aNewPassword");
+
+ String[] args =
+ {
+ "-h", "127.0.0.1",
+ "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
+ "-D", "cn=Directory Manager",
+ "-w", "password",
+ "-f", path
+ };
+
+ assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
+ }
}
--
Gitblit v1.10.0