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.schema;
21
22
23 import org.apache.directory.server.core.entry.ServerAttribute;
24 import org.apache.directory.server.core.entry.ServerEntry;
25 import org.apache.directory.server.schema.registries.ObjectClassRegistry;
26 import org.apache.directory.server.schema.registries.OidRegistry;
27 import org.apache.directory.shared.ldap.constants.SchemaConstants;
28 import org.apache.directory.shared.ldap.entry.EntryAttribute;
29 import org.apache.directory.shared.ldap.entry.ModificationOperation;
30 import org.apache.directory.shared.ldap.entry.Value;
31 import org.apache.directory.shared.ldap.exception.LdapSchemaViolationException;
32 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
33 import org.apache.directory.shared.ldap.name.LdapDN;
34 import org.apache.directory.shared.ldap.schema.AttributeType;
35 import org.apache.directory.shared.ldap.schema.ObjectClass;
36 import org.apache.directory.shared.ldap.schema.ObjectClassTypeEnum;
37 import org.apache.directory.shared.ldap.util.NamespaceTools;
38
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import javax.naming.NamingException;
43
44 import java.util.ArrayList;
45 import java.util.List;
46 import java.util.Set;
47 import java.util.HashSet;
48
49
50
51
52
53
54
55
56
57 public class SchemaChecker
58 {
59
60 private static Logger log = LoggerFactory.getLogger( SchemaChecker.class );
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 public static void preventStructuralClassRemovalOnModifyReplace( ObjectClassRegistry registry, LdapDN name, ModificationOperation mod,
77 ServerAttribute attribute ) throws NamingException
78 {
79 if ( mod != ModificationOperation.REPLACE_ATTRIBUTE )
80 {
81 return;
82 }
83
84 if ( !SchemaConstants.OBJECT_CLASS_AT.equalsIgnoreCase( attribute.getUpId() ) )
85 {
86 return;
87 }
88
89
90
91 if ( attribute.size() == 0 )
92 {
93 String msg = "Modify operation leaves no structural objectClass for entry " + name;
94
95 if ( log.isInfoEnabled() )
96 {
97 log.info( msg + ". Raising LdapSchemaViolationException." );
98 }
99
100 throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED );
101 }
102
103
104 for ( Value<?> value:attribute )
105 {
106 ObjectClass ocType = registry.lookup( ( String ) value.get() );
107
108 if ( ocType.getType() == ObjectClassTypeEnum.STRUCTURAL )
109 {
110 return;
111 }
112 }
113
114
115
116 String msg = "Modify operation leaves no structural objectClass for entry " + name;
117 if ( log.isInfoEnabled() )
118 {
119 log.info( msg + ". Raising LdapSchemaViolationException." );
120 }
121 throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED );
122 }
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138 public static void preventStructuralClassRemovalOnModifyReplace(
139 ObjectClassRegistry registry, LdapDN name, ModificationOperation mod, ServerEntry entry ) throws NamingException
140 {
141 if ( mod != ModificationOperation.REPLACE_ATTRIBUTE )
142 {
143 return;
144 }
145
146 EntryAttribute objectClass = entry.get( SchemaConstants.OBJECT_CLASS_AT );
147
148 if ( objectClass == null )
149 {
150 return;
151 }
152
153
154
155 if ( objectClass.size() == 0 )
156 {
157 String msg = "Modify operation leaves no structural objectClass for entry " + name;
158 if ( log.isInfoEnabled() )
159 {
160 log.info( msg + ". Raising LdapSchemaViolationException." );
161 }
162 throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED );
163 }
164
165
166 for ( Value<?> value:objectClass )
167 {
168 ObjectClass ocType = registry.lookup( ( String ) value.get() );
169
170 if ( ocType.getType() == ObjectClassTypeEnum.STRUCTURAL )
171 {
172 return;
173 }
174 }
175
176
177
178 String msg = "Modify operation leaves no structural objectClass for entry " + name;
179 if ( log.isInfoEnabled() )
180 {
181 log.info( msg + ". Raising LdapSchemaViolationException." );
182 }
183 throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED );
184 }
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201 public static void preventStructuralClassRemovalOnModifyRemove( ObjectClassRegistry registry, LdapDN name, ModificationOperation mod,
202 EntryAttribute attribute, EntryAttribute entryObjectClasses ) throws NamingException
203 {
204 if ( mod != ModificationOperation.REMOVE_ATTRIBUTE )
205 {
206 return;
207 }
208
209 if ( !((ServerAttribute)attribute).instanceOf( SchemaConstants.OBJECT_CLASS_AT ) )
210 {
211 return;
212 }
213
214
215
216 List<Value<?>> removed = new ArrayList<Value<?>>();
217
218
219 for ( Value<?> value:attribute )
220 {
221 if ( ((String)value.get()).length() == 0 )
222 {
223 removed.add( value );
224 }
225 }
226
227
228 for ( Value<?> value:removed )
229 {
230 attribute.remove( value );
231 }
232
233
234
235 if ( attribute.size() == 0 )
236 {
237 String msg = "Modify operation leaves no structural objectClass for entry " + name;
238
239 if ( log.isInfoEnabled() )
240 {
241 log.info( msg + ". Raising LdapSchemaViolationException." );
242 }
243
244 throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED );
245 }
246
247
248
249
250
251 ServerAttribute cloned = ( ServerAttribute ) entryObjectClasses.clone();
252
253 for ( Value<?> value:attribute )
254 {
255 cloned.remove( value );
256 }
257
258
259 for ( Value<?> objectClass:cloned )
260 {
261 ObjectClass oc = registry.lookup( (String)objectClass.get() );
262
263 if ( oc.getType() == ObjectClassTypeEnum.STRUCTURAL )
264 {
265 return;
266 }
267 }
268
269
270
271 String msg = "Modify operation leaves no structural objectClass for entry " + name;
272
273 if ( log.isInfoEnabled() )
274 {
275 log.info( msg + ". Raising LdapSchemaViolationException." );
276 }
277
278 throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED );
279 }
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
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
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384 public static void preventRdnChangeOnModifyReplace( LdapDN name, ModificationOperation mod, ServerAttribute attribute, OidRegistry oidRegistry )
385 throws NamingException
386 {
387 if ( mod != ModificationOperation.REPLACE_ATTRIBUTE )
388 {
389 return;
390 }
391
392 Set<String> rdnAttributes = getRdnAttributes( name );
393 String id = oidRegistry.getOid( attribute.getUpId() );
394
395 if ( !rdnAttributes.contains( id ) )
396 {
397 return;
398 }
399
400
401
402
403 if ( attribute.size() == 0 )
404 {
405 String msg = "Modify operation attempts to delete RDN attribute ";
406 msg += id + " on entry " + name + " violates schema constraints";
407
408 if ( log.isInfoEnabled() )
409 {
410 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
411 }
412 throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOT_ALLOWED_ON_RDN );
413 }
414
415
416
417
418 String rdnValue = getRdnValue( id, name, oidRegistry );
419 for ( int ii = 0; ii < attribute.size(); ii++ )
420 {
421
422
423 if ( !attribute.contains( rdnValue ) )
424 {
425 String msg = "Modify operation attempts to delete RDN attribute values in use for ";
426 msg += id + " on entry " + name + " and violates schema constraints";
427
428 if ( log.isInfoEnabled() )
429 {
430 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
431 }
432 throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOT_ALLOWED_ON_RDN );
433 }
434 }
435 }
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458 public static void preventRdnChangeOnModifyReplace(
459 LdapDN name, ModificationOperation mod, ServerEntry entry, OidRegistry oidRegistry )
460 throws NamingException
461 {
462 if ( mod != ModificationOperation.REPLACE_ATTRIBUTE )
463 {
464 return;
465 }
466
467 Set<String> rdnAttributes = getRdnAttributes( name );
468
469 for ( AttributeType attributeType:entry.getAttributeTypes() )
470 {
471 String id = attributeType.getName();
472
473 if ( rdnAttributes.contains( id ) )
474 {
475 EntryAttribute rdnAttr = entry.get( id );
476
477
478
479
480 if ( rdnAttr.size() == 0 )
481 {
482 String msg = "Modify operation attempts to delete RDN attribute ";
483 msg += id + " on entry " + name + " violates schema constraints";
484
485 if ( log.isInfoEnabled() )
486 {
487 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
488 }
489
490 throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOT_ALLOWED_ON_RDN );
491 }
492
493
494
495
496 String rdnValue = getRdnValue( id, name, oidRegistry );
497
498
499
500 if ( !rdnAttr.contains( rdnValue ) )
501 {
502 String msg = "Modify operation attempts to delete RDN attribute values in use for ";
503 msg += id + " on entry " + name + " and violates schema constraints";
504
505 if ( log.isInfoEnabled() )
506 {
507 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
508 }
509
510 throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOT_ALLOWED_ON_RDN );
511 }
512 }
513 }
514 }
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536 public static void preventRdnChangeOnModifyRemove( LdapDN name, ModificationOperation mod, ServerAttribute attribute,
537 OidRegistry oidRegistry ) throws NamingException
538 {
539 if ( mod != ModificationOperation.REMOVE_ATTRIBUTE )
540 {
541 return;
542 }
543
544 Set<String> rdnAttributes = getRdnAttributes( name );
545 String id = attribute.getId();
546
547 if ( !rdnAttributes.contains( oidRegistry.getOid( id ) ) )
548 {
549 return;
550 }
551
552
553
554
555 if ( attribute.size() == 0 )
556 {
557 String msg = "Modify operation attempts to delete RDN attribute ";
558 msg += id + " on entry " + name + " violates schema constraints";
559
560 if ( log.isInfoEnabled() )
561 {
562 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
563 }
564
565 throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOT_ALLOWED_ON_RDN );
566 }
567
568
569
570
571 String rdnValue = getRdnValue( id, name, oidRegistry );
572
573 for ( Value<?> value:attribute )
574 {
575 if ( rdnValue.equals( (String)value.get() ) )
576 {
577 String msg = "Modify operation attempts to delete RDN attribute values in use for ";
578 msg += id + " on entry " + name + " and violates schema constraints";
579
580 if ( log.isInfoEnabled() )
581 {
582 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
583 }
584
585 throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOT_ALLOWED_ON_RDN );
586 }
587 }
588 }
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611 public static void preventRdnChangeOnModifyRemove( LdapDN name, ModificationOperation mod, ServerEntry entry, OidRegistry oidRegistry )
612 throws NamingException
613 {
614 if ( mod != ModificationOperation.REMOVE_ATTRIBUTE )
615 {
616 return;
617 }
618
619 Set<String> rdnAttributes = getRdnAttributes( name );
620
621 for ( AttributeType attributeType:entry.getAttributeTypes() )
622 {
623 String id = attributeType.getName();
624
625 if ( rdnAttributes.contains( id ) )
626 {
627
628
629
630 if ( entry.get( id ).size() == 0 )
631 {
632 String msg = "Modify operation attempts to delete RDN attribute ";
633 msg += id + " on entry " + name + " violates schema constraints";
634
635 if ( log.isInfoEnabled() )
636 {
637 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
638 }
639 throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOT_ALLOWED_ON_RDN );
640 }
641
642
643
644
645 String rdnValue = getRdnValue( id, name, oidRegistry );
646 EntryAttribute rdnAttr = entry.get( id );
647
648 for ( Value<?> value:rdnAttr )
649 {
650 if ( rdnValue.equals( (String)value.get() ) )
651 {
652 String msg = "Modify operation attempts to delete RDN attribute values in use for ";
653 msg += id + " on entry " + name + " and violates schema constraints";
654
655 if ( log.isInfoEnabled() )
656 {
657 log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
658 }
659 throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOT_ALLOWED_ON_RDN );
660 }
661 }
662 }
663 }
664 }
665
666
667
668
669
670
671
672
673
674
675
676
677
678 private static String getRdnValue( String id, LdapDN name, OidRegistry oidRegistry ) throws NamingException
679 {
680
681 String idOid = oidRegistry.getOid( id );
682
683 if ( idOid == null )
684 {
685 log.error( "The id {} does not have any OID. It should be a wrong AttributeType.", id);
686 throw new NamingException( "Wrong AttributeType, does not have an associated OID : " + id );
687 }
688
689 String[] comps = NamespaceTools.getCompositeComponents( name.get( name.size() - 1 ) );
690
691 for ( int ii = 0; ii < comps.length; ii++ )
692 {
693 String rdnAttrId = NamespaceTools.getRdnAttribute( comps[ii] );
694
695
696 String rdnAttrOid = oidRegistry.getOid( rdnAttrId );
697
698 if ( rdnAttrOid == null )
699 {
700 log.error( "The id {} does not have any OID. It should be a wrong AttributeType.", rdnAttrOid);
701 throw new NamingException( "Wrong AttributeType, does not have an associated OID : " + rdnAttrOid );
702 }
703
704 if ( rdnAttrOid.equalsIgnoreCase( idOid ) )
705 {
706 return NamespaceTools.getRdnValue( comps[ii] );
707 }
708 }
709
710 return null;
711 }
712
713
714
715
716
717
718
719
720
721
722 private static Set<String> getRdnAttributes( LdapDN name ) throws NamingException
723 {
724 String[] comps = NamespaceTools.getCompositeComponents( name.get( name.size() - 1 ) );
725 Set<String> attributes = new HashSet<String>();
726
727 for ( int ii = 0; ii < comps.length; ii++ )
728 {
729 attributes.add( NamespaceTools.getRdnAttribute( comps[ii] ) );
730 }
731
732 return attributes;
733 }
734 }