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 java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.concurrent.ConcurrentHashMap;
31
32 import org.apache.commons.codec.Charsets;
33 import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
34 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
35 import org.apache.directory.api.ldap.model.cursor.EmptyCursor;
36 import org.apache.directory.api.ldap.model.cursor.SingletonCursor;
37 import org.apache.directory.api.ldap.model.entry.Attribute;
38 import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
39 import org.apache.directory.api.ldap.model.entry.DefaultModification;
40 import org.apache.directory.api.ldap.model.entry.Entry;
41 import org.apache.directory.api.ldap.model.entry.Modification;
42 import org.apache.directory.api.ldap.model.entry.Value;
43 import org.apache.directory.api.ldap.model.exception.LdapAttributeInUseException;
44 import org.apache.directory.api.ldap.model.exception.LdapException;
45 import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeTypeException;
46 import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
47 import org.apache.directory.api.ldap.model.exception.LdapNoPermissionException;
48 import org.apache.directory.api.ldap.model.exception.LdapNoSuchAttributeException;
49 import org.apache.directory.api.ldap.model.exception.LdapSchemaViolationException;
50 import org.apache.directory.api.ldap.model.filter.ApproximateNode;
51 import org.apache.directory.api.ldap.model.filter.BranchNode;
52 import org.apache.directory.api.ldap.model.filter.EqualityNode;
53 import org.apache.directory.api.ldap.model.filter.ExprNode;
54 import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
55 import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
56 import org.apache.directory.api.ldap.model.filter.LessEqNode;
57 import org.apache.directory.api.ldap.model.filter.ObjectClassNode;
58 import org.apache.directory.api.ldap.model.filter.SimpleNode;
59 import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
60 import org.apache.directory.api.ldap.model.message.SearchScope;
61 import org.apache.directory.api.ldap.model.message.controls.Cascade;
62 import org.apache.directory.api.ldap.model.name.Ava;
63 import org.apache.directory.api.ldap.model.name.Dn;
64 import org.apache.directory.api.ldap.model.name.Rdn;
65 import org.apache.directory.api.ldap.model.schema.AttributeType;
66 import org.apache.directory.api.ldap.model.schema.ObjectClass;
67 import org.apache.directory.api.ldap.model.schema.ObjectClassTypeEnum;
68 import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
69 import org.apache.directory.api.ldap.model.schema.UsageEnum;
70 import org.apache.directory.api.ldap.model.schema.registries.Schema;
71 import org.apache.directory.api.ldap.model.schema.syntaxCheckers.OctetStringSyntaxChecker;
72 import org.apache.directory.api.util.Strings;
73 import org.apache.directory.server.core.api.DirectoryService;
74 import org.apache.directory.server.core.api.InterceptorEnum;
75 import org.apache.directory.server.core.api.entry.ClonedServerEntry;
76 import org.apache.directory.server.core.api.entry.ServerEntryUtils;
77 import org.apache.directory.server.core.api.filtering.EntryFilteringCursorImpl;
78 import org.apache.directory.server.core.api.filtering.EntryFilter;
79 import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
80 import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
81 import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
82 import org.apache.directory.server.core.api.interceptor.context.CompareOperationContext;
83 import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
84 import org.apache.directory.server.core.api.interceptor.context.ModDnAva;
85 import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
86 import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
87 import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
88 import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
89 import org.apache.directory.server.core.api.partition.PartitionNexus;
90 import org.apache.directory.server.core.shared.SchemaService;
91 import org.apache.directory.server.i18n.I18n;
92 import org.slf4j.Logger;
93 import org.slf4j.LoggerFactory;
94
95
96
97
98
99
100
101
102
103 public class SchemaInterceptor extends BaseInterceptor
104 {
105
106 private static final Logger LOG = LoggerFactory.getLogger( SchemaInterceptor.class );
107
108
109 private static final boolean IS_DEBUG = LOG.isDebugEnabled();
110
111
112
113
114 private PartitionNexus nexus;
115
116 private TopFilter topFilter;
117
118 private List<EntryFilter> filters = new ArrayList<>();
119
120
121 private Dn subschemaSubentryDn;
122
123
124 private SchemaSubentryManager schemaSubEntryManager;
125
126
127 private Dn schemaBaseDn;
128
129
130 private Map<String, List<ObjectClass>> superiors;
131
132
133 private Map<String, List<AttributeType>> allMay;
134
135
136 private Map<String, List<AttributeType>> allMust;
137
138
139 private Map<String, List<AttributeType>> allowed;
140
141
142
143
144
145 public SchemaInterceptor()
146 {
147 super( InterceptorEnum.SCHEMA_INTERCEPTOR );
148 }
149
150
151
152
153
154
155
156
157 @Override
158 public void init( DirectoryService directoryService ) throws LdapException
159 {
160 if ( IS_DEBUG )
161 {
162 LOG.debug( "Initializing SchemaInterceptor..." );
163 }
164
165 super.init( directoryService );
166
167 nexus = directoryService.getPartitionNexus();
168 topFilter = new TopFilter();
169 filters.add( topFilter );
170
171 schemaBaseDn = dnFactory.create( SchemaConstants.OU_SCHEMA );
172
173
174 Value subschemaSubentry = nexus.getRootDseValue( directoryService.getAtProvider().getSubschemaSubentry() );
175 subschemaSubentryDn = dnFactory.create( subschemaSubentry.getString() );
176
177 computeSuperiors();
178
179
180 schemaSubEntryManager = new SchemaSubentryManager( schemaManager, dnFactory );
181
182 if ( IS_DEBUG )
183 {
184 LOG.debug( "SchemaInterceptor Initialized !" );
185 }
186 }
187
188
189
190
191
192
193
194
195
196 private void computeMustAttributes( ObjectClass objectClass, Set<String> atSeen )
197 {
198 List<ObjectClass> parents = superiors.get( objectClass.getOid() );
199
200 List<AttributeType> mustList = new ArrayList<>();
201 List<AttributeType> allowedList = new ArrayList<>();
202 Set<String> mustSeen = new HashSet<>();
203
204 allMust.put( objectClass.getOid(), mustList );
205 allowed.put( objectClass.getOid(), allowedList );
206
207 for ( ObjectClass parent : parents )
208 {
209 List<AttributeType> mustParent = parent.getMustAttributeTypes();
210
211 if ( ( mustParent != null ) && !mustParent.isEmpty() )
212 {
213 for ( AttributeType attributeType : mustParent )
214 {
215 String oid = attributeType.getOid();
216
217 if ( !mustSeen.contains( oid ) )
218 {
219 mustSeen.add( oid );
220 mustList.add( attributeType );
221 allowedList.add( attributeType );
222 atSeen.add( attributeType.getOid() );
223 }
224 }
225 }
226 }
227 }
228
229
230
231
232
233
234
235
236
237
238
239 private void computeMayAttributes( ObjectClass objectClass, Set<String> atSeen )
240 {
241 List<ObjectClass> parents = superiors.get( objectClass.getOid() );
242
243 List<AttributeType> mayList = new ArrayList<>();
244 Set<String> maySeen = new HashSet<>();
245 List<AttributeType> allowedList = allowed.get( objectClass.getOid() );
246
247 allMay.put( objectClass.getOid(), mayList );
248
249 for ( ObjectClass parent : parents )
250 {
251 List<AttributeType> mustParent = parent.getMustAttributeTypes();
252
253 if ( ( mustParent != null ) && !mustParent.isEmpty() )
254 {
255 for ( AttributeType attributeType : mustParent )
256 {
257 String oid = attributeType.getOid();
258
259 if ( !maySeen.contains( oid ) )
260 {
261 maySeen.add( oid );
262 mayList.add( attributeType );
263
264 if ( !atSeen.contains( oid ) )
265 {
266 allowedList.add( attributeType );
267 }
268 }
269 }
270 }
271 }
272 }
273
274
275
276
277
278
279
280
281
282
283 private void computeOCSuperiors( ObjectClass objectClass, List<ObjectClass> superiors, Set<String> ocSeen )
284 throws LdapException
285 {
286 List<ObjectClass> parents = objectClass.getSuperiors();
287
288
289 if ( ( parents != null ) && !parents.isEmpty() )
290 {
291 for ( ObjectClass parent : parents )
292 {
293
294 if ( SchemaConstants.TOP_OC.equals( parent.getName() ) )
295 {
296 continue;
297 }
298
299
300 computeOCSuperiors( parent, superiors, ocSeen );
301
302 String oid = parent.getOid();
303
304 if ( !ocSeen.contains( oid ) )
305 {
306 superiors.add( parent );
307 ocSeen.add( oid );
308 }
309 }
310 }
311 }
312
313
314
315
316
317
318 private void computeSuperior( ObjectClass objectClass ) throws LdapException
319 {
320 List<ObjectClass> ocSuperiors = new ArrayList<>();
321
322 superiors.put( objectClass.getOid(), ocSuperiors );
323
324 computeOCSuperiors( objectClass, ocSuperiors, new HashSet<String>() );
325
326 Set<String> atSeen = new HashSet<>();
327 computeMustAttributes( objectClass, atSeen );
328 computeMayAttributes( objectClass, atSeen );
329
330 superiors.put( objectClass.getName(), ocSuperiors );
331 }
332
333
334
335
336
337
338 private void computeSuperiors() throws LdapException
339 {
340 Iterator<ObjectClass> objectClasses = schemaManager.getObjectClassRegistry().iterator();
341 superiors = new ConcurrentHashMap<>();
342 allMust = new ConcurrentHashMap<>();
343 allMay = new ConcurrentHashMap<>();
344 allowed = new ConcurrentHashMap<>();
345
346 while ( objectClasses.hasNext() )
347 {
348 ObjectClass objectClass = objectClasses.next();
349 computeSuperior( objectClass );
350 }
351 }
352
353
354 private Value convert( AttributeType attributeType, Value value ) throws LdapException
355 {
356 if ( attributeType.getSyntax().isHumanReadable() )
357 {
358 if ( !value.isHumanReadable() )
359 {
360 return new Value( attributeType, new String( value.getBytes(), Charsets.UTF_8 ) );
361 }
362 }
363 else
364 {
365 return new Value( attributeType, value.getBytes() );
366 }
367
368 return null;
369 }
370
371
372
373
374
375
376
377 private void checkFilter( ExprNode filter ) throws LdapException
378 {
379 if ( filter == null )
380 {
381 String message = I18n.err( I18n.ERR_49 );
382 LOG.error( message );
383 throw new LdapException( message );
384 }
385
386 if ( filter instanceof ObjectClassNode )
387 {
388
389 return;
390 }
391
392 if ( filter.isLeaf() )
393 {
394 if ( filter instanceof EqualityNode )
395 {
396 EqualityNode node = ( EqualityNode ) filter;
397 Value value = node.getValue();
398
399 Value newValue = convert( node.getAttributeType(), value );
400
401 if ( newValue != null )
402 {
403 node.setValue( newValue );
404 }
405 }
406 else if ( filter instanceof GreaterEqNode )
407 {
408 GreaterEqNode node = ( GreaterEqNode ) filter;
409 Value value = node.getValue();
410
411 Value newValue = convert( node.getAttributeType(), value );
412
413 if ( newValue != null )
414 {
415 node.setValue( newValue );
416 }
417
418 }
419 else if ( filter instanceof LessEqNode )
420 {
421 LessEqNode node = ( LessEqNode ) filter;
422 Value value = node.getValue();
423
424 Value newValue = convert( node.getAttributeType(), value );
425
426 if ( newValue != null )
427 {
428 node.setValue( newValue );
429 }
430 }
431 else if ( filter instanceof ExtensibleNode )
432 {
433 ExtensibleNode node = ( ExtensibleNode ) filter;
434
435
436 }
437 else if ( filter instanceof ApproximateNode )
438 {
439 ApproximateNode node = ( ApproximateNode ) filter;
440 Value value = node.getValue();
441
442 Value newValue = convert( node.getAttributeType(), value );
443
444 if ( newValue != null )
445 {
446 node.setValue( newValue );
447 }
448 }
449
450 }
451 else
452 {
453
454 for ( ExprNode child : ( ( BranchNode ) filter ).getChildren() )
455 {
456 checkFilter( child );
457 }
458 }
459 }
460
461
462 private void getSuperiors( ObjectClass oc, Set<String> ocSeen, List<ObjectClass> result ) throws LdapException
463 {
464 for ( ObjectClass parent : oc.getSuperiors() )
465 {
466
467 if ( SchemaConstants.TOP_OC.equals( parent.getName() ) )
468 {
469 continue;
470 }
471
472 if ( !ocSeen.contains( parent.getOid() ) )
473 {
474 ocSeen.add( parent.getOid() );
475 result.add( parent );
476 }
477
478
479 getSuperiors( parent, ocSeen, result );
480 }
481 }
482
483
484 private boolean getObjectClasses( Attribute objectClasses, List<ObjectClass> result ) throws LdapException
485 {
486 Set<String> ocSeen = new HashSet<>();
487
488
489
490 boolean hasExtensibleObject = false;
491
492 for ( Value objectClass : objectClasses )
493 {
494 String objectClassName = objectClass.getString();
495
496 if ( SchemaConstants.TOP_OC.equals( objectClassName ) )
497 {
498 continue;
499 }
500
501 if ( SchemaConstants.EXTENSIBLE_OBJECT_OC.equalsIgnoreCase( objectClassName ) )
502 {
503 hasExtensibleObject = true;
504 }
505
506 ObjectClass oc = schemaManager.lookupObjectClassRegistry( objectClassName );
507
508
509 if ( !ocSeen.contains( oc.getOid() ) )
510 {
511 ocSeen.add( oc.getOid() );
512 result.add( oc );
513 }
514
515
516 getSuperiors( oc, ocSeen, result );
517 }
518
519 return hasExtensibleObject;
520 }
521
522
523 private Set<String> getAllMust( Attribute objectClasses ) throws LdapException
524 {
525 Set<String> must = new HashSet<>();
526
527
528 for ( Value value : objectClasses )
529 {
530 String ocName = value.getString();
531 ObjectClass oc = schemaManager.lookupObjectClassRegistry( ocName );
532
533 List<AttributeType> types = oc.getMustAttributeTypes();
534
535
536 if ( ( types != null ) && !types.isEmpty() )
537 {
538 for ( AttributeType type : types )
539 {
540 must.add( type.getOid() );
541 }
542 }
543 }
544
545 return must;
546 }
547
548
549 private Set<String> getAllAllowed( Attribute objectClasses, Set<String> must ) throws LdapException
550 {
551 Set<String> allAllowed = new HashSet<>( must );
552
553
554 allAllowed.add( SchemaConstants.OBJECT_CLASS_AT_OID );
555
556
557 for ( Value objectClass : objectClasses )
558 {
559 String ocName = objectClass.getString();
560 ObjectClass oc = schemaManager.lookupObjectClassRegistry( ocName );
561
562 List<AttributeType> types = oc.getMayAttributeTypes();
563
564
565 if ( ( types != null ) && !types.isEmpty() )
566 {
567 for ( AttributeType type : types )
568 {
569 String oid = type.getOid();
570
571 allAllowed.add( oid );
572 }
573 }
574 }
575
576 return allAllowed;
577 }
578
579
580
581
582
583
584
585
586
587
588
589 private void alterObjectClasses( Attribute objectClassAttr ) throws LdapException
590 {
591 Set<String> objectClasses = new HashSet<>();
592 Set<String> objectClassesUP = new HashSet<>();
593
594
595 objectClasses.add( SchemaConstants.TOP_OC );
596 objectClassesUP.add( SchemaConstants.TOP_OC );
597
598
599 for ( Value ocValue : objectClassAttr )
600 {
601 String ocName = ocValue.getString();
602
603 if ( !ocName.equalsIgnoreCase( SchemaConstants.TOP_OC ) )
604 {
605 String ocLowerName = Strings.toLowerCaseAscii( ocName );
606
607 ObjectClass objectClass = schemaManager.lookupObjectClassRegistry( ocLowerName );
608
609 if ( !objectClasses.contains( ocLowerName ) )
610 {
611 objectClasses.add( ocLowerName );
612 objectClassesUP.add( ocName );
613 }
614
615 List<ObjectClass> ocSuperiors = superiors.get( objectClass.getOid() );
616
617 if ( ocSuperiors != null )
618 {
619 for ( ObjectClass oc : ocSuperiors )
620 {
621 if ( !objectClasses.contains( Strings.toLowerCaseAscii( oc.getName() ) ) )
622 {
623 objectClasses.add( oc.getName() );
624 objectClassesUP.add( oc.getName() );
625 }
626 }
627 }
628 }
629 }
630
631
632 objectClassAttr.clear();
633
634 for ( String attribute : objectClassesUP )
635 {
636 objectClassAttr.add( attribute );
637 }
638 }
639
640
641
642
643
644 private Attribute createNewAttribute( Attribute attribute ) throws LdapException
645 {
646 AttributeType attributeType = attribute.getAttributeType();
647
648
649 Attribute newAttribute = new DefaultAttribute( attribute.getUpId(), attributeType );
650
651 for ( Value value : attribute )
652 {
653 newAttribute.add( value );
654 }
655
656 return newAttribute;
657 }
658
659
660
661
662
663 private void checkModifyEntry( ModifyOperationContext modifyContext ) throws LdapException
664 {
665 Dn dn = modifyContext.getDn();
666 Entry currentEntry = modifyContext.getEntry();
667 List<Modification> mods = modifyContext.getModItems();
668
669
670
671
672
673
674 Entry tempEntry = currentEntry.clone();
675
676
677 for ( Modification mod : mods )
678 {
679 Attribute attribute = mod.getAttribute();
680 AttributeType attributeType = attribute.getAttributeType();
681
682 assertAttributeIsModifyable( modifyContext, attributeType );
683
684 switch ( mod.getOperation() )
685 {
686 case ADD_ATTRIBUTE:
687
688 Attribute currentAttribute = tempEntry.get( attributeType );
689
690
691
692 if ( currentAttribute != null )
693 {
694 for ( Value value : attribute )
695 {
696
697
698
699 if ( currentAttribute.contains( value ) )
700 {
701
702 String msg = I18n.err( I18n.ERR_54, value );
703 LOG.error( msg );
704 throw new LdapAttributeInUseException( msg );
705 }
706
707 currentAttribute.add( value );
708 }
709 }
710 else
711 {
712
713
714
715 Attribute newAttribute = attribute.clone();
716
717
718 if ( ( newAttribute.size() == 0 ) && !newAttribute.isValid( attributeType ) )
719 {
720
721 String msg = I18n.err( I18n.ERR_54, ( Object[] ) null );
722 LOG.error( msg );
723 throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg );
724 }
725
726 tempEntry.put( newAttribute );
727 }
728
729 break;
730
731 case REMOVE_ATTRIBUTE:
732
733 if ( !tempEntry.containsAttribute( attributeType ) )
734 {
735 String msg = I18n.err( I18n.ERR_55, attributeType );
736 LOG.error( msg );
737 throw new LdapNoSuchAttributeException( msg );
738 }
739
740
741 if ( attribute.size() == 0 )
742 {
743
744 tempEntry.removeAttributes( attributeType );
745 }
746 else
747 {
748 currentAttribute = tempEntry.get( attributeType );
749
750
751 for ( Value value : attribute )
752 {
753
754 if ( currentAttribute.contains( value ) )
755 {
756 currentAttribute.remove( value );
757 }
758 else
759 {
760 String msg = I18n.err( I18n.ERR_56, attributeType );
761 LOG.error( msg );
762 throw new LdapNoSuchAttributeException( msg );
763 }
764 }
765
766
767
768 if ( currentAttribute.size() == 0 )
769 {
770 tempEntry.removeAttributes( attributeType );
771 }
772 }
773
774 break;
775
776 case REPLACE_ATTRIBUTE:
777
778
779 if ( !tempEntry.containsAttribute( attributeType ) )
780 {
781 if ( attribute.size() == 0 )
782 {
783
784
785 break;
786 }
787 else
788 {
789
790 Attribute newAttribute = createNewAttribute( attribute );
791
792 tempEntry.put( newAttribute );
793 }
794 }
795 else
796 {
797 if ( attribute.size() == 0 )
798 {
799
800 tempEntry.removeAttributes( attributeType );
801 }
802 else
803 {
804
805
806 tempEntry.removeAttributes( attributeType );
807
808
809 Attribute newAttribute = createNewAttribute( attribute );
810
811 tempEntry.put( newAttribute );
812 }
813 }
814
815 break;
816
817 case INCREMENT_ATTRIBUTE:
818
819 if ( !tempEntry.containsAttribute( attributeType ) )
820 {
821 throw new IllegalArgumentException( "Increment operation on a non existing attribute"
822 + attributeType );
823 }
824 else if ( !SchemaConstants.INTEGER_SYNTAX.equals( attributeType.getSyntax().getOid() ) )
825 {
826 throw new IllegalArgumentException( "Increment operation on a non integer attribute"
827 + attributeType );
828 }
829 else
830 {
831 Attribute modified = tempEntry.get( attributeType );
832 Value[] newValues = new Value[ modified.size() ];
833 int increment = 1;
834 int i = 0;
835
836 if ( mod.getAttribute().size() != 0 )
837 {
838 increment = Integer.parseInt( mod.getAttribute().getString() );
839 }
840
841 for ( Value value : modified )
842 {
843 int intValue = Integer.parseInt( value.getNormalized() );
844
845 if ( intValue >= Integer.MAX_VALUE - increment )
846 {
847 throw new IllegalArgumentException( "Increment operation overflow for attribute"
848 + attributeType );
849 }
850
851 newValues[i++] = new Value( Integer.toString( intValue + increment ) );
852 modified.remove( value );
853 }
854
855 modified.add( newValues );
856 }
857
858 break;
859
860 default:
861 throw new IllegalArgumentException( "Unexpected modify operation " + mod.getOperation() );
862 }
863 }
864
865
866
867
868
869
870
871
872
873
874 check( dn, tempEntry );
875 }
876
877
878 private void assertAttributeIsModifyable( ModifyOperationContext modifyContext, AttributeType attributeType )
879 throws LdapNoPermissionException
880 {
881 if ( attributeType.isUserModifiable() )
882 {
883
884 return;
885 }
886
887 if ( modifyContext.isReplEvent() && modifyContext.getSession().isAdministrator() )
888 {
889
890 return;
891 }
892
893 if ( !attributeType.equals( directoryService.getAtProvider().getModifiersName() )
894 && !attributeType.equals( directoryService.getAtProvider().getModifyTimestamp() )
895 && !attributeType.equals( directoryService.getAtProvider().getEntryCSN() )
896 && !PWD_POLICY_STATE_ATTRIBUTE_TYPES.contains( attributeType ) )
897 {
898 String msg = I18n.err( I18n.ERR_52, attributeType );
899 LOG.error( msg );
900 throw new LdapNoPermissionException( msg );
901 }
902 }
903
904
905
906
907
908 private class TopFilter implements EntryFilter
909 {
910
911
912
913 @Override
914 public boolean accept( SearchOperationContext operationContext, Entry entry ) throws LdapException
915 {
916 ServerEntryUtils.filterContents( schemaManager, operationContext, entry );
917
918 return true;
919 }
920
921
922
923
924
925 @Override
926 public String toString( String tabs )
927 {
928 return tabs + "TopFilter";
929 }
930 }
931
932
933
934
935
936
937
938 private void check( Dn dn, Entry entry ) throws LdapException
939 {
940
941
942
943 for ( Attribute attribute : entry.getAttributes() )
944 {
945 AttributeType attributeType = attribute.getAttributeType();
946
947 if ( !schemaManager.getAttributeTypeRegistry().contains( attributeType.getName() ) )
948 {
949 throw new LdapInvalidAttributeTypeException( I18n.err( I18n.ERR_275, attributeType.getName() ) );
950 }
951 }
952
953
954
955
956
957
958
959
960 Attribute objectClassAttr = entry.get( directoryService.getAtProvider().getObjectClass() );
961
962
963
964
965 if ( objectClassAttr == null )
966 {
967 objectClassAttr = new DefaultAttribute( directoryService.getAtProvider().getObjectClass() );
968 }
969
970 List<ObjectClass> ocs = new ArrayList<>();
971
972 alterObjectClasses( objectClassAttr );
973
974
975 Set<String> must = getAllMust( objectClassAttr );
976 Set<String> allAllowed = getAllAllowed( objectClassAttr, must );
977
978 boolean hasExtensibleObject = getObjectClasses( objectClassAttr, ocs );
979
980
981
982 assertObjectClasses( dn, ocs );
983
984 assertRequiredAttributesPresent( dn, entry, must );
985 assertNumberOfAttributeValuesValid( entry );
986
987 if ( !hasExtensibleObject )
988 {
989 assertAllAttributesAllowed( dn, entry, allAllowed );
990 }
991
992
993 entry = assertHumanReadable( entry );
994
995
996 assertSyntaxes( entry );
997
998 assertRdn( dn, entry );
999 }
1000
1001
1002 private void checkOcSuperior( Entry entry ) throws LdapException
1003 {
1004
1005 Attribute supOC = entry.get( MetaSchemaConstants.M_SUP_OBJECT_CLASS_AT );
1006
1007 if ( supOC != null )
1008 {
1009 ObjectClassTypeEnum ocType = ObjectClassTypeEnum.STRUCTURAL;
1010
1011 if ( entry.get( MetaSchemaConstants.M_TYPE_OBJECT_CLASS_AT ) != null )
1012 {
1013 String type = entry.get( MetaSchemaConstants.M_TYPE_OBJECT_CLASS_AT ).getString();
1014 ocType = ObjectClassTypeEnum.getClassType( type );
1015 }
1016
1017
1018
1019 for ( Value sup : supOC )
1020 {
1021 try
1022 {
1023 String supName = sup.getString();
1024
1025 ObjectClass superior = schemaManager.lookupObjectClassRegistry( supName );
1026
1027 switch ( ocType )
1028 {
1029 case ABSTRACT:
1030 if ( !superior.isAbstract() )
1031 {
1032 String message = I18n.err( I18n.ERR_57 );
1033 LOG.error( message );
1034 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, message );
1035 }
1036
1037 break;
1038
1039 case AUXILIARY:
1040 if ( !superior.isAbstract() && !superior.isAuxiliary() )
1041 {
1042 String message = I18n.err( I18n.ERR_58 );
1043 LOG.error( message );
1044 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, message );
1045 }
1046
1047 break;
1048
1049 case STRUCTURAL:
1050 break;
1051
1052 default:
1053 throw new IllegalArgumentException( "Unexpected object class type " + ocType );
1054 }
1055 }
1056 catch ( LdapException ne )
1057 {
1058
1059 String message = I18n.err( I18n.ERR_59 );
1060 LOG.error( message );
1061 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, message );
1062 }
1063 }
1064 }
1065 }
1066
1067
1068
1069
1070
1071
1072
1073
1074 @Override
1075 public void add( AddOperationContext addContext ) throws LdapException
1076 {
1077 Dn name = addContext.getDn();
1078 Entry entry = addContext.getEntry();
1079
1080 check( name, entry );
1081
1082
1083 if ( name.isDescendantOf( schemaBaseDn ) )
1084 {
1085
1086 String schemaName = getSchemaName( name );
1087
1088 if ( entry.contains( directoryService.getAtProvider().getObjectClass(), SchemaConstants.META_SCHEMA_OC ) )
1089 {
1090 next( addContext );
1091
1092 if ( schemaManager.isSchemaLoaded( schemaName ) )
1093 {
1094
1095 computeSuperiors();
1096 }
1097 }
1098 else if ( entry.contains( directoryService.getAtProvider().getObjectClass(),
1099 SchemaConstants.META_OBJECT_CLASS_OC ) )
1100 {
1101
1102 checkOcSuperior( addContext.getEntry() );
1103
1104 next( addContext );
1105
1106
1107 Schema schema = schemaManager.getLoadedSchema( schemaName );
1108
1109 if ( ( schema != null ) && schema.isEnabled() )
1110 {
1111 Attribute oidAT = entry.get( MetaSchemaConstants.M_OID_AT );
1112 String ocOid = oidAT.getString();
1113
1114 ObjectClass addedOC = schemaManager.lookupObjectClassRegistry( ocOid );
1115 computeSuperior( addedOC );
1116 }
1117 }
1118 else if ( entry.contains( directoryService.getAtProvider().getObjectClass(),
1119 SchemaConstants.META_ATTRIBUTE_TYPE_OC ) )
1120 {
1121
1122 next( addContext );
1123 }
1124 else
1125 {
1126 next( addContext );
1127 }
1128
1129 }
1130 else
1131 {
1132 next( addContext );
1133 }
1134 }
1135
1136
1137
1138
1139
1140 @Override
1141 public boolean compare( CompareOperationContext compareContext ) throws LdapException
1142 {
1143 if ( IS_DEBUG )
1144 {
1145 LOG.debug( "Operation Context: {}", compareContext );
1146 }
1147
1148
1149
1150 if ( !schemaManager.getAttributeTypeRegistry().contains( compareContext.getOid() ) )
1151 {
1152 throw new LdapInvalidAttributeTypeException( I18n.err( I18n.ERR_266, compareContext.getOid() ) );
1153 }
1154
1155 return next( compareContext );
1156 }
1157
1158
1159
1160
1161
1162 @Override
1163 public Entry lookup( LookupOperationContext lookupContext ) throws LdapException
1164 {
1165 Entry entry = next( lookupContext );
1166
1167 ServerEntryUtils.filterContents(
1168 lookupContext.getSession().getDirectoryService().getSchemaManager(),
1169 lookupContext, entry );
1170
1171 return entry;
1172 }
1173
1174
1175
1176
1177
1178 @Override
1179 public void modify( ModifyOperationContext modifyContext ) throws LdapException
1180 {
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196 Dn dn = modifyContext.getDn();
1197
1198
1199 if ( dn.equals( subschemaSubentryDn ) )
1200 {
1201 LOG.debug( "Modification attempt on schema subentry {}: \n{}", dn, modifyContext );
1202
1203
1204 List<Modification> mods = modifyContext.getModItems();
1205 List<Modification> cleanMods = new ArrayList<>();
1206
1207 for ( Modification mod : mods )
1208 {
1209 AttributeType at = ( ( DefaultModification ) mod ).getAttribute().getAttributeType();
1210
1211 if ( !directoryService.getAtProvider().getModifiersName().equals( at )
1212 && !directoryService.getAtProvider().getModifyTimestamp().equals( at )
1213 && !directoryService.getAtProvider().getEntryCSN().equals( at ) )
1214 {
1215 cleanMods.add( mod );
1216 }
1217 }
1218
1219 modifyContext.setModItems( cleanMods );
1220
1221
1222 schemaSubEntryManager.modifySchemaSubentry( modifyContext, modifyContext
1223 .hasRequestControl( Cascade.OID ) );
1224
1225 return;
1226 }
1227
1228 checkModifyEntry( modifyContext );
1229
1230 next( modifyContext );
1231 }
1232
1233
1234 private Map<String, List<ModDnAva>> processRdn( Rdn oldRdn, Rdn newRdn, boolean deleteOldRdn )
1235 {
1236 Map<String, List<ModDnAva>> listAvas = new HashMap<>();
1237
1238
1239 for ( Ava ava : newRdn )
1240 {
1241
1242
1243
1244
1245 boolean found = false;
1246
1247 for ( Ava oldAva : oldRdn )
1248 {
1249 if ( oldAva.getAttributeType().equals( ava.getAttributeType() ) )
1250 {
1251
1252 if ( !oldAva.getValue().equals( ava.getValue() ) )
1253 {
1254 List<ModDnAva> modDnAvas = listAvas.get( ava.getAttributeType().getOid() );
1255
1256 if ( modDnAvas == null )
1257 {
1258 modDnAvas = new ArrayList<>();
1259 listAvas.put( ava.getAttributeType().getOid(), modDnAvas );
1260 }
1261
1262 modDnAvas.add( new ModDnAva( ModDnAva.ModDnType.UPDATE_ADD, ava ) );
1263 found = true;
1264 break;
1265 }
1266 }
1267 }
1268
1269 if ( !found )
1270 {
1271 List<ModDnAva> modDnAvas = listAvas.get( ava.getAttributeType().getOid() );
1272
1273 if ( modDnAvas == null )
1274 {
1275 modDnAvas = new ArrayList<>();
1276 listAvas.put( ava.getAttributeType().getOid(), modDnAvas );
1277 }
1278
1279 modDnAvas.add( new ModDnAva( ModDnAva.ModDnType.ADD, ava ) );
1280 }
1281 }
1282
1283
1284 if ( deleteOldRdn )
1285 {
1286 for ( Ava oldAva : oldRdn )
1287 {
1288 boolean found = false;
1289
1290 for ( Ava newAva : newRdn )
1291 {
1292 if ( newAva.getAttributeType().equals( oldAva.getAttributeType() ) )
1293 {
1294
1295 if ( !newAva.getValue().equals( oldAva.getValue() ) )
1296 {
1297 List<ModDnAva> modDnAvas = listAvas.get( oldAva.getAttributeType().getOid() );
1298
1299 if ( modDnAvas == null )
1300 {
1301 modDnAvas = new ArrayList<>();
1302 listAvas.put( oldAva.getAttributeType().getOid(), modDnAvas );
1303 }
1304
1305 modDnAvas.add( new ModDnAva( ModDnAva.ModDnType.UPDATE_DELETE, oldAva ) );
1306 found = true;
1307 break;
1308 }
1309 }
1310 }
1311
1312 if ( !found )
1313 {
1314 List<ModDnAva> modDnAvas = listAvas.get( oldAva.getAttributeType().getOid() );
1315
1316 if ( modDnAvas == null )
1317 {
1318 modDnAvas = new ArrayList<>();
1319 listAvas.put( oldAva.getAttributeType().getOid(), modDnAvas );
1320 }
1321
1322 modDnAvas.add( new ModDnAva( ModDnAva.ModDnType.DELETE, oldAva ) );
1323 }
1324 }
1325 }
1326
1327 return listAvas;
1328 }
1329
1330
1331 private void applyRdn( MoveAndRenameOperationContext moveAndRenameContext, Map<String, List<ModDnAva>> modifiedAvas ) throws LdapException
1332 {
1333 Entry modifiedEntry = moveAndRenameContext.getModifiedEntry();
1334 List<ModDnAva> removedSVs = null;
1335
1336 for ( List<ModDnAva> modDnAvas : modifiedAvas.values() )
1337 {
1338 List<ModDnAva> addedModDnAvs = new ArrayList<>();
1339
1340 for ( ModDnAva modDnAva : modDnAvas )
1341 {
1342 Ava ava = modDnAva.getAva();
1343
1344 switch ( modDnAva.getType() )
1345 {
1346 case ADD :
1347 case UPDATE_ADD :
1348
1349 if ( ava.getAttributeType().isSingleValued() )
1350 {
1351 Attribute svAttribute = modifiedEntry.get( ava.getAttributeType() );
1352 modifiedEntry.removeAttributes( ava.getAttributeType() );
1353
1354 if ( removedSVs == null )
1355 {
1356 removedSVs = new ArrayList<>();
1357 }
1358
1359 addedModDnAvs.add( new ModDnAva( ModDnAva.ModDnType.UPDATE_DELETE, ava ) );
1360 removedSVs.add( new ModDnAva( ModDnAva.ModDnType.UPDATE_DELETE, new Ava( schemaManager, svAttribute.getId(), svAttribute.getString() ) ) );
1361 }
1362
1363 modifiedEntry.add( ava.getAttributeType(), ava.getValue() );
1364 break;
1365
1366 case DELETE :
1367 case UPDATE_DELETE :
1368 modifiedEntry.remove( ava.getAttributeType(), ava.getValue() );
1369 break;
1370
1371 default :
1372 break;
1373 }
1374 }
1375
1376 modDnAvas.addAll( addedModDnAvs );
1377 }
1378
1379
1380 if ( removedSVs != null )
1381 {
1382 for ( ModDnAva modDnAva : removedSVs )
1383 {
1384 String oid = modDnAva.getAva().getAttributeType().getOid();
1385 List<ModDnAva> modDnAvas = modifiedAvas.get( oid );
1386
1387 modDnAvas.add( modDnAva );
1388 }
1389 }
1390
1391 moveAndRenameContext.setModifiedAvas( modifiedAvas );
1392 moveAndRenameContext.setModifiedEntry( modifiedEntry );
1393 }
1394
1395
1396
1397
1398
1399 @Override
1400 public void moveAndRename( MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
1401 {
1402
1403
1404
1405
1406 Entry entry = moveAndRenameContext.getOriginalEntry();
1407 Dn entryDn = entry.getDn();
1408 Rdn oldRdn = entryDn.getRdn();
1409 Rdn newRdn = moveAndRenameContext.getNewRdn();
1410
1411
1412 Map<String, List<ModDnAva>> modifiedAvas = processRdn( oldRdn, newRdn, moveAndRenameContext.getDeleteOldRdn() );
1413
1414
1415 applyRdn( moveAndRenameContext, modifiedAvas );
1416
1417
1418 check( moveAndRenameContext.getNewDn(), moveAndRenameContext.getModifiedEntry() );
1419
1420 next( moveAndRenameContext );
1421 }
1422
1423
1424
1425
1426
1427 @Override
1428 public void rename( RenameOperationContext renameContext ) throws LdapException
1429 {
1430 Dn oldDn = renameContext.getDn();
1431 Rdn newRdn = renameContext.getNewRdn();
1432 boolean deleteOldRn = renameContext.getDeleteOldRdn();
1433 Entry entry = ( ( ClonedServerEntry ) renameContext.getEntry() ).getClonedEntry();
1434
1435
1436
1437
1438
1439
1440
1441 if ( deleteOldRn )
1442 {
1443 Rdn oldRdn = oldDn.getRdn();
1444
1445
1446
1447
1448 for ( Ava atav : oldRdn )
1449 {
1450 AttributeType type = schemaManager.lookupAttributeTypeRegistry( atav.getType() );
1451 entry.remove( type, atav.getValue() );
1452 }
1453
1454
1455 for ( Ava atav : oldRdn )
1456 {
1457 AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( atav.getType() );
1458
1459 if ( !attributeType.isUserModifiable() )
1460 {
1461 throw new LdapNoPermissionException( "Cannot modify the attribute '" + atav.getType() + "'" );
1462 }
1463 }
1464 }
1465
1466 for ( Ava atav : newRdn )
1467 {
1468 AttributeType type = schemaManager.lookupAttributeTypeRegistry( atav.getType() );
1469
1470 entry.add( new DefaultAttribute( type, atav.getValue() ) );
1471 }
1472
1473
1474 entry.setDn( renameContext.getNewDn() );
1475
1476 check( renameContext.getNewDn(), entry );
1477
1478 next( renameContext );
1479 }
1480
1481
1482
1483
1484
1485 @Override
1486 public EntryFilteringCursor search( SearchOperationContext searchContext ) throws LdapException
1487 {
1488 Dn base = searchContext.getDn();
1489 ExprNode filter = searchContext.getFilter();
1490
1491
1492 checkFilter( filter );
1493
1494
1495 if ( !subschemaSubentryDn.equals( base ) )
1496 {
1497 EntryFilteringCursor cursor = next( searchContext );
1498
1499 if ( searchContext.getReturningAttributesString() != null )
1500 {
1501 cursor.addEntryFilter( topFilter );
1502 return cursor;
1503 }
1504
1505 for ( EntryFilter ef : filters )
1506 {
1507 cursor.addEntryFilter( ef );
1508 }
1509
1510 return cursor;
1511 }
1512
1513
1514
1515
1516 if ( searchContext.getScope() == SearchScope.OBJECT )
1517 {
1518
1519 if ( filter instanceof SimpleNode )
1520 {
1521
1522
1523 SimpleNode node = ( SimpleNode ) filter;
1524 String objectClass;
1525
1526 objectClass = node.getValue().getString();
1527
1528 String objectClassOid;
1529
1530 if ( schemaManager.getObjectClassRegistry().contains( objectClass ) )
1531 {
1532 objectClassOid = schemaManager.lookupObjectClassRegistry( objectClass ).getOid();
1533 }
1534 else
1535 {
1536 return new EntryFilteringCursorImpl( new EmptyCursor<Entry>(), searchContext, schemaManager );
1537 }
1538
1539 AttributeType nodeAt = node.getAttributeType();
1540
1541
1542 if ( nodeAt.equals( directoryService.getAtProvider().getObjectClass() )
1543 && ( objectClassOid.equals( SchemaConstants.TOP_OC_OID ) || objectClassOid
1544 .equals( SchemaConstants.SUBSCHEMA_OC_OID ) ) && ( node instanceof EqualityNode ) )
1545 {
1546 Entry serverEntry = SchemaService.getSubschemaEntry( directoryService,
1547 searchContext );
1548 serverEntry.setDn( base );
1549 return new EntryFilteringCursorImpl( new SingletonCursor<Entry>( serverEntry ), searchContext,
1550 schemaManager );
1551 }
1552 else
1553 {
1554 return new EntryFilteringCursorImpl( new EmptyCursor<Entry>(), searchContext, schemaManager );
1555 }
1556 }
1557 else if ( filter instanceof ObjectClassNode )
1558 {
1559
1560 Entry serverEntry = SchemaService.getSubschemaEntry( directoryService,
1561 searchContext );
1562 serverEntry.setDn( base );
1563 return new EntryFilteringCursorImpl(
1564 new SingletonCursor<Entry>( serverEntry ), searchContext, schemaManager );
1565 }
1566 }
1567
1568
1569 return new EntryFilteringCursorImpl( new EmptyCursor<Entry>(), searchContext, schemaManager );
1570 }
1571
1572
1573 private String getSchemaName( Dn dn ) throws LdapException
1574 {
1575 int size = dn.size();
1576
1577 if ( size < 2 )
1578 {
1579 throw new LdapException( I18n.err( I18n.ERR_276 ) );
1580 }
1581
1582 Rdn rdn = dn.getRdn( size - 2 );
1583
1584 return rdn.getValue();
1585 }
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595 private void assertAllAttributesAllowed( Dn dn, Entry entry, Set<String> allowed ) throws LdapException
1596 {
1597
1598 for ( Attribute attribute : entry )
1599 {
1600 String attrOid = attribute.getAttributeType().getOid();
1601
1602 AttributeType attributeType = attribute.getAttributeType();
1603
1604 if ( !attributeType.isCollective() && ( attributeType.getUsage() == UsageEnum.USER_APPLICATIONS )
1605 && !allowed.contains( attrOid ) )
1606 {
1607 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, I18n.err( I18n.ERR_277,
1608 attribute.getUpId(), dn.getName() ) );
1609 }
1610 }
1611 }
1612
1613
1614
1615
1616
1617 private void assertNumberOfAttributeValuesValid( Entry entry ) throws LdapInvalidAttributeValueException
1618 {
1619 for ( Attribute attribute : entry )
1620 {
1621 assertNumberOfAttributeValuesValid( attribute );
1622 }
1623 }
1624
1625
1626
1627
1628
1629 private void assertNumberOfAttributeValuesValid( Attribute attribute ) throws LdapInvalidAttributeValueException
1630 {
1631 if ( attribute.size() > 1 && attribute.getAttributeType().isSingleValued() )
1632 {
1633 throw new LdapInvalidAttributeValueException( ResultCodeEnum.CONSTRAINT_VIOLATION, I18n.err( I18n.ERR_278,
1634 attribute.getUpId() ) );
1635 }
1636 }
1637
1638
1639
1640
1641
1642 private void assertRequiredAttributesPresent( Dn dn, Entry entry, Set<String> must ) throws LdapException
1643 {
1644 for ( Attribute attribute : entry )
1645 {
1646 must.remove( attribute.getAttributeType().getOid() );
1647 }
1648
1649 if ( !must.isEmpty() )
1650 {
1651
1652 StringBuilder sb = new StringBuilder();
1653 sb.append( '[' );
1654
1655 for ( String oid : must )
1656 {
1657 String name = schemaManager.getAttributeType( oid ).getName();
1658 sb.append( name )
1659 .append( '(' )
1660 .append( oid )
1661 .append( "), " );
1662 }
1663
1664 int end = sb.length();
1665 sb.replace( end - 2, end, "" );
1666 sb.append( ']' );
1667
1668 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, I18n.err( I18n.ERR_279,
1669 sb, dn.getName() ) );
1670 }
1671 }
1672
1673
1674
1675
1676
1677
1678
1679
1680 private void assertObjectClasses( Dn dn, List<ObjectClass> ocs ) throws LdapException
1681 {
1682 Set<ObjectClass> structuralObjectClasses = new HashSet<>();
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695 for ( ObjectClass oc : ocs )
1696 {
1697 if ( oc.isStructural() )
1698 {
1699 structuralObjectClasses.add( oc );
1700 }
1701 }
1702
1703
1704
1705
1706
1707 if ( structuralObjectClasses.isEmpty() )
1708 {
1709 String message = I18n.err( I18n.ERR_60, dn );
1710 LOG.error( message );
1711 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, message );
1712 }
1713
1714
1715
1716
1717
1718
1719
1720
1721 Set<ObjectClass> remaining = new HashSet<>( structuralObjectClasses.size() );
1722 remaining.addAll( structuralObjectClasses );
1723
1724 for ( ObjectClass oc : structuralObjectClasses )
1725 {
1726 if ( oc.getSuperiors() != null )
1727 {
1728 for ( ObjectClass superClass : oc.getSuperiors() )
1729 {
1730 if ( superClass.isStructural() )
1731 {
1732 remaining.remove( superClass );
1733 }
1734 }
1735 }
1736 }
1737
1738
1739 if ( remaining.size() > 1 )
1740 {
1741 String message = I18n.err( I18n.ERR_61, dn, remaining );
1742 LOG.error( message );
1743 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, message );
1744 }
1745 }
1746
1747
1748
1749
1750
1751 private void assertSyntaxes( Entry entry ) throws LdapException
1752 {
1753
1754 for ( Attribute attribute : entry )
1755 {
1756 AttributeType attributeType = attribute.getAttributeType();
1757 SyntaxChecker syntaxChecker = attributeType.getSyntax().getSyntaxChecker();
1758
1759 if ( syntaxChecker instanceof OctetStringSyntaxChecker )
1760 {
1761
1762
1763 continue;
1764 }
1765
1766
1767 for ( Value value : attribute )
1768 {
1769 if ( value.isSchemaAware() )
1770 {
1771
1772 continue;
1773 }
1774
1775 if ( !syntaxChecker.isValidSyntax( value.getString() ) )
1776 {
1777 String message = I18n.err( I18n.ERR_280, value.getString(), attribute.getUpId() );
1778 LOG.info( message );
1779 throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
1780 }
1781 }
1782 }
1783 }
1784
1785
1786 private void assertRdn( Dn dn, Entry entry ) throws LdapException
1787 {
1788 for ( Ava atav : dn.getRdn() )
1789 {
1790 Attribute attribute = entry.get( atav.getNormType() );
1791
1792 if ( ( attribute == null ) || ( !attribute.contains( atav.getValue() ) ) )
1793 {
1794 String message = I18n.err( I18n.ERR_62, dn, atav.getType() );
1795 LOG.error( message );
1796 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, message );
1797 }
1798 }
1799 }
1800
1801
1802
1803
1804
1805
1806
1807 private boolean checkHumanReadable( Attribute attribute ) throws LdapException
1808 {
1809 boolean isModified = false;
1810
1811
1812 for ( Value value : attribute )
1813 {
1814 if ( !value.isHumanReadable() )
1815 {
1816
1817
1818 String valStr = new String( value.getBytes(), Charsets.UTF_8 );
1819 attribute.remove( value );
1820 attribute.add( valStr );
1821 isModified = true;
1822 }
1823 }
1824
1825 return isModified;
1826 }
1827
1828
1829
1830
1831
1832
1833
1834 private boolean checkNotHumanReadable( Attribute attribute ) throws LdapException
1835 {
1836 boolean isModified = false;
1837
1838
1839 for ( Value value : attribute )
1840 {
1841 if ( value.isHumanReadable() )
1842 {
1843
1844
1845 byte[] valBytes = value.getBytes();
1846
1847 attribute.remove( value );
1848 attribute.add( valBytes );
1849 isModified = true;
1850 }
1851 }
1852
1853 return isModified;
1854 }
1855
1856
1857
1858
1859
1860
1861
1862 private Entry assertHumanReadable( Entry entry ) throws LdapException
1863 {
1864 Entry clonedEntry = null;
1865
1866
1867 for ( Attribute attribute : entry )
1868 {
1869 boolean isModified;
1870
1871 AttributeType attributeType = attribute.getAttributeType();
1872
1873
1874 if ( attributeType.getSyntax().isHumanReadable() )
1875 {
1876 isModified = checkHumanReadable( attribute );
1877 }
1878 else
1879 {
1880 isModified = checkNotHumanReadable( attribute );
1881 }
1882
1883
1884
1885 if ( isModified )
1886 {
1887 if ( clonedEntry == null )
1888 {
1889 clonedEntry = entry.clone();
1890 }
1891
1892
1893 clonedEntry.put( attribute );
1894 }
1895 }
1896
1897 if ( clonedEntry != null )
1898 {
1899 return clonedEntry;
1900 }
1901 else
1902 {
1903 return entry;
1904 }
1905 }
1906 }