You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ak...@apache.org on 2005/08/24 03:21:59 UTC
svn commit: r239501 - in /directory/apacheds/trunk/core/src:
main/java/org/apache/ldap/server/schema/
test/org/apache/ldap/server/schema/ test/resources/
Author: akarasulu
Date: Tue Aug 23 18:21:51 2005
New Revision: 239501
URL: http://svn.apache.org/viewcvs?rev=239501&view=rev
Log:
changes ...
o added some schema checking for 2251 compliance to the SchemaService which
is an interceptor responsible for schema checks
o added satelite class for actually doing the checks called SchemaChecker
which I suspect can be split into several other classes for the specific
nature of the schema checks it performs
o added test case to unit test the operation of functions in the SchemaChecker
o added log4j configuration for testing only which is not packaged into the
core jar
todos ...
o this stuff needs serious refactoring because of crazy amounts of code
duplication - it was easier (quick and dirty) to get the code working
as separate functions for now
This commit resolves the following issue, DIREVE-230, filed by Stefan:
http://issues.apache.org/jira/browse/DIREVE-230
Added:
directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaChecker.java
directory/apacheds/trunk/core/src/test/org/apache/ldap/server/schema/SchemaCheckerTest.java
directory/apacheds/trunk/core/src/test/resources/
directory/apacheds/trunk/core/src/test/resources/log4j.properties
Modified:
directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaService.java
Added: directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaChecker.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaChecker.java?rev=239501&view=auto
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaChecker.java (added)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaChecker.java Tue Aug 23 18:21:51 2005
@@ -0,0 +1,658 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.ldap.server.schema;
+
+
+import org.apache.ldap.common.util.NamespaceTools;
+import org.apache.ldap.common.exception.LdapSchemaViolationException;
+import org.apache.ldap.common.message.ResultCodeEnum;
+import org.apache.ldap.common.schema.ObjectClass;
+import org.apache.ldap.common.schema.ObjectClassTypeEnum;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.naming.NamingException;
+import javax.naming.Name;
+import javax.naming.NamingEnumeration;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.Attribute;
+import java.util.Set;
+import java.util.HashSet;
+
+
+/**
+ * Performs schema checks on behalf of the SchemaService.
+ *
+ * @todo we really need to refactor this code since there's much duplication
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class SchemaChecker
+{
+ /** the SLF4J logger for this class */
+ private static Logger log = LoggerFactory.getLogger( SchemaChecker.class );
+
+
+ /**
+ * Makes sure modify operations do not leave the entry without a STRUCTURAL
+ * objectClass. At least one STRUCTURAL objectClass must be specified for
+ * the entry after modifications take effect.
+ *
+ * @param registry the objectClass registry to lookup ObjectClass specifications
+ * @param name the name of the entry being modified
+ * @param mod the type of modification operation being performed (should be
+ * REMOVE_ATTRIBUTE)
+ * @param attribute the attribute being modified
+ * @throws NamingException if modify operations leave the entry inconsistent
+ * without a STRUCTURAL objectClass
+ */
+ public static void preventStructuralClassRemovalOnModifyReplace( ObjectClassRegistry registry, Name name, int mod,
+ Attribute attribute )
+ throws NamingException
+ {
+ if ( mod != DirContext.REPLACE_ATTRIBUTE )
+ {
+ return;
+ }
+
+ if ( ! "objectclass".equalsIgnoreCase( attribute.getID() ) )
+ {
+ return;
+ }
+
+ // whoever issued the modify operation is insane they want to delete
+ // all the objectClass values in which case we must throw an exception
+ if ( attribute.size() == 0 )
+ {
+ String msg = "Modify operation leaves no structural objectClass for entry " + name;
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". Raising LdapSchemaViolationException." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+
+ // check that there is at least one structural objectClass in the replacement set
+ for ( int ii = 0; ii < attribute.size(); ii++ )
+ {
+ ObjectClass ocType = registry.lookup( ( String ) attribute.get( ii ) );
+ if ( ocType.getType() == ObjectClassTypeEnum.STRUCTURAL )
+ {
+ return;
+ }
+ }
+
+ // no structural object classes exist for the entry in the replacement
+ // set for the objectClass attribute so we need to complain about that
+ String msg = "Modify operation leaves no structural objectClass for entry " + name;
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". Raising LdapSchemaViolationException." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+
+
+ /**
+ * Makes sure modify operations do not leave the entry without a STRUCTURAL
+ * objectClass. At least one STRUCTURAL objectClass must be specified for
+ * the entry after modifications take effect.
+ *
+ * @param registry the objectClass registry to lookup ObjectClass specifications
+ * @param name the name of the entry being modified
+ * @param mod the type of modification operation being performed (should be
+ * REMOVE_ATTRIBUTE)
+ * @param attributes the attributes being modified
+ * @throws NamingException if modify operations leave the entry inconsistent
+ * without a STRUCTURAL objectClass
+ */
+ public static void preventStructuralClassRemovalOnModifyReplace( ObjectClassRegistry registry, Name name, int mod,
+ Attributes attributes )
+ throws NamingException
+ {
+ if ( mod != DirContext.REPLACE_ATTRIBUTE )
+ {
+ return;
+ }
+
+ Attribute objectClass = attributes.get( "objectClass" );
+ if ( objectClass == null )
+ {
+ return;
+ }
+
+ // whoever issued the modify operation is insane they want to delete
+ // all the objectClass values in which case we must throw an exception
+ if ( objectClass.size() == 0 )
+ {
+ String msg = "Modify operation leaves no structural objectClass for entry " + name;
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". Raising LdapSchemaViolationException." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+
+ // check that there is at least one structural objectClass in the replacement set
+ for ( int ii = 0; ii < objectClass.size(); ii++ )
+ {
+ ObjectClass ocType = registry.lookup( ( String ) objectClass.get( ii ) );
+ if ( ocType.getType() == ObjectClassTypeEnum.STRUCTURAL )
+ {
+ return;
+ }
+ }
+
+ // no structural object classes exist for the entry in the replacement
+ // set for the objectClass attribute so we need to complain about that
+ String msg = "Modify operation leaves no structural objectClass for entry " + name;
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". Raising LdapSchemaViolationException." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+
+
+ /**
+ * Makes sure modify operations do not leave the entry without a STRUCTURAL
+ * objectClass. At least one STRUCTURAL objectClass must be specified for
+ * the entry after modifications take effect.
+ *
+ * @param registry the objectClass registry to lookup ObjectClass specifications
+ * @param name the name of the entry being modified
+ * @param mod the type of modification operation being performed (should be
+ * REMOVE_ATTRIBUTE)
+ * @param attribute the attribute being modified
+ * @param entryObjectClasses the entry being modified
+ * @throws NamingException if modify operations leave the entry inconsistent
+ * without a STRUCTURAL objectClass
+ */
+ public static void preventStructuralClassRemovalOnModifyRemove( ObjectClassRegistry registry, Name name, int mod,
+ Attribute attribute, Attribute entryObjectClasses )
+ throws NamingException
+ {
+ if ( mod != DirContext.REMOVE_ATTRIBUTE )
+ {
+ return;
+ }
+
+ if ( ! "objectclass".equalsIgnoreCase( attribute.getID() ) )
+ {
+ return;
+ }
+
+ // whoever issued the modify operation is insane they want to delete
+ // all the objectClass values in which case we must throw an exception
+ if ( attribute.size() == 0 )
+ {
+ String msg = "Modify operation leaves no structural objectClass for entry " + name;
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". Raising LdapSchemaViolationException." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+
+ // remove all the objectClass attribute values from a cloned copy and then
+ // we can analyze what remains in this attribute to make sure a structural
+ // objectClass is present for the entry
+
+ Attribute cloned = ( Attribute ) entryObjectClasses.clone();
+ for ( int ii = 0; ii < attribute.size(); ii++ )
+ {
+ cloned.remove( attribute.get( ii ) );
+ }
+
+ // check resultant set of objectClass values for a structural objectClass
+ for ( int ii = 0; ii < cloned.size(); ii++ )
+ {
+ ObjectClass ocType = registry.lookup( ( String ) cloned.get( ii ) );
+ if ( ocType.getType() == ObjectClassTypeEnum.STRUCTURAL )
+ {
+ return;
+ }
+ }
+
+ // no structural object classes exist for the entry after the modifications
+ // to the objectClass attribute so we need to complain about that
+ String msg = "Modify operation leaves no structural objectClass for entry " + name;
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". Raising LdapSchemaViolationException." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+
+
+ /**
+ * Makes sure modify operations do not leave the entry without a STRUCTURAL
+ * objectClass. At least one STRUCTURAL objectClass must be specified for
+ * the entry after modifications take effect.
+ *
+ * @param registry the objectClass registry to lookup ObjectClass specifications
+ * @param name the name of the entry being modified
+ * @param mod the type of modification operation being performed (should be
+ * REMOVE_ATTRIBUTE)
+ * @param attributes the attributes being modified
+ * @param entryObjectClasses the entry being modified
+ * @throws NamingException if modify operations leave the entry inconsistent
+ * without a STRUCTURAL objectClass
+ */
+ public static void preventStructuralClassRemovalOnModifyRemove( ObjectClassRegistry registry, Name name, int mod,
+ Attributes attributes, Attribute entryObjectClasses )
+ throws NamingException
+ {
+ if ( mod != DirContext.REMOVE_ATTRIBUTE )
+ {
+ return;
+ }
+
+ Attribute objectClass = attributes.get( "objectClass" );
+ if ( objectClass == null )
+ {
+ return;
+ }
+
+ // whoever issued the modify operation is insane they want to delete
+ // all the objectClass values in which case we must throw an exception
+ if ( objectClass.size() == 0 )
+ {
+ String msg = "Modify operation leaves no structural objectClass for entry " + name;
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". Raising LdapSchemaViolationException." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+
+ // remove all the objectClass attribute values from a cloned copy and then
+ // we can analyze what remains in this attribute to make sure a structural
+ // objectClass is present for the entry
+
+ Attribute cloned = ( Attribute ) entryObjectClasses.clone();
+ for ( int ii = 0; ii < objectClass.size(); ii++ )
+ {
+ cloned.remove( objectClass.get( ii ) );
+ }
+
+ // check resultant set of objectClass values for a structural objectClass
+ for ( int ii = 0; ii < cloned.size(); ii++ )
+ {
+ ObjectClass ocType = registry.lookup( ( String ) cloned.get( ii ) );
+ if ( ocType.getType() == ObjectClassTypeEnum.STRUCTURAL )
+ {
+ return;
+ }
+ }
+
+ // no structural object classes exist for the entry after the modifications
+ // to the objectClass attribute so we need to complain about that
+ String msg = "Modify operation leaves no structural objectClass for entry " + name;
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". Raising LdapSchemaViolationException." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+
+
+ /**
+ * Makes sure a modify operation does not replace RDN attributes or their value.
+ * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6.">
+ * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as
+ * seen below:
+ * <p/>
+ * <pre>
+ * The Modify Operation cannot be used to remove from an entry any of
+ * its distinguished values, those values which form the entry's
+ * relative distinguished name. An attempt to do so will result in the
+ * server returning the error notAllowedOnRDN. The Modify DN Operation
+ * described in section 4.9 is used to rename an entry.
+ * </pre>
+ *
+ * @param name the distinguished name of the attribute being modified
+ * @param mod the modification operation being performed (should be REPLACE_ATTRIBUTE )
+ * @param attribute the attribute being modified
+ * @throws NamingException if the modify operation is removing an Rdn attribute
+ */
+ public static void preventRdnChangeOnModifyReplace( Name name, int mod, Attribute attribute )
+ throws NamingException
+ {
+ if ( mod != DirContext.REPLACE_ATTRIBUTE )
+ {
+ return;
+ }
+
+ Set rdnAttributes = getRdnAttributes( name );
+ String id = ( String ) attribute.getID();
+
+ if ( ! rdnAttributes.contains( id ) )
+ {
+ return;
+ }
+
+ // if the attribute values to delete are not specified then all values
+ // for the attribute are to be deleted in which case we must just throw
+ // a schema violation exception with the notAllowedOnRdn result code
+ if ( attribute.size() == 0 )
+ {
+ String msg = "Modify operation attempts to delete RDN attribute ";
+ msg += id + " on entry " + name + " violates schema constraints";
+
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOTALLOWEDONRDN );
+ }
+
+ // from here on the modify operation replaces specific values
+ // of the Rdn attribute so we must check to make sure all the old
+ // rdn attribute values are present in the replacement set
+ String rdnValue = getRdnValue( id, name );
+ for ( int ii = 0; ii < attribute.size(); ii++ )
+ {
+ // if the old rdn value is not in the rdn attribute then
+ // we must complain with a schema violation
+ if ( ! attribute.contains( rdnValue ) )
+ {
+ String msg = "Modify operation attempts to delete RDN attribute values in use for ";
+ msg += id + " on entry " + name + " and violates schema constraints";
+
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOTALLOWEDONRDN );
+ }
+ }
+ }
+
+
+ /**
+ * Makes sure a modify operation does not replace RDN attributes or their value.
+ * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6.">
+ * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as
+ * seen below:
+ * <p/>
+ * <pre>
+ * The Modify Operation cannot be used to remove from an entry any of
+ * its distinguished values, those values which form the entry's
+ * relative distinguished name. An attempt to do so will result in the
+ * server returning the error notAllowedOnRDN. The Modify DN Operation
+ * described in section 4.9 is used to rename an entry.
+ * </pre>
+ *
+ * @param name the distinguished name of the attribute being modified
+ * @param mod the modification operation being performed (should be REPLACE_ATTRIBUTE )
+ * @param attributes the attributes being modified
+ * @throws NamingException if the modify operation is removing an Rdn attribute
+ */
+ public static void preventRdnChangeOnModifyReplace( Name name, int mod, Attributes attributes )
+ throws NamingException
+ {
+ if ( mod != DirContext.REPLACE_ATTRIBUTE )
+ {
+ return;
+ }
+
+ Set rdnAttributes = getRdnAttributes( name );
+ NamingEnumeration list = attributes.getIDs();
+ while ( list.hasMore() )
+ {
+ String id = ( String ) list.next();
+
+ if ( rdnAttributes.contains( id ) )
+ {
+ // if the attribute values to delete are not specified then all values
+ // for the attribute are to be deleted in which case we must just throw
+ // a schema violation exception with the notAllowedOnRdn result code
+ if ( attributes.get( id ).size() == 0 )
+ {
+ String msg = "Modify operation attempts to delete RDN attribute ";
+ msg += id + " on entry " + name + " violates schema constraints";
+
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOTALLOWEDONRDN );
+ }
+
+ // from here on the modify operation replaces specific values
+ // of the Rdn attribute so we must check to make sure all the old
+ // rdn attribute values are present in the replacement set
+ String rdnValue = getRdnValue( id, name );
+ Attribute rdnAttr = attributes.get( id );
+ for ( int ii = 0; ii < rdnAttr.size(); ii++ )
+ {
+ // if the old rdn value is not in the rdn attribute then
+ // we must complain with a schema violation
+ if ( ! rdnAttr.contains( rdnValue ) )
+ {
+ String msg = "Modify operation attempts to delete RDN attribute values in use for ";
+ msg += id + " on entry " + name + " and violates schema constraints";
+
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOTALLOWEDONRDN );
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Makes sure a modify operation does not delete RDN attributes or their value.
+ * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6.">
+ * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as
+ * seen below:
+ * <p/>
+ * <pre>
+ * The Modify Operation cannot be used to remove from an entry any of
+ * its distinguished values, those values which form the entry's
+ * relative distinguished name. An attempt to do so will result in the
+ * server returning the error notAllowedOnRDN. The Modify DN Operation
+ * described in section 4.9 is used to rename an entry.
+ * </pre>
+ *
+ * @param name the distinguished name of the attribute being modified
+ * @param mod the modification operation being performed (should be REMOVE_ATTRIBUTE )
+ * @param attribute the attribute being modified
+ * @throws NamingException if the modify operation is removing an Rdn attribute
+ */
+ public static void preventRdnChangeOnModifyRemove( Name name, int mod, Attribute attribute )
+ throws NamingException
+ {
+ if ( mod != DirContext.REMOVE_ATTRIBUTE )
+ {
+ return;
+ }
+
+ Set rdnAttributes = getRdnAttributes( name );
+ String id = attribute.getID();
+
+ if ( ! rdnAttributes.contains( id ) )
+ {
+ return;
+ }
+
+ // if the attribute values to delete are not specified then all values
+ // for the attribute are to be deleted in which case we must just throw
+ // a schema violation exception with the notAllowedOnRdn result code
+ if ( attribute.size() == 0 )
+ {
+ String msg = "Modify operation attempts to delete RDN attribute ";
+ msg += id + " on entry " + name + " violates schema constraints";
+
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOTALLOWEDONRDN );
+ }
+
+ // from here on the modify operation only deletes specific values
+ // of the Rdn attribute so we must check if one of those values
+ // are used by the Rdn attribute value pair for the name of the entry
+ String rdnValue = getRdnValue( id, name );
+ for ( int ii = 0; ii < attribute.size(); ii++ )
+ {
+ if ( rdnValue.equals( attribute.get( ii ) ) )
+ {
+ String msg = "Modify operation attempts to delete RDN attribute values in use for ";
+ msg += id + " on entry " + name + " and violates schema constraints";
+
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOTALLOWEDONRDN );
+ }
+ }
+ }
+
+
+ /**
+ * Makes sure a modify operation does not delete RDN attributes or their value.
+ * According to section 4.6 of <a href="http://rfc.net/rfc2251.html#s4.6.">
+ * RFC 2251</a> a modify operation cannot be used to remove Rdn attributes as
+ * seen below:
+ * <p/>
+ * <pre>
+ * The Modify Operation cannot be used to remove from an entry any of
+ * its distinguished values, those values which form the entry's
+ * relative distinguished name. An attempt to do so will result in the
+ * server returning the error notAllowedOnRDN. The Modify DN Operation
+ * described in section 4.9 is used to rename an entry.
+ * </pre>
+ *
+ * @param name the distinguished name of the attribute being modified
+ * @param mod the modification operation being performed (should be REMOVE_ATTRIBUTE )
+ * @param attributes the attributes being modified
+ * @throws NamingException if the modify operation is removing an Rdn attribute
+ */
+ public static void preventRdnChangeOnModifyRemove( Name name, int mod, Attributes attributes )
+ throws NamingException
+ {
+ if ( mod != DirContext.REMOVE_ATTRIBUTE )
+ {
+ return;
+ }
+
+ Set rdnAttributes = getRdnAttributes( name );
+ NamingEnumeration list = attributes.getIDs();
+ while ( list.hasMore() )
+ {
+ String id = ( String ) list.next();
+
+ if ( rdnAttributes.contains( id ) )
+ {
+ // if the attribute values to delete are not specified then all values
+ // for the attribute are to be deleted in which case we must just throw
+ // a schema violation exception with the notAllowedOnRdn result code
+ if ( attributes.get( id ).size() == 0 )
+ {
+ String msg = "Modify operation attempts to delete RDN attribute ";
+ msg += id + " on entry " + name + " violates schema constraints";
+
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOTALLOWEDONRDN );
+ }
+
+ // from here on the modify operation only deletes specific values
+ // of the Rdn attribute so we must check if one of those values
+ // are used by the Rdn attribute value pair for the name of the entry
+ String rdnValue = getRdnValue( id, name );
+ Attribute rdnAttr = attributes.get( id );
+ for ( int ii = 0; ii < rdnAttr.size(); ii++ )
+ {
+ if ( rdnValue.equals( rdnAttr.get( ii ) ) )
+ {
+ String msg = "Modify operation attempts to delete RDN attribute values in use for ";
+ msg += id + " on entry " + name + " and violates schema constraints";
+
+ if ( log.isInfoEnabled() )
+ {
+ log.info( msg + ". SchemaChecker is throwing a schema violation exception." );
+ }
+ throw new LdapSchemaViolationException( msg, ResultCodeEnum.NOTALLOWEDONRDN );
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Gets the Rdn attribute value. This method works even if the Rdn is
+ * composed of multiple attributes.
+ *
+ * @param id the attribute id of the Rdn attribute to return
+ * @param name the distinguished name of the entry
+ * @return the Rdn attribute value corresponding to the id, or null if the
+ * attribute is not an rdn attribute
+ * @throws NamingException if the name is malformed in any way
+ */
+ private static String getRdnValue( String id, Name name ) throws NamingException
+ {
+ String [] comps = NamespaceTools.getCompositeComponents( name.get( name.size() - 1 ) );
+
+ for ( int ii = 0; ii < comps.length; ii++ )
+ {
+ String rdnAttrId = NamespaceTools.getRdnAttribute( comps[ii] );
+
+ if ( rdnAttrId.equalsIgnoreCase( id ) )
+ {
+ return NamespaceTools.getRdnValue( comps[ii] );
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Collects the set of Rdn attributes whether or not the Rdn is based on a
+ * single attribute or multiple attributes.
+ *
+ * @param name the distinguished name of an entry
+ * @return the set of attributes composing the Rdn for the name
+ * @throws NamingException if the syntax of the Rdn is incorrect
+ */
+ private static Set getRdnAttributes( Name name ) throws NamingException
+ {
+ String [] comps = NamespaceTools.getCompositeComponents( name.get( name.size() - 1 ) );
+ Set attributes = new HashSet();
+
+ for ( int ii = 0; ii < comps.length; ii++ )
+ {
+ attributes.add( NamespaceTools.getRdnAttribute( comps[ii] ) );
+ }
+
+ return attributes;
+ }
+}
Modified: directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaService.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaService.java?rev=239501&r1=239500&r2=239501&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaService.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/schema/SchemaService.java Tue Aug 23 18:21:51 2005
@@ -26,10 +26,7 @@
import javax.naming.Name;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
+import javax.naming.directory.*;
import javax.naming.ldap.LdapContext;
import org.apache.ldap.common.filter.ExprNode;
@@ -56,6 +53,8 @@
import org.apache.ldap.server.jndi.ContextFactoryConfiguration;
import org.apache.ldap.server.jndi.ServerLdapContext;
import org.apache.ldap.server.partition.ContextPartitionNexus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
@@ -69,6 +68,9 @@
{
private static final String BINARY_KEY = "java.naming.ldap.attributes.binary";
+ /** The LoggerFactory used by this Interceptor */
+ private static Logger log = LoggerFactory.getLogger( SchemaService.class );
+
/**
* the root nexus to all database partitions
*/
@@ -127,8 +129,8 @@
public NamingEnumeration search( NextInterceptor nextInterceptor,
- Name base, Map env, ExprNode filter,
- SearchControls searchCtls ) throws NamingException
+ Name base, Map env, ExprNode filter,
+ SearchControls searchCtls ) throws NamingException
{
// check to make sure the DN searched for is a subentry
if ( !subentryDn.equals( base.toString() ) )
@@ -328,12 +330,60 @@
}
+ public void modify( NextInterceptor next, Name name, int modOp, Attributes mods ) throws NamingException
+ {
+ ObjectClassRegistry ocRegistry = this.globalRegistries.getObjectClassRegistry();
+
+ if ( modOp == DirContext.REMOVE_ATTRIBUTE )
+ {
+ SchemaChecker.preventRdnChangeOnModifyRemove( name, modOp, mods );
+ Attribute ocAttr = this.nexus.lookup( name ).get( "objectClass" );
+ SchemaChecker.preventStructuralClassRemovalOnModifyRemove( ocRegistry, name, modOp, mods, ocAttr );
+ }
+
+ if ( modOp == DirContext.REPLACE_ATTRIBUTE )
+ {
+ SchemaChecker.preventRdnChangeOnModifyReplace( name, modOp, mods );
+ SchemaChecker.preventStructuralClassRemovalOnModifyReplace( ocRegistry, name, modOp, mods );
+ }
+
+ next.modify( name, modOp, mods );
+ }
+
+
+ public void modify( NextInterceptor next, Name name, ModificationItem[] mods ) throws NamingException
+ {
+ ObjectClassRegistry ocRegistry = this.globalRegistries.getObjectClassRegistry();
+
+ for ( int ii = 0; ii < mods.length; ii++ )
+ {
+ int modOp = mods[ii].getModificationOp();
+ Attribute change = mods[ii].getAttribute();
+
+ if ( modOp == DirContext.REMOVE_ATTRIBUTE )
+ {
+ SchemaChecker.preventRdnChangeOnModifyRemove( name, modOp, change );
+ Attribute ocAttr = this.nexus.lookup( name ).get( "objectClass" );
+ SchemaChecker.preventStructuralClassRemovalOnModifyRemove( ocRegistry, name, modOp, change, ocAttr );
+ }
+
+ if ( modOp == DirContext.REPLACE_ATTRIBUTE )
+ {
+ SchemaChecker.preventRdnChangeOnModifyReplace( name, modOp, change );
+ SchemaChecker.preventStructuralClassRemovalOnModifyReplace( ocRegistry, name, modOp, change );
+ }
+ }
+
+ next.modify( name, mods );
+ }
+
+
private void doFilter( LdapContext ctx, Attributes entry )
throws NamingException
{
// set of AttributeType objects that are to behave as binaries
Set binaries;
-
+
// construct the set for fast lookups while filtering
String binaryIds = ( String ) ctx.getEnvironment().get( BINARY_KEY );
@@ -354,11 +404,11 @@
binaries.add( type );
}
}
-
+
/*
- * start converting values of attributes to byte[]s which are not
- * human readable and those that are in the binaries set
- */
+ * start converting values of attributes to byte[]s which are not
+ * human readable and those that are in the binaries set
+ */
NamingEnumeration list = entry.getIDs();
while ( list.hasMore() )
Added: directory/apacheds/trunk/core/src/test/org/apache/ldap/server/schema/SchemaCheckerTest.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/core/src/test/org/apache/ldap/server/schema/SchemaCheckerTest.java?rev=239501&view=auto
==============================================================================
--- directory/apacheds/trunk/core/src/test/org/apache/ldap/server/schema/SchemaCheckerTest.java (added)
+++ directory/apacheds/trunk/core/src/test/org/apache/ldap/server/schema/SchemaCheckerTest.java Tue Aug 23 18:21:51 2005
@@ -0,0 +1,577 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.ldap.server.schema;
+
+
+import junit.framework.TestCase;
+
+import javax.naming.directory.*;
+import javax.naming.Name;
+import javax.naming.NamingException;
+
+import org.apache.ldap.common.name.LdapName;
+import org.apache.ldap.common.exception.LdapSchemaViolationException;
+import org.apache.ldap.common.message.ResultCodeEnum;
+import org.apache.ldap.server.schema.bootstrap.*;
+
+import java.util.Set;
+import java.util.HashSet;
+
+
+/**
+ * Tests to make sure the schema checker is operating correctly.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class SchemaCheckerTest extends TestCase
+{
+ GlobalRegistries registries = null;
+
+
+ public SchemaCheckerTest() throws NamingException
+ {
+ this( "SchemaCheckerTest" );
+ }
+
+
+ public SchemaCheckerTest( String name ) throws NamingException
+ {
+ super( name );
+
+ BootstrapRegistries bootstrapRegistries = new BootstrapRegistries();
+
+ BootstrapSchemaLoader loader = new BootstrapSchemaLoader();
+ Set schemas = new HashSet();
+ schemas.add( new SystemSchema() );
+ schemas.add( new ApacheSchema() );
+ schemas.add( new CoreSchema() );
+ schemas.add( new CosineSchema() );
+ schemas.add( new InetorgpersonSchema() );
+ schemas.add( new JavaSchema() );
+ loader.load( schemas, bootstrapRegistries );
+
+ java.util.List errors = bootstrapRegistries.checkRefInteg();
+ if ( !errors.isEmpty() )
+ {
+ NamingException e = new NamingException();
+ e.setRootCause( ( Throwable ) errors.get( 0 ) );
+ throw e;
+ }
+
+ registries = new GlobalRegistries( bootstrapRegistries );
+ }
+
+
+ private GlobalRegistries getGlobalRegistries() throws NamingException
+ {
+ BootstrapRegistries bootstrapRegistries = new BootstrapRegistries();
+
+ BootstrapSchemaLoader loader = new BootstrapSchemaLoader();
+ Set schemas = new HashSet();
+ schemas.add( new SystemSchema() );
+ schemas.add( new ApacheSchema() );
+ schemas.add( new CoreSchema() );
+ schemas.add( new CosineSchema() );
+ schemas.add( new InetorgpersonSchema() );
+ schemas.add( new JavaSchema() );
+ loader.load( schemas, bootstrapRegistries );
+
+ java.util.List errors = bootstrapRegistries.checkRefInteg();
+ if ( !errors.isEmpty() )
+ {
+ NamingException e = new NamingException();
+ e.setRootCause( ( Throwable ) errors.get( 0 ) );
+ throw e;
+ }
+
+ return new GlobalRegistries( bootstrapRegistries );
+ }
+
+
+ /**
+ * Test case to check the schema checker operates correctly when modify
+ * operations replace objectClasses.
+ */
+ public void testPreventStructuralClassRemovalOnModifyReplace() throws Exception
+ {
+ Name name = new LdapName( "uid=akarasulu,ou=users,dc=example,dc=com" );
+ int mod = DirContext.REPLACE_ATTRIBUTE;
+ Attributes modifyAttributes = new BasicAttributes( true );
+ modifyAttributes.put( new BasicAttribute( "cn" ) );
+
+ ObjectClassRegistry ocRegistry = registries.getObjectClassRegistry();
+
+ // this should pass
+ SchemaChecker.preventStructuralClassRemovalOnModifyReplace( ocRegistry, name, mod, modifyAttributes );
+
+ // this should succeed since person is still in replaced set and is structural
+ modifyAttributes.remove( "cn" );
+ BasicAttribute objectClassesReplaced = new BasicAttribute( "objectClass" );
+ objectClassesReplaced.add( "top" );
+ objectClassesReplaced.add( "person" );
+ modifyAttributes.put( objectClassesReplaced );
+ SchemaChecker.preventStructuralClassRemovalOnModifyReplace( ocRegistry, name, mod, modifyAttributes );
+
+ // this should fail since only top is left
+ objectClassesReplaced = new BasicAttribute( "objectClass" );
+ objectClassesReplaced.add( "top" );
+ modifyAttributes.put( objectClassesReplaced );
+ try
+ {
+ SchemaChecker.preventStructuralClassRemovalOnModifyReplace( ocRegistry, name, mod, modifyAttributes );
+ fail( "should never get here due to an LdapSchemaViolationException" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( e.getResultCode(), ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+
+ // this should fail since the modify operation tries to delete all
+ // objectClass attribute values
+ modifyAttributes.remove( "cn" );
+ objectClassesReplaced = new BasicAttribute( "objectClass" );
+ modifyAttributes.put( objectClassesReplaced );
+ try
+ {
+ SchemaChecker.preventStructuralClassRemovalOnModifyReplace( ocRegistry, name, mod, modifyAttributes );
+ fail( "should never get here due to an LdapSchemaViolationException" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( e.getResultCode(), ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+ }
+
+
+ /**
+ * Test case to check the schema checker operates correctly when modify
+ * operations remove objectClasses.
+ */
+ public void testPreventStructuralClassRemovalOnModifyRemove() throws Exception
+ {
+ Name name = new LdapName( "uid=akarasulu,ou=users,dc=example,dc=com" );
+ int mod = DirContext.REMOVE_ATTRIBUTE;
+ Attributes modifyAttributes = new BasicAttributes( true );
+ Attribute entryObjectClasses = new BasicAttribute( "objectClass" );
+ entryObjectClasses.add( "top" );
+ entryObjectClasses.add( "person" );
+ entryObjectClasses.add( "organizationalPerson" );
+ modifyAttributes.put( new BasicAttribute( "cn" ) );
+
+ ObjectClassRegistry ocRegistry = registries.getObjectClassRegistry();
+
+ // this should pass
+ SchemaChecker.preventStructuralClassRemovalOnModifyRemove( ocRegistry, name, mod, modifyAttributes,
+ entryObjectClasses );
+
+ // this should succeed since person is left and is structural
+ modifyAttributes.remove( "cn" );
+ BasicAttribute objectClassesRemoved = new BasicAttribute( "objectClass" );
+ objectClassesRemoved.add( "person" );
+ modifyAttributes.put( objectClassesRemoved );
+ SchemaChecker.preventStructuralClassRemovalOnModifyRemove( ocRegistry, name, mod, modifyAttributes,
+ entryObjectClasses );
+
+ // this should fail since only top is left
+ modifyAttributes.remove( "cn" );
+ objectClassesRemoved = new BasicAttribute( "objectClass" );
+ objectClassesRemoved.add( "person" );
+ objectClassesRemoved.add( "organizationalPerson" );
+ modifyAttributes.put( objectClassesRemoved );
+ try
+ {
+ SchemaChecker.preventStructuralClassRemovalOnModifyRemove( ocRegistry, name, mod, modifyAttributes,
+ entryObjectClasses );
+ fail( "should never get here due to an LdapSchemaViolationException" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( e.getResultCode(), ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+
+ // this should fail since the modify operation tries to delete all
+ // objectClass attribute values
+ modifyAttributes.remove( "cn" );
+ objectClassesRemoved = new BasicAttribute( "objectClass" );
+ modifyAttributes.put( objectClassesRemoved );
+ try
+ {
+ SchemaChecker.preventStructuralClassRemovalOnModifyRemove( ocRegistry, name, mod, modifyAttributes,
+ entryObjectClasses );
+ fail( "should never get here due to an LdapSchemaViolationException" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( e.getResultCode(), ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+ }
+
+
+ /**
+ * Test case to check the schema checker operates correctly when modify
+ * operations remove RDN attributes.
+ */
+ public void testPreventRdnChangeOnModifyRemove() throws Exception
+ {
+ int mod = DirContext.REMOVE_ATTRIBUTE;
+ Name name = new LdapName( "ou=user,dc=example,dc=com" );
+ Attributes attributes = new BasicAttributes( true );
+ attributes.put( "cn", "does not matter" );
+
+ // postive test which should pass
+ SchemaChecker.preventRdnChangeOnModifyRemove( name, mod, attributes );
+
+ // test should fail since we are removing the ou attribute
+ attributes.put( new BasicAttribute( "ou" ) );
+ try
+ {
+ SchemaChecker.preventRdnChangeOnModifyRemove( name, mod, attributes );
+ fail( "should never get here due to a LdapSchemaViolationException being thrown" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( ResultCodeEnum.NOTALLOWEDONRDN, e.getResultCode() );
+ }
+
+ // test success using more than one attribute for the Rdn but not modifying rdn attribute
+ name = new LdapName( "ou=users+cn=system users,dc=example,dc=com" );
+ attributes = new BasicAttributes( true );
+ attributes.put( "sn", "does not matter" );
+ SchemaChecker.preventRdnChangeOnModifyRemove( name, mod, attributes );
+
+ // test for failure when modifying Rdn attribute in multi attribute Rdn
+ attributes.put( new BasicAttribute( "cn" ) );
+ try
+ {
+ SchemaChecker.preventRdnChangeOnModifyRemove( name, mod, attributes );
+ fail( "should never get here due to a LdapSchemaViolationException being thrown" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( ResultCodeEnum.NOTALLOWEDONRDN, e.getResultCode() );
+ }
+
+ // should succeed since the value being deleted from the rdn attribute is
+ // is not used when composing the Rdn
+ attributes = new BasicAttributes( true );
+ attributes.put( "ou", "container" );
+ SchemaChecker.preventRdnChangeOnModifyRemove( name, mod, attributes );
+
+ // now let's make it fail again just by providing the right value for ou (users)
+ attributes = new BasicAttributes( true );
+ attributes.put( "ou", "users" );
+ try
+ {
+ SchemaChecker.preventRdnChangeOnModifyRemove( name, mod, attributes );
+ fail( "should never get here due to a LdapSchemaViolationException being thrown" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( ResultCodeEnum.NOTALLOWEDONRDN, e.getResultCode() );
+ }
+ }
+
+
+ /**
+ * Test case to check the schema checker operates correctly when modify
+ * operations replace RDN attributes.
+ */
+ public void testPreventRdnChangeOnModifyReplace() throws Exception
+ {
+ int mod = DirContext.REPLACE_ATTRIBUTE;
+ Name name = new LdapName( "ou=user,dc=example,dc=com" );
+ Attributes attributes = new BasicAttributes( true );
+ attributes.put( "cn", "does not matter" );
+
+ // postive test which should pass
+ SchemaChecker.preventRdnChangeOnModifyReplace( name, mod, attributes );
+
+ // test should fail since we are removing the ou attribute
+ attributes.put( new BasicAttribute( "ou" ) );
+ try
+ {
+ SchemaChecker.preventRdnChangeOnModifyReplace( name, mod, attributes );
+ fail( "should never get here due to a LdapSchemaViolationException being thrown" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( ResultCodeEnum.NOTALLOWEDONRDN, e.getResultCode() );
+ }
+
+ // test success using more than one attribute for the Rdn but not modifying rdn attribute
+ name = new LdapName( "ou=users+cn=system users,dc=example,dc=com" );
+ attributes = new BasicAttributes( true );
+ attributes.put( "sn", "does not matter" );
+ SchemaChecker.preventRdnChangeOnModifyReplace( name, mod, attributes );
+
+ // test for failure when modifying Rdn attribute in multi attribute Rdn
+ attributes.put( new BasicAttribute( "cn" ) );
+ try
+ {
+ SchemaChecker.preventRdnChangeOnModifyReplace( name, mod, attributes );
+ fail( "should never get here due to a LdapSchemaViolationException being thrown" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( ResultCodeEnum.NOTALLOWEDONRDN, e.getResultCode() );
+ }
+
+ // should succeed since the values being replaced from the rdn attribute is
+ // is includes the old Rdn attribute value
+ attributes = new BasicAttributes( true );
+ attributes.put( "ou", "container" );
+ attributes.put( "ou", "users" );
+ SchemaChecker.preventRdnChangeOnModifyReplace( name, mod, attributes );
+
+ // now let's make it fail by not including the old value for ou (users)
+ attributes = new BasicAttributes( true );
+ attributes.put( "ou", "container" );
+ try
+ {
+ SchemaChecker.preventRdnChangeOnModifyReplace( name, mod, attributes );
+ fail( "should never get here due to a LdapSchemaViolationException being thrown" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( ResultCodeEnum.NOTALLOWEDONRDN, e.getResultCode() );
+ }
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Single Attribute Test Cases
+ // ------------------------------------------------------------------------
+
+
+ /**
+ * Test case to check the schema checker operates correctly when modify
+ * operations replace objectClasses.
+ */
+ public void testPreventStructuralClassRemovalOnModifyReplaceAttribute() throws Exception
+ {
+ ObjectClassRegistry ocRegistry = registries.getObjectClassRegistry();
+
+ // this should pass
+ Name name = new LdapName( "uid=akarasulu,ou=users,dc=example,dc=com" );
+ int mod = DirContext.REPLACE_ATTRIBUTE;
+ SchemaChecker.preventStructuralClassRemovalOnModifyReplace( ocRegistry, name, mod, new BasicAttribute( "cn" ) );
+
+ // this should succeed since person is still in replaced set and is structural
+ BasicAttribute objectClassesReplaced = new BasicAttribute( "objectClass" );
+ objectClassesReplaced.add( "top" );
+ objectClassesReplaced.add( "person" );
+ SchemaChecker.preventStructuralClassRemovalOnModifyReplace( ocRegistry, name, mod, objectClassesReplaced );
+
+ // this should fail since only top is left
+ objectClassesReplaced = new BasicAttribute( "objectClass" );
+ objectClassesReplaced.add( "top" );
+ try
+ {
+ SchemaChecker.preventStructuralClassRemovalOnModifyReplace( ocRegistry, name, mod, objectClassesReplaced );
+ fail( "should never get here due to an LdapSchemaViolationException" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( e.getResultCode(), ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+
+ // this should fail since the modify operation tries to delete all
+ // objectClass attribute values
+ objectClassesReplaced = new BasicAttribute( "objectClass" );
+ try
+ {
+ SchemaChecker.preventStructuralClassRemovalOnModifyReplace( ocRegistry, name, mod, objectClassesReplaced );
+ fail( "should never get here due to an LdapSchemaViolationException" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( e.getResultCode(), ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+ }
+
+
+ /**
+ * Test case to check the schema checker operates correctly when modify
+ * operations remove objectClasses.
+ */
+ public void testPreventStructuralClassRemovalOnModifyRemoveAttribute() throws Exception
+ {
+ Name name = new LdapName( "uid=akarasulu,ou=users,dc=example,dc=com" );
+ int mod = DirContext.REMOVE_ATTRIBUTE;
+ Attribute entryObjectClasses = new BasicAttribute( "objectClass" );
+ entryObjectClasses.add( "top" );
+ entryObjectClasses.add( "person" );
+ entryObjectClasses.add( "organizationalPerson" );
+
+ ObjectClassRegistry ocRegistry = registries.getObjectClassRegistry();
+
+ // this should pass
+ SchemaChecker.preventStructuralClassRemovalOnModifyRemove( ocRegistry, name, mod, new BasicAttribute( "cn" ),
+ entryObjectClasses );
+
+ // this should succeed since person is left and is structural
+ BasicAttribute objectClassesRemoved = new BasicAttribute( "objectClass" );
+ objectClassesRemoved.add( "person" );
+ SchemaChecker.preventStructuralClassRemovalOnModifyRemove( ocRegistry, name, mod, objectClassesRemoved,
+ entryObjectClasses );
+
+ // this should fail since only top is left
+ objectClassesRemoved = new BasicAttribute( "objectClass" );
+ objectClassesRemoved.add( "person" );
+ objectClassesRemoved.add( "organizationalPerson" );
+ try
+ {
+ SchemaChecker.preventStructuralClassRemovalOnModifyRemove( ocRegistry, name, mod, objectClassesRemoved,
+ entryObjectClasses );
+ fail( "should never get here due to an LdapSchemaViolationException" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( e.getResultCode(), ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+
+ // this should fail since the modify operation tries to delete all
+ // objectClass attribute values
+ objectClassesRemoved = new BasicAttribute( "objectClass" );
+ try
+ {
+ SchemaChecker.preventStructuralClassRemovalOnModifyRemove( ocRegistry, name, mod, objectClassesRemoved,
+ entryObjectClasses );
+ fail( "should never get here due to an LdapSchemaViolationException" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( e.getResultCode(), ResultCodeEnum.OBJECTCLASSMODSPROHIBITED );
+ }
+ }
+
+
+ /**
+ * Test case to check the schema checker operates correctly when modify
+ * operations remove RDN attributes.
+ */
+ public void testPreventRdnChangeOnModifyRemoveAttribute() throws Exception
+ {
+ int mod = DirContext.REMOVE_ATTRIBUTE;
+ Name name = new LdapName( "ou=user,dc=example,dc=com" );
+
+ // postive test which should pass
+ SchemaChecker.preventRdnChangeOnModifyRemove( name, mod, new BasicAttribute( "cn", "does not matter" ) );
+
+ // test should fail since we are removing the ou attribute
+ try
+ {
+ SchemaChecker.preventRdnChangeOnModifyRemove( name, mod, new BasicAttribute( "ou" ) );
+ fail( "should never get here due to a LdapSchemaViolationException being thrown" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( ResultCodeEnum.NOTALLOWEDONRDN, e.getResultCode() );
+ }
+
+ // test success using more than one attribute for the Rdn but not modifying rdn attribute
+ name = new LdapName( "ou=users+cn=system users,dc=example,dc=com" );
+ SchemaChecker.preventRdnChangeOnModifyRemove( name, mod, new BasicAttribute( "sn", "does not matter" ) );
+
+ // test for failure when modifying Rdn attribute in multi attribute Rdn
+ try
+ {
+ SchemaChecker.preventRdnChangeOnModifyRemove( name, mod, new BasicAttribute( "cn" ) );
+ fail( "should never get here due to a LdapSchemaViolationException being thrown" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( ResultCodeEnum.NOTALLOWEDONRDN, e.getResultCode() );
+ }
+
+ // should succeed since the value being deleted from the rdn attribute is
+ // is not used when composing the Rdn
+ SchemaChecker.preventRdnChangeOnModifyRemove( name, mod, new BasicAttribute( "ou", "container" ) );
+
+ // now let's make it fail again just by providing the right value for ou (users)
+ try
+ {
+ SchemaChecker.preventRdnChangeOnModifyRemove( name, mod, new BasicAttribute( "ou", "users" ) );
+ fail( "should never get here due to a LdapSchemaViolationException being thrown" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( ResultCodeEnum.NOTALLOWEDONRDN, e.getResultCode() );
+ }
+ }
+
+
+ /**
+ * Test case to check the schema checker operates correctly when modify
+ * operations replace RDN attributes.
+ */
+ public void testPreventRdnChangeOnModifyReplaceAttribute() throws Exception
+ {
+ int mod = DirContext.REPLACE_ATTRIBUTE;
+ Name name = new LdapName( "ou=user,dc=example,dc=com" );
+
+ // postive test which should pass
+ SchemaChecker.preventRdnChangeOnModifyReplace( name, mod, new BasicAttribute( "cn", "does not matter" ) );
+
+ // test should fail since we are removing the ou attribute
+ try
+ {
+ SchemaChecker.preventRdnChangeOnModifyReplace( name, mod, new BasicAttribute( "ou" ) );
+ fail( "should never get here due to a LdapSchemaViolationException being thrown" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( ResultCodeEnum.NOTALLOWEDONRDN, e.getResultCode() );
+ }
+
+ // test success using more than one attribute for the Rdn but not modifying rdn attribute
+ name = new LdapName( "ou=users+cn=system users,dc=example,dc=com" );
+ SchemaChecker.preventRdnChangeOnModifyReplace( name, mod, new BasicAttribute( "sn", "does not matter" ) );
+
+ // test for failure when modifying Rdn attribute in multi attribute Rdn
+ try
+ {
+ SchemaChecker.preventRdnChangeOnModifyReplace( name, mod, new BasicAttribute( "cn" ) );
+ fail( "should never get here due to a LdapSchemaViolationException being thrown" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( ResultCodeEnum.NOTALLOWEDONRDN, e.getResultCode() );
+ }
+
+ // should succeed since the values being replaced from the rdn attribute is
+ // is includes the old Rdn attribute value
+ Attribute attribute = new BasicAttribute( "ou" );
+ attribute.add( "container" );
+ attribute.add( "users" );
+ SchemaChecker.preventRdnChangeOnModifyReplace( name, mod, attribute );
+
+ // now let's make it fail by not including the old value for ou (users)
+ attribute = new BasicAttribute( "ou" );
+ attribute.add( "container" );
+ try
+ {
+ SchemaChecker.preventRdnChangeOnModifyReplace( name, mod, attribute );
+ fail( "should never get here due to a LdapSchemaViolationException being thrown" );
+ }
+ catch ( LdapSchemaViolationException e )
+ {
+ assertEquals( ResultCodeEnum.NOTALLOWEDONRDN, e.getResultCode() );
+ }
+ }
+}
Added: directory/apacheds/trunk/core/src/test/resources/log4j.properties
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/core/src/test/resources/log4j.properties?rev=239501&view=auto
==============================================================================
--- directory/apacheds/trunk/core/src/test/resources/log4j.properties (added)
+++ directory/apacheds/trunk/core/src/test/resources/log4j.properties Tue Aug 23 18:21:51 2005
@@ -0,0 +1,6 @@
+log4j.rootCategory=DEBUG, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
+