1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.core.admin;
21
22
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29 import java.util.concurrent.locks.ReentrantReadWriteLock;
30
31 import javax.naming.directory.SearchControls;
32
33 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
34 import org.apache.directory.api.ldap.model.entry.Attribute;
35 import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
36 import org.apache.directory.api.ldap.model.entry.Entry;
37 import org.apache.directory.api.ldap.model.entry.Modification;
38 import org.apache.directory.api.ldap.model.entry.Value;
39 import org.apache.directory.api.ldap.model.exception.LdapException;
40 import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
41 import org.apache.directory.api.ldap.model.exception.LdapNoSuchAttributeException;
42 import org.apache.directory.api.ldap.model.exception.LdapOperationException;
43 import org.apache.directory.api.ldap.model.exception.LdapOtherException;
44 import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
45 import org.apache.directory.api.ldap.model.filter.ExprNode;
46 import org.apache.directory.api.ldap.model.filter.PresenceNode;
47 import org.apache.directory.api.ldap.model.message.AliasDerefMode;
48 import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
49 import org.apache.directory.api.ldap.model.name.Dn;
50 import org.apache.directory.api.ldap.model.subtree.AdministrativeRole;
51 import org.apache.directory.api.ldap.util.tree.DnNode;
52 import org.apache.directory.api.util.Strings;
53 import org.apache.directory.server.core.api.CoreSession;
54 import org.apache.directory.server.core.api.DirectoryService;
55 import org.apache.directory.server.core.api.InterceptorEnum;
56 import org.apache.directory.server.core.api.administrative.AccessControlAAP;
57 import org.apache.directory.server.core.api.administrative.AccessControlAdministrativePoint;
58 import org.apache.directory.server.core.api.administrative.AccessControlIAP;
59 import org.apache.directory.server.core.api.administrative.AccessControlSAP;
60 import org.apache.directory.server.core.api.administrative.AdministrativePoint;
61 import org.apache.directory.server.core.api.administrative.CollectiveAttributeAAP;
62 import org.apache.directory.server.core.api.administrative.CollectiveAttributeAdministrativePoint;
63 import org.apache.directory.server.core.api.administrative.CollectiveAttributeIAP;
64 import org.apache.directory.server.core.api.administrative.CollectiveAttributeSAP;
65 import org.apache.directory.server.core.api.administrative.SubschemaAAP;
66 import org.apache.directory.server.core.api.administrative.SubschemaAdministrativePoint;
67 import org.apache.directory.server.core.api.administrative.SubschemaSAP;
68 import org.apache.directory.server.core.api.administrative.TriggerExecutionAAP;
69 import org.apache.directory.server.core.api.administrative.TriggerExecutionAdministrativePoint;
70 import org.apache.directory.server.core.api.administrative.TriggerExecutionIAP;
71 import org.apache.directory.server.core.api.administrative.TriggerExecutionSAP;
72 import org.apache.directory.server.core.api.entry.ClonedServerEntry;
73 import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
74 import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
75 import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
76 import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
77 import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
78 import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
79 import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
80 import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
81 import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
82 import org.apache.directory.server.core.api.partition.Partition;
83 import org.apache.directory.server.core.api.partition.PartitionNexus;
84 import org.apache.directory.server.core.api.partition.PartitionTxn;
85 import org.slf4j.Logger;
86 import org.slf4j.LoggerFactory;
87
88
89
90
91
92
93
94 public class AdministrativePointInterceptor extends BaseInterceptor
95 {
96
97 private static final Logger LOG = LoggerFactory.getLogger( AdministrativePointInterceptor.class );
98
99
100 private PartitionNexus nexus;
101
102
103 private static final Set<String> ROLES = new HashSet<>();
104
105
106 static
107 {
108 ROLES.add( Strings.toLowerCaseAscii( SchemaConstants.AUTONOMOUS_AREA ) );
109 ROLES.add( SchemaConstants.AUTONOMOUS_AREA_OID );
110 ROLES.add( Strings.toLowerCaseAscii( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA ) );
111 ROLES.add( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA_OID );
112 ROLES.add( Strings.toLowerCaseAscii( SchemaConstants.ACCESS_CONTROL_INNER_AREA ) );
113 ROLES.add( SchemaConstants.ACCESS_CONTROL_INNER_AREA_OID );
114 ROLES.add( Strings.toLowerCaseAscii( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA ) );
115 ROLES.add( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID );
116 ROLES.add( Strings.toLowerCaseAscii( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA ) );
117 ROLES.add( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA_OID );
118 ROLES.add( Strings.toLowerCaseAscii( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA ) );
119 ROLES.add( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA_OID );
120 ROLES.add( Strings.toLowerCaseAscii( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA ) );
121 ROLES.add( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID );
122 ROLES.add( Strings.toLowerCaseAscii( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA ) );
123 ROLES.add( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA_OID );
124 }
125
126
127 private static final Map<String, String> ROLES_OID = new HashMap<>();
128
129
130 static
131 {
132 ROLES_OID.put( Strings.toLowerCaseAscii( SchemaConstants.AUTONOMOUS_AREA ), SchemaConstants.AUTONOMOUS_AREA_OID );
133 ROLES_OID.put( Strings.toLowerCaseAscii( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA ),
134 SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA_OID );
135 ROLES_OID.put( Strings.toLowerCaseAscii( SchemaConstants.ACCESS_CONTROL_INNER_AREA ),
136 SchemaConstants.ACCESS_CONTROL_INNER_AREA_OID );
137 ROLES_OID.put( Strings.toLowerCaseAscii( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA ),
138 SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID );
139 ROLES_OID.put( Strings.toLowerCaseAscii( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA ),
140 SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA_OID );
141 ROLES_OID.put( Strings.toLowerCaseAscii( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA ),
142 SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA_OID );
143 ROLES_OID.put( Strings.toLowerCaseAscii( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA ),
144 SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID );
145 ROLES_OID.put( Strings.toLowerCaseAscii( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA ),
146 SchemaConstants.TRIGGER_EXECUTION_INNER_AREA_OID );
147 }
148
149
150 private static final Set<String> INNER_AREA_ROLES = new HashSet<>();
151
152 static
153 {
154 INNER_AREA_ROLES.add( Strings.toLowerCaseAscii( SchemaConstants.ACCESS_CONTROL_INNER_AREA ) );
155 INNER_AREA_ROLES.add( SchemaConstants.ACCESS_CONTROL_INNER_AREA_OID );
156 INNER_AREA_ROLES.add( Strings.toLowerCaseAscii( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA ) );
157 INNER_AREA_ROLES.add( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA_OID );
158 INNER_AREA_ROLES.add( Strings.toLowerCaseAscii( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA ) );
159 INNER_AREA_ROLES.add( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA_OID );
160 }
161
162
163 private static final Set<String> SPECIFIC_AREA_ROLES = new HashSet<>();
164
165 static
166 {
167 SPECIFIC_AREA_ROLES.add( Strings.toLowerCaseAscii( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA ) );
168 SPECIFIC_AREA_ROLES.add( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA_OID );
169 SPECIFIC_AREA_ROLES.add( Strings.toLowerCaseAscii( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA ) );
170 SPECIFIC_AREA_ROLES.add( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID );
171 SPECIFIC_AREA_ROLES.add( Strings.toLowerCaseAscii( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA ) );
172 SPECIFIC_AREA_ROLES.add( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA_OID );
173 SPECIFIC_AREA_ROLES.add( Strings.toLowerCaseAscii( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA ) );
174 SPECIFIC_AREA_ROLES.add( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID );
175 }
176
177
178 private ReentrantReadWriteLock mutex = new ReentrantReadWriteLock();
179
180
181
182
183
184 public AdministrativePointInterceptor()
185 {
186 super( InterceptorEnum.ADMINISTRATIVE_POINT_INTERCEPTOR );
187 }
188
189
190
191
192
193
194
195 public void lockRead()
196 {
197 mutex.readLock().lock();
198 }
199
200
201
202
203
204
205
206 public void lockWrite()
207 {
208 mutex.writeLock().lock();
209 }
210
211
212
213
214
215
216
217 public void unlock()
218 {
219 if ( mutex.isWriteLockedByCurrentThread() )
220 {
221 mutex.writeLock().unlock();
222 }
223 else
224 {
225 mutex.readLock().unlock();
226 }
227 }
228
229
230
231
232
233 private void createAdministrativePoints( Attribute adminPoint, Dn dn, String uuid ) throws LdapException
234 {
235 if ( isAAP( adminPoint ) )
236 {
237
238 AccessControlAdministrativePoint acAap = new AccessControlAAP( dn, uuid );
239 directoryService.getAccessControlAPCache().add( dn, acAap );
240
241
242 CollectiveAttributeAdministrativePoint caAap = new CollectiveAttributeAAP( dn, uuid );
243 directoryService.getCollectiveAttributeAPCache().add( dn, caAap );
244
245
246 TriggerExecutionAdministrativePoint teAap = new TriggerExecutionAAP( dn, uuid );
247 directoryService.getTriggerExecutionAPCache().add( dn, teAap );
248
249
250 SubschemaAdministrativePoint ssAap = new SubschemaAAP( dn, uuid );
251 directoryService.getSubschemaAPCache().add( dn, ssAap );
252
253
254
255
256
257 return;
258 }
259
260 for ( Value value : adminPoint )
261 {
262 String role = value.getString();
263
264
265 if ( isAccessControlSpecificRole( role ) )
266 {
267 AccessControlAdministrativePoint sap = new AccessControlSAP( dn, uuid );
268 directoryService.getAccessControlAPCache().add( dn, sap );
269
270
271
272
273 continue;
274 }
275
276 if ( isAccessControlInnerRole( role ) )
277 {
278 AccessControlAdministrativePoint iap = new AccessControlIAP( dn, uuid );
279 directoryService.getAccessControlAPCache().add( dn, iap );
280
281 continue;
282 }
283
284
285 if ( isCollectiveAttributeSpecificRole( role ) )
286 {
287 CollectiveAttributeAdministrativePoint sap = new CollectiveAttributeSAP( dn, uuid );
288 directoryService.getCollectiveAttributeAPCache().add( dn, sap );
289
290
291
292
293 continue;
294 }
295
296 if ( isCollectiveAttributeInnerRole( role ) )
297 {
298 CollectiveAttributeAdministrativePoint iap = new CollectiveAttributeIAP( dn, uuid );
299 directoryService.getCollectiveAttributeAPCache().add( dn, iap );
300
301 continue;
302 }
303
304
305 if ( isSubschemaSpecficRole( role ) )
306 {
307 SubschemaAdministrativePoint sap = new SubschemaSAP( dn, uuid );
308 directoryService.getSubschemaAPCache().add( dn, sap );
309
310
311
312
313 continue;
314 }
315
316
317 if ( isTriggerExecutionSpecificRole( role ) )
318 {
319 TriggerExecutionAdministrativePoint sap = new TriggerExecutionSAP( dn, uuid );
320 directoryService.getTriggerExecutionAPCache().add( dn, sap );
321
322
323
324
325 continue;
326 }
327
328 if ( isTriggerExecutionInnerRole( role ) )
329 {
330 TriggerExecutionAdministrativePoint iap = new TriggerExecutionIAP( dn, uuid );
331 directoryService.getTriggerExecutionAPCache().add( dn, iap );
332 }
333 }
334 }
335
336
337
338
339
340 private void addRole( String role, Dn dn, String uuid, DnNode<AccessControlAdministrativePoint> acapCache,
341 DnNode<CollectiveAttributeAdministrativePoint> caapCache,
342 DnNode<TriggerExecutionAdministrativePoint> teapCache,
343 DnNode<SubschemaAdministrativePoint> ssapCache ) throws LdapException
344 {
345
346 if ( isAutonomousAreaRole( role ) )
347 {
348
349 AccessControlAdministrativePoint acAap = new AccessControlAAP( dn, uuid );
350 acapCache.add( dn, acAap );
351
352
353 CollectiveAttributeAdministrativePoint caAap = new CollectiveAttributeAAP( dn, uuid );
354 caapCache.add( dn, caAap );
355
356
357 TriggerExecutionAdministrativePoint teAap = new TriggerExecutionAAP( dn, uuid );
358 teapCache.add( dn, teAap );
359
360
361 SubschemaAdministrativePoint ssAap = new SubschemaAAP( dn, uuid );
362 ssapCache.add( dn, ssAap );
363
364
365 return;
366 }
367
368
369 if ( isAccessControlSpecificRole( role ) )
370 {
371 AccessControlAdministrativePoint sap = new AccessControlSAP( dn, uuid );
372 acapCache.add( dn, sap );
373
374 return;
375 }
376
377 if ( isAccessControlInnerRole( role ) )
378 {
379 AccessControlAdministrativePoint iap = new AccessControlIAP( dn, uuid );
380 acapCache.add( dn, iap );
381
382 return;
383 }
384
385
386 if ( isCollectiveAttributeSpecificRole( role ) )
387 {
388 CollectiveAttributeAdministrativePoint sap = new CollectiveAttributeSAP( dn, uuid );
389 caapCache.add( dn, sap );
390
391 return;
392 }
393
394 if ( isCollectiveAttributeInnerRole( role ) )
395 {
396 CollectiveAttributeAdministrativePoint iap = new CollectiveAttributeIAP( dn, uuid );
397 caapCache.add( dn, iap );
398
399 return;
400 }
401
402
403 if ( isSubschemaSpecficRole( role ) )
404 {
405 SubschemaAdministrativePoint sap = new SubschemaSAP( dn, uuid );
406 ssapCache.add( dn, sap );
407
408 return;
409 }
410
411
412 if ( isTriggerExecutionSpecificRole( role ) )
413 {
414 TriggerExecutionAdministrativePoint sap = new TriggerExecutionSAP( dn, uuid );
415 teapCache.add( dn, sap );
416
417 return;
418 }
419
420 if ( isTriggerExecutionInnerRole( role ) )
421 {
422 TriggerExecutionAdministrativePoint iap = new TriggerExecutionIAP( dn, uuid );
423 teapCache.add( dn, iap );
424 }
425 }
426
427
428
429
430
431 private void delRole( String role, Dn dn, String uuid, DnNode<AccessControlAdministrativePoint> acapCache,
432 DnNode<CollectiveAttributeAdministrativePoint> caapCache,
433 DnNode<TriggerExecutionAdministrativePoint> teapCache,
434 DnNode<SubschemaAdministrativePoint> ssapCache ) throws LdapException
435 {
436
437 if ( isAutonomousAreaRole( role ) )
438 {
439
440 acapCache.remove( dn );
441
442
443 caapCache.remove( dn );
444
445
446 teapCache.remove( dn );
447
448
449 ssapCache.remove( dn );
450
451 return;
452 }
453
454
455 if ( isAccessControlSpecificRole( role ) || isAccessControlInnerRole( role ) )
456 {
457 acapCache.remove( dn );
458
459 return;
460 }
461
462
463 if ( isCollectiveAttributeSpecificRole( role ) || isCollectiveAttributeInnerRole( role ) )
464 {
465 caapCache.remove( dn );
466
467 return;
468 }
469
470
471 if ( isSubschemaSpecficRole( role ) )
472 {
473 ssapCache.remove( dn );
474
475 return;
476 }
477
478
479 if ( isTriggerExecutionSpecificRole( role ) || isTriggerExecutionInnerRole( role ) )
480 {
481 teapCache.remove( dn );
482 }
483 }
484
485
486 private AdministrativePoint/../org/apache/directory/server/core/api/administrative/AdministrativePoint.html#AdministrativePoint">AdministrativePoint getParent( AdministrativePoint ap, List<AdministrativePoint> aps,
487 AdministrativeRole role, DnNode<List<AdministrativePoint>> currentNode )
488 {
489 AdministrativePoint parent = null;
490
491 for ( AdministrativePoint adminPoint : aps )
492 {
493 if ( adminPoint.isAutonomous() || ( adminPoint.getRole() == ap.getRole() ) )
494 {
495
496 return adminPoint;
497 }
498 else if ( adminPoint.getRole() == role )
499 {
500 parent = adminPoint;
501 }
502 }
503
504 if ( parent != null )
505 {
506 return parent;
507 }
508
509
510 if ( currentNode.hasParent() )
511 {
512 return findParent( ap, currentNode );
513 }
514 else
515 {
516 return null;
517 }
518 }
519
520
521
522
523
524
525 private AdministrativePoint../org/apache/directory/server/core/api/administrative/AdministrativePoint.html#AdministrativePoint">AdministrativePoint findParent( AdministrativePoint ap, DnNode<List<AdministrativePoint>> currentNode )
526 {
527 List<AdministrativePoint> aps = currentNode.getElement();
528
529 if ( aps != null )
530 {
531
532 switch ( ap.getRole() )
533 {
534 case AutonomousArea:
535 AdministrativePoint currentAp = aps.get( 0 );
536
537 if ( currentAp.isAutonomous() )
538 {
539 return currentAp;
540 }
541 else
542 {
543
544
545 if ( currentNode.hasParent() )
546 {
547 return findParent( ap, currentNode );
548 }
549 else
550 {
551 return null;
552 }
553 }
554
555 case AccessControlInnerArea:
556 return getParent( ap, aps, AdministrativeRole.AccessControlSpecificArea, currentNode );
557
558 case CollectiveAttributeInnerArea:
559 return getParent( ap, aps, AdministrativeRole.CollectiveAttributeSpecificArea, currentNode );
560
561 case TriggerExecutionInnerArea:
562 return getParent( ap, aps, AdministrativeRole.TriggerExecutionSpecificArea, currentNode );
563
564 case AccessControlSpecificArea:
565 return getParent( ap, aps, AdministrativeRole.AccessControlSpecificArea, currentNode );
566
567 case CollectiveAttributeSpecificArea:
568 return getParent( ap, aps, AdministrativeRole.CollectiveAttributeSpecificArea, currentNode );
569
570 case SubSchemaSpecificArea:
571 return getParent( ap, aps, AdministrativeRole.SubSchemaSpecificArea, currentNode );
572
573 case TriggerExecutionSpecificArea:
574 return getParent( ap, aps, AdministrativeRole.TriggerExecutionSpecificArea, currentNode );
575
576 default:
577 return null;
578 }
579 }
580 else
581 {
582 if ( currentNode.hasParent() )
583 {
584 return findParent( ap, currentNode.getParent() );
585 }
586 else
587 {
588 return null;
589 }
590 }
591 }
592
593
594
595
596
597
598 private void checkAddRole( Value role, Attribute adminPoint, Dn dn ) throws LdapException
599 {
600 String roleStr = Strings.toLowerCaseAscii( Strings.trim( role.getString() ) );
601
602
603 if ( !ROLES.contains( roleStr ) )
604 {
605 String message = "Cannot add the given role, it's not a valid one :" + role;
606 LOG.error( message );
607 throw new LdapUnwillingToPerformException( message );
608 }
609
610
611
612 if ( isAutonomousAreaRole( roleStr ) )
613 {
614 if ( adminPoint.size() > 1 )
615 {
616 String message = "Cannot add an Autonomous Administratve Point when some other roles are added : "
617 + adminPoint;
618 LOG.error( message );
619 throw new LdapUnwillingToPerformException( message );
620 }
621 else
622 {
623
624 return;
625 }
626 }
627
628
629
630 if ( adminPoint.contains( SchemaConstants.AUTONOMOUS_AREA ) )
631 {
632 String message = "Cannot add a role when an Autonomous Administratve Point is already present : "
633 + adminPoint;
634 LOG.error( message );
635 throw new LdapUnwillingToPerformException( message );
636 }
637
638
639 checkInnerSpecificMix( roleStr, adminPoint );
640
641
642
643 if ( isIAP( roleStr ) )
644 {
645 checkIAPHasParent( roleStr, adminPoint, dn );
646 }
647 }
648
649
650
651
652
653 private void checkDelRole( Value role, Attribute adminPoint, Dn dn ) throws LdapException
654 {
655 String roleStr = Strings.toLowerCaseAscii( Strings.trim( role.getString() ) );
656
657
658 if ( !ROLES.contains( roleStr ) )
659 {
660 String message = "Cannot delete the given role, it's not a valid one :" + role;
661 LOG.error( message );
662 throw new LdapUnwillingToPerformException( message );
663 }
664
665
666
667 if ( isAutonomousAreaRole( roleStr ) )
668 {
669
670
671
672
673
674
675
676 DnNode<AccessControlAdministrativePoint> acAps = directoryService.getAccessControlAPCache();
677
678 if ( !acAps.hasParent( dn ) )
679 {
680
681 List<AccessControlAdministrativePoint> children = acAps.getDescendantElements( dn );
682
683 for ( AccessControlAdministrativePoint child : children )
684 {
685 if ( child.isInner() )
686 {
687
688 String message = "Cannot delete the given role, the " + child.getDn()
689 + " AccessControl IAP will remain orphan";
690 LOG.error( message );
691 throw new LdapUnwillingToPerformException( message );
692 }
693 }
694 }
695
696
697 DnNode<CollectiveAttributeAdministrativePoint> caAps = directoryService.getCollectiveAttributeAPCache();
698
699 if ( !acAps.hasParent( dn ) )
700 {
701
702 List<CollectiveAttributeAdministrativePoint> children = caAps.getDescendantElements( dn );
703
704 for ( CollectiveAttributeAdministrativePoint child : children )
705 {
706 if ( child.isInner() )
707 {
708
709 String message = "Cannot delete the given role, the " + child.getDn()
710 + " CollectiveAttribute IAP will remain orphan";
711 LOG.error( message );
712 throw new LdapUnwillingToPerformException( message );
713 }
714 }
715 }
716
717
718 DnNode<TriggerExecutionAdministrativePoint> teAps = directoryService.getTriggerExecutionAPCache();
719
720 if ( !acAps.hasParent( dn ) )
721 {
722
723 List<TriggerExecutionAdministrativePoint> children = teAps.getDescendantElements( dn );
724
725 for ( TriggerExecutionAdministrativePoint child : children )
726 {
727 if ( child.isInner() )
728 {
729
730 String message = "Cannot delete the given role, the " + child.getDn()
731 + " TriggerExecution IAP will remain orphan";
732 LOG.error( message );
733 throw new LdapUnwillingToPerformException( message );
734 }
735 }
736 }
737 }
738 }
739
740
741
742
743
744 private List<Entry> getAdministrativePoints() throws LdapException
745 {
746 List<Entry> entries = new ArrayList<>();
747
748 SearchControls controls = new SearchControls();
749 controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
750 controls.setReturningAttributes( new String[]
751 { SchemaConstants.ADMINISTRATIVE_ROLE_AT, SchemaConstants.ENTRY_UUID_AT } );
752
753
754 ExprNode filter = new PresenceNode( directoryService.getAtProvider().getAdministrativeRole() );
755
756 CoreSession adminSession = directoryService.getAdminSession();
757
758 SearchOperationContextxt/SearchOperationContext.html#SearchOperationContext">SearchOperationContext searchOperationContext = new SearchOperationContext( adminSession, Dn.ROOT_DSE, filter,
759 controls );
760 Partition partition = nexus.getPartition( Dn.ROOT_DSE );
761 searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
762 searchOperationContext.setPartition( partition );
763
764 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() )
765 {
766 searchOperationContext.setTransaction( partitionTxn );
767 EntryFilteringCursor results = nexus.search( searchOperationContext );
768
769 try
770 {
771 while ( results.next() )
772 {
773 Entry entry = results.get();
774
775 entries.add( entry );
776 }
777
778 results.close();
779 }
780 catch ( Exception e )
781 {
782 throw new LdapOperationException( e.getMessage(), e );
783 }
784 }
785 catch ( Exception e )
786 {
787 throw new LdapOtherException( e.getMessage(), e );
788 }
789
790 return entries;
791 }
792
793
794
795
796
797
798 private boolean isValidRole( String role )
799 {
800 return ROLES.contains( Strings.toLowerCaseAscii( Strings.trim( role ) ) );
801 }
802
803
804
805
806
807 private void addAdminPointCache( List<Entry> adminPointEntries ) throws LdapException
808 {
809 for ( Entry adminPointEntry : adminPointEntries )
810 {
811
812 Dn dn = adminPointEntry.getDn();
813
814 String uuid = adminPointEntry.get( directoryService.getAtProvider().getEntryUUID() ).getString();
815 Attribute adminPoint = adminPointEntry.get( directoryService.getAtProvider().getAdministrativeRole() );
816
817 createAdministrativePoints( adminPoint, dn, uuid );
818 }
819 }
820
821
822
823
824
825 private void deleteAdminPointCache( Attribute adminPoint, DeleteOperationContext deleteContext )
826 throws LdapException
827 {
828 Dn dn = deleteContext.getDn();
829
830
831 for ( Value value : adminPoint )
832 {
833 String role = value.getString();
834
835
836 if ( isAutonomousAreaRole( role ) )
837 {
838
839 directoryService.getAccessControlAPCache().remove( dn );
840
841
842 directoryService.getCollectiveAttributeAPCache().remove( dn );
843
844
845 directoryService.getTriggerExecutionAPCache().remove( dn );
846
847
848 directoryService.getSubschemaAPCache().remove( dn );
849
850
851 return;
852 }
853
854
855 if ( isAccessControlSpecificRole( role ) || isAccessControlInnerRole( role ) )
856 {
857 directoryService.getAccessControlAPCache().remove( dn );
858
859 continue;
860 }
861
862
863 if ( isCollectiveAttributeSpecificRole( role ) || isCollectiveAttributeInnerRole( role ) )
864 {
865 directoryService.getCollectiveAttributeAPCache().remove( dn );
866
867 continue;
868 }
869
870
871 if ( isSubschemaSpecficRole( role ) )
872 {
873 directoryService.getSubschemaAPCache().remove( dn );
874
875 continue;
876 }
877
878
879 if ( isTriggerExecutionSpecificRole( role ) || isTriggerExecutionInnerRole( role ) )
880 {
881 directoryService.getTriggerExecutionAPCache().remove( dn );
882 }
883 }
884 }
885
886
887
888
889
890 private boolean isAccessControlInnerRole( String role )
891 {
892 return role.equalsIgnoreCase( SchemaConstants.ACCESS_CONTROL_INNER_AREA )
893 || role.equals( SchemaConstants.ACCESS_CONTROL_INNER_AREA_OID );
894 }
895
896
897
898
899
900 private boolean isAccessControlSpecificRole( String role )
901 {
902 return role.equalsIgnoreCase( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA )
903 || role.equals( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA_OID );
904 }
905
906
907
908
909
910 private boolean isCollectiveAttributeInnerRole( String role )
911 {
912 return role.equalsIgnoreCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA )
913 || role.equals( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA_OID );
914 }
915
916
917
918
919
920 private boolean isCollectiveAttributeSpecificRole( String role )
921 {
922 return role.equalsIgnoreCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA )
923 || role.equals( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID );
924 }
925
926
927
928
929
930 private boolean isTriggerExecutionInnerRole( String role )
931 {
932 return role.equalsIgnoreCase( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA )
933 || role.equals( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA_OID );
934 }
935
936
937
938
939
940 private boolean isTriggerExecutionSpecificRole( String role )
941 {
942 return role.equalsIgnoreCase( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA )
943 || role.equals( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID );
944 }
945
946
947
948
949
950 private boolean isSubschemaSpecficRole( String role )
951 {
952 return role.equalsIgnoreCase( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA )
953 || role.equals( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA_OID );
954 }
955
956
957
958
959
960 private boolean isAutonomousAreaRole( String role )
961 {
962 return role.equalsIgnoreCase( SchemaConstants.AUTONOMOUS_AREA )
963 || role.equals( SchemaConstants.AUTONOMOUS_AREA_OID );
964 }
965
966
967
968
969
970 private boolean isAAP( Attribute adminPoint )
971 {
972 return adminPoint.contains( SchemaConstants.AUTONOMOUS_AREA )
973 || adminPoint.contains( SchemaConstants.AUTONOMOUS_AREA_OID );
974 }
975
976
977 private boolean hasAccessControlSpecificRole( Attribute adminPoint )
978 {
979 return adminPoint.contains( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA )
980 || adminPoint.contains( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA_OID );
981 }
982
983
984 private boolean isIAP( String role )
985 {
986 return INNER_AREA_ROLES.contains( role );
987 }
988
989
990 private boolean hasCollectiveAttributeSpecificRole( Attribute adminPoint )
991 {
992 return adminPoint.contains( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA )
993 || adminPoint.contains( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID );
994 }
995
996
997 private boolean hasTriggerExecutionSpecificRole( Attribute adminPoint )
998 {
999 return adminPoint.contains( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA )
1000 || adminPoint.contains( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID );
1001 }
1002
1003
1004
1005
1006
1007 private void checkInnerSpecificMix( String role, Attribute adminPoint ) throws LdapUnwillingToPerformException
1008 {
1009 if ( isAccessControlInnerRole( role ) )
1010 {
1011 if ( hasAccessControlSpecificRole( adminPoint ) )
1012 {
1013
1014 String message = "Cannot add a specific Administrative Point and the same"
1015 + " inner Administrative point at the same time : " + adminPoint;
1016 LOG.error( message );
1017 throw new LdapUnwillingToPerformException( message );
1018 }
1019 else
1020 {
1021 return;
1022 }
1023 }
1024
1025 if ( isCollectiveAttributeInnerRole( role ) )
1026 {
1027 if ( hasCollectiveAttributeSpecificRole( adminPoint ) )
1028 {
1029
1030 String message = "Cannot add a specific Administrative Point and the same"
1031 + " inner Administrative point at the same time : " + adminPoint;
1032 LOG.error( message );
1033 throw new LdapUnwillingToPerformException( message );
1034 }
1035 else
1036 {
1037 return;
1038 }
1039 }
1040
1041 if ( isTriggerExecutionInnerRole( role ) )
1042 {
1043 if ( hasTriggerExecutionSpecificRole( adminPoint ) )
1044 {
1045
1046 String message = "Cannot add a specific Administrative Point and the same"
1047 + " inner Administrative point at the same time : " + adminPoint;
1048 LOG.error( message );
1049 throw new LdapUnwillingToPerformException( message );
1050 }
1051 }
1052 }
1053
1054
1055
1056
1057
1058
1059 private void checkIAPHasParent( String role, Attribute adminPoint, Dn dn ) throws LdapUnwillingToPerformException
1060 {
1061
1062 if ( isAccessControlInnerRole( role ) )
1063 {
1064 DnNode<AccessControlAdministrativePoint> acCache = directoryService.getAccessControlAPCache();
1065
1066 DnNode<AccessControlAdministrativePoint> parent = acCache.getNode( dn );
1067
1068 if ( parent == null )
1069 {
1070
1071 String message = "Cannot add an IAP with no parent : " + adminPoint;
1072 LOG.error( message );
1073 throw new LdapUnwillingToPerformException( message );
1074 }
1075 }
1076 else if ( isCollectiveAttributeInnerRole( role ) )
1077 {
1078 DnNode<CollectiveAttributeAdministrativePoint> caCache = directoryService.getCollectiveAttributeAPCache();
1079
1080 boolean hasAP = caCache.hasParentElement( dn );
1081
1082 if ( !hasAP )
1083 {
1084
1085 String message = "Cannot add an IAP with no parent : " + adminPoint;
1086 LOG.error( message );
1087 throw new LdapUnwillingToPerformException( message );
1088 }
1089 }
1090 else if ( isTriggerExecutionInnerRole( role ) )
1091 {
1092 DnNode<TriggerExecutionAdministrativePoint> caCache = directoryService.getTriggerExecutionAPCache();
1093
1094 DnNode<TriggerExecutionAdministrativePoint> parent = caCache.getNode( dn );
1095
1096 if ( parent == null )
1097 {
1098
1099 String message = "Cannot add an IAP with no parent : " + adminPoint;
1100 LOG.error( message );
1101 throw new LdapUnwillingToPerformException( message );
1102 }
1103 }
1104 else
1105 {
1106
1107 String message = "This is not an IAP : " + role;
1108 LOG.error( message );
1109 throw new LdapUnwillingToPerformException( message );
1110 }
1111 }
1112
1113
1114
1115
1116
1117
1118
1119
1120 @Override
1121 public void init( DirectoryService directoryService ) throws LdapException
1122 {
1123 LOG.debug( "Initializing the AdministrativeInterceptor" );
1124
1125 super.init( directoryService );
1126 nexus = directoryService.getPartitionNexus();
1127
1128
1129
1130
1131
1132 List<Entry> administrativePoints = getAdministrativePoints();
1133
1134 lockWrite();
1135
1136 try
1137 {
1138 addAdminPointCache( administrativePoints );
1139 }
1140 finally
1141 {
1142 unlock();
1143 }
1144 }
1145
1146
1147
1148
1149
1150 @Override
1151 public void destroy()
1152 {
1153 }
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168 @Override
1169 public void add( AddOperationContext addContext ) throws LdapException
1170 {
1171 LOG.debug( ">>> Entering into the Administrative Interceptor, addRequest" );
1172 Entry entry = addContext.getEntry();
1173 Dn dn = entry.getDn();
1174
1175
1176 Attribute adminPoint = entry.get( directoryService.getAtProvider().getAdministrativeRole() );
1177
1178 if ( adminPoint == null )
1179 {
1180
1181 next( addContext );
1182
1183 LOG.debug( "Exit from Administrative Interceptor, no AP in the added entry" );
1184
1185 return;
1186 }
1187
1188 LOG.debug( "Addition of an administrative point at {} for the role {}", dn, adminPoint );
1189
1190
1191 lockWrite();
1192
1193 try
1194 {
1195
1196 for ( Value role : adminPoint )
1197 {
1198 checkAddRole( role, adminPoint, dn );
1199 }
1200
1201
1202 next( addContext );
1203
1204 String apUuid = entry.get( directoryService.getAtProvider().getEntryUUID() ).getString();
1205
1206
1207 createAdministrativePoints( adminPoint, dn, apUuid );
1208 }
1209 finally
1210 {
1211
1212 unlock();
1213 }
1214
1215 if ( LOG.isDebugEnabled() )
1216 {
1217 LOG.debug( "Added an Administrative Point at {}", dn );
1218 }
1219 }
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230 @Override
1231 public void delete( DeleteOperationContext deleteContext ) throws LdapException
1232 {
1233 LOG.debug( ">>> Entering into the Administrative Interceptor, delRequest" );
1234 Entry entry = deleteContext.getEntry();
1235 Dn dn = entry.getDn();
1236
1237
1238 Attribute adminPoint = entry.get( directoryService.getAtProvider().getAdministrativeRole() );
1239
1240 if ( adminPoint == null )
1241 {
1242
1243 next( deleteContext );
1244
1245 LOG.debug( "Exit from Administrative Interceptor" );
1246
1247 return;
1248 }
1249
1250 LOG.debug( "Deletion of an administrative point at {} for the role {}", dn, adminPoint );
1251
1252
1253 lockWrite();
1254
1255 try
1256 {
1257
1258
1259 for ( Value role : adminPoint )
1260 {
1261 if ( !isValidRole( role.getString() ) )
1262 {
1263 String message = "Cannot remove the given role, it's not a valid one :" + role;
1264 LOG.error( message );
1265 throw new LdapUnwillingToPerformException( message );
1266 }
1267 }
1268
1269
1270 next( deleteContext );
1271
1272
1273 deleteAdminPointCache( adminPoint, deleteContext );
1274 }
1275 finally
1276 {
1277
1278 unlock();
1279 }
1280
1281 if ( LOG.isDebugEnabled() )
1282 {
1283 LOG.debug( "Deleted an Administrative Point at {}", dn );
1284 }
1285 }
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299 @Override
1300 public void modify( ModifyOperationContext modifyContext ) throws LdapException
1301 {
1302 LOG.debug( ">>> Entering into the Administrative Interceptor, modifyRequest" );
1303
1304 List<Modification> modifications = modifyContext.getModItems();
1305 Dn dn = modifyContext.getDn();
1306 String uuid = modifyContext.getEntry().get( directoryService.getAtProvider().getEntryUUID() ).getString();
1307
1308
1309 boolean adminRolePresent = false;
1310
1311 for ( Modification modification : modifications )
1312 {
1313 if ( modification.getAttribute().getAttributeType() == directoryService.getAtProvider().getAdministrativeRole() )
1314 {
1315 adminRolePresent = true;
1316 break;
1317 }
1318 }
1319
1320 if ( adminRolePresent )
1321 {
1322
1323
1324
1325 Attribute modifiedAdminRole = ( ( ClonedServerEntry ) modifyContext.getEntry() ).getOriginalEntry().get(
1326 directoryService.getAtProvider().getAdministrativeRole() );
1327
1328 if ( modifiedAdminRole == null )
1329 {
1330
1331 modifiedAdminRole = new DefaultAttribute( directoryService.getAtProvider().getAdministrativeRole() );
1332 }
1333 else
1334 {
1335
1336 modifiedAdminRole = modifiedAdminRole.clone();
1337 }
1338
1339 try
1340 {
1341
1342 lockWrite();
1343
1344
1345 DnNode<AccessControlAdministrativePoint> acapCache = directoryService.getAccessControlAPCache();
1346 DnNode<CollectiveAttributeAdministrativePoint> caapCache = directoryService
1347 .getCollectiveAttributeAPCache();
1348 DnNode<TriggerExecutionAdministrativePoint> teapCache = directoryService.getTriggerExecutionAPCache();
1349 DnNode<SubschemaAdministrativePoint> ssapCache = directoryService.getSubschemaAPCache();
1350
1351
1352
1353
1354 for ( Modification modification : modifications )
1355 {
1356 Attribute attribute = modification.getAttribute();
1357
1358
1359 if ( attribute.getAttributeType() == directoryService.getAtProvider().getAdministrativeRole() )
1360 {
1361
1362
1363 switch ( modification.getOperation() )
1364 {
1365 case ADD_ATTRIBUTE:
1366 for ( Value role : attribute )
1367 {
1368 addRole( role.getString(), dn, uuid, acapCache, caapCache, teapCache,
1369 ssapCache );
1370
1371
1372 modifiedAdminRole.add( role );
1373 }
1374
1375 break;
1376
1377 case REMOVE_ATTRIBUTE:
1378
1379 if ( attribute.size() == 0 )
1380 {
1381
1382 for ( Value role : modifiedAdminRole )
1383 {
1384 delRole( role.getString(), dn, uuid, acapCache, caapCache, teapCache, ssapCache );
1385 }
1386
1387 modifiedAdminRole.clear();
1388 break;
1389 }
1390
1391
1392 for ( Value value : attribute )
1393 {
1394 if ( !isValidRole( value.getString() ) )
1395 {
1396
1397 String msg = "Invalid role : " + value.getString();
1398 LOG.error( msg );
1399 throw new LdapInvalidAttributeValueException(
1400 ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX,
1401 msg );
1402 }
1403
1404 if ( !modifiedAdminRole.contains( value ) )
1405 {
1406
1407 String msg = "Cannot remove the administrative role value" + value
1408 + ", it does not exist";
1409 LOG.error( msg );
1410 throw new LdapNoSuchAttributeException( msg );
1411 }
1412
1413 modifiedAdminRole.remove( value );
1414 delRole( value.getString(), dn, uuid, acapCache, caapCache, teapCache, ssapCache );
1415
1416 }
1417
1418 break;
1419
1420 case REPLACE_ATTRIBUTE:
1421 if ( !( modifyContext.isReplEvent() && modifyContext.getSession().isAdministrator() ) )
1422 {
1423
1424 String msg = "Cannot replace an administrative role, the opertion is not supported";
1425 LOG.error( msg );
1426 throw new LdapUnwillingToPerformException( msg );
1427 }
1428
1429 break;
1430
1431 default:
1432 throw new IllegalArgumentException( "Unexpected modify operation "
1433 + modification.getOperation() );
1434 }
1435 }
1436 }
1437
1438
1439
1440
1441 }
1442 finally
1443 {
1444 unlock();
1445 }
1446 }
1447
1448 next( modifyContext );
1449 }
1450
1451
1452
1453
1454
1455 @Override
1456 public void move( MoveOperationContext moveContext ) throws LdapException
1457 {
1458 LOG.debug( ">>> Entering into the Administrative Interceptor, moveRequest" );
1459 Entry entry = moveContext.getOriginalEntry();
1460
1461
1462 Attribute adminPoint = entry.get( directoryService.getAtProvider().getAdministrativeRole() );
1463
1464 if ( adminPoint == null )
1465 {
1466
1467 next( moveContext );
1468
1469 LOG.debug( "Exit from Administrative Interceptor" );
1470
1471 return;
1472 }
1473
1474
1475 String message = "Cannot move an Administrative Point in the current version";
1476 LOG.error( message );
1477 throw new LdapUnwillingToPerformException( message );
1478 }
1479
1480
1481
1482
1483
1484 @Override
1485 public void moveAndRename( MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
1486 {
1487 LOG.debug( ">>> Entering into the Administrative Interceptor, moveAndRenameRequest" );
1488 Entry entry = moveAndRenameContext.getOriginalEntry();
1489
1490
1491 Attribute adminPoint = entry.get( directoryService.getAtProvider().getAdministrativeRole() );
1492
1493 if ( adminPoint == null )
1494 {
1495
1496 next( moveAndRenameContext );
1497
1498 LOG.debug( "Exit from Administrative Interceptor" );
1499
1500 return;
1501 }
1502
1503
1504 String message = "Cannot move and rename an Administrative Point in the current version";
1505 LOG.error( message );
1506 throw new LdapUnwillingToPerformException( message );
1507 }
1508
1509
1510
1511
1512
1513 @Override
1514 public void rename( RenameOperationContext renameContext ) throws LdapException
1515 {
1516 LOG.debug( ">>> Entering into the Administrative Interceptor, renameRequest" );
1517 Entry entry = renameContext.getEntry();
1518
1519
1520 Attribute adminPoint = entry.get( directoryService.getAtProvider().getAdministrativeRole() );
1521
1522 if ( adminPoint == null )
1523 {
1524
1525 next( renameContext );
1526
1527 LOG.debug( "Exit from Administrative Interceptor" );
1528
1529 return;
1530 }
1531
1532
1533 String message = "Cannot rename an Administrative Point in the current version";
1534 LOG.error( message );
1535 throw new LdapUnwillingToPerformException( message );
1536 }
1537 }