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