1
2
3
4
5
6
7
8
9
10
11
12
13
14
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.NamingEnumeration;
25 import javax.naming.Name;
26 import javax.naming.directory.*;
27 import java.util.List;
28 import java.util.ArrayList;
29
30
31 /***
32 * Tests whether or not authorization around entry modify operations work properly.
33 *
34 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
35 * @version $Rev$
36 */
37 public class ModifyAuthorizationTest extends AbstractAuthorizationTest
38 {
39 /***
40 * Checks if an attribute of a simple entry (an organizationalUnit) with an RDN
41 * relative to ou=system can be modified by a specific non-admin user. If a
42 * permission exception is encountered it is caught and false is returned,
43 * otherwise true is returned. The entry is deleted after being created just in case
44 * subsequent calls to this method are made in the same test case: the admin account
45 * is used to add and delete this test entry so permissions to add and delete are not
46 * required to test the modify operation by the user.
47 *
48 * @param uid the unique identifier for the user (presumed to exist under ou=users,ou=system)
49 * @param password the password of this user
50 * @param entryRdn the relative DN, relative to ou=system where entry is created
51 * for modification test
52 * @param mods the modifications to make to the entry
53 * @return true if the modifications can be made by the user at the specified location,
54 * false otherwise.
55 * @throws javax.naming.NamingException if there are problems conducting the test
56 */
57 public boolean checkCanModifyAs( String uid, String password, String entryRdn, ModificationItem[] mods )
58 throws NamingException
59 {
60
61 Attributes testEntry = new BasicAttributes( "ou", "testou", true );
62 Attribute objectClass = new BasicAttribute( "objectClass" );
63 testEntry.put( objectClass );
64 objectClass.add( "top" );
65 objectClass.add( "organizationalUnit" );
66 testEntry.put( "telephoneNumber", "867-5309" );
67
68 DirContext adminContext = getContextAsAdmin();
69
70 try
71 {
72
73 LdapName userName = new LdapName( "uid="+uid+",ou=users,ou=system" );
74 adminContext.createSubcontext( entryRdn, testEntry );
75
76
77 DirContext userContext = getContextAs( userName, password );
78 userContext.modifyAttributes( entryRdn, mods );
79
80 return true;
81 }
82 catch ( LdapNoPermissionException e )
83 {
84 return false;
85 }
86 finally
87 {
88
89 adminContext.destroySubcontext( entryRdn );
90 }
91 }
92
93
94 /***
95 * Checks if an attribute of a simple entry (an organizationalUnit) with an RDN
96 * relative to ou=system can be modified by a specific non-admin user. If a
97 * permission exception is encountered it is caught and false is returned,
98 * otherwise true is returned. The entry is deleted after being created just in case
99 * subsequent calls to this method are made in the same test case: the admin account
100 * is used to add and delete this test entry so permissions to add and delete are not
101 * required to test the modify operation by the user.
102 *
103 * @param uid the unique identifier for the user (presumed to exist under ou=users,ou=system)
104 * @param password the password of this user
105 * @param entryRdn the relative DN, relative to ou=system where entry is created
106 * for modification test
107 * @param mods the attributes to modify in the entry
108 * @param modOp the modification operation to use for all attributes
109 * @return true if the modifications can be made by the user at the specified location,
110 * false otherwise.
111 * @throws javax.naming.NamingException if there are problems conducting the test
112 */
113 public boolean checkCanModifyAs( String uid, String password, String entryRdn, int modOp, Attributes mods )
114 throws NamingException
115 {
116
117 Attributes testEntry = new BasicAttributes( "ou", "testou", true );
118 Attribute objectClass = new BasicAttribute( "objectClass" );
119 testEntry.put( objectClass );
120 objectClass.add( "top" );
121 objectClass.add( "organizationalUnit" );
122 testEntry.put( "telephoneNumber", "867-5309" );
123
124 DirContext adminContext = getContextAsAdmin();
125
126 try
127 {
128
129 LdapName userName = new LdapName( "uid="+uid+",ou=users,ou=system" );
130 adminContext.createSubcontext( entryRdn, testEntry );
131
132
133 DirContext userContext = getContextAs( userName, password );
134 userContext.modifyAttributes( entryRdn, modOp, mods );
135
136 return true;
137 }
138 catch ( LdapNoPermissionException e )
139 {
140 return false;
141 }
142 finally
143 {
144
145 adminContext.destroySubcontext( entryRdn );
146 }
147 }
148
149
150 /***
151 * Checks if a user can modify an attribute of their own entry. Users are
152 * presumed to reside under ou=users,ou=system. If a permission exception is
153 * encountered it is caught and false is returned, otherwise true is returned.
154 *
155 * @param uid the unique identifier for the user (presumed to exist under ou=users,ou=system)
156 * @param password the password of this user
157 * @param mods the attributes to modify in the entry
158 * @param modOp the modification operation to use for all attributes
159 * @return true if the modifications can be made by the user his/her own entry,
160 * false otherwise.
161 * @throws javax.naming.NamingException if there are problems conducting the test
162 */
163 public boolean checkCanSelfModify( String uid, String password, int modOp, Attributes mods )
164 throws NamingException
165 {
166 try
167 {
168
169 Name userEntry = new LdapName( "uid="+uid+",ou=users,ou=system" );
170 DirContext userContext = getContextAs( userEntry, password, userEntry.toString() );
171 userContext.modifyAttributes( "", modOp, mods );
172 return true;
173 }
174 catch ( LdapNoPermissionException e )
175 {
176 return false;
177 }
178 }
179
180
181 /***
182 * Checks if a user can modify an attribute of their own entry. Users are
183 * presumed to reside under ou=users,ou=system. If a permission exception is
184 * encountered it is caught and false is returned, otherwise true is returned.
185 *
186 * @param uid the unique identifier for the user (presumed to exist under ou=users,ou=system)
187 * @param password the password of this user
188 * @param mods the attributes to modify in the entry
189 * @return true if the modifications can be made by the user his/her own entry,
190 * false otherwise.
191 * @throws javax.naming.NamingException if there are problems conducting the test
192 */
193 public boolean checkCanSelfModify( String uid, String password, ModificationItem[] mods )
194 throws NamingException
195 {
196 try
197 {
198
199 Name userEntry = new LdapName( "uid="+uid+",ou=users,ou=system" );
200 DirContext userContext = getContextAs( userEntry, password, userEntry.toString() );
201 userContext.modifyAttributes( "", mods );
202 return true;
203 }
204 catch ( LdapNoPermissionException e )
205 {
206 return false;
207 }
208 }
209
210
211 /***
212 * Converts a set of attributes and a modification operation type into a MoficationItem array.
213 *
214 * @param modOp the modification operation to perform
215 * @param changes the modifications to the attribute
216 * @return the array of modification items represting the changes
217 * @throws NamingException if there are problems accessing attributes
218 */
219 private ModificationItem[] toItems( int modOp, Attributes changes ) throws NamingException
220 {
221 List mods = new ArrayList();
222 NamingEnumeration list = changes.getAll();
223 while ( list.hasMore() )
224 {
225 Attribute attr = ( Attribute ) list.next();
226 mods.add( new ModificationItem( modOp, attr ) );
227 }
228 ModificationItem[] modArray = new ModificationItem[mods.size()];
229 return ( ModificationItem[] ) mods.toArray( modArray );
230 }
231
232
233 public void testSelfModification() throws NamingException
234 {
235
236
237
238
239
240 createUser( "billyd", "billyd" );
241
242
243 ModificationItem[] mods = toItems( DirContext.REPLACE_ATTRIBUTE,
244 new BasicAttributes( "userPassword", "williams", true ) );
245
246
247 assertFalse( checkCanSelfModify( "billyd", "billyd", mods ) );
248
249
250
251 createAccessControlSubentry( "selfModifyUserPassword",
252 "{ " +
253 "identificationTag \"addAci\", " +
254 "precedence 14, " +
255 "authenticationLevel none, " +
256 "itemOrUserFirst userFirst: { " +
257 "userClasses { thisEntry }, " +
258 "userPermissions { " +
259 "{ protectedItems {entry}, grantsAndDenials { grantModify, grantBrowse, grantRead } }, " +
260 "{ protectedItems {allAttributeValues {userPassword}}, grantsAndDenials { grantAdd, grantRemove } } " +
261 "} } }" );
262
263
264 assertTrue( checkCanSelfModify( "billyd", "billyd", mods ) );
265 deleteAccessControlSubentry( "selfModifyUserPassword" );
266 }
267
268
269 /***
270 * Checks to make sure group membership based userClass works for modify operations.
271 *
272 * @throws javax.naming.NamingException if the test encounters an error
273 */
274 public void testGrantModifyByAdministrators() throws NamingException
275 {
276
277
278
279
280
281 ModificationItem[] mods = toItems( DirContext.ADD_ATTRIBUTE,
282 new BasicAttributes( "registeredAddress", "100 Park Ave.", true ) );
283
284
285 createUser( "billyd", "billyd" );
286
287
288 assertFalse( checkCanModifyAs( "billyd", "billyd", "ou=testou", mods ) );
289
290
291
292 createAccessControlSubentry( "administratorModifyAdd",
293 "{ " +
294 "identificationTag \"addAci\", " +
295 "precedence 14, " +
296 "authenticationLevel none, " +
297 "itemOrUserFirst userFirst: { " +
298 "userClasses { userGroup { \"cn=Administrators,ou=groups,ou=system\" } }, " +
299 "userPermissions { " +
300 "{ protectedItems {entry}, grantsAndDenials { grantModify, grantBrowse } }, " +
301 "{ protectedItems {allAttributeValues {registeredAddress}}, grantsAndDenials { grantAdd } } " +
302 "} } }" );
303
304
305
306 assertFalse( checkCanModifyAs( "billyd", "billyd", "ou=testou", mods ) );
307
308
309 addUserToGroup( "billyd", "Administrators" );
310
311
312 assertTrue( checkCanModifyAs( "billyd", "billyd", "ou=testou", mods ) );
313 deleteAccessControlSubentry( "administratorModifyAdd" );
314
315
316
317
318
319
320 mods = toItems( DirContext.REMOVE_ATTRIBUTE,
321 new BasicAttributes( "telephoneNumber", "867-5309", true ) );
322
323
324 assertFalse( checkCanModifyAs( "billyd", "billyd", "ou=testou", mods ) );
325
326
327
328 createAccessControlSubentry( "administratorModifyRemove", "{ " +
329 "identificationTag \"addAci\", " +
330 "precedence 14, " +
331 "authenticationLevel none, " +
332 "itemOrUserFirst userFirst: { " +
333 "userClasses { userGroup { \"cn=Administrators,ou=groups,ou=system\" } }, " +
334 "userPermissions { " +
335 "{ protectedItems {entry}, grantsAndDenials { grantModify, grantBrowse } }, " +
336 "{ protectedItems {allAttributeValues {telephoneNumber}}, grantsAndDenials { grantRemove } } " +
337 "} } }" );
338
339
340 assertTrue( checkCanModifyAs( "billyd", "billyd", "ou=testou", mods ) );
341 deleteAccessControlSubentry( "administratorModifyRemove" );
342
343
344
345
346
347
348 mods = toItems( DirContext.REPLACE_ATTRIBUTE,
349 new BasicAttributes( "telephoneNumber", "867-5309", true ) );
350
351
352 assertFalse( checkCanModifyAs( "billyd", "billyd", "ou=testou", mods ) );
353
354
355
356 createAccessControlSubentry( "administratorModifyReplace", "{ " +
357 "identificationTag \"addAci\", " +
358 "precedence 14, " +
359 "authenticationLevel none, " +
360 "itemOrUserFirst userFirst: { " +
361 "userClasses { userGroup { \"cn=Administrators,ou=groups,ou=system\" } }, " +
362 "userPermissions { " +
363 "{ protectedItems {entry}, grantsAndDenials { grantModify, grantBrowse } }, " +
364 "{ protectedItems {allAttributeValues {telephoneNumber}}, grantsAndDenials { grantAdd, grantRemove } } " +
365 "} } }" );
366
367
368 assertTrue( checkCanModifyAs( "billyd", "billyd", "ou=testou", mods ) );
369 deleteAccessControlSubentry( "administratorModifyReplace" );
370
371
372
373
374
375
376
377
378
379
380 Attributes changes = new BasicAttributes( "registeredAddress", "100 Park Ave.", true );
381
382
383 assertFalse( checkCanModifyAs( "billyd", "billyd", "ou=testou", DirContext.ADD_ATTRIBUTE, changes ) );
384
385
386
387 createAccessControlSubentry( "administratorModifyAdd", "{ " +
388 "identificationTag \"addAci\", " +
389 "precedence 14, " +
390 "authenticationLevel none, " +
391 "itemOrUserFirst userFirst: { " +
392 "userClasses { userGroup { \"cn=Administrators,ou=groups,ou=system\" } }, " +
393 "userPermissions { " +
394 "{ protectedItems {entry}, grantsAndDenials { grantModify, grantBrowse } }, " +
395 "{ protectedItems {allAttributeValues {registeredAddress}}, grantsAndDenials { grantAdd } } " +
396 "} } }" );
397
398
399 assertTrue( checkCanModifyAs( "billyd", "billyd", "ou=testou", DirContext.ADD_ATTRIBUTE, changes ) );
400 deleteAccessControlSubentry( "administratorModifyAdd" );
401
402
403
404
405
406
407 changes = new BasicAttributes( "telephoneNumber", "867-5309", true );
408
409
410 assertFalse( checkCanModifyAs( "billyd", "billyd", "ou=testou", DirContext.REMOVE_ATTRIBUTE, changes ) );
411
412
413
414 createAccessControlSubentry( "administratorModifyRemove", "{ " +
415 "identificationTag \"addAci\", " +
416 "precedence 14, " +
417 "authenticationLevel none, " +
418 "itemOrUserFirst userFirst: { " +
419 "userClasses { userGroup { \"cn=Administrators,ou=groups,ou=system\" } }, " +
420 "userPermissions { " +
421 "{ protectedItems {entry}, grantsAndDenials { grantModify, grantBrowse } }, " +
422 "{ protectedItems {allAttributeValues {telephoneNumber}}, grantsAndDenials { grantRemove } } " +
423 "} } }" );
424
425
426 assertTrue( checkCanModifyAs( "billyd", "billyd", "ou=testou", DirContext.REMOVE_ATTRIBUTE, changes ) );
427 deleteAccessControlSubentry( "administratorModifyRemove" );
428
429
430
431
432
433
434 changes = new BasicAttributes( "telephoneNumber", "867-5309", true );
435
436
437 assertFalse( checkCanModifyAs( "billyd", "billyd", "ou=testou", DirContext.REPLACE_ATTRIBUTE, changes ) );
438
439
440
441 createAccessControlSubentry( "administratorModifyReplace", "{ " +
442 "identificationTag \"addAci\", " +
443 "precedence 14, " +
444 "authenticationLevel none, " +
445 "itemOrUserFirst userFirst: { " +
446 "userClasses { userGroup { \"cn=Administrators,ou=groups,ou=system\" } }, " +
447 "userPermissions { " +
448 "{ protectedItems {entry}, grantsAndDenials { grantModify, grantBrowse } }, " +
449 "{ protectedItems {allAttributeValues {telephoneNumber}}, grantsAndDenials { grantAdd, grantRemove } } " +
450 "} } }" );
451
452
453 assertTrue( checkCanModifyAs( "billyd", "billyd", "ou=testou", DirContext.REPLACE_ATTRIBUTE, changes ) );
454 deleteAccessControlSubentry( "administratorModifyReplace" );
455 }
456
457
458 /***
459 // * Checks to make sure name based userClass works for modify operations.
460 // *
461 // * @throws javax.naming.NamingException if the test encounters an error
462 // */
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487 /***
488 // * Checks to make sure subtree based userClass works for modify operations.
489 // *
490 // * @throws javax.naming.NamingException if the test encounters an error
491 // */
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516 /***
517 // * Checks to make sure <b>allUsers</b> userClass works for modify operations.
518 // *
519 // * @throws javax.naming.NamingException if the test encounters an error
520 // */
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544 }