1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.core.authz;
21  
22  import org.apache.directory.shared.ldap.name.LdapDN;
23  
24  
25  import org.apache.directory.shared.ldap.exception.LdapNoPermissionException;
26  import org.apache.directory.server.core.integ.CiRunner;
27  import org.apache.directory.server.core.integ.annotations.Factory;
28  import org.apache.directory.server.core.DirectoryService;
29  import org.junit.runner.RunWith;
30  
31  import javax.naming.directory.Attribute;
32  import javax.naming.directory.Attributes;
33  import javax.naming.directory.BasicAttribute;
34  import javax.naming.directory.BasicAttributes;
35  import javax.naming.directory.DirContext;
36  
37  import static org.junit.Assert.assertTrue;
38  import static org.junit.Assert.assertFalse;
39  import org.junit.Test;
40  
41  import static org.apache.directory.server.core.authz.AutzIntegUtils.createUser;
42  import static org.apache.directory.server.core.authz.AutzIntegUtils.deleteUser;
43  import static org.apache.directory.server.core.authz.AutzIntegUtils.getContextAs;
44  import static org.apache.directory.server.core.authz.AutzIntegUtils.getContextAsAdmin;
45  import static org.apache.directory.server.core.authz.AutzIntegUtils.createAccessControlSubentry;
46  import static org.apache.directory.server.core.authz.AutzIntegUtils.addUserToGroup;
47  import static org.apache.directory.server.core.authz.AutzIntegUtils.deleteAccessControlSubentry;
48  import static org.apache.directory.server.core.authz.AutzIntegUtils.removeUserFromGroup;
49  
50  
51  /**
52   * Tests whether or not authorization around entry renames and moves work properly.
53   *
54   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
55   * @version $Rev: 691024 $
56   */
57  @RunWith ( CiRunner.class )
58  @Factory ( AutzIntegUtils.ServiceFactory.class )
59  public class MoveRenameAuthorizationIT
60  {
61      public static DirectoryService service;
62  
63  
64      /**
65       * Checks if a simple entry (organizationalUnit) can be renamed at an RDN relative
66       * to ou=system by a specific non-admin user.  If a permission exception
67       * is encountered it is caught and false is returned, otherwise true is returned
68       * when the entry is created.  The entry is deleted after being created just in case
69       * subsequent calls to this method do not fail: the admin account is used to delete
70       * this test entry so permissions to delete are not required to delete it by the user.
71       *
72       * @param uid the unique identifier for the user (presumed to exist under ou=users,ou=system)
73       * @param password the password of this user
74       * @param entryRdn the relative DN, relative to ou=system where entry renames are tested
75       * @param newRdn the new RDN for the entry under ou=system
76       * @return true if the entry can be renamed by the user at the specified location, false otherwise
77       * @throws javax.naming.NamingException if there are problems conducting the test
78       */
79      public boolean checkCanRenameAs( String uid, String password, String entryRdn, String newRdn )
80          throws Exception
81      {
82          Attributes testEntry = new BasicAttributes( "ou", "testou", true );
83          Attribute objectClass = new BasicAttribute( "objectClass" );
84          testEntry.put( objectClass );
85          objectClass.add( "top" );
86          objectClass.add( "organizationalUnit" );
87  
88          DirContext adminContext = getContextAsAdmin();
89          try
90          {
91              // create the new entry as the admin user
92              adminContext.createSubcontext( entryRdn, testEntry );
93  
94              LdapDN userName = new LdapDN( "uid=" + uid + ",ou=users,ou=system" );
95              DirContext userContext = getContextAs( userName, password );
96              userContext.rename( entryRdn, newRdn );
97  
98              // delete the renamed context as the admin user
99              adminContext.destroySubcontext( newRdn );
100             return true;
101         }
102         catch ( LdapNoPermissionException e )
103         {
104             // delete the original context as the admin user since rename
105             // of newly created test entry did not succeed
106             adminContext.destroySubcontext( entryRdn );
107             return false;
108         }
109     }
110 
111 
112     /**
113      * Checks to make sure group membership based userClass works for renames,
114      * moves and moves with renames.
115      *
116      * @throws javax.naming.NamingException if the test encounters an error
117      */
118     @Test
119     public void testGrantByAdministrators() throws Exception
120     {
121         // ----------------------------------------------------------------------------
122         // Test simple RDN change: NO SUBTREE MOVEMENT!
123         // ----------------------------------------------------------------------------
124 
125         // create the non-admin user
126         createUser( "billyd", "billyd" );
127 
128         // try the rename operation which should fail without any ACI
129         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou", "ou=newname" ) );
130 
131         // Gives grantRename perm to all users in the Administrators group for entries
132         createAccessControlSubentry( "grantRenameByAdmin", "{ " + "identificationTag \"addAci\", " + "precedence 14, "
133             + "authenticationLevel none, " + "itemOrUserFirst userFirst: { "
134             + "userClasses { userGroup { \"cn=Administrators,ou=groups,ou=system\" } }, " + "userPermissions { { "
135             + "protectedItems {entry}, " + "grantsAndDenials { grantRename, grantBrowse } } } } }" );
136 
137         // see if we can now rename that test entry which we could not before
138         // rename op should still fail since billyd is not in the admin group
139         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou", "ou=newname" ) );
140 
141         // now add billyd to the Administrator group and try again
142         addUserToGroup( "billyd", "Administrators" );
143 
144         // try a rename operation which should succeed with ACI and group membership change
145         assertTrue( checkCanRenameAs( "billyd", "billyd", "ou=testou", "ou=newname" ) );
146 
147         // now let's cleanup
148         removeUserFromGroup( "billyd", "Administrators" );
149         deleteAccessControlSubentry( "grantRenameByAdmin" );
150         deleteUser( "billyd" );
151 
152         // ----------------------------------------------------------------------------
153         // Test move and RDN change at the same time.
154         // ----------------------------------------------------------------------------
155 
156         // create the non-admin user
157         createUser( "billyd", "billyd" );
158 
159         // try an move w/ rdn change which should fail without any ACI
160         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=newname,ou=groups" ) );
161 
162         // Gives grantRename, grantImport, grantExport perm to all users in the Administrators
163         // group for entries - browse is needed just to read navigate the tree at root
164         createAccessControlSubentry( "grantRenameMoveByAdmin", "{ " + "identificationTag \"addAci\", "
165             + "precedence 14, " + "authenticationLevel none, " + "itemOrUserFirst userFirst: { "
166             + "userClasses { userGroup { \"cn=Administrators,ou=groups,ou=system\" } }, " + "userPermissions { { "
167             + "protectedItems {entry}, "
168             + "grantsAndDenials { grantExport, grantImport, grantRename, grantBrowse } } } } }" );
169 
170         // see if we can move and rename the test entry which we could not before
171         // op should still fail since billyd is not in the admin group
172         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=newname,ou=groups" ) );
173 
174         // now add billyd to the Administrator group and try again
175         addUserToGroup( "billyd", "Administrators" );
176 
177         // try move w/ rdn change which should succeed with ACI and group membership change
178         assertTrue( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=newname,ou=groups" ) );
179 
180         // now let's cleanup
181         removeUserFromGroup( "billyd", "Administrators" );
182         deleteAccessControlSubentry( "grantRenameMoveByAdmin" );
183         deleteUser( "billyd" );
184 
185         // ----------------------------------------------------------------------------
186         // Test move ONLY without any RDN changes.
187         // ----------------------------------------------------------------------------
188 
189         // create the non-admin user
190         createUser( "billyd", "billyd" );
191 
192         // try move operation which should fail without any ACI
193         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=testou,ou=groups" ) );
194 
195         // Gives grantImport, and grantExport perm to all users in the Administrators group for entries
196         createAccessControlSubentry( "grantMoveByAdmin", "{ " + "identificationTag \"addAci\", " + "precedence 14, "
197             + "authenticationLevel none, " + "itemOrUserFirst userFirst: { "
198             + "userClasses { userGroup { \"cn=Administrators,ou=groups,ou=system\" } }, " + "userPermissions { { "
199             + "protectedItems {entry}, " + "grantsAndDenials { grantExport, grantImport, grantBrowse } } } } }" );
200 
201         // see if we can now move that test entry which we could not before
202         // op should still fail since billyd is not in the admin group
203         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=testou,ou=groups" ) );
204 
205         // now add billyd to the Administrator group and try again
206         addUserToGroup( "billyd", "Administrators" );
207 
208         // try move operation which should succeed with ACI and group membership change
209         assertTrue( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=testou,ou=groups" ) );
210 
211         // now let's cleanup
212         removeUserFromGroup( "billyd", "Administrators" );
213         deleteAccessControlSubentry( "grantMoveByAdmin" );
214         deleteUser( "billyd" );
215     }
216 
217 
218     /**
219      * Checks to make sure name based userClass works for rename, move, and
220      * rename with move operation access controls.
221      *
222      * @throws javax.naming.NamingException if the test encounters an error
223      */
224     @Test
225     public void testGrantByName() throws Exception
226     {
227         // ----------------------------------------------------------------------------
228         // Test simple RDN change: NO SUBTREE MOVEMENT!
229         // ----------------------------------------------------------------------------
230 
231         // create the non-admin user
232         createUser( "billyd", "billyd" );
233 
234         // try the rename operation which should fail without any ACI
235         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou", "ou=newname" ) );
236 
237         // Gives grantRename perm specifically to the billyd user
238         createAccessControlSubentry( "grantRenameByName", "{ " + "identificationTag \"addAci\", " + "precedence 14, "
239             + "authenticationLevel none, " + "itemOrUserFirst userFirst: { "
240             + "userClasses { name { \"uid=billyd,ou=users,ou=system\" } }, " + "userPermissions { { "
241             + "protectedItems {entry}, " + "grantsAndDenials { grantRename, grantBrowse } } } } }" );
242 
243         // try a rename operation which should succeed with ACI
244         assertTrue( checkCanRenameAs( "billyd", "billyd", "ou=testou", "ou=newname" ) );
245 
246         // now let's cleanup
247         deleteAccessControlSubentry( "grantRenameByName" );
248         deleteUser( "billyd" );
249 
250         // ----------------------------------------------------------------------------
251         // Test move and RDN change at the same time.
252         // ----------------------------------------------------------------------------
253 
254         // create the non-admin user
255         createUser( "billyd", "billyd" );
256 
257         // try an move w/ rdn change which should fail without any ACI
258         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=newname,ou=groups" ) );
259 
260         // Gives grantRename, grantImport, grantExport perm to billyd user on entries
261         createAccessControlSubentry( "grantRenameMoveByName", "{ " + "identificationTag \"addAci\", "
262             + "precedence 14, " + "authenticationLevel none, " + "itemOrUserFirst userFirst: { "
263             + "userClasses { name { \"uid=billyd,ou=users,ou=system\" } }, " + "userPermissions { { "
264             + "protectedItems {entry}, "
265             + "grantsAndDenials { grantExport, grantImport, grantRename, grantBrowse } } } } }" );
266 
267         // try move w/ rdn change which should succeed with ACI
268         assertTrue( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=newname,ou=groups" ) );
269 
270         // now let's cleanup
271         deleteAccessControlSubentry( "grantRenameMoveByName" );
272         deleteUser( "billyd" );
273 
274         // ----------------------------------------------------------------------------
275         // Test move ONLY without any RDN changes.
276         // ----------------------------------------------------------------------------
277 
278         // create the non-admin user
279         createUser( "billyd", "billyd" );
280 
281         // try move operation which should fail without any ACI
282         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=testou,ou=groups" ) );
283 
284         // Gives grantImport, and grantExport perm to billyd user for entries
285         createAccessControlSubentry( "grantMoveByName", "{ " + "identificationTag \"addAci\", " + "precedence 14, "
286             + "authenticationLevel none, " + "itemOrUserFirst userFirst: { "
287             + "userClasses { name { \"uid=billyd,ou=users,ou=system\" } }, " + "userPermissions { { "
288             + "protectedItems {entry}, " + "grantsAndDenials { grantExport, grantImport, grantBrowse } } } } }" );
289 
290         // try move operation which should succeed with ACI
291         assertTrue( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=testou,ou=groups" ) );
292 
293         // now let's cleanup
294         deleteAccessControlSubentry( "grantMoveByName" );
295         deleteUser( "billyd" );
296     }
297 
298 
299     /**
300      * Checks to make sure subtree based userClass works for rename, move, and
301      * rename with move operation access controls.
302      *
303      * @throws javax.naming.NamingException if the test encounters an error
304      */
305     @Test
306     public void testGrantBySubtree() throws Exception
307     {
308         // ----------------------------------------------------------------------------
309         // Test simple RDN change: NO SUBTREE MOVEMENT!
310         // ----------------------------------------------------------------------------
311 
312         // create the non-admin user
313         createUser( "billyd", "billyd" );
314 
315         // try the rename operation which should fail without any ACI
316         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou", "ou=newname" ) );
317 
318         // Gives grantRename perm for entries to those users selected by the subtree
319         createAccessControlSubentry( "grantRenameByTree", "{ " + "identificationTag \"addAci\", " + "precedence 14, "
320             + "authenticationLevel none, " + "itemOrUserFirst userFirst: { "
321             + "userClasses { subtree { { base \"ou=users,ou=system\" } } }, " + "userPermissions { { "
322             + "protectedItems {entry}, " + "grantsAndDenials { grantRename, grantBrowse } } } } }" );
323 
324         // try a rename operation which should succeed with ACI
325         assertTrue( checkCanRenameAs( "billyd", "billyd", "ou=testou", "ou=newname" ) );
326 
327         // now let's cleanup
328         deleteAccessControlSubentry( "grantRenameByTree" );
329         deleteUser( "billyd" );
330 
331         // ----------------------------------------------------------------------------
332         // Test move and RDN change at the same time.
333         // ----------------------------------------------------------------------------
334 
335         // create the non-admin user
336         createUser( "billyd", "billyd" );
337 
338         // try an move w/ rdn change which should fail without any ACI
339         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=newname,ou=groups" ) );
340 
341         // Gives grantRename, grantImport, grantExport for entries to users selected by subtree
342         createAccessControlSubentry( "grantRenameMoveByTree", "{ " + "identificationTag \"addAci\", "
343             + "precedence 14, " + "authenticationLevel none, " + "itemOrUserFirst userFirst: { "
344             + "userClasses { subtree { { base \"ou=users,ou=system\" } } }, " + "userPermissions { { "
345             + "protectedItems {entry}, "
346             + "grantsAndDenials { grantExport, grantImport, grantRename, grantBrowse } } } } }" );
347 
348         // try move w/ rdn change which should succeed with ACI
349         assertTrue( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=newname,ou=groups" ) );
350 
351         // now let's cleanup
352         deleteAccessControlSubentry( "grantRenameMoveByTree" );
353         deleteUser( "billyd" );
354 
355         // ----------------------------------------------------------------------------
356         // Test move ONLY without any RDN changes.
357         // ----------------------------------------------------------------------------
358 
359         // create the non-admin user
360         createUser( "billyd", "billyd" );
361 
362         // try move operation which should fail without any ACI
363         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=testou,ou=groups" ) );
364 
365         // Gives grantImport, and grantExport perm for entries to subtree selected users
366         createAccessControlSubentry( "grantMoveByTree", "{ " + "identificationTag \"addAci\", " + "precedence 14, "
367             + "authenticationLevel none, " + "itemOrUserFirst userFirst: { "
368             + "userClasses { subtree { { base \"ou=users,ou=system\" } } }, " + "userPermissions { { "
369             + "protectedItems {entry}, " + "grantsAndDenials { grantExport, grantImport, grantBrowse } } } } }" );
370 
371         // try move operation which should succeed with ACI
372         assertTrue( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=testou,ou=groups" ) );
373 
374         // now let's cleanup
375         deleteAccessControlSubentry( "grantMoveByTree" );
376         deleteUser( "billyd" );
377     }
378 
379 
380     /**
381      * Checks to make sure the <b>anyUser</b> userClass works for rename, move, and
382      * rename with move operation access controls.
383      *
384      * @throws javax.naming.NamingException if the test encounters an error
385      */
386     @Test
387     public void testGrantByAnyuser() throws Exception
388     {
389         // ----------------------------------------------------------------------------
390         // Test simple RDN change: NO SUBTREE MOVEMENT!
391         // ----------------------------------------------------------------------------
392 
393         // create the non-admin user
394         createUser( "billyd", "billyd" );
395 
396         // try the rename operation which should fail without any ACI
397         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou", "ou=newname" ) );
398 
399         // Gives grantRename perm for entries to any user
400         createAccessControlSubentry( "grantRenameByAny", "{ " + "identificationTag \"addAci\", " + "precedence 14, "
401             + "authenticationLevel none, " + "itemOrUserFirst userFirst: { " + "userClasses { allUsers }, "
402             + "userPermissions { { " + "protectedItems {entry}, "
403             + "grantsAndDenials { grantRename, grantBrowse } } } } }" );
404 
405         // try a rename operation which should succeed with ACI
406         assertTrue( checkCanRenameAs( "billyd", "billyd", "ou=testou", "ou=newname" ) );
407 
408         // now let's cleanup
409         deleteAccessControlSubentry( "grantRenameByAny" );
410         deleteUser( "billyd" );
411 
412         // ----------------------------------------------------------------------------
413         // Test move and RDN change at the same time.
414         // ----------------------------------------------------------------------------
415 
416         // create the non-admin user
417         createUser( "billyd", "billyd" );
418 
419         // try an move w/ rdn change which should fail without any ACI
420         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=newname,ou=groups" ) );
421 
422         // Gives grantRename, grantImport, grantExport for entries to any user
423         createAccessControlSubentry( "grantRenameMoveByAny", "{ " + "identificationTag \"addAci\", "
424             + "precedence 14, " + "authenticationLevel none, " + "itemOrUserFirst userFirst: { "
425             + "userClasses { allUsers }, " + "userPermissions { { " + "protectedItems {entry}, "
426             + "grantsAndDenials { grantExport, grantImport, grantRename, grantBrowse } } } } }" );
427 
428         // try move w/ rdn change which should succeed with ACI
429         assertTrue( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=newname,ou=groups" ) );
430 
431         // now let's cleanup
432         deleteAccessControlSubentry( "grantRenameMoveByAny" );
433         deleteUser( "billyd" );
434 
435         // ----------------------------------------------------------------------------
436         // Test move ONLY without any RDN changes.
437         // ----------------------------------------------------------------------------
438 
439         // create the non-admin user
440         createUser( "billyd", "billyd" );
441 
442         // try move operation which should fail without any ACI
443         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=testou,ou=groups" ) );
444 
445         // Gives grantImport, and grantExport perm for entries to any user
446         createAccessControlSubentry( "grantMoveByAny", "{ " + "identificationTag \"addAci\", " + "precedence 14, "
447             + "authenticationLevel none, " + "itemOrUserFirst userFirst: { " + "userClasses { allUsers }, "
448             + "userPermissions { { " + "protectedItems {entry}, "
449             + "grantsAndDenials { grantExport, grantImport, grantBrowse } } } } }" );
450 
451         // try move operation which should succeed with ACI
452         assertTrue( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=testou,ou=groups" ) );
453 
454         // now let's cleanup
455         deleteAccessControlSubentry( "grantMoveByAny" );
456         deleteUser( "billyd" );
457     }
458     
459     
460     /**
461      * Checks to make sure Export and Import permissions work correctly
462      * when they are defined on seperate contexts.
463      *
464      * @throws javax.naming.NamingException if the test encounters an error
465      */
466     @Test
467     public void testExportAndImportSeperately() throws Exception
468     {
469         // ----------------------------------------------------------------------------
470         // Test move and RDN change at the same time.
471         // ----------------------------------------------------------------------------
472 
473         // create the non-admin user
474         createUser( "billyd", "billyd" );
475 
476         // try an move w/ rdn change which should fail without any ACI
477         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=newname,ou=groups" ) );
478 
479         
480         // Gives grantBrowse perm to all users in the Administrators
481         // group for entries
482         // It's is needed just to read navigate the tree at root
483         createAccessControlSubentry(
484             "grantBrowseForTheWholeNamingContext",
485             "{ }",
486             "{ " + "identificationTag \"browseACI\", "
487             + "precedence 14, " + "authenticationLevel none, " + "itemOrUserFirst userFirst: { "
488             + "userClasses { userGroup { \"cn=Administrators,ou=groups,ou=system\" } }, " + "userPermissions { { "
489             + "protectedItems { entry }, "
490             + "grantsAndDenials { grantBrowse } } } } }" );
491         
492         // Gives grantExport, grantRename perm to all users in the Administrators
493         // group for entries
494         createAccessControlSubentry(
495             "grantExportFromASubtree",
496             "{ base \"ou=users\" }", // !!!!! =====>>>>> { base "ou=users" }
497             "{ " + "identificationTag \"exportACI\", "
498             + "precedence 14, " + "authenticationLevel none, " + "itemOrUserFirst userFirst: { "
499             + "userClasses { userGroup { \"cn=Administrators,ou=groups,ou=system\" } }, " + "userPermissions { { "
500             + "protectedItems { entry }, "
501             + "grantsAndDenials { grantExport, grantRename } } } } }" );
502         
503         // Gives grantImport perm to all users in the Administrators
504         // group for the target context
505         createAccessControlSubentry(
506             "grantImportToASubtree",
507             "{ base \"ou=groups\" }", // !!!!! =====>>>>> { base "ou=groups" }
508             "{ " + "identificationTag \"importACI\", "
509             + "precedence 14, " + "authenticationLevel none, " + "itemOrUserFirst userFirst: { "
510             + "userClasses { userGroup { \"cn=Administrators,ou=groups,ou=system\" } }, " + "userPermissions { { "
511             + "protectedItems { entry }, "
512             + "grantsAndDenials { grantImport } } } } }" );
513 
514         // see if we can move and rename the test entry which we could not before
515         // op should still fail since billyd is not in the admin group
516         assertFalse( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=newname,ou=groups" ) );
517 
518         // now add billyd to the Administrator group and try again
519         addUserToGroup( "billyd", "Administrators" );
520 
521         // try move w/ rdn change which should succeed with ACI and group membership change
522         assertTrue( checkCanRenameAs( "billyd", "billyd", "ou=testou,ou=users", "ou=newname,ou=groups" ) );
523 
524         // now let's cleanup
525         removeUserFromGroup( "billyd", "Administrators" );
526         deleteAccessControlSubentry( "grantBrowseForTheWholeNamingContext" );
527         deleteAccessControlSubentry( "grantExportFromASubtree" );
528         deleteAccessControlSubentry( "grantImportToASubtree" );
529         deleteUser( "billyd" );
530     }
531 }