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.collective;
21
22
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Set;
26
27 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
28 import org.apache.directory.api.ldap.model.entry.Attribute;
29 import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
30 import org.apache.directory.api.ldap.model.entry.Entry;
31 import org.apache.directory.api.ldap.model.entry.Modification;
32 import org.apache.directory.api.ldap.model.entry.ModificationOperation;
33 import org.apache.directory.api.ldap.model.entry.Value;
34 import org.apache.directory.api.ldap.model.exception.LdapException;
35 import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeTypeException;
36 import org.apache.directory.api.ldap.model.exception.LdapSchemaViolationException;
37 import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
38 import org.apache.directory.api.ldap.model.name.Dn;
39 import org.apache.directory.api.ldap.model.schema.AttributeType;
40 import org.apache.directory.api.ldap.model.schema.SchemaUtils;
41 import org.apache.directory.server.core.api.CoreSession;
42 import org.apache.directory.server.core.api.DirectoryService;
43 import org.apache.directory.server.core.api.InterceptorEnum;
44 import org.apache.directory.server.core.api.entry.ClonedServerEntry;
45 import org.apache.directory.server.core.api.filtering.EntryFilter;
46 import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
47 import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
48 import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
49 import org.apache.directory.server.core.api.interceptor.context.FilteringOperationContext;
50 import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
51 import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
52 import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
53 import org.apache.directory.server.i18n.I18n;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57
58
59
60
61
62
63
64
65
66
67 public class CollectiveAttributeInterceptor extends BaseInterceptor
68 {
69
70 private static final Logger LOG = LoggerFactory.getLogger( CollectiveAttributeInterceptor.class );
71
72
73
74
75
76 public CollectiveAttributeInterceptor()
77 {
78 super( InterceptorEnum.COLLECTIVE_ATTRIBUTE_INTERCEPTOR );
79 }
80
81
82
83
84 private class CollectiveAttributeFilter implements EntryFilter
85 {
86
87
88
89 @Override
90 public boolean accept( SearchOperationContext operation, Entry entry ) throws LdapException
91 {
92 addCollectiveAttributes( operation, entry );
93
94 return true;
95 }
96
97
98
99
100
101 @Override
102 public String toString( String tabs )
103 {
104 return tabs + "CollectiveAttributeFilter";
105 }
106 }
107
108
109 private final EntryFilter searchFilter = new CollectiveAttributeFilter();
110
111
112
113
114
115
116
117
118 @Override
119 public void init( DirectoryService directoryService ) throws LdapException
120 {
121 super.init( directoryService );
122
123 LOG.debug( "CollectiveAttribute interceptor initialized" );
124 }
125
126
127
128
129
130
131
132
133 @Override
134 public void add( AddOperationContext addContext ) throws LdapException
135 {
136 checkAdd( addContext.getDn(), addContext.getEntry() );
137
138 next( addContext );
139 }
140
141
142
143
144
145 @Override
146 public Entry lookup( LookupOperationContext lookupContext ) throws LdapException
147 {
148 Entry result = next( lookupContext );
149
150
151 if ( lookupContext.isSyncreplLookup() )
152 {
153 return result;
154 }
155
156
157 addCollectiveAttributes( lookupContext, result );
158
159 return result;
160 }
161
162
163
164
165
166 @Override
167 public void modify( ModifyOperationContext modifyContext ) throws LdapException
168 {
169 checkModify( modifyContext );
170
171 next( modifyContext );
172 }
173
174
175
176
177
178 @Override
179 public EntryFilteringCursor search( SearchOperationContext searchContext ) throws LdapException
180 {
181 EntryFilteringCursor cursor = next( searchContext );
182
183
184 if ( !searchContext.isSyncreplSearch() )
185 {
186 cursor.addEntryFilter( searchFilter );
187 }
188
189 return cursor;
190 }
191
192
193
194
195
196
197
198
199
200
201
202
203 private void checkAdd( Dn normName, Entry entry ) throws LdapException
204 {
205 if ( entry.hasObjectClass( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRY_OC ) )
206 {
207
208
209 for ( Attribute attribute : entry )
210 {
211 if ( attribute.getAttributeType().isCollective() )
212 {
213 return;
214 }
215 }
216
217 LOG.info( "A CollectiveAttribute subentry *should* have at least one collectiveAttribute" );
218 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION,
219 I18n.err( I18n.ERR_257_COLLECTIVE_SUBENTRY_WITHOUT_COLLECTIVE_AT ) );
220 }
221
222 if ( containsAnyCollectiveAttributes( entry ) )
223 {
224
225
226
227 LOG.info(
228 "Cannot add the entry {} : it contains some CollectiveAttributes and is not a collective subentry",
229 entry );
230 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION,
231 I18n.err( I18n.ERR_241_CANNOT_STORE_COLLECTIVE_ATT_IN_ENTRY ) );
232 }
233 }
234
235
236
237
238
239 private void checkModify( ModifyOperationContext modifyContext ) throws LdapException
240 {
241 List<Modification> mods = modifyContext.getModItems();
242 Entry originalEntry = modifyContext.getEntry();
243 Entry targetEntry = SchemaUtils.getTargetEntry( mods, originalEntry );
244
245
246
247 if ( targetEntry.contains( directoryService.getAtProvider().getObjectClass(),
248 SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRY_OC ) )
249 {
250 return;
251 }
252
253
254 if ( hasCollectiveAttributes( mods ) )
255 {
256
257
258
259 LOG.info(
260 "Cannot modify the entry {} : it contains some CollectiveAttributes and is not a collective subentry",
261 targetEntry );
262 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, I18n.err( I18n.ERR_242 ) );
263 }
264 }
265
266
267
268
269
270
271 private boolean hasCollectiveAttributes( List<Modification> mods ) throws LdapException
272 {
273 for ( Modification mod : mods )
274 {
275
276 Attribute attr = mod.getAttribute();
277 AttributeType attrType = attr.getAttributeType();
278
279
280 if ( attrType == null )
281 {
282 try
283 {
284 attrType = schemaManager.lookupAttributeTypeRegistry( attr.getUpId() );
285 }
286 catch ( LdapException le )
287 {
288 throw new LdapInvalidAttributeTypeException();
289 }
290 }
291
292 ModificationOperation modOp = mod.getOperation();
293
294
295 if ( attrType.isCollective() && ( modOp != ModificationOperation.REMOVE_ATTRIBUTE ) )
296 {
297 return true;
298 }
299 }
300
301
302 return false;
303 }
304
305
306
307
308
309 private boolean containsAnyCollectiveAttributes( Entry entry )
310 {
311 for ( Attribute attribute : entry.getAttributes() )
312 {
313 AttributeType attributeType = attribute.getAttributeType();
314
315 if ( attributeType.isCollective() )
316 {
317 return true;
318 }
319 }
320
321 return false;
322 }
323
324
325
326
327
328
329
330
331
332
333
334
335
336 private void addCollectiveAttributes( FilteringOperationContext opContext, Entry entry )
337 throws LdapException
338 {
339 CoreSession session = opContext.getSession();
340
341 Attribute collectiveAttributeSubentries = ( ( ClonedServerEntry ) entry ).getOriginalEntry().get(
342 directoryService.getAtProvider().getCollectiveAttributeSubentries() );
343
344
345
346
347
348 if ( collectiveAttributeSubentries == null )
349 {
350 return;
351 }
352
353 if ( LOG.isDebugEnabled() )
354 {
355 LOG.debug( "Filtering entry {}", entry.getDn() );
356 }
357
358
359
360
361
362
363
364 Attribute collectiveExclusions = ( ( ClonedServerEntry ) entry ).getOriginalEntry().get(
365 directoryService.getAtProvider().getCollectiveExclusions() );
366 Set<AttributeType> exclusions = new HashSet<>();
367
368 if ( collectiveExclusions != null )
369 {
370 LOG.debug( "The entry has some exclusions : {}", collectiveExclusions );
371
372 if ( collectiveExclusions.contains( SchemaConstants.EXCLUDE_ALL_COLLECTIVE_ATTRIBUTES_AT_OID )
373 || collectiveExclusions.contains( SchemaConstants.EXCLUDE_ALL_COLLECTIVE_ATTRIBUTES_AT ) )
374 {
375
376
377
378
379 LOG.debug( "The entry excludes all the collectiveAttributes" );
380
381 return;
382 }
383
384 for ( Value value : collectiveExclusions )
385 {
386 AttributeType attrType = schemaManager.lookupAttributeTypeRegistry( value.getString() );
387 exclusions.add( attrType );
388 LOG.debug( "Adding {} in the list of excluded collectiveAttributes", attrType.getName() );
389 }
390 }
391
392
393
394
395
396
397 for ( Value value : collectiveAttributeSubentries )
398 {
399 String subentryDnStr = value.getString();
400 Dn subentryDn = dnFactory.create( subentryDnStr );
401
402 LOG.debug( "Applying subentries {}", subentryDn.getName() );
403
404
405
406
407
408
409
410
411 LookupOperationContexttor/context/LookupOperationContext.html#LookupOperationContext">LookupOperationContext lookupContext = new LookupOperationContext( session, subentryDn,
412 SchemaConstants.ALL_ATTRIBUTES_ARRAY );
413 lookupContext.setPartition( opContext.getPartition() );
414 lookupContext.setTransaction( opContext.getTransaction() );
415
416 Entry subentry = directoryService.getPartitionNexus().lookup( lookupContext );
417
418
419
420 for ( Attribute attribute : subentry.getAttributes() )
421 {
422 AttributeType attributeType = attribute.getAttributeType();
423
424
425 if ( !attributeType.isCollective() )
426 {
427
428 continue;
429 }
430
431
432
433
434
435 if ( exclusions.contains( attributeType ) )
436 {
437 LOG.debug( "The {} subentry attribute has been removed, it's in the exclusion list",
438 attributeType.getName() );
439 continue;
440 }
441
442
443
444
445
446 if ( !opContext.isAllUserAttributes() && !opContext.contains( schemaManager, attributeType ) )
447 {
448 LOG.debug( "The {} subentry attribute is not in the list of attributes to return",
449 attributeType.getName() );
450 continue;
451 }
452
453 Attribute subentryColAttr = subentry.get( attributeType );
454 Attribute entryColAttr = entry.get( attributeType );
455
456
457
458
459 if ( entryColAttr == null )
460 {
461 entryColAttr = new DefaultAttribute( attributeType );
462 entry.put( entryColAttr );
463 }
464
465
466
467
468
469 for ( Value subentryColVal : subentryColAttr )
470 {
471 LOG.debug( "Adding the {} collective attribute into the entry", subentryColAttr );
472 entryColAttr.add( subentryColVal.getString() );
473 }
474 }
475 }
476 }
477 }