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.server.DirectoryServiceConfiguration;
21 import org.apache.ldap.server.enumeration.SearchResultFilter;
22 import org.apache.ldap.server.enumeration.SearchResultFilteringEnumeration;
23 import org.apache.ldap.server.interceptor.BaseInterceptor;
24 import org.apache.ldap.server.interceptor.NextInterceptor;
25 import org.apache.ldap.server.interceptor.InterceptorChain;
26 import org.apache.ldap.server.jndi.ServerContext;
27 import org.apache.ldap.server.jndi.ServerLdapContext;
28 import org.apache.ldap.server.configuration.InterceptorConfiguration;
29 import org.apache.ldap.server.partition.DirectoryPartitionNexus;
30 import org.apache.ldap.server.partition.DirectoryPartitionNexusProxy;
31 import org.apache.ldap.server.authz.support.ACDFEngine;
32 import org.apache.ldap.server.invocation.InvocationStack;
33 import org.apache.ldap.server.invocation.Invocation;
34 import org.apache.ldap.server.authn.LdapPrincipal;
35 import org.apache.ldap.server.schema.ConcreteNameComponentNormalizer;
36 import org.apache.ldap.server.schema.AttributeTypeRegistry;
37 import org.apache.ldap.server.subtree.SubentryService;
38 import org.apache.ldap.common.filter.ExprNode;
39 import org.apache.ldap.common.aci.MicroOperation;
40 import org.apache.ldap.common.aci.ACIItemParser;
41 import org.apache.ldap.common.aci.ACIItem;
42 import org.apache.ldap.common.exception.LdapNamingException;
43 import org.apache.ldap.common.message.ResultCodeEnum;
44 import org.apache.ldap.common.name.DnParser;
45
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 import javax.naming.Name;
50 import javax.naming.NamingException;
51 import javax.naming.NamingEnumeration;
52 import javax.naming.directory.*;
53 import java.util.*;
54 import java.text.ParseException;
55
56
57 /***
58 * An ACI based authorization service.
59 *
60 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
61 * @version $Rev: 327983 $
62 */
63 public class AuthorizationService extends BaseInterceptor
64 {
65 /*** the logger for this class */
66 private static final Logger log = LoggerFactory.getLogger( AuthorizationService.class );
67 /*** the entry ACI attribute string: entryACI */
68 private static final String ENTRYACI_ATTR = "entryACI";
69 /*** the subentry ACI attribute string: subentryACI */
70 private static final String SUBENTRYACI_ATTR = "subentryACI";
71 /***
72 * the multivalued op attr used to track the perscriptive access control
73 * subentries that apply to an entry.
74 */
75 private static final String AC_SUBENTRY_ATTR = "accessControlSubentries";
76
77 private static final Collection ADD_PERMS;
78 private static final Collection READ_PERMS;
79 private static final Collection COMPARE_PERMS;
80 private static final Collection SEARCH_ENTRY_PERMS;
81 private static final Collection SEARCH_ATTRVAL_PERMS;
82 private static final Collection REMOVE_PERMS;
83 private static final Collection MATCHEDNAME_PERMS;
84 private static final Collection BROWSE_PERMS;
85 private static final Collection LOOKUP_PERMS;
86 private static final Collection REPLACE_PERMS;
87 private static final Collection RENAME_PERMS;
88 private static final Collection EXPORT_PERMS;
89 private static final Collection IMPORT_PERMS;
90 private static final Collection MOVERENAME_PERMS;
91
92
93 static
94 {
95 HashSet set = new HashSet( 2 );
96 set.add( MicroOperation.BROWSE );
97 set.add( MicroOperation.RETURN_DN );
98 SEARCH_ENTRY_PERMS = Collections.unmodifiableCollection( set );
99
100 set = new HashSet( 2 );
101 set.add( MicroOperation.READ );
102 set.add( MicroOperation.BROWSE );
103 LOOKUP_PERMS = Collections.unmodifiableCollection( set );
104
105 set = new HashSet( 2 );
106 set.add( MicroOperation.ADD );
107 set.add( MicroOperation.REMOVE );
108 REPLACE_PERMS = Collections.unmodifiableCollection( set );
109
110 set = new HashSet( 3 );
111 set.add( MicroOperation.IMPORT );
112 set.add( MicroOperation.EXPORT );
113 set.add( MicroOperation.RENAME );
114 MOVERENAME_PERMS = Collections.unmodifiableCollection( set );
115
116 SEARCH_ATTRVAL_PERMS = Collections.singleton( MicroOperation.READ );
117 ADD_PERMS = Collections.singleton( MicroOperation.ADD );
118 READ_PERMS = Collections.singleton( MicroOperation.READ );
119 COMPARE_PERMS = Collections.singleton( MicroOperation.COMPARE );
120 REMOVE_PERMS = Collections.singleton( MicroOperation.REMOVE );
121 MATCHEDNAME_PERMS = Collections.singleton( MicroOperation.DISCLOSE_ON_ERROR );
122 BROWSE_PERMS = Collections.singleton( MicroOperation.BROWSE );
123 RENAME_PERMS = Collections.singleton( MicroOperation.RENAME );
124 EXPORT_PERMS = Collections.singleton( MicroOperation.EXPORT );
125 IMPORT_PERMS = Collections.singleton( MicroOperation.IMPORT );
126 }
127
128 /*** a tupleCache that responds to add, delete, and modify attempts */
129 private TupleCache tupleCache;
130 /*** a groupCache that responds to add, delete, and modify attempts */
131 private GroupCache groupCache;
132 /*** a normalizing ACIItem parser */
133 private ACIItemParser aciParser;
134 /*** use and instance of the ACDF engine */
135 private ACDFEngine engine;
136 /*** interceptor chain */
137 private InterceptorChain chain;
138 /*** attribute type registry */
139 private AttributeTypeRegistry attrRegistry;
140 /*** whether or not this interceptor is activated */
141 private boolean enabled = false;
142
143
144 /***
145 * Initializes this interceptor based service by getting a handle on the nexus, setting up
146 * the tupe and group membership caches and the ACIItem parser and the ACDF engine.
147 *
148 * @param factoryCfg the ContextFactory configuration for the server
149 * @param cfg the interceptor configuration
150 * @throws NamingException if there are problems during initialization
151 */
152 public void init( DirectoryServiceConfiguration factoryCfg, InterceptorConfiguration cfg ) throws NamingException
153 {
154 super.init( factoryCfg, cfg );
155 tupleCache = new TupleCache( factoryCfg );
156 groupCache = new GroupCache( factoryCfg );
157 attrRegistry = factoryCfg.getGlobalRegistries().getAttributeTypeRegistry();
158 aciParser = new ACIItemParser( new ConcreteNameComponentNormalizer( attrRegistry ) );
159 engine = new ACDFEngine( factoryCfg.getGlobalRegistries().getOidRegistry(), attrRegistry );
160 chain = factoryCfg.getInterceptorChain();
161 enabled = factoryCfg.getStartupConfiguration().isAccessControlEnabled();
162 }
163
164
165 /***
166 * Adds perscriptiveACI tuples to a collection of tuples by accessing the
167 * tupleCache. The tuple cache is accessed for each A/C subentry
168 * associated with the protected entry. Note that subentries are handled
169 * differently: their parent, the administrative entry is accessed to
170 * determine the perscriptiveACIs effecting the AP and hence the subentry
171 * which is considered to be in the same context.
172 *
173 * @param tuples the collection of tuples to add to
174 * @param dn the normalized distinguished name of the protected entry
175 * @param entry the target entry that access to is being controled
176 * @throws NamingException if there are problems accessing attribute values
177 */
178 private void addPerscriptiveAciTuples( DirectoryPartitionNexusProxy proxy, Collection tuples,
179 Name dn, Attributes entry )
180 throws NamingException
181 {
182
183
184
185
186
187
188
189
190
191 if ( entry.get( "objectClass" ).contains( "subentry" ) )
192 {
193 Name parentDn = ( Name ) dn.clone();
194 parentDn.remove( dn.size() - 1 );
195 entry = proxy.lookup( parentDn, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
196 }
197
198 Attribute subentries = entry.get( AC_SUBENTRY_ATTR );
199 if ( subentries == null )
200 {
201 return;
202 }
203 for ( int ii = 0; ii < subentries.size(); ii++ )
204 {
205 String subentryDn = ( String ) subentries.get( ii );
206 tuples.addAll( tupleCache.getACITuples( subentryDn ) );
207 }
208 }
209
210
211 /***
212 * Adds the set of entryACI tuples to a collection of tuples. The entryACI
213 * is parsed and tuples are generated on they fly then added to the collection.
214 *
215 * @param tuples the collection of tuples to add to
216 * @param entry the target entry that access to is being regulated
217 * @throws NamingException if there are problems accessing attribute values
218 */
219 private void addEntryAciTuples( Collection tuples, Attributes entry ) throws NamingException
220 {
221 Attribute entryAci = entry.get( ENTRYACI_ATTR );
222 if ( entryAci == null )
223 {
224 return;
225 }
226
227 for ( int ii = 0; ii < entryAci.size(); ii++ )
228 {
229 String aciString = ( String ) entryAci.get( ii );
230 ACIItem item;
231
232 try
233 {
234 item = aciParser.parse( aciString );
235 }
236 catch ( ParseException e )
237 {
238 String msg = "failed to parse entryACI: " + aciString ;
239 log.error( msg, e );
240 throw new LdapNamingException( msg, ResultCodeEnum.OPERATIONSERROR );
241 }
242
243 tuples.addAll( item.toTuples() );
244 }
245 }
246
247
248 /***
249 * Adds the set of subentryACI tuples to a collection of tuples. The subentryACI
250 * is parsed and tuples are generated on the fly then added to the collection.
251 *
252 * @param tuples the collection of tuples to add to
253 * @param dn the normalized distinguished name of the protected entry
254 * @param entry the target entry that access to is being regulated
255 * @throws NamingException if there are problems accessing attribute values
256 */
257 private void addSubentryAciTuples( DirectoryPartitionNexusProxy proxy, Collection tuples,
258 Name dn, Attributes entry ) throws NamingException
259 {
260
261 if ( ! entry.get("objectClass").contains("subentry") )
262 {
263 return;
264 }
265
266
267
268 Name parentDn = ( Name ) dn.clone();
269 parentDn.remove( dn.size() - 1 );
270 Attributes administrativeEntry = proxy.lookup( parentDn, new String[] { SUBENTRYACI_ATTR },
271 DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
272 Attribute subentryAci = administrativeEntry.get( SUBENTRYACI_ATTR );
273
274 if ( subentryAci == null )
275 {
276 return;
277 }
278
279 for ( int ii = 0; ii < subentryAci.size(); ii++ )
280 {
281 String aciString = ( String ) subentryAci.get( ii );
282 ACIItem item;
283
284 try
285 {
286 item = aciParser.parse( aciString );
287 }
288 catch ( ParseException e )
289 {
290 String msg = "failed to parse subentryACI: " + aciString ;
291 log.error( msg, e );
292 throw new LdapNamingException( msg, ResultCodeEnum.OPERATIONSERROR );
293 }
294
295 tuples.addAll( item.toTuples() );
296 }
297 }
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321 public void add( NextInterceptor next, String upName, Name normName, Attributes entry ) throws NamingException
322 {
323
324 Invocation invocation = InvocationStack.getInstance().peek();
325 LdapPrincipal user = ( ( ServerContext ) invocation.getCaller() ).getPrincipal();
326
327
328 if ( ! enabled )
329 {
330 next.add( upName, normName, entry );
331 return;
332 }
333
334
335 if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) )
336 {
337 next.add( upName, normName, entry );
338 tupleCache.subentryAdded( upName, normName, entry );
339 groupCache.groupAdded( upName, normName, entry );
340 return;
341 }
342
343
344 SubentryService subentryService = ( SubentryService ) chain.get( "subentryService" );
345 Attributes subentryAttrs = subentryService.getSubentryAttributes( normName, entry );
346 NamingEnumeration attrList = entry.getAll();
347 while( attrList.hasMore() )
348 {
349 subentryAttrs.put( ( Attribute ) attrList.next() );
350 }
351
352
353 Set userGroups = groupCache.getGroups( user.getName() );
354 Collection tuples = new HashSet();
355
356
357
358 addPerscriptiveAciTuples( invocation.getProxy(), tuples, normName, subentryAttrs );
359 addSubentryAciTuples( invocation.getProxy(), tuples, normName, subentryAttrs );
360
361
362 DirectoryPartitionNexusProxy proxy = invocation.getProxy();
363 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(),
364 normName, null, null, ADD_PERMS, tuples, subentryAttrs );
365
366
367 NamingEnumeration attributeList = entry.getAll();
368 while ( attributeList.hasMore() )
369 {
370 Attribute attr = ( Attribute ) attributeList.next();
371 for ( int ii = 0; ii < attr.size(); ii++ )
372 {
373 engine.checkPermission( proxy, userGroups, user.getJndiName(),
374 user.getAuthenticationLevel(), normName, attr.getID(),
375 attr.get( ii ), ADD_PERMS, tuples, entry );
376 }
377 }
378
379
380 next.add( upName, normName, entry );
381
382
383
384 tupleCache.subentryAdded( upName, normName, entry );
385 groupCache.groupAdded( upName, normName, entry );
386 }
387
388
389 public void delete( NextInterceptor next, Name name ) throws NamingException
390 {
391
392 Invocation invocation = InvocationStack.getInstance().peek();
393 DirectoryPartitionNexusProxy proxy = invocation.getProxy();
394 Attributes entry = proxy.lookup( name, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
395 LdapPrincipal user = ( ( ServerContext ) invocation.getCaller() ).getPrincipal();
396
397
398 if ( ! enabled )
399 {
400 next.delete( name );
401 return;
402 }
403
404
405 if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) )
406 {
407 next.delete( name );
408 tupleCache.subentryDeleted( name, entry );
409 groupCache.groupDeleted( name, entry );
410 return;
411 }
412
413 Set userGroups = groupCache.getGroups( user.getName() );
414 Collection tuples = new HashSet();
415 addPerscriptiveAciTuples( proxy, tuples, name, entry );
416 addEntryAciTuples( tuples, entry );
417 addSubentryAciTuples( proxy, tuples, name, entry );
418
419 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
420 null, REMOVE_PERMS, tuples, entry );
421
422 next.delete( name );
423 tupleCache.subentryDeleted( name, entry );
424 groupCache.groupDeleted( name, entry );
425 }
426
427
428 public void modify( NextInterceptor next, Name name, int modOp, Attributes mods ) throws NamingException
429 {
430
431 Invocation invocation = InvocationStack.getInstance().peek();
432 DirectoryPartitionNexusProxy proxy = invocation.getProxy();
433 Attributes entry = proxy.lookup( name, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
434 LdapPrincipal user = ( ( ServerContext ) invocation.getCaller() ).getPrincipal();
435
436
437 if ( ! enabled )
438 {
439 next.modify( name, modOp, mods );
440 return;
441 }
442
443
444 if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) )
445 {
446 next.modify( name, modOp, mods );
447 tupleCache.subentryModified( name, modOp, mods, entry );
448 groupCache.groupModified( name, modOp, mods, entry );
449 return;
450 }
451
452 Set userGroups = groupCache.getGroups( user.getName() );
453 Collection tuples = new HashSet();
454 addPerscriptiveAciTuples( proxy, tuples, name, entry );
455 addEntryAciTuples( tuples, entry );
456 addSubentryAciTuples( proxy, tuples, name, entry );
457
458 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
459 null, Collections.singleton( MicroOperation.MODIFY ), tuples, entry );
460
461 NamingEnumeration attrList = mods.getAll();
462 Collection perms = null;
463 switch( modOp )
464 {
465 case( DirContext.ADD_ATTRIBUTE ):
466 perms = ADD_PERMS;
467 break;
468 case( DirContext.REMOVE_ATTRIBUTE ):
469 perms = REMOVE_PERMS;
470 break;
471 case( DirContext.REPLACE_ATTRIBUTE ):
472 perms = REPLACE_PERMS;
473 break;
474 }
475
476 while( attrList.hasMore() )
477 {
478 Attribute attr = ( Attribute ) attrList.next();
479 for ( int ii = 0; ii < attr.size(); ii++ )
480 {
481 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(),
482 name, attr.getID(), attr.get( ii ), perms, tuples, entry );
483 }
484 }
485
486 next.modify( name, modOp, mods );
487 tupleCache.subentryModified( name, modOp, mods, entry );
488 groupCache.groupModified( name, modOp, mods, entry );
489 }
490
491
492 public void modify( NextInterceptor next, Name name, ModificationItem[] mods ) throws NamingException
493 {
494
495 Invocation invocation = InvocationStack.getInstance().peek();
496 DirectoryPartitionNexusProxy proxy = invocation.getProxy();
497 Attributes entry = proxy.lookup( name, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
498 LdapPrincipal user = ( ( ServerContext ) invocation.getCaller() ).getPrincipal();
499
500
501 if ( ! enabled )
502 {
503 next.modify( name, mods );
504 return;
505 }
506
507
508 if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) )
509 {
510 next.modify( name, mods );
511 tupleCache.subentryModified( name, mods, entry );
512 groupCache.groupModified( name, mods, entry );
513 return;
514 }
515
516 Set userGroups = groupCache.getGroups( user.getName() );
517 Collection tuples = new HashSet();
518 addPerscriptiveAciTuples( proxy, tuples, name, entry );
519 addEntryAciTuples( tuples, entry );
520 addSubentryAciTuples( proxy, tuples, name, entry );
521
522 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
523 null, Collections.singleton( MicroOperation.MODIFY ), tuples, entry );
524
525 Collection perms = null;
526 for ( int ii = 0; ii < mods.length; ii++ )
527 {
528 switch( mods[ii].getModificationOp() )
529 {
530 case( DirContext.ADD_ATTRIBUTE ):
531 perms = ADD_PERMS;
532 break;
533 case( DirContext.REMOVE_ATTRIBUTE ):
534 perms = REMOVE_PERMS;
535 break;
536 case( DirContext.REPLACE_ATTRIBUTE ):
537 perms = REPLACE_PERMS;
538 break;
539 }
540
541 Attribute attr = mods[ii].getAttribute();
542 for ( int jj = 0; jj < attr.size(); jj++ )
543 {
544 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(),
545 name, attr.getID(), attr.get( jj ), perms, tuples, entry );
546 }
547 }
548
549 next.modify( name, mods );
550 tupleCache.subentryModified( name, mods, entry );
551 groupCache.groupModified( name, mods, entry );
552 }
553
554
555 public boolean hasEntry( NextInterceptor next, Name name ) throws NamingException
556 {
557 Invocation invocation = InvocationStack.getInstance().peek();
558 DirectoryPartitionNexusProxy proxy = invocation.getProxy();
559 Attributes entry = proxy.lookup( name, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
560 LdapPrincipal user = ( ( ServerContext ) invocation.getCaller() ).getPrincipal();
561
562 if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) || ! enabled )
563 {
564 return next.hasEntry( name );
565 }
566
567 Set userGroups = groupCache.getGroups( user.getName() );
568 Collection tuples = new HashSet();
569 addPerscriptiveAciTuples( proxy, tuples, name, entry );
570 addEntryAciTuples( tuples, entry );
571 addSubentryAciTuples( proxy, tuples, name, entry );
572
573
574 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
575 null, BROWSE_PERMS, tuples, entry );
576
577 return next.hasEntry( name );
578 }
579
580
581 /***
582 * Checks if the READ permissions exist to the entry and to each attribute type and
583 * value.
584 *
585 * @todo not sure if we should hide attribute types/values or throw an exception
586 * instead. I think we're going to have to use a filter to restrict the return
587 * of attribute types and values instead of throwing an exception. Lack of read
588 * perms to attributes and their values results in their removal when returning
589 * the entry.
590 *
591 * @param user the user associated with the call
592 * @param dn the name of the entry being looked up
593 * @param entry the raw entry pulled from the nexus
594 * @throws NamingException
595 */
596 private void checkLookupAccess( LdapPrincipal user, Name dn, Attributes entry )
597 throws NamingException
598 {
599 DirectoryPartitionNexusProxy proxy = InvocationStack.getInstance().peek().getProxy();
600 Set userGroups = groupCache.getGroups( user.getName() );
601 Collection tuples = new HashSet();
602 addPerscriptiveAciTuples( proxy, tuples, dn, entry );
603 addEntryAciTuples( tuples, entry );
604 addSubentryAciTuples( proxy, tuples, dn, entry );
605
606
607 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(), dn, null,
608 null, LOOKUP_PERMS, tuples, entry );
609
610
611 NamingEnumeration attributeList = entry.getAll();
612 while ( attributeList.hasMore() )
613 {
614 Attribute attr = ( Attribute ) attributeList.next();
615 for ( int ii = 0; ii < attr.size(); ii++ )
616 {
617 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(), dn,
618 attr.getID(), attr.get( ii ), READ_PERMS, tuples, entry );
619 }
620 }
621 }
622
623
624 public Attributes lookup( NextInterceptor next, Name dn, String[] attrIds ) throws NamingException
625 {
626 Invocation invocation = InvocationStack.getInstance().peek();
627 DirectoryPartitionNexusProxy proxy = invocation.getProxy();
628 Attributes entry = proxy.lookup( dn, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
629 LdapPrincipal user = ( ( ServerContext ) invocation.getCaller() ).getPrincipal();
630
631 if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) || ! enabled )
632 {
633 return next.lookup( dn, attrIds );
634 }
635
636 checkLookupAccess( user, dn, entry );
637
638 return next.lookup( dn, attrIds );
639 }
640
641
642 public Attributes lookup( NextInterceptor next, Name name ) throws NamingException
643 {
644 Invocation invocation = InvocationStack.getInstance().peek();
645 DirectoryPartitionNexusProxy proxy = invocation.getProxy();
646 Attributes entry = proxy.lookup( name, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
647 LdapPrincipal user = ( ( ServerContext ) invocation.getCaller() ).getPrincipal();
648
649 if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) || ! enabled )
650 {
651 return next.lookup( name );
652 }
653
654 checkLookupAccess( user, name, entry );
655
656 return next.lookup( name );
657 }
658
659
660 public void modifyRn( NextInterceptor next, Name name, String newRn, boolean deleteOldRn ) throws NamingException
661 {
662
663 Invocation invocation = InvocationStack.getInstance().peek();
664 DirectoryPartitionNexusProxy proxy = invocation.getProxy();
665 Attributes entry = proxy.lookup( name, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
666 LdapPrincipal user = ( ( ServerContext ) invocation.getCaller() ).getPrincipal();
667 Name newName = ( Name ) name.clone();
668 newName.remove( name.size() - 1 );
669 newName.add( newRn );
670
671
672
673 if ( ! enabled )
674 {
675 next.modifyRn( name, newRn, deleteOldRn );
676 return;
677 }
678
679
680 if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) )
681 {
682 next.modifyRn( name, newRn, deleteOldRn );
683 tupleCache.subentryRenamed( name, newName );
684 groupCache.groupRenamed( name, newName );
685 return;
686 }
687
688 Set userGroups = groupCache.getGroups( user.getName() );
689 Collection tuples = new HashSet();
690 addPerscriptiveAciTuples( proxy, tuples, name, entry );
691 addEntryAciTuples( tuples, entry );
692 addSubentryAciTuples( proxy, tuples, name, entry );
693
694 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
695 null, RENAME_PERMS, tuples, entry );
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724 next.modifyRn( name, newRn, deleteOldRn );
725 tupleCache.subentryRenamed( name, newName );
726 groupCache.groupRenamed( name, newName );
727 }
728
729
730 public void move( NextInterceptor next, Name oriChildName, Name newParentName, String newRn, boolean deleteOldRn )
731 throws NamingException
732 {
733
734 Invocation invocation = InvocationStack.getInstance().peek();
735 DirectoryPartitionNexusProxy proxy = invocation.getProxy();
736 Attributes entry = proxy.lookup( oriChildName, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
737 LdapPrincipal user = ( ( ServerContext ) invocation.getCaller() ).getPrincipal();
738 Name newName = ( Name ) newParentName.clone();
739 newName.add( newRn );
740
741
742 if ( ! enabled )
743 {
744 next.move( oriChildName, newParentName, newRn, deleteOldRn );
745 return;
746 }
747
748
749 if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) )
750 {
751 next.move( oriChildName, newParentName, newRn, deleteOldRn );
752 tupleCache.subentryRenamed( oriChildName, newName );
753 groupCache.groupRenamed( oriChildName, newName );
754 return;
755 }
756
757 Set userGroups = groupCache.getGroups( user.getName() );
758 Collection tuples = new HashSet();
759 addPerscriptiveAciTuples( proxy, tuples, oriChildName, entry );
760 addEntryAciTuples( tuples, entry );
761 addSubentryAciTuples( proxy, tuples, oriChildName, entry );
762
763 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(),
764 oriChildName, null, null, MOVERENAME_PERMS, tuples, entry );
765
766 Collection destTuples = new HashSet();
767 addPerscriptiveAciTuples( proxy, destTuples, oriChildName, entry );
768 addEntryAciTuples( destTuples, entry );
769 addSubentryAciTuples( proxy, destTuples, oriChildName, entry );
770 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(),
771 oriChildName, null, null, IMPORT_PERMS, tuples, entry );
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800 next.move( oriChildName, newParentName, newRn, deleteOldRn );
801 tupleCache.subentryRenamed( oriChildName, newName );
802 groupCache.groupRenamed( oriChildName, newName );
803 }
804
805
806 public void move( NextInterceptor next, Name oriChildName, Name newParentName ) throws NamingException
807 {
808
809 Invocation invocation = InvocationStack.getInstance().peek();
810 DirectoryPartitionNexusProxy proxy = invocation.getProxy();
811 Attributes entry = proxy.lookup( oriChildName, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
812 Name newName = ( Name ) newParentName.clone();
813 newName.add( oriChildName.get( oriChildName.size() - 1 ) );
814 LdapPrincipal user = ( ( ServerContext ) invocation.getCaller() ).getPrincipal();
815
816
817 if ( ! enabled )
818 {
819 next.move( oriChildName, newParentName );
820 return;
821 }
822
823
824 if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) )
825 {
826 next.move( oriChildName, newParentName );
827 tupleCache.subentryRenamed( oriChildName, newName );
828 groupCache.groupRenamed( oriChildName, newName );
829 return;
830 }
831
832 Set userGroups = groupCache.getGroups( user.getName() );
833 Collection tuples = new HashSet();
834 addPerscriptiveAciTuples( proxy, tuples, oriChildName, entry );
835 addEntryAciTuples( tuples, entry );
836 addSubentryAciTuples( proxy, tuples, oriChildName, entry );
837
838 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(),
839 oriChildName, null, null, EXPORT_PERMS, tuples, entry );
840
841 Collection destTuples = new HashSet();
842 addPerscriptiveAciTuples( proxy, destTuples, oriChildName, entry );
843 addEntryAciTuples( destTuples, entry );
844 addSubentryAciTuples( proxy, destTuples, oriChildName, entry );
845 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(),
846 oriChildName, null, null, IMPORT_PERMS, tuples, entry );
847
848 next.move( oriChildName, newParentName );
849 tupleCache.subentryRenamed( oriChildName, newName );
850 groupCache.groupRenamed( oriChildName, newName );
851 }
852
853
854 public static final SearchControls DEFUALT_SEARCH_CONTROLS = new SearchControls();
855
856 public NamingEnumeration list( NextInterceptor next, Name base ) throws NamingException
857 {
858 Invocation invocation = InvocationStack.getInstance().peek();
859 ServerLdapContext ctx = ( ServerLdapContext ) invocation.getCaller();
860 LdapPrincipal user = ctx.getPrincipal();
861 NamingEnumeration e = next.list( base );
862 if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) || ! enabled )
863 {
864 return e;
865 }
866 AuthorizationFilter authzFilter = new AuthorizationFilter();
867 return new SearchResultFilteringEnumeration( e, DEFUALT_SEARCH_CONTROLS, invocation, authzFilter );
868 }
869
870
871 public NamingEnumeration search( NextInterceptor next, Name base, Map env, ExprNode filter,
872 SearchControls searchCtls ) throws NamingException
873 {
874 Invocation invocation = InvocationStack.getInstance().peek();
875 ServerLdapContext ctx = ( ServerLdapContext ) invocation.getCaller();
876 LdapPrincipal user = ctx.getPrincipal();
877 NamingEnumeration e = next.search( base, env, filter, searchCtls );
878 if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) || ! enabled )
879 {
880 return e;
881 }
882 AuthorizationFilter authzFilter = new AuthorizationFilter();
883 return new SearchResultFilteringEnumeration( e, searchCtls, invocation, authzFilter );
884 }
885
886
887 public boolean compare( NextInterceptor next, Name name, String oid, Object value ) throws NamingException
888 {
889
890 Invocation invocation = InvocationStack.getInstance().peek();
891 DirectoryPartitionNexusProxy proxy = invocation.getProxy();
892 Attributes entry = proxy.lookup( name, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
893 LdapPrincipal user = ( ( ServerContext ) invocation.getCaller() ).getPrincipal();
894 if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) || ! enabled )
895 {
896 return next.compare( name, oid, value );
897 }
898
899 Set userGroups = groupCache.getGroups( user.getName() );
900 Collection tuples = new HashSet();
901 addPerscriptiveAciTuples( proxy, tuples, name, entry );
902 addEntryAciTuples( tuples, entry );
903 addSubentryAciTuples( proxy, tuples, name, entry );
904
905 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, null,
906 null, READ_PERMS, tuples, entry );
907 engine.checkPermission( proxy, userGroups, user.getJndiName(), user.getAuthenticationLevel(), name, oid,
908 value, COMPARE_PERMS, tuples, entry );
909
910 return next.compare( name, oid, value );
911 }
912
913
914 public Name getMatchedName( NextInterceptor next, Name dn, boolean normalized ) throws NamingException
915 {
916
917 Invocation invocation = InvocationStack.getInstance().peek();
918 DirectoryPartitionNexusProxy proxy = invocation.getProxy();
919 LdapPrincipal user = ( ( ServerContext ) invocation.getCaller() ).getPrincipal();
920 if ( user.getName().equalsIgnoreCase( DirectoryPartitionNexus.ADMIN_PRINCIPAL ) || ! enabled )
921 {
922 return next.getMatchedName( dn, normalized );
923 }
924
925
926 Attributes entry;
927 Name matched = next.getMatchedName( dn, normalized );
928
929
930
931
932 while ( matched.size() > 0 )
933 {
934 if ( normalized )
935 {
936 entry = proxy.lookup( matched, DirectoryPartitionNexusProxy.GETMATCHEDDN_BYPASS );
937 }
938 else
939 {
940 entry = proxy.lookup( matched, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
941 }
942
943 Set userGroups = groupCache.getGroups( user.getName() );
944 Collection tuples = new HashSet();
945 addPerscriptiveAciTuples( proxy, tuples, matched, entry );
946 addEntryAciTuples( tuples, entry );
947 addSubentryAciTuples( proxy, tuples, matched, entry );
948
949 if ( engine.hasPermission( proxy, userGroups, user.getJndiName(),
950 user.getAuthenticationLevel(), matched, null, null,
951 MATCHEDNAME_PERMS, tuples, entry ) )
952 {
953 return matched;
954 }
955
956 matched.remove( matched.size() - 1 );
957 }
958
959 return matched;
960 }
961
962
963 public void cacheNewGroup( String upName, Name normName, Attributes entry ) throws NamingException
964 {
965 this.groupCache.groupAdded( upName, normName, entry );
966 }
967
968
969 private boolean filter( Invocation invocation, Name normName, SearchResult result ) throws NamingException
970 {
971
972
973
974
975
976 Attributes entry = invocation.getProxy().lookup( normName, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
977 ServerLdapContext ctx = ( ServerLdapContext ) invocation.getCaller();
978 Name userDn = ctx.getPrincipal().getJndiName();
979 Set userGroups = groupCache.getGroups( userDn.toString() );
980 Collection tuples = new HashSet();
981 addPerscriptiveAciTuples( invocation.getProxy(), tuples, normName, entry );
982 addEntryAciTuples( tuples, entry );
983 addSubentryAciTuples( invocation.getProxy(), tuples, normName, entry );
984
985 if ( ! engine.hasPermission( invocation.getProxy(), userGroups, userDn,
986 ctx.getPrincipal().getAuthenticationLevel(),
987 normName, null, null, SEARCH_ENTRY_PERMS, tuples, entry ) )
988 {
989 return false;
990 }
991
992
993
994
995
996
997
998
999 NamingEnumeration idList = result.getAttributes().getIDs();
1000 while ( idList.hasMore() )
1001 {
1002
1003 String id = ( String ) idList.next();
1004 Attribute attr = result.getAttributes().get( id );
1005 if ( ! engine.hasPermission( invocation.getProxy(), userGroups, userDn,
1006 ctx.getPrincipal().getAuthenticationLevel(),
1007 normName, attr.getID(), null, SEARCH_ATTRVAL_PERMS, tuples, entry ) )
1008 {
1009 result.getAttributes().remove( attr.getID() );
1010
1011 if ( attr.size() == 0 )
1012 {
1013 result.getAttributes().remove( attr.getID() );
1014 }
1015 continue;
1016 }
1017
1018
1019 for ( int ii = 0; ii < attr.size(); ii++ )
1020 {
1021 if ( ! engine.hasPermission( invocation.getProxy(), userGroups, userDn,
1022 ctx.getPrincipal().getAuthenticationLevel(), normName,
1023 attr.getID(), attr.get( ii ), SEARCH_ATTRVAL_PERMS, tuples, entry ) )
1024 {
1025 attr.remove( ii );
1026
1027 if ( ii > 0 )
1028 {
1029 ii--;
1030 }
1031 }
1032 }
1033 }
1034
1035 return true;
1036 }
1037
1038
1039 /***
1040 * WARNING: create one of these filters fresh every time for each new search.
1041 */
1042 class AuthorizationFilter implements SearchResultFilter
1043 {
1044 /*** dedicated normalizing parser for this search - cheaper than synchronization */
1045 final DnParser parser;
1046
1047 public AuthorizationFilter() throws NamingException
1048 {
1049 parser = new DnParser( new ConcreteNameComponentNormalizer( attrRegistry ) );
1050 }
1051
1052
1053 public boolean accept( Invocation invocation, SearchResult result, SearchControls controls )
1054 throws NamingException
1055 {
1056 Name normName = parser.parse( result.getName() );
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067 return filter( invocation, normName, result );
1068 }
1069 }
1070 }