001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 package org.apache.directory.server.core.schema; 021 022 023 import java.util.ArrayList; 024 import java.util.HashSet; 025 import java.util.List; 026 import java.util.Set; 027 028 import org.apache.directory.server.i18n.I18n; 029 import org.apache.directory.shared.ldap.constants.SchemaConstants; 030 import org.apache.directory.shared.ldap.entry.EntryAttribute; 031 import org.apache.directory.shared.ldap.entry.ModificationOperation; 032 import org.apache.directory.shared.ldap.entry.ServerEntry; 033 import org.apache.directory.shared.ldap.entry.Value; 034 import org.apache.directory.shared.ldap.exception.LdapException; 035 import org.apache.directory.shared.ldap.exception.LdapSchemaViolationException; 036 import org.apache.directory.shared.ldap.message.ResultCodeEnum; 037 import org.apache.directory.shared.ldap.name.DN; 038 import org.apache.directory.shared.ldap.schema.AttributeType; 039 import org.apache.directory.shared.ldap.schema.ObjectClass; 040 import org.apache.directory.shared.ldap.schema.ObjectClassTypeEnum; 041 import org.apache.directory.shared.ldap.schema.SchemaManager; 042 import org.apache.directory.shared.ldap.schema.registries.ObjectClassRegistry; 043 import org.apache.directory.shared.ldap.util.NamespaceTools; 044 import org.slf4j.Logger; 045 import org.slf4j.LoggerFactory; 046 047 048 /** 049 * Performs schema checks on behalf of the SchemaInterceptor. 050 * 051 * TODO: we really need to refactor this code since there's much duplication 052 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 053 * @version $Rev: 927839 $, $Date: 2010-03-26 14:25:10 +0100 (Fri, 26 Mar 2010) $ 054 */ 055 public class SchemaChecker 056 { 057 /** the SLF4J logger for this class */ 058 private static Logger log = LoggerFactory.getLogger( SchemaChecker.class ); 059 060 061 /** 062 * Makes sure modify operations do not leave the entry without a STRUCTURAL 063 * objectClass. At least one STRUCTURAL objectClass must be specified for 064 * the entry after modifications take effect. 065 * 066 * @param registry the objectClass registry to lookup ObjectClass specifications 067 * @param name the name of the entry being modified 068 * @param mod the type of modification operation being performed (should be 069 * REMOVE_ATTRIBUTE) 070 * @param attribute the attribute being modified 071 * @throws LdapException if modify operations leave the entry inconsistent 072 * without a STRUCTURAL objectClass 073 */ 074 public static void preventStructuralClassRemovalOnModifyReplace( SchemaManager schemaManager, DN name, ModificationOperation mod, 075 EntryAttribute attribute ) throws LdapException 076 { 077 if ( mod != ModificationOperation.REPLACE_ATTRIBUTE ) 078 { 079 return; 080 } 081 082 if ( !SchemaConstants.OBJECT_CLASS_AT.equalsIgnoreCase( attribute.getUpId() ) ) 083 { 084 return; 085 } 086 087 // whoever issued the modify operation is insane they want to delete 088 // all the objectClass values in which case we must throw an exception 089 if ( attribute.size() == 0 ) 090 { 091 String msg = I18n.err( I18n.ERR_272, name ); 092 093 if ( log.isInfoEnabled() ) 094 { 095 log.info( msg + ". Raising LdapSchemaViolationException." ); 096 } 097 098 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED, msg ); 099 } 100 101 // check that there is at least one structural objectClass in the replacement set 102 for ( Value<?> value:attribute ) 103 { 104 ObjectClass ocType = schemaManager.getObjectClassRegistry().lookup( value.getString() ); 105 106 if ( ocType.getType() == ObjectClassTypeEnum.STRUCTURAL ) 107 { 108 return; 109 } 110 } 111 112 // no structural object classes exist for the entry in the replacement 113 // set for the objectClass attribute so we need to complain about that 114 String msg = I18n.err( I18n.ERR_272, name ); 115 if ( log.isInfoEnabled() ) 116 { 117 log.info( msg + ". Raising LdapSchemaViolationException." ); 118 } 119 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED, msg ); 120 } 121 122 123 /** 124 * Makes sure modify operations do not leave the entry without a STRUCTURAL 125 * objectClass. At least one STRUCTURAL objectClass must be specified for 126 * the entry after modifications take effect. 127 * 128 * @param registry the objectClass registry to lookup ObjectClass specifications 129 * @param name the name of the entry being modified 130 * @param mod the type of modification operation being performed (should be 131 * REMOVE_ATTRIBUTE) 132 * @param entry the entry being modified 133 * @throws LdapException if modify operations leave the entry inconsistent 134 * without a STRUCTURAL objectClass 135 */ 136 public static void preventStructuralClassRemovalOnModifyReplace( 137 ObjectClassRegistry registry, DN name, ModificationOperation mod, ServerEntry entry ) throws LdapException 138 { 139 if ( mod != ModificationOperation.REPLACE_ATTRIBUTE ) 140 { 141 return; 142 } 143 144 EntryAttribute objectClass = entry.get( SchemaConstants.OBJECT_CLASS_AT ); 145 146 if ( objectClass == null ) 147 { 148 return; 149 } 150 151 // whoever issued the modify operation is insane they want to delete 152 // all the objectClass values in which case we must throw an exception 153 if ( objectClass.size() == 0 ) 154 { 155 String msg = I18n.err( I18n.ERR_272, name ); 156 if ( log.isInfoEnabled() ) 157 { 158 log.info( msg + ". Raising LdapSchemaViolationException." ); 159 } 160 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED, msg ); 161 } 162 163 // check that there is at least one structural objectClass in the replacement set 164 for ( Value<?> value:objectClass ) 165 { 166 ObjectClass ocType = registry.lookup( value.getString() ); 167 168 if ( ocType.getType() == ObjectClassTypeEnum.STRUCTURAL ) 169 { 170 return; 171 } 172 } 173 174 // no structural object classes exist for the entry in the replacement 175 // set for the objectClass attribute so we need to complain about that 176 String msg = I18n.err( I18n.ERR_272, name ); 177 if ( log.isInfoEnabled() ) 178 { 179 log.info( msg + ". Raising LdapSchemaViolationException." ); 180 } 181 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED, msg ); 182 } 183 184 185 /** 186 * Makes sure modify operations do not leave the entry without a STRUCTURAL 187 * objectClass. At least one STRUCTURAL objectClass must be specified for 188 * the entry after modifications take effect. 189 * 190 * @param registry the objectClass registry to lookup ObjectClass specifications 191 * @param name the name of the entry being modified 192 * @param mod the type of modification operation being performed (should be 193 * REMOVE_ATTRIBUTE) 194 * @param attribute the attribute being modified 195 * @param entryObjectClasses the entry being modified 196 * @throws LdapException if modify operations leave the entry inconsistent 197 * without a STRUCTURAL objectClass 198 */ 199 public static void preventStructuralClassRemovalOnModifyRemove( SchemaManager schemaManager, DN name, ModificationOperation mod, 200 EntryAttribute attribute, EntryAttribute entryObjectClasses ) throws LdapException 201 { 202 if ( mod != ModificationOperation.REMOVE_ATTRIBUTE ) 203 { 204 return; 205 } 206 207 if ( !attribute.instanceOf( SchemaConstants.OBJECT_CLASS_AT ) ) 208 { 209 return; 210 } 211 212 // check if there is any attribute value as "". 213 // if there is remove it so that it will be considered as not even provided. 214 List<Value<?>> removed = new ArrayList<Value<?>>(); 215 216 // Fist gather the value to remove 217 for ( Value<?> value:attribute ) 218 { 219 if ( value.getString().length() == 0 ) 220 { 221 removed.add( value ); 222 } 223 } 224 225 // Now remove the values from the attribute 226 for ( Value<?> value:removed ) 227 { 228 attribute.remove( value ); 229 } 230 231 // whoever issued the modify operation is insane they want to delete 232 // all the objectClass values in which case we must throw an exception 233 if ( attribute.size() == 0 ) 234 { 235 String msg = I18n.err( I18n.ERR_272, name ); 236 237 if ( log.isInfoEnabled() ) 238 { 239 log.info( msg + ". Raising LdapSchemaViolationException." ); 240 } 241 242 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED, msg ); 243 } 244 245 // remove all the objectClass attribute values from a cloned copy and then 246 // we can analyze what remains in this attribute to make sure a structural 247 // objectClass is present for the entry 248 249 EntryAttribute cloned = entryObjectClasses.clone(); 250 251 for ( Value<?> value:attribute ) 252 { 253 cloned.remove( value ); 254 } 255 256 // check resultant set of objectClass values for a structural objectClass 257 for ( Value<?> objectClass:cloned ) 258 { 259 ObjectClass oc = schemaManager.getObjectClassRegistry().lookup( objectClass.getString() ); 260 261 if ( oc.getType() == ObjectClassTypeEnum.STRUCTURAL ) 262 { 263 return; 264 } 265 } 266 267 // no structural object classes exist for the entry after the modifications 268 // to the objectClass attribute so we need to complain about that 269 String msg = I18n.err( I18n.ERR_272, name ); 270 271 if ( log.isInfoEnabled() ) 272 { 273 log.info( msg + ". Raising LdapSchemaViolationException." ); 274 } 275 276 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED, msg ); 277 } 278 279 280 /** 281 * Makes sure modify operations do not leave the entry without a STRUCTURAL 282 * objectClass. At least one STRUCTURAL objectClass must be specified for 283 * the entry after modifications take effect. 284 * 285 * @param registry the objectClass registry to lookup ObjectClass specifications 286 * @param name the name of the entry being modified 287 * @param mod the type of modification operation being performed (should be 288 * REMOVE_ATTRIBUTE) 289 * @param attributes the attributes being modified 290 * @param entryObjectClasses the entry being modified 291 * @throws NamingException if modify operations leave the entry inconsistent 292 * without a STRUCTURAL objectClass 293 * 294 public static void preventStructuralClassRemovalOnModifyRemove( ObjectClassRegistry registry, Name name, int mod, 295 Attributes attributes, Attribute entryObjectClasses ) throws NamingException 296 { 297 if ( mod != DirContext.REMOVE_ATTRIBUTE ) 298 { 299 return; 300 } 301 302 Attribute objectClass = attributes.get( SchemaConstants.OBJECT_CLASS_AT ); 303 if ( objectClass == null ) 304 { 305 return; 306 } 307 308 // check if there is any attribute value as "". 309 // if there is remove it so that it will be considered as not even provided. 310 for( int ii = 0; ii < objectClass.size(); ii++ ) 311 { 312 Object value = objectClass.get( ii ); 313 if ( "".equals( value ) ) 314 { 315 objectClass.remove( ii ); 316 } 317 } 318 319 // whoever issued the modify operation is insane they want to delete 320 // all the objectClass values in which case we must throw an exception 321 if ( objectClass.size() == 0 ) 322 { 323 String msg = "Modify operation leaves no structural objectClass for entry " + name; 324 if ( log.isInfoEnabled() ) 325 { 326 log.info( msg + ". Raising LdapSchemaViolationException." ); 327 } 328 throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED ); 329 } 330 331 // remove all the objectClass attribute values from a cloned copy and then 332 // we can analyze what remains in this attribute to make sure a structural 333 // objectClass is present for the entry 334 335 Attribute cloned = ( Attribute ) entryObjectClasses.clone(); 336 for ( int ii = 0; ii < objectClass.size(); ii++ ) 337 { 338 cloned.remove( objectClass.get( ii ) ); 339 } 340 341 // check resultant set of objectClass values for a structural objectClass 342 for ( int ii = 0; ii < cloned.size(); ii++ ) 343 { 344 ObjectClass ocType = registry.lookup( ( String ) cloned.get( ii ) ); 345 if ( ocType.getType() == ObjectClassTypeEnum.STRUCTURAL ) 346 { 347 return; 348 } 349 } 350 351 // no structural object classes exist for the entry after the modifications 352 // to the objectClass attribute so we need to complain about that 353 String msg = "Modify operation leaves no structural objectClass for entry " + name; 354 if ( log.isInfoEnabled() ) 355 { 356 log.info( msg + ". Raising LdapSchemaViolationException." ); 357 } 358 throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECT_CLASS_MODS_PROHIBITED ); 359 } 360 */ 361 362 /** 363 * Makes sure a modify operation does not replace RDN attributes or their value. 364 * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6."> 365 * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as 366 * seen below: 367 * <p/> 368 * <pre> 369 * The Modify Operation cannot be used to remove from an entry any of 370 * its distinguished values, those values which form the entry's 371 * relative distinguished name. An attempt to do so will result in the 372 * server returning the error notAllowedOnRDN. The Modify DN Operation 373 * described in section 4.9 is used to rename an entry. 374 * </pre> 375 * 376 * @param name the distinguished name of the attribute being modified 377 * @param mod the modification operation being performed (should be REPLACE_ATTRIBUTE ) 378 * @param attribute the attribute being modified 379 * @param oidRegistry 380 * @throws LdapException if the modify operation is removing an Rdn attribute 381 */ 382 public static void preventRdnChangeOnModifyReplace( DN name, ModificationOperation mod, 383 EntryAttribute attribute, SchemaManager schemaManager ) 384 throws LdapException 385 { 386 if ( mod != ModificationOperation.REPLACE_ATTRIBUTE ) 387 { 388 return; 389 } 390 391 Set<String> rdnAttributes = getRdnAttributes( name ); 392 String id = schemaManager.getAttributeTypeRegistry().getOidByName( attribute.getUpId() ); 393 394 if ( !rdnAttributes.contains( id ) ) 395 { 396 return; 397 } 398 399 // if the attribute values to delete are not specified then all values 400 // for the attribute are to be deleted in which case we must just throw 401 // a schema violation exception with the notAllowedOnRdn result code 402 if ( attribute.size() == 0 ) 403 { 404 String msg = I18n.err( I18n.ERR_273, id, name ); 405 406 if ( log.isInfoEnabled() ) 407 { 408 log.info( msg + ". SchemaChecker is throwing a schema violation exception." ); 409 } 410 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg ); 411 } 412 413 // from here on the modify operation replaces specific values 414 // of the Rdn attribute so we must check to make sure all the old 415 // rdn attribute values are present in the replacement set 416 String rdnValue = getRdnValue( id, name, schemaManager ); 417 418 for ( int ii = 0; ii < attribute.size(); ii++ ) 419 { 420 // if the old rdn value is not in the rdn attribute then 421 // we must complain with a schema violation 422 if ( !attribute.contains( rdnValue ) ) 423 { 424 String msg = I18n.err( I18n.ERR_274, id, name ); 425 426 if ( log.isInfoEnabled() ) 427 { 428 log.info( msg + ". SchemaChecker is throwing a schema violation exception." ); 429 } 430 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg ); 431 } 432 } 433 } 434 435 436 /** 437 * Makes sure a modify operation does not replace RDN attributes or their value. 438 * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6."> 439 * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as 440 * seen below: 441 * <p/> 442 * <pre> 443 * The Modify Operation cannot be used to remove from an entry any of 444 * its distinguished values, those values which form the entry's 445 * relative distinguished name. An attempt to do so will result in the 446 * server returning the error notAllowedOnRDN. The Modify DN Operation 447 * described in section 4.9 is used to rename an entry. 448 * </pre> 449 * 450 * @param name the distinguished name of the attribute being modified 451 * @param mod the modification operation being performed (should be REPLACE_ATTRIBUTE ) 452 * @param entry 453 * @param oidRegistry 454 * @throws LdapException if the modify operation is removing an Rdn attribute 455 */ 456 public static void preventRdnChangeOnModifyReplace( 457 DN name, ModificationOperation mod, ServerEntry entry, 458 SchemaManager schemaManager ) 459 throws LdapException 460 { 461 if ( mod != ModificationOperation.REPLACE_ATTRIBUTE ) 462 { 463 return; 464 } 465 466 Set<String> rdnAttributes = getRdnAttributes( name ); 467 468 for ( AttributeType attributeType:entry.getAttributeTypes() ) 469 { 470 String id = attributeType.getName(); 471 472 if ( rdnAttributes.contains( id ) ) 473 { 474 EntryAttribute rdnAttr = entry.get( id ); 475 476 // if the attribute values to delete are not specified then all values 477 // for the attribute are to be deleted in which case we must just throw 478 // a schema violation exception with the notAllowedOnRdn result code 479 if ( rdnAttr.size() == 0 ) 480 { 481 String msg = I18n.err( I18n.ERR_273, id, name ); 482 483 if ( log.isInfoEnabled() ) 484 { 485 log.info( msg + ". SchemaChecker is throwing a schema violation exception." ); 486 } 487 488 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg ); 489 } 490 491 // from here on the modify operation replaces specific values 492 // of the Rdn attribute so we must check to make sure all the old 493 // rdn attribute values are present in the replacement set 494 String rdnValue = getRdnValue( id, name, schemaManager ); 495 496 // if the old rdn value is not in the rdn attribute then 497 // we must complain with a schema violation 498 if ( !rdnAttr.contains( rdnValue ) ) 499 { 500 String msg = I18n.err( I18n.ERR_274, id, name ); 501 502 if ( log.isInfoEnabled() ) 503 { 504 log.info( msg + ". SchemaChecker is throwing a schema violation exception." ); 505 } 506 507 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg ); 508 } 509 } 510 } 511 } 512 513 514 /** 515 * Makes sure a modify operation does not delete RDN attributes or their value. 516 * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6."> 517 * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as 518 * seen below: 519 * <p/> 520 * <pre> 521 * The Modify Operation cannot be used to remove from an entry any of 522 * its distinguished values, those values which form the entry's 523 * relative distinguished name. An attempt to do so will result in the 524 * server returning the error notAllowedOnRDN. The Modify DN Operation 525 * described in section 4.9 is used to rename an entry. 526 * </pre> 527 * 528 * @param name the distinguished name of the attribute being modified 529 * @param mod the modification operation being performed (should be REMOVE_ATTRIBUTE ) 530 * @param attribute the attribute being modified 531 * @throws LdapException if the modify operation is removing an Rdn attribute 532 */ 533 public static void preventRdnChangeOnModifyRemove( DN name, ModificationOperation mod, EntryAttribute attribute, 534 SchemaManager schemaManager ) throws LdapException 535 { 536 if ( mod != ModificationOperation.REMOVE_ATTRIBUTE ) 537 { 538 return; 539 } 540 541 Set<String> rdnAttributes = getRdnAttributes( name ); 542 String id = attribute.getId(); 543 544 if ( !rdnAttributes.contains( schemaManager.getAttributeTypeRegistry().getOidByName( id ) ) ) 545 { 546 return; 547 } 548 549 // if the attribute values to delete are not specified then all values 550 // for the attribute are to be deleted in which case we must just throw 551 // a schema violation exception with the notAllowedOnRdn result code 552 if ( attribute.size() == 0 ) 553 { 554 String msg = I18n.err( I18n.ERR_273, id, name ); 555 556 if ( log.isInfoEnabled() ) 557 { 558 log.info( msg + ". SchemaChecker is throwing a schema violation exception." ); 559 } 560 561 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg ); 562 } 563 564 // from here on the modify operation only deletes specific values 565 // of the Rdn attribute so we must check if one of those values 566 // are used by the Rdn attribute value pair for the name of the entry 567 String rdnValue = getRdnValue( id, name, schemaManager ); 568 569 for ( Value<?> value:attribute ) 570 { 571 if ( rdnValue.equals( value.getString() ) ) 572 { 573 String msg = I18n.err( I18n.ERR_274, id, name ); 574 575 if ( log.isInfoEnabled() ) 576 { 577 log.info( msg + ". SchemaChecker is throwing a schema violation exception." ); 578 } 579 580 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg ); 581 } 582 } 583 } 584 585 586 /** 587 * Makes sure a modify operation does not delete RDN attributes or their value. 588 * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6."> 589 * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as 590 * seen below: 591 * <p/> 592 * <pre> 593 * The Modify Operation cannot be used to remove from an entry any of 594 * its distinguished values, those values which form the entry's 595 * relative distinguished name. An attempt to do so will result in the 596 * server returning the error notAllowedOnRDN. The Modify DN Operation 597 * described in section 4.9 is used to rename an entry. 598 * </pre> 599 * 600 * @param name the distinguished name of the attribute being modified 601 * @param mod the modification operation being performed (should be REMOVE_ATTRIBUTE ) 602 * @param entry 603 * @param oidRegistry 604 * @throws LdapException if the modify operation is removing an Rdn attribute 605 */ 606 public static void preventRdnChangeOnModifyRemove( DN name, ModificationOperation mod, 607 ServerEntry entry, SchemaManager schemaManager ) 608 throws LdapException 609 { 610 if ( mod != ModificationOperation.REMOVE_ATTRIBUTE ) 611 { 612 return; 613 } 614 615 Set<String> rdnAttributes = getRdnAttributes( name ); 616 617 for ( AttributeType attributeType:entry.getAttributeTypes() ) 618 { 619 String id = attributeType.getName(); 620 621 if ( rdnAttributes.contains( id ) ) 622 { 623 // if the attribute values to delete are not specified then all values 624 // for the attribute are to be deleted in which case we must just throw 625 // a schema violation exception with the notAllowedOnRdn result code 626 if ( entry.get( id ).size() == 0 ) 627 { 628 String msg = I18n.err( I18n.ERR_273, id, name ); 629 630 if ( log.isInfoEnabled() ) 631 { 632 log.info( msg + ". SchemaChecker is throwing a schema violation exception." ); 633 } 634 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg ); 635 } 636 637 // from here on the modify operation only deletes specific values 638 // of the Rdn attribute so we must check if one of those values 639 // are used by the Rdn attribute value pair for the name of the entry 640 String rdnValue = getRdnValue( id, name, schemaManager ); 641 EntryAttribute rdnAttr = entry.get( id ); 642 643 for ( Value<?> value:rdnAttr ) 644 { 645 if ( rdnValue.equals( value.getString() ) ) 646 { 647 String msg = I18n.err( I18n.ERR_274, id, name ); 648 649 if ( log.isInfoEnabled() ) 650 { 651 log.info( msg + ". SchemaChecker is throwing a schema violation exception." ); 652 } 653 throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg ); 654 } 655 } 656 } 657 } 658 } 659 660 661 /** 662 * Gets the Rdn attribute value. This method works even if the Rdn is 663 * composed of multiple attributes. 664 * 665 * @param id the attribute id of the Rdn attribute to return 666 * @param name the distinguished name of the entry 667 * @param oidRegistry the OID registry 668 * @return the Rdn attribute value corresponding to the id, or null if the 669 * attribute is not an rdn attribute 670 * @throws LdapException if the name is malformed in any way 671 */ 672 private static String getRdnValue( String id, DN name, SchemaManager schemaManager ) throws LdapException 673 { 674 // Transform the rdnAttrId to it's OID counterPart 675 String idOid = schemaManager.getAttributeTypeRegistry().getOidByName( id ); 676 677 if ( idOid == null ) 678 { 679 log.error( I18n.err( I18n.ERR_43, id ) ); 680 throw new LdapException( I18n.err( I18n.ERR_44, id ) ); 681 } 682 683 String[] comps = NamespaceTools.getCompositeComponents( name.get( name.size() - 1 ) ); 684 685 for ( int ii = 0; ii < comps.length; ii++ ) 686 { 687 String rdnAttrId = NamespaceTools.getRdnAttribute( comps[ii] ); 688 689 // Transform the rdnAttrId to it's OID counterPart 690 String rdnAttrOid = schemaManager.getAttributeTypeRegistry().getOidByName( rdnAttrId ); 691 692 if ( rdnAttrOid == null ) 693 { 694 log.error( I18n.err( I18n.ERR_43, rdnAttrOid ) ); 695 throw new LdapException( I18n.err( I18n.ERR_44, rdnAttrOid ) ); 696 } 697 698 if ( rdnAttrOid.equalsIgnoreCase( idOid ) ) 699 { 700 return NamespaceTools.getRdnValue( comps[ii] ); 701 } 702 } 703 704 return null; 705 } 706 707 708 /** 709 * Collects the set of Rdn attributes whether or not the Rdn is based on a 710 * single attribute or multiple attributes. 711 * 712 * @param name the distinguished name of an entry 713 * @return the set of attributes composing the Rdn for the name 714 * @throws LdapException if the syntax of the Rdn is incorrect 715 */ 716 private static Set<String> getRdnAttributes( DN name ) throws LdapException 717 { 718 String[] comps = NamespaceTools.getCompositeComponents( name.get( name.size() - 1 ) ); 719 Set<String> attributes = new HashSet<String>(); 720 721 for ( int ii = 0; ii < comps.length; ii++ ) 722 { 723 attributes.add( NamespaceTools.getRdnAttribute( comps[ii] ) ); 724 } 725 726 return attributes; 727 } 728 }