1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
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 * Performs schema checks on behalf of the SchemaInterceptor.
52 *
53 * TODO: we really need to refactor this code since there's much duplication
54 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
55 * @version $Rev: 691847 $, $Date: 2008-09-04 03:23:12 +0200 (Do, 04 Sep 2008) $
56 */
57 public class SchemaChecker
58 {
59 /** the SLF4J logger for this class */
60 private static Logger log = LoggerFactory.getLogger( SchemaChecker.class );
61
62
63 /**
64 * Makes sure modify operations do not leave the entry without a STRUCTURAL
65 * objectClass. At least one STRUCTURAL objectClass must be specified for
66 * the entry after modifications take effect.
67 *
68 * @param registry the objectClass registry to lookup ObjectClass specifications
69 * @param name the name of the entry being modified
70 * @param mod the type of modification operation being performed (should be
71 * REMOVE_ATTRIBUTE)
72 * @param attribute the attribute being modified
73 * @throws NamingException if modify operations leave the entry inconsistent
74 * without a STRUCTURAL objectClass
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 // whoever issued the modify operation is insane they want to delete
90 // all the objectClass values in which case we must throw an exception
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 // check that there is at least one structural objectClass in the replacement set
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 // no structural object classes exist for the entry in the replacement
115 // set for the objectClass attribute so we need to complain about that
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 * Makes sure modify operations do not leave the entry without a STRUCTURAL
127 * objectClass. At least one STRUCTURAL objectClass must be specified for
128 * the entry after modifications take effect.
129 *
130 * @param registry the objectClass registry to lookup ObjectClass specifications
131 * @param name the name of the entry being modified
132 * @param mod the type of modification operation being performed (should be
133 * REMOVE_ATTRIBUTE)
134 * @param entry the entry being modified
135 * @throws NamingException if modify operations leave the entry inconsistent
136 * without a STRUCTURAL objectClass
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 // whoever issued the modify operation is insane they want to delete
154 // all the objectClass values in which case we must throw an exception
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 // check that there is at least one structural objectClass in the replacement set
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 // no structural object classes exist for the entry in the replacement
177 // set for the objectClass attribute so we need to complain about that
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 * Makes sure modify operations do not leave the entry without a STRUCTURAL
189 * objectClass. At least one STRUCTURAL objectClass must be specified for
190 * the entry after modifications take effect.
191 *
192 * @param registry the objectClass registry to lookup ObjectClass specifications
193 * @param name the name of the entry being modified
194 * @param mod the type of modification operation being performed (should be
195 * REMOVE_ATTRIBUTE)
196 * @param attribute the attribute being modified
197 * @param entryObjectClasses the entry being modified
198 * @throws NamingException if modify operations leave the entry inconsistent
199 * without a STRUCTURAL objectClass
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 // check if there is any attribute value as "".
215 // if there is remove it so that it will be considered as not even provided.
216 List<Value<?>> removed = new ArrayList<Value<?>>();
217
218 // Fist gather the value to remove
219 for ( Value<?> value:attribute )
220 {
221 if ( ((String)value.get()).length() == 0 )
222 {
223 removed.add( value );
224 }
225 }
226
227 // Now remove the values from the attribute
228 for ( Value<?> value:removed )
229 {
230 attribute.remove( value );
231 }
232
233 // whoever issued the modify operation is insane they want to delete
234 // all the objectClass values in which case we must throw an exception
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 // remove all the objectClass attribute values from a cloned copy and then
248 // we can analyze what remains in this attribute to make sure a structural
249 // objectClass is present for the entry
250
251 ServerAttribute cloned = ( ServerAttribute ) entryObjectClasses.clone();
252
253 for ( Value<?> value:attribute )
254 {
255 cloned.remove( value );
256 }
257
258 // check resultant set of objectClass values for a structural objectClass
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 // no structural object classes exist for the entry after the modifications
270 // to the objectClass attribute so we need to complain about that
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 * Makes sure modify operations do not leave the entry without a STRUCTURAL
284 * objectClass. At least one STRUCTURAL objectClass must be specified for
285 * the entry after modifications take effect.
286 *
287 * @param registry the objectClass registry to lookup ObjectClass specifications
288 * @param name the name of the entry being modified
289 * @param mod the type of modification operation being performed (should be
290 * REMOVE_ATTRIBUTE)
291 * @param attributes the attributes being modified
292 * @param entryObjectClasses the entry being modified
293 * @throws NamingException if modify operations leave the entry inconsistent
294 * without a STRUCTURAL objectClass
295 *
296 public static void preventStructuralClassRemovalOnModifyRemove( ObjectClassRegistry registry, Name name, int mod,
297 Attributes attributes, Attribute entryObjectClasses ) throws NamingException
298 {
299 if ( mod != DirContext.REMOVE_ATTRIBUTE )
300 {
301 return;
302 }
303
304 Attribute objectClass = attributes.get( SchemaConstants.OBJECT_CLASS_AT );
305 if ( objectClass == null )
306 {
307 return;
308 }
309
310 // check if there is any attribute value as "".
311 // if there is remove it so that it will be considered as not even provided.
312 for( int ii = 0; ii < objectClass.size(); ii++ )
313 {
314 Object value = objectClass.get( ii );
315 if ( "".equals( value ) )
316 {
317 objectClass.remove( ii );
318 }
319 }
320
321 // whoever issued the modify operation is insane they want to delete
322 // all the objectClass values in which case we must throw an exception
323 if ( objectClass.size() == 0 )
324 {
325 String msg = "Modify operation leaves no structural objectClass for entry " + name;
326 if ( log.isInfoEnabled() )
327 {
328 log.info( msg + ". Raising LdapSchemaViolationException." );
329 }
330 throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED );
331 }
332
333 // remove all the objectClass attribute values from a cloned copy and then
334 // we can analyze what remains in this attribute to make sure a structural
335 // objectClass is present for the entry
336
337 Attribute cloned = ( Attribute ) entryObjectClasses.clone();
338 for ( int ii = 0; ii < objectClass.size(); ii++ )
339 {
340 cloned.remove( objectClass.get( ii ) );
341 }
342
343 // check resultant set of objectClass values for a structural objectClass
344 for ( int ii = 0; ii < cloned.size(); ii++ )
345 {
346 ObjectClass ocType = registry.lookup( ( String ) cloned.get( ii ) );
347 if ( ocType.getType() == ObjectClassTypeEnum.STRUCTURAL )
348 {
349 return;
350 }
351 }
352
353 // no structural object classes exist for the entry after the modifications
354 // to the objectClass attribute so we need to complain about that
355 String msg = "Modify operation leaves no structural objectClass for entry " + name;
356 if ( log.isInfoEnabled() )
357 {
358 log.info( msg + ". Raising LdapSchemaViolationException." );
359 }
360 throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED );
361 }
362 */
363
364 /**
365 * Makes sure a modify operation does not replace RDN attributes or their value.
366 * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6.">
367 * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as
368 * seen below:
369 * <p/>
370 * <pre>
371 * The Modify Operation cannot be used to remove from an entry any of
372 * its distinguished values, those values which form the entry's
373 * relative distinguished name. An attempt to do so will result in the
374 * server returning the error notAllowedOnRDN. The Modify DN Operation
375 * described in section 4.9 is used to rename an entry.
376 * </pre>
377 *
378 * @param name the distinguished name of the attribute being modified
379 * @param mod the modification operation being performed (should be REPLACE_ATTRIBUTE )
380 * @param attribute the attribute being modified
381 * @param oidRegistry
382 * @throws NamingException if the modify operation is removing an Rdn attribute
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 // if the attribute values to delete are not specified then all values
401 // for the attribute are to be deleted in which case we must just throw
402 // a schema violation exception with the notAllowedOnRdn result code
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 // from here on the modify operation replaces specific values
416 // of the Rdn attribute so we must check to make sure all the old
417 // rdn attribute values are present in the replacement set
418 String rdnValue = getRdnValue( id, name, oidRegistry );
419 for ( int ii = 0; ii < attribute.size(); ii++ )
420 {
421 // if the old rdn value is not in the rdn attribute then
422 // we must complain with a schema violation
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 * Makes sure a modify operation does not replace RDN attributes or their value.
440 * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6.">
441 * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as
442 * seen below:
443 * <p/>
444 * <pre>
445 * The Modify Operation cannot be used to remove from an entry any of
446 * its distinguished values, those values which form the entry's
447 * relative distinguished name. An attempt to do so will result in the
448 * server returning the error notAllowedOnRDN. The Modify DN Operation
449 * described in section 4.9 is used to rename an entry.
450 * </pre>
451 *
452 * @param name the distinguished name of the attribute being modified
453 * @param mod the modification operation being performed (should be REPLACE_ATTRIBUTE )
454 * @param entry
455 * @param oidRegistry
456 * @throws NamingException if the modify operation is removing an Rdn attribute
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 // if the attribute values to delete are not specified then all values
478 // for the attribute are to be deleted in which case we must just throw
479 // a schema violation exception with the notAllowedOnRdn result code
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 // from here on the modify operation replaces specific values
494 // of the Rdn attribute so we must check to make sure all the old
495 // rdn attribute values are present in the replacement set
496 String rdnValue = getRdnValue( id, name, oidRegistry );
497
498 // if the old rdn value is not in the rdn attribute then
499 // we must complain with a schema violation
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 * Makes sure a modify operation does not delete RDN attributes or their value.
519 * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6.">
520 * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as
521 * seen below:
522 * <p/>
523 * <pre>
524 * The Modify Operation cannot be used to remove from an entry any of
525 * its distinguished values, those values which form the entry's
526 * relative distinguished name. An attempt to do so will result in the
527 * server returning the error notAllowedOnRDN. The Modify DN Operation
528 * described in section 4.9 is used to rename an entry.
529 * </pre>
530 *
531 * @param name the distinguished name of the attribute being modified
532 * @param mod the modification operation being performed (should be REMOVE_ATTRIBUTE )
533 * @param attribute the attribute being modified
534 * @throws NamingException if the modify operation is removing an Rdn attribute
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 // if the attribute values to delete are not specified then all values
553 // for the attribute are to be deleted in which case we must just throw
554 // a schema violation exception with the notAllowedOnRdn result code
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 // from here on the modify operation only deletes specific values
569 // of the Rdn attribute so we must check if one of those values
570 // are used by the Rdn attribute value pair for the name of the entry
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 * Makes sure a modify operation does not delete RDN attributes or their value.
593 * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6.">
594 * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as
595 * seen below:
596 * <p/>
597 * <pre>
598 * The Modify Operation cannot be used to remove from an entry any of
599 * its distinguished values, those values which form the entry's
600 * relative distinguished name. An attempt to do so will result in the
601 * server returning the error notAllowedOnRDN. The Modify DN Operation
602 * described in section 4.9 is used to rename an entry.
603 * </pre>
604 *
605 * @param name the distinguished name of the attribute being modified
606 * @param mod the modification operation being performed (should be REMOVE_ATTRIBUTE )
607 * @param entry
608 * @param oidRegistry
609 * @throws NamingException if the modify operation is removing an Rdn attribute
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 // if the attribute values to delete are not specified then all values
628 // for the attribute are to be deleted in which case we must just throw
629 // a schema violation exception with the notAllowedOnRdn result code
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 // from here on the modify operation only deletes specific values
643 // of the Rdn attribute so we must check if one of those values
644 // are used by the Rdn attribute value pair for the name of the entry
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 * Gets the Rdn attribute value. This method works even if the Rdn is
669 * composed of multiple attributes.
670 *
671 * @param id the attribute id of the Rdn attribute to return
672 * @param name the distinguished name of the entry
673 * @param oidRegistry the OID registry
674 * @return the Rdn attribute value corresponding to the id, or null if the
675 * attribute is not an rdn attribute
676 * @throws NamingException if the name is malformed in any way
677 */
678 private static String getRdnValue( String id, LdapDN name, OidRegistry oidRegistry ) throws NamingException
679 {
680 // Transform the rdnAttrId to it's OID counterPart
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 // Transform the rdnAttrId to it's OID counterPart
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 * Collects the set of Rdn attributes whether or not the Rdn is based on a
716 * single attribute or multiple attributes.
717 *
718 * @param name the distinguished name of an entry
719 * @return the set of attributes composing the Rdn for the name
720 * @throws NamingException if the syntax of the Rdn is incorrect
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 }