opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
@@ -183,7 +183,7 @@ public static final int ACI_SEARCH = 0x0020; /** * ACI_SELF is used for the SELFWRITE right. Currently not implemented. * ACI_SELF is used for the SELFWRITE right. */ public static final int ACI_SELF = 0x0040; @@ -200,13 +200,13 @@ /** * ACI_IMPORT is used to set the container rights for a LDAP * modify dn operation. Currently not used. * modify dn operation. */ public static final int ACI_IMPORT = 0x0100; /** * ACI_EXPORT is used to set the container rights for a LDAP * modify dn operation. Currently not used. * modify dn operation. */ public static final int ACI_EXPORT = 0x0200; opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -44,8 +44,10 @@ import static org.opends.server.loggers.debug.DebugLogger.debugCaught; import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.protocols.internal.InternalClientConnection; import static org.opends.server.schema.SchemaConstants.*; import java.util.*; import java.util.concurrent.locks.Lock; /** * The AciHandler class performs the main processing for the @@ -216,9 +218,9 @@ List<Modification> modifications=container.getModifications(); for(Modification m : modifications) { Attribute modAttr=m.getAttribute(); AttributeType modType=modAttr.getAttributeType(); AttributeType modAttrType=modAttr.getAttributeType(); if(modType.equals(aciType)) { if(modAttrType.equals(aciType)) { /* * Check that the operation has modify privileges if * it contains an "aci" attribute type. @@ -236,20 +238,22 @@ return false; } } switch(m.getModificationType()) { case DELETE: case REPLACE: case INCREMENT: { /* //This access check handles the case where all attributes of this //type are being replaced or deleted. If only a subset is being //deleted than this access check is skipped. ModificationType modType=m.getModificationType(); if((modType == ModificationType.DELETE && modAttr.getValues().isEmpty()) || (modType == ModificationType.REPLACE || modType == ModificationType.INCREMENT)) { /* * Check if we have rights to delete all values of * an attribute type in the resource entry. */ if(resourceEntry.hasAttribute(modType)) { container.setCurrentAttributeType(modType); if(resourceEntry.hasAttribute(modAttrType)) { container.setCurrentAttributeType(modAttrType); List<Attribute> attrList = resourceEntry.getAttribute(modType,modAttr.getOptions()); resourceEntry.getAttribute(modAttrType,modAttr.getOptions()); for (Attribute a : attrList) { for (AttributeValue v : a.getValues()) { container.setCurrentAttributeValue(v); @@ -260,11 +264,11 @@ } } } } } } if(modAttr.hasValue()) { for(AttributeValue v : modAttr.getValues()) { container.setCurrentAttributeType(modType); container.setCurrentAttributeType(modAttrType); switch (m.getModificationType()) { case ADD: @@ -283,7 +287,7 @@ case INCREMENT: Entry modifiedEntry = operation.getModifiedEntry(); List<Attribute> modifiedAttrs = modifiedEntry.getAttribute(modType, modifiedEntry.getAttribute(modAttrType, modAttr.getOptions()); if (modifiedAttrs != null) { @@ -305,12 +309,12 @@ If so, check the syntax of that attribute value. Fail the the operation if the syntax check fails. */ if(modType.equals(aciType) || modType.equals(globalAciType)) { if(modAttrType.equals(aciType) || modAttrType.equals(globalAciType)) { try { //A global ACI needs a NULL DN, not the DN of the //modification. if(modType.equals(globalAciType)) if(modAttrType.equals(globalAciType)) dn=DN.nullDN(); Aci.decode(v.getValue(),dn); } catch (AciException ex) { @@ -420,6 +424,25 @@ if(container.hasRights(ACI_WRITE_ADD) || container.hasRights(ACI_WRITE_DELETE)) container.setRights(container.getRights() | ACI_WRITE); //Check if the ACI_SELF right needs to be set (selfwrite right). //Only done if the right is ACI_WRITE, an attribute value is set and //that attribute value is a DN. if((container.getCurrentAttributeValue() != null) && (container.hasRights(ACI_WRITE)) && (isAttributeDN(container.getCurrentAttributeType()))) { try { String DNString = container.getCurrentAttributeValue().getStringValue(); DN tmpDN = DN.decode(DNString); //Have a valid DN, compare to clientDN to see if the ACI_SELF //right should be set. if(tmpDN.equals(container.getClientDN())) { container.setRights(container.getRights() | ACI_SELF); } } catch (DirectoryException ex) { return false; } } /* * First get all allowed candidate ACIs. */ @@ -435,6 +458,17 @@ return(testApplicableLists(container)); } /** * Check if the specified attribute type is a DN by checking if its syntax * OID is equal to the DN syntax OID. * @param attribute The attribute type to check. * @return True if the attribute type syntax OID is equal to a DN syntax OID. */ private boolean isAttributeDN(AttributeType attribute) { return (attribute.getSyntaxOID().equals(SYNTAX_DN_OID)); } /** * Performs an access check against all of the attributes of an entry. * The attributes that fail access are removed from the entry. This method @@ -781,15 +815,148 @@ return returnEntry; } //Planned to be implemented methods /** * Perform all needed RDN checks for the modifyDN operation. These checks * are: * * - Verify WRITE access to the entry. * - Verfiy WRITE_ADD access on each RDN component of the new RDN. The * WRITE_ADD access is used because this access could be restricted by * the targattrfilters keyword. * - If the deleteOLDRDN flag is set, verify WRITE_DELETE access on the * old RDN. The WRITE_DELETE access is used because this access could be * restricted by the targattrfilters keyword. * * @param operation The ModifyDN operation class containing information to * check access on. * @return True if access is allowed. */ private boolean aciCheckRDNs(ModifyDNOperation operation) { boolean ret; AciLDAPOperationContainer operationContainer = new AciLDAPOperationContainer(operation, (ACI_WRITE), operation.getOriginalEntry()); ret=accessAllowed(operationContainer); if(ret) ret=checkRDN(ACI_WRITE_ADD,operation.getNewRDN(),operationContainer); if(ret && operation.deleteOldRDN()) { RDN oldRDN=operation.getOriginalEntry().getDN().getRDN(); ret = checkRDN(ACI_WRITE_DELETE, oldRDN, operationContainer); } return ret; } /** * Check access on each attribute-value pair component of the specified RDN. * There may be more than one attribute-value pair if the RDN is multi-valued. * * @param right The access right to check for. * @param rdn The RDN to examine the attribute-value pairs of. * @param container The container containing the information needed to * evaluate the specified RDN. * @return True if access is allowed for all attribute-value pairs. */ private boolean checkRDN(int right, RDN rdn, AciContainer container) { boolean ret=false; int numAVAs = rdn.getNumValues(); container.setRights(right); for (int i = 0; i < numAVAs; i++){ AttributeType type=rdn.getAttributeType(i); AttributeValue value=rdn.getAttributeValue(i); container.setCurrentAttributeType(type); container.setCurrentAttributeValue(value); if(!(ret=accessAllowed(container))) break; } return ret; } /** * Check access on the new superior entry if it exists. If the entry does not * exist or the DN cannot be locked then false is returned. * * @param superiorDN The DN of the new superior entry. * @param op The modifyDN operation to check access on. * @return True if access is granted to the new superior entry. * @throws DirectoryException If a problem occurs while trying to * retrieve the new superior entry. */ private boolean aciCheckSuperiorEntry(DN superiorDN, ModifyDNOperation op) throws DirectoryException { boolean ret=false; Lock entryLock = null; for (int i=0; i < 3; i++) { entryLock = LockManager.lockRead(superiorDN); if (entryLock != null) break; } if (entryLock == null) { int msgID = MSGID_ACI_HANDLER_CANNOT_LOCK_NEW_SUPERIOR_USER; String message = getMessage(msgID, String.valueOf(superiorDN)); logError(ErrorLogCategory.ACCESS_CONTROL, ErrorLogSeverity.INFORMATIONAL, message, msgID); return false; } try { Entry superiorEntry=DirectoryServer.getEntry(superiorDN); if(superiorEntry!= null) { AciLDAPOperationContainer operationContainer = new AciLDAPOperationContainer(op, (ACI_IMPORT), superiorEntry); ret=accessAllowed(operationContainer); } } finally { LockManager.unlock(superiorDN, entryLock); } return ret; } /** * Checks access on a modifyDN operation. * * @param operation The modifyDN operation to check access on. * @return True if access is allowed. * */ public boolean isAllowed(ModifyDNOperation operation) { boolean ret=true; DN newSuperiorDN; if(!skipAccessCheck(operation)) { //If this is a modifyDN move to a new superior, then check if the //superior DN has import accesss. if((newSuperiorDN=operation.getNewSuperior()) != null) { try { ret=aciCheckSuperiorEntry(newSuperiorDN, operation); } catch (DirectoryException ex) { ret=false; } } //Perform the RDN access checks. if(ret) ret=aciCheckRDNs(operation); //If this is a modifyDN move to a new superior, then check if the //original entry DN has export access. if(ret && (newSuperiorDN != null)) { AciLDAPOperationContainer operationContainer = new AciLDAPOperationContainer(operation, (ACI_EXPORT), operation.getOriginalEntry()); ret=accessAllowed(operationContainer); } } return ret; } //Not planned to be implemented methods. /** * {@inheritDoc} */ @Override public boolean maySend(SearchOperation operation, SearchResultReference reference) { //TODO: Planned to be implemented. //TODO: Deferred. return true; } @@ -797,16 +964,6 @@ * {@inheritDoc} */ @Override public boolean isAllowed(ModifyDNOperation modifyDNOperation) { // TODO: Planned to be implemented. return true; } //Not planned to be implemented methods. /** * {@inheritDoc} */ @Override public boolean isAllowed(BindOperation bindOperation) { //Not planned to be implemented. return true; opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java
@@ -29,13 +29,10 @@ import java.util.List; import org.opends.server.core.AddOperation; import org.opends.server.core.CompareOperation; import org.opends.server.core.DeleteOperation; import org.opends.server.core.ModifyOperation; import org.opends.server.core.SearchOperation; import org.opends.server.core.*; import org.opends.server.types.Modification; import org.opends.server.types.SearchResultEntry; import org.opends.server.types.Entry; /** * The AciLDAPOperationContainer is an AciContainer @@ -93,6 +90,17 @@ } /** * Constructor interface for the modify DN operation. * @param operation The modify DN operation. * @param rights The rights of the modify DN operation. * @param entry The entry to evalauted for this modify DN. */ public AciLDAPOperationContainer(ModifyDNOperation operation, int rights, Entry entry) { super(operation, rights, entry); } /** * Constructor interface for the LDAP search operation. * @param operation The search operation. * @param rights The rights of a search operation. opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java
@@ -343,4 +343,51 @@ // Replace the ACI list with the copy. aciList = aciCopy; } /** * Rename all ACIs under the specified old DN to the new DN. A simple * interation over the entire list is performed. * @param oldDN The DN of the original entry that was moved. * @param newDN The DN of the new entry. */ public synchronized void renameAci(DN oldDN, DN newDN ) { LinkedHashMap<DN, List<Aci>> newCopyList = new LinkedHashMap<DN, List<Aci>>(); int oldRDNCount=oldDN.getNumComponents(); int newRDNCount=newDN.getNumComponents(); for (Map.Entry<DN,List<Aci>> hashEntry : aciList.entrySet()) { if(hashEntry.getKey().isDescendantOf(oldDN)) { int keyRDNCount=hashEntry.getKey().getNumComponents(); int keepRDNCount=keyRDNCount - oldRDNCount; RDN[] newRDNs = new RDN[keepRDNCount + newRDNCount]; for (int i=0; i < keepRDNCount; i++) newRDNs[i] = hashEntry.getKey().getRDN(i); for (int i=keepRDNCount, j=0; j < newRDNCount; i++,j++) newRDNs[i] = newDN.getRDN(j); DN relocateDN=new DN(newRDNs); List<Aci> acis = new LinkedList<Aci>(); for(Aci aci : hashEntry.getValue()) { try { Aci newAci = Aci.decode(ByteStringFactory.create(aci.toString()), relocateDN); acis.add(newAci); } catch (AciException ex) { //This should never happen since only a copy of the //ACI with a new DN is being made. Log a message if it does and //keep going. int msgID = MSGID_ACI_ADD_LIST_FAILED_DECODE; String message = getMessage(msgID, ex.getMessage()); logError(ErrorLogCategory.ACCESS_CONTROL, ErrorLogSeverity.INFORMATIONAL, message, msgID); } } newCopyList.put(relocateDN, acis); } else newCopyList.put(hashEntry.getKey(), hashEntry.getValue()); } // Replace the ACI list with the copy. aciList = newCopyList; } } opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
@@ -150,7 +150,8 @@ } /** * Not implemented. * A modify DN operation has succeeded. Adjust the ACIs by moving ACIs * under the old entry DN to the new entry DN. * @param modifyDNOperation The LDAP modify DN operation. * @param oldEntry The old entry. * @param newEntry The new entry. @@ -159,9 +160,7 @@ PostResponseModifyDNOperation modifyDNOperation, Entry oldEntry, Entry newEntry) { /* * TODO Not yet implemented. */ aciList.renameAci(oldEntry.getDN(), newEntry.getDN()); } /** opendj-sdk/opends/src/server/org/opends/server/messages/AciMessages.java
@@ -722,6 +722,13 @@ public static final int MSGID_PATTERN_DN_TYPE_WILDCARD_IN_MULTIVALUED_RDN = CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 71; /** * The message ID for the message that will be used if the server is unable to * obtain a lock on a ModifyDN new superior entry. This takes a * single argument, which is the DN of the new superior entry. */ public static final int MSGID_ACI_HANDLER_CANNOT_LOCK_NEW_SUPERIOR_USER = CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 72; /** * Associates a set of generic messages with the message IDs defined in @@ -1137,5 +1144,8 @@ registerMessage(MSGID_PATTERN_DN_TYPE_WILDCARD_IN_MULTIVALUED_RDN, "The pattern DN %s is not valid because it contains a wildcard in " + "an attribute type in a multi-valued RDN"); registerMessage(MSGID_ACI_HANDLER_CANNOT_LOCK_NEW_SUPERIOR_USER, "Unable to obtain a lock on the ModifyDN new superior entry %s."); } } opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
@@ -155,10 +155,18 @@ private static final String OU_GROUP_1_DN = "cn=group1," + OU_GROUPS_DN; private static final String OU_GROUP_2_DN = "cn=group2," + OU_GROUPS_DN; //End group entries. private static final String MANAGER_DN = "cn=the managers,dc=example,dc=com"; //Used by modrdn new superior private static final String MANAGER_NEW_DN = "cn=new managers," + OU_BASE_DN; private static final String MGR_NEW_DN_URL = "ldap:///" + MANAGER_NEW_DN; private static final String MANAGER_DN = "cn=the managers," + OU_BASE_DN; private static final String MGR_DN_URL = "ldap:///" + MANAGER_DN; //These entries are going to be used to test userattr parent stuff. private static final String SALES_DN = "cn=sales dept," + MANAGER_DN; private static final String SALES_NEW_DN = "cn=sales dept," + MANAGER_NEW_DN; private static final String SALES_USER_1 = "cn=sales1 person," + SALES_DN; private static final String SALES_USER_NEW_1 = "cn=sales1 person," + SALES_NEW_DN; private static final String SALES_USER_2 = "cn=sales2 person," + SALES_DN; private static final String SALES_USER_3 = "cn=sales3 person," + SALES_DN; private static final String LEVEL_1_USER_URL = @@ -190,6 +198,7 @@ OU_LEAF_DN, OU_INNER_DN, MANAGER_DN, MANAGER_NEW_DN, OU_GROUPS_DN, OU_BASE_DN, ADMIN_DN, @@ -297,6 +306,27 @@ private static final String ALLOW_ALL_TO_COMPARE = buildAciValue("name", "allow compare", "targetattr", "*", "target", "ldap:///cn=*," + OU_LEAF_DN, "allow(compare)", BIND_RULE_USERDN_ALL); private static final String ALLOW_ALL_TO_IMPORT_MGR_NEW = buildAciValue("name", "allow import mgr new tree", "target", MGR_NEW_DN_URL, "allow(import)", BIND_RULE_USERDN_ALL); private static final String ALLOW_ALL_TO_IMPORT_MGR= buildAciValue("name", "allow import mgr tree", "target", MGR_DN_URL, "allow(import)", BIND_RULE_USERDN_ALL); private static final String ALLOW_ALL_TO_EXPORT_MGR_NEW = buildAciValue("name", "allow export mgr new tree", "target", MGR_NEW_DN_URL, "allow(export)", BIND_RULE_USERDN_ALL); private static final String ALLOW_ALL_TO_EXPORT_MGR= buildAciValue("name", "allow export mgr tree", "target", MGR_DN_URL, "allow(export)", BIND_RULE_USERDN_ALL); private static final String ALLOW_ALL_TO_WRITE_RDN_ATTRS= buildAciValue("name", "allow write to RDN attrs", "targetattr", "uid || cn || sn", "allow(write)", BIND_RULE_USERDN_ALL); private static final String ALLOW_ALL_TO_MOVED_ENTRY = buildAciValue("name", "allow all to moved", "targetattr", "*", "allow(search,read)", BIND_RULE_USERDN_ALL); private static final String ALLOW_ALL_TO_SELFWRITE = buildAciValue("name", "allow selfwrite", "targetattr", "member", "allow(selfwrite)", BIND_RULE_USERDN_ALL); private static final String ALLOW_ALL_TO_ADMIN = buildAciValue("name", "allow all to admin", "targetattr", "*", "allow(all)", BIND_RULE_USERDN_ADMIN); @@ -944,6 +974,11 @@ makeUserLdif(MANAGER_DN, "the", "managers", "pa$$word", ADMIN_DN, OU_GROUP_2_DN ); private static final String MANAGER_NEW__SEARCH_TESTS = makeUserLdif(MANAGER_NEW_DN, "new", "managers", "pa$$word", ADMIN_DN, OU_GROUP_2_DN ); private static final String SALES__SEARCH_TESTS = makeUserLdif(SALES_DN, "sales", "dept", "pa$$word", LEVEL_2_USER_DN, LEVEL_1_USER_URL); @@ -951,6 +986,7 @@ //LDIF entries used to test group stuff. private static final String GROUP_LDIF__SEARCH_TESTS = makeOuLdif(OU_GROUPS_DN, "groups"); private static final String GROUP_1_LDIF__SEARCH_TESTS = makeGroupLdif(OU_GROUP_1_DN, LEVEL_1_USER_DN, @@ -1009,6 +1045,31 @@ String COMPARE_ACI = makeAddAciLdif(OU_LEAF_DN, ALLOW_ALL_TO_COMPARE); //ACI used to test selfwrite private static final String SELFWRITE_ACI = makeAddAciLdif(OU_GROUP_1_DN, ALLOW_ALL_TO_SELFWRITE); //ACIs used for modDN tests (export, import) private static final String ACI_IMPORT_MGR_NEW = makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_IMPORT_MGR_NEW); private static final String ACI_IMPORT_MGR = makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_IMPORT_MGR); private static final String ACI_EXPORT_MGR_NEW = makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_EXPORT_MGR_NEW); private static final String ACI_EXPORT_MGR = makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_EXPORT_MGR); private static final String ACI_WRITE_RDN_ATTRS = makeAddAciLdif(OU_BASE_DN, ALLOW_ALL_TO_WRITE_RDN_ATTRS); private static final String ACI_MOVED_ENTRY = makeAddAciLdif(SALES_USER_1, ALLOW_ALL_TO_MOVED_ENTRY); //ACI used in testing the groupdn/roledn bind rule keywords. private static final @@ -1046,6 +1107,7 @@ USER_LDIF__SEARCH_TESTS + BASE_OU_LDIF__SEARCH_TESTS + MANAGER__SEARCH_TESTS + MANAGER_NEW__SEARCH_TESTS + SALES__SEARCH_TESTS + SALES_USER_1__SEARCH_TESTS + SALES_USER_2__SEARCH_TESTS + @@ -1578,7 +1640,7 @@ /** * Test LDAP compare. * @throws Throwable If the search returned is not valid for the ACI. * @throws Throwable If the compare is not valid for the ACI. */ @Test() public void testCompare() throws Throwable { @@ -1597,7 +1659,82 @@ } } /** /** * Test modify DN. Add a set of ACIs to allow exports, imports and write * rights. Also add an aci low in the DIT to test the ACI list after a move * has been made. Move the subtree, search with base at new DN, move the * tree back and re-search with base at orig DN. * @throws Throwable */ @Test() public void testModDN() throws Throwable { SingleSearchParams userParamOrig = new SingleSearchParams(LEVEL_1_USER_DN, "pa$$word", SALES_USER_1, OBJECTCLASS_STAR, SCOPE_BASE, null, null, null); SingleSearchParams userParamNew = new SingleSearchParams(LEVEL_1_USER_DN, "pa$$word", SALES_USER_NEW_1, OBJECTCLASS_STAR, SCOPE_BASE, null, null, null); try { addEntries(BASIC_LDIF__GROUP_SEARCH_TESTS, DIR_MGR_DN, DIR_MGR_PW); modEntries(ACI_IMPORT_MGR, DIR_MGR_DN, DIR_MGR_PW); modEntries(ACI_IMPORT_MGR_NEW, DIR_MGR_DN, DIR_MGR_PW); modEntries(ACI_EXPORT_MGR, DIR_MGR_DN, DIR_MGR_PW); modEntries(ACI_EXPORT_MGR_NEW, DIR_MGR_DN, DIR_MGR_PW); modEntries(ACI_WRITE_RDN_ATTRS, DIR_MGR_DN, DIR_MGR_PW); modEntries(ACI_MOVED_ENTRY, DIR_MGR_DN, DIR_MGR_PW); String modrdnLdif = makeModDN(SALES_DN, "cn=sales dept", "0", MANAGER_NEW_DN); modEntries(modrdnLdif, LEVEL_1_USER_DN, "pa$$word"); String userNewResults = ldapSearch(userParamNew.getLdapSearchArgs()); Assert.assertFalse(userNewResults.equals("")); String modrdnLdif1 = makeModDN(SALES_NEW_DN, "cn=sales dept", "0", MANAGER_DN); modEntries(modrdnLdif1, LEVEL_1_USER_DN, "pa$$word"); String userOrigResults = ldapSearch(userParamOrig.getLdapSearchArgs()); Assert.assertFalse(userOrigResults.equals("")); } catch (Throwable e) { throw e; } } /** * Test selfwrite right. Attempt to bind as level3 user and remove level1 * user from a group, should fail. * @throws Throwable If the delete succeeds. */ @Test() public void testNonSelfWrite() throws Throwable { try { addEntries(BASIC_LDIF__GROUP_SEARCH_TESTS, DIR_MGR_DN, DIR_MGR_PW); modEntries(SELFWRITE_ACI, DIR_MGR_DN, DIR_MGR_PW); deleteAttrFromEntry(OU_GROUP_1_DN, "member",LEVEL_1_USER_DN, LEVEL_3_USER_DN, "pa$$word", false); } catch(Throwable e) { throw e; } } /** * Test selfwrite right. Attempt to bind as level1 user and remove itself * from a group, should succeed. * @throws Throwable If the delete fails. */ @Test() public void testSelfWrite() throws Throwable { try { addEntries(BASIC_LDIF__GROUP_SEARCH_TESTS, DIR_MGR_DN, DIR_MGR_PW); modEntries(SELFWRITE_ACI, DIR_MGR_DN, DIR_MGR_PW); deleteAttrFromEntry(OU_GROUP_1_DN, "member",LEVEL_1_USER_DN, LEVEL_1_USER_DN, "pa$$word", true); } catch(Throwable e) { throw e; } } /** * Test group and role bind rule ACI keywords. Both groupdn and roledn keywords * funnel through the same code so the results should be the same. * @throws Throwable @@ -1919,15 +2056,43 @@ deleteEntries(ALL_TEST_ENTRY_DNS_BOTTOM_UP); } private void deleteAttrFromEntry(String dn, String attr, boolean errorOk) throws Exception { private void deleteAttrFromEntry(String dn, String attr, String val, String bindDN, String pwd, boolean errorOk) throws Exception { StringBuilder ldif = new StringBuilder(); ldif.append(TestCaseUtils.makeLdif( "dn: " + dn, "changetype: modify", "delete: " + attr)); modEntries(ldif.toString(), DIR_MGR_DN, DIR_MGR_PW, errorOk, false); "delete: " + attr, attr + ":" + val)); modEntries(ldif.toString(), bindDN, pwd, errorOk, false); } private static String makeModDN(String dn, String newRDN, String deleteOldRDN, String newSuperior ) throws Exception { StringBuilder ldif = new StringBuilder(); ldif.append("dn: " + dn).append(EOL); ldif.append("changetype: modrdn").append(EOL); ldif.append("newrdn: " + newRDN).append(EOL); ldif.append("deleteoldrdn: " + deleteOldRDN).append(EOL); if(newSuperior != null) ldif.append("newsuperior: " + newSuperior).append(EOL); ldif.append(EOL); return ldif.toString(); } private void deleteAttrFromEntry(String dn, String attr, boolean errorOk) throws Exception { StringBuilder ldif = new StringBuilder(); ldif.append(TestCaseUtils.makeLdif( "dn: " + dn, "changetype: modify", "delete: " + attr)); modEntries(ldif.toString(), DIR_MGR_DN, DIR_MGR_PW, errorOk, false); } private void deleteEntries(String[] entries) throws Exception { // TODO: make this actually do a search first! StringBuilder ldif = new StringBuilder(); opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java
@@ -147,6 +147,7 @@ "sn: User", "cn: Proxy User", "userPassword: password", "ds-privilege-name: bypass-acl", "ds-privilege-name: proxied-auth"); Entry proxyUserEntry = @@ -1116,7 +1117,19 @@ ASN1Reader r = new ASN1Reader(s); ASN1Writer w = new ASN1Writer(s); r.setIOTimeout(6000); BindRequestProtocolOp bindRequest = new BindRequestProtocolOp( new ASN1OctetString("cn=Directory Manager"), 3, new ASN1OctetString("password")); LDAPMessage bindMessage = new LDAPMessage(1, bindRequest); w.writeElement(bindMessage.encode()); bindMessage = LDAPMessage.decode(r.readElement().decodeAsSequence()); BindResponseProtocolOp bindResponse = bindMessage.getBindResponseProtocolOp(); assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS); assertTrue(DirectoryServer.getWorkQueue().waitUntilIdle(10000)); InvocationCounterPlugin.resetAllCounters(); ModifyDNRequestProtocolOp modifyRequest = new ModifyDNRequestProtocolOp( new ASN1OctetString(entry.getDN().toString()),