You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2020/03/29 17:24:14 UTC

[syncope] branch master updated: Upgrading ApacheDS (#170)

This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/master by this push:
     new 87e5f12  Upgrading ApacheDS (#170)
87e5f12 is described below

commit 87e5f125f5a41a687ba9e1997b2f45b0e6671073
Author: Francesco Chicchiriccò <il...@users.noreply.github.com>
AuthorDate: Sun Mar 29 19:14:41 2020 +0200

    Upgrading ApacheDS (#170)
---
 fit/build-tools/pom.xml                            |  16 +-
 .../normalization/NormalizationInterceptor.java    | 628 +++++++++++++++++++++
 .../fit/buildtools/ApacheDSStartStopListener.java  | 115 ++--
 pom.xml                                            |  24 +-
 4 files changed, 694 insertions(+), 89 deletions(-)

diff --git a/fit/build-tools/pom.xml b/fit/build-tools/pom.xml
index 1c6f019..86a9726 100644
--- a/fit/build-tools/pom.xml
+++ b/fit/build-tools/pom.xml
@@ -64,23 +64,15 @@ under the License.
     </dependency>
     <dependency>
       <groupId>org.apache.directory.server</groupId>
-      <artifactId>apacheds-service-builder</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.directory.api</groupId>
-      <artifactId>api-ldap-codec-standalone</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.directory.api</groupId>
-      <artifactId>api-ldap-model</artifactId>
+      <artifactId>apacheds-core-annotations</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.directory.api</groupId>
-      <artifactId>api-ldap-schema-data</artifactId>
+      <groupId>org.apache.directory.server</groupId>
+      <artifactId>apacheds-service-builder</artifactId>
     </dependency>
     <dependency>
       <groupId>org.apache.directory.api</groupId>
-      <artifactId>api-util</artifactId>
+      <artifactId>api-ldap-codec-standalone</artifactId>
     </dependency>
 
     <dependency>
diff --git a/fit/build-tools/src/main/java/org/apache/directory/server/core/normalization/NormalizationInterceptor.java b/fit/build-tools/src/main/java/org/apache/directory/server/core/normalization/NormalizationInterceptor.java
new file mode 100644
index 0000000..e5cfb5a
--- /dev/null
+++ b/fit/build-tools/src/main/java/org/apache/directory/server/core/normalization/NormalizationInterceptor.java
@@ -0,0 +1,628 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.directory.server.core.normalization;
+
+// Remove this class as soon as upgrade to ApacheDS 2.0.0.AM27 is available
+
+// CHECKSTYLE:OFF
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.cursor.EmptyCursor;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeTypeException;
+import org.apache.directory.api.ldap.model.filter.AndNode;
+import org.apache.directory.api.ldap.model.filter.BranchNode;
+import org.apache.directory.api.ldap.model.filter.EqualityNode;
+import org.apache.directory.api.ldap.model.filter.ExprNode;
+import org.apache.directory.api.ldap.model.filter.LeafNode;
+import org.apache.directory.api.ldap.model.filter.NotNode;
+import org.apache.directory.api.ldap.model.filter.ObjectClassNode;
+import org.apache.directory.api.ldap.model.filter.OrNode;
+import org.apache.directory.api.ldap.model.filter.PresenceNode;
+import org.apache.directory.api.ldap.model.filter.UndefinedNode;
+import org.apache.directory.api.ldap.model.name.Ava;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.normalizers.ConcreteNameComponentNormalizer;
+import org.apache.directory.api.ldap.model.schema.normalizers.NameComponentNormalizer;
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.InterceptorEnum;
+import org.apache.directory.server.core.api.filtering.EntryFilteringCursorImpl;
+import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
+import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
+import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.CompareOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.HasEntryOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
+import org.apache.directory.server.core.api.normalization.FilterNormalizingVisitor;
+import org.apache.directory.server.i18n.I18n;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A name normalization service.  This service makes sure all relative and distinguished
+ * names are normalized before calls are made against the respective interface methods
+ * on DefaultPartitionNexus.
+ *
+ * The Filters are also normalized.
+ *
+ * If the Rdn AttributeTypes are not present in the entry for an Add request,
+ * they will be added.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class NormalizationInterceptor extends BaseInterceptor
+{
+    /** logger used by this class */
+    private static final Logger LOG = LoggerFactory.getLogger( NormalizationInterceptor.class );
+
+    /** a filter node value normalizer and undefined node remover */
+    private FilterNormalizingVisitor normVisitor;
+
+
+    /**
+     * Creates a new instance of a NormalizationInterceptor.
+     */
+    public NormalizationInterceptor()
+    {
+        super( InterceptorEnum.NORMALIZATION_INTERCEPTOR );
+    }
+
+
+    /**
+     * Initialize the registries, normalizers.
+     */
+    @Override
+    public void init( DirectoryService directoryService ) throws LdapException
+    {
+        LOG.debug( "Initialiazing the NormalizationInterceptor" );
+
+        super.init( directoryService );
+
+        NameComponentNormalizer ncn = new ConcreteNameComponentNormalizer( schemaManager );
+        normVisitor = new FilterNormalizingVisitor( ncn, schemaManager );
+    }
+
+
+    /**
+     * The destroy method does nothing
+     */
+    @Override
+    public void destroy()
+    {
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Normalize all Name based arguments for ContextPartition interface operations
+    // ------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void add( AddOperationContext addContext ) throws LdapException
+    {
+        Dn addDn = addContext.getDn();
+        
+        if ( !addDn.isSchemaAware() )
+        {
+            addContext.setDn( new Dn( schemaManager, addDn ) );
+        }
+        
+        Dn entryDn = addContext.getEntry().getDn();
+        
+        if ( !entryDn.isSchemaAware() )
+        {
+            addContext.getEntry().setDn( new Dn( schemaManager, entryDn ) );
+        }
+        
+        addRdnAttributesToEntry( addContext.getDn(), addContext.getEntry() );
+        
+        next( addContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean compare( CompareOperationContext compareContext ) throws LdapException
+    {
+        Dn dn = compareContext.getDn();
+        
+        if ( !dn.isSchemaAware() )
+        {
+            compareContext.setDn( new Dn( schemaManager, dn ) );
+        }
+
+        // Get the attributeType from the OID
+        try
+        {
+            AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( compareContext.getOid() );
+
+            // Translate the value from binary to String if the AT is HR
+            if ( attributeType.getSyntax().isHumanReadable() && ( !compareContext.getValue().isHumanReadable() ) )
+            {
+                compareContext.setValue( compareContext.getValue() );
+            }
+
+            compareContext.setAttributeType( attributeType );
+        }
+        catch ( LdapException le )
+        {
+            throw new LdapInvalidAttributeTypeException( I18n.err( I18n.ERR_266, compareContext.getOid() ) );
+        }
+
+        return next( compareContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void delete( DeleteOperationContext deleteContext ) throws LdapException
+    {
+        Dn dn = deleteContext.getDn();
+        
+        if ( !dn.isSchemaAware() )
+        {
+            deleteContext.setDn( new Dn( schemaManager, dn ) );
+        }
+
+        next( deleteContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean hasEntry( HasEntryOperationContext hasEntryContext ) throws LdapException
+    {
+        Dn dn = hasEntryContext.getDn();
+        
+        if ( !dn.isSchemaAware() )
+        {
+            hasEntryContext.setDn( new Dn( schemaManager, dn ) );
+        }
+
+        return next( hasEntryContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Entry lookup( LookupOperationContext lookupContext ) throws LdapException
+    {
+        Dn dn = lookupContext.getDn();
+        
+        if ( !dn.isSchemaAware() )
+        {
+            lookupContext.setDn( new Dn( schemaManager, dn ) );
+        }
+
+        return next( lookupContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void modify( ModifyOperationContext modifyContext ) throws LdapException
+    {
+        Dn dn = modifyContext.getDn();
+        
+        if ( !dn.isSchemaAware() )
+        {
+            modifyContext.setDn( new Dn( schemaManager, dn ) );
+        }
+
+        if ( modifyContext.getModItems() != null )
+        {
+            for ( Modification modification : modifyContext.getModItems() )
+            {
+                AttributeType attributeType = schemaManager.getAttributeType( modification.getAttribute().getId() );
+                modification.apply( attributeType );
+            }
+        }
+
+        next( modifyContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void move( MoveOperationContext moveContext ) throws LdapException
+    {
+        Dn moveDn = moveContext.getDn();
+        
+        if ( !moveDn.isSchemaAware() )
+        {
+            moveContext.setDn( new Dn( schemaManager, moveDn ) );
+        }
+
+        Dn oldSuperiorDn = moveContext.getOldSuperior();
+        
+        if ( !oldSuperiorDn.isSchemaAware() )
+        {
+            moveContext.setOldSuperior( new Dn( schemaManager, oldSuperiorDn ) );
+        }
+
+        Dn newSuperiorDn = moveContext.getNewSuperior();
+        
+        if ( !newSuperiorDn.isSchemaAware() )
+        {
+            moveContext.setNewSuperior( new Dn( schemaManager, newSuperiorDn ) );
+        }
+        
+        Dn newDn = moveContext.getNewDn();
+        
+        if ( !newDn.isSchemaAware() )
+        {
+            moveContext.setNewDn( new Dn( schemaManager, newDn ) );
+        }
+
+        Rdn rdn = moveContext.getRdn();
+        
+        if ( !rdn.isSchemaAware() )
+        {
+            moveContext.setRdn( new Rdn( schemaManager, rdn ) );
+        }
+
+        next( moveContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void moveAndRename( MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
+    {
+        Rdn newRdn = moveAndRenameContext.getNewRdn();
+        
+        if ( !newRdn.isSchemaAware() )
+        {
+            moveAndRenameContext.setNewRdn( new Rdn( schemaManager, newRdn ) );
+        }
+        
+        Dn dn = moveAndRenameContext.getDn();
+        
+        if ( !dn.isSchemaAware() )
+        {
+            moveAndRenameContext.setDn( new Dn( schemaManager, dn ) );
+        }
+        
+        Dn newDn = moveAndRenameContext.getNewDn();
+        
+        if ( !newDn.isSchemaAware() )
+        {
+            moveAndRenameContext.setNewDn( new Dn( schemaManager, newDn ) );
+        }
+        
+        Dn newSuperiorDn = moveAndRenameContext.getNewSuperiorDn();
+        
+        if ( !newSuperiorDn.isSchemaAware() )
+        {
+            moveAndRenameContext.setNewSuperiorDn( new Dn( schemaManager, newSuperiorDn ) );
+        }
+
+        next( moveAndRenameContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void rename( RenameOperationContext renameContext ) throws LdapException
+    {
+        // Normalize the new Rdn and the Dn if needed
+        Dn dn = renameContext.getDn();
+        
+        if ( !dn.isSchemaAware() )
+        {
+            renameContext.setDn( new Dn( schemaManager, dn ) );
+        }
+        
+        Rdn newRdn = renameContext.getNewRdn();
+        
+        if ( !newRdn.isSchemaAware() )
+        {
+            renameContext.setNewRdn( new Rdn( schemaManager, newRdn ) );
+        }
+        
+        Dn newDn = renameContext.getNewDn();
+        
+        if ( !newDn.isSchemaAware() )
+        {
+            renameContext.setNewDn( new Dn( schemaManager, newDn ) );
+        }
+
+        // Push to the next interceptor
+        next( renameContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public EntryFilteringCursor search( SearchOperationContext searchContext ) throws LdapException
+    {
+        Dn dn = searchContext.getDn();
+        
+        if ( !dn.isSchemaAware() )
+        {
+            searchContext.setDn( new Dn( schemaManager, dn ) );
+        }
+
+        ExprNode filter = searchContext.getFilter();
+
+        if ( filter == null )
+        {
+            LOG.warn( "undefined filter based on undefined attributeType not evaluted at all.  Returning empty enumeration." );
+            return new EntryFilteringCursorImpl( new EmptyCursor<Entry>(), searchContext, schemaManager );
+        }
+
+        // Normalize the filter
+        filter = ( ExprNode ) filter.accept( normVisitor );
+
+        if ( filter == null )
+        {
+            LOG.warn( "undefined filter based on undefined attributeType not evaluted at all.  Returning empty enumeration." );
+            return new EntryFilteringCursorImpl( new EmptyCursor<Entry>(), searchContext, schemaManager );
+        }
+
+        // We now have to remove the (ObjectClass=*) filter if it's present, and to add the scope filter
+        ExprNode modifiedFilter = removeObjectClass( filter );
+
+        searchContext.setFilter( modifiedFilter );
+
+        // TODO Normalize the returned Attributes, storing the UP attributes to format the returned values.
+        return next( searchContext );
+    }
+
+
+    /**
+     * Remove the (ObjectClass=*) node from an AndNode, if we have one.
+     */
+    private ExprNode handleAndNode( ExprNode node )
+    {
+        int nbNodes = 0;
+        AndNode newAndNode = new AndNode();
+
+        for ( ExprNode child : ( ( BranchNode ) node ).getChildren() )
+        {
+            ExprNode modifiedNode = removeObjectClass( child );
+
+            if ( !( modifiedNode instanceof ObjectClassNode ) )
+            {
+                newAndNode.addNode( modifiedNode );
+                nbNodes++;
+            }
+
+            if ( modifiedNode instanceof UndefinedNode )
+            {
+                // We can just return an Undefined node as nothing will get selected
+                return UndefinedNode.UNDEFINED_NODE;
+            }
+        }
+
+        switch ( nbNodes )
+        {
+            case 0:
+                // Unlikely... But (&(ObjectClass=*)) or (|(ObjectClass=*)) are still an option
+                return ObjectClassNode.OBJECT_CLASS_NODE;
+
+            case 1:
+                // We can safely remove the AND/OR node and replace it with its first child
+                return newAndNode.getFirstChild();
+
+            default:
+                return newAndNode;
+        }
+    }
+
+
+    /**
+     * Remove the (ObjectClass=*) node from a NotNode, if we have one.
+     */
+    private ExprNode handleNotNode( ExprNode node )
+    {
+        NotNode newNotNode = new NotNode();
+
+        for ( ExprNode child : ( ( BranchNode ) node ).getChildren() )
+        {
+            ExprNode modifiedNode = removeObjectClass( child );
+
+            if ( modifiedNode instanceof ObjectClassNode )
+            {
+                // We don't want any entry which has an ObjectClass, return an undefined node
+                return UndefinedNode.UNDEFINED_NODE;
+            }
+
+            if ( modifiedNode instanceof UndefinedNode )
+            {
+                // Here, we will select everything
+                return ObjectClassNode.OBJECT_CLASS_NODE;
+            }
+            
+            newNotNode.addNode( modifiedNode );
+
+        }
+
+        return newNotNode;
+    }
+
+
+    /**
+     * Remove the (ObjectClass=*) node from an OrNode, if we have one.
+     */
+    private ExprNode handleOrNode( ExprNode node )
+    {
+        OrNode newOrNode = new OrNode();
+
+        for ( ExprNode child : ( ( BranchNode ) node ).getChildren() )
+        {
+            ExprNode modifiedNode = removeObjectClass( child );
+
+            if ( modifiedNode instanceof ObjectClassNode )
+            {
+                // We can return immediately with an ObjectClass node
+                return ObjectClassNode.OBJECT_CLASS_NODE;
+            }
+            
+            newOrNode.addNode( modifiedNode );
+        }
+
+        return newOrNode;
+    }
+
+
+    /**
+     * Remove the (ObjectClass=*) and ( ObjectClass=top) nodes from the filter, if we have one.
+     */
+    private ExprNode removeObjectClass( ExprNode node )
+    {
+        if ( node instanceof LeafNode )
+        {
+            LeafNode leafNode = ( LeafNode ) node;
+
+            if ( leafNode.getAttributeType() == directoryService.getAtProvider().getObjectClass() )
+            {
+                if ( leafNode instanceof PresenceNode )
+                {
+                    // We can safely remove the node and return an undefined node
+                    return ObjectClassNode.OBJECT_CLASS_NODE;
+                }
+                else if ( leafNode instanceof EqualityNode )
+                {
+                    Value value = ( ( EqualityNode<String> ) leafNode ).getValue();
+
+                    if ( value.equals( SchemaConstants.TOP_OC ) )
+                    {
+                        // Here too we can safely remove the node and return an undefined node
+                        return ObjectClassNode.OBJECT_CLASS_NODE;
+                    }
+                }
+            }
+        }
+
+        // --------------------------------------------------------------------
+        //                 H A N D L E   B R A N C H   N O D E S
+        // --------------------------------------------------------------------
+
+        if ( node instanceof AndNode )
+        {
+            return handleAndNode( node );
+        }
+        else if ( node instanceof OrNode )
+        {
+            return handleOrNode( node );
+        }
+        else if ( node instanceof NotNode )
+        {
+            return handleNotNode( node );
+        }
+        else
+        {
+            // Failover : we return the initial node as is
+            return node;
+        }
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Normalize all Name based arguments for other interface operations
+    // ------------------------------------------------------------------------
+    /**
+     * Adds missing Rdn's attributes and values to the entry.
+     *
+     * @param dn the Dn
+     * @param entry the entry
+     */
+    private void addRdnAttributesToEntry( Dn dn, Entry entry ) throws LdapException
+    {
+        if ( dn == null || entry == null )
+        {
+            return;
+        }
+
+        Rdn rdn = dn.getRdn();
+
+        // Loop on all the AVAs
+        for ( Ava ava : rdn )
+        {
+            Value value = ava.getValue();
+            String upValue = ava.getValue().getString();
+            String upId = ava.getType();
+
+            // Check that the entry contains this Ava
+            if ( !entry.contains( upId, value ) )
+            {
+                String message = "The Rdn '" + upId + "=" + upValue + "' is not present in the entry";
+                LOG.warn( message );
+
+                // We don't have this attribute : add it.
+                // Two cases :
+                // 1) The attribute does not exist
+                if ( !entry.containsAttribute( upId ) )
+                {
+                    entry.add( upId, upValue );
+                }
+                // 2) The attribute exists
+                else
+                {
+                    AttributeType at = schemaManager.lookupAttributeTypeRegistry( upId );
+
+                    // 2.1 if the attribute is single valued, replace the value
+                    if ( at.isSingleValued() )
+                    {
+                        entry.removeAttributes( upId );
+                        entry.add( upId, upValue );
+                    }
+                    // 2.2 the attribute is multi-valued : add the missing value
+                    else
+                    {
+                        entry.add( upId, upValue );
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/fit/build-tools/src/main/java/org/apache/syncope/fit/buildtools/ApacheDSStartStopListener.java b/fit/build-tools/src/main/java/org/apache/syncope/fit/buildtools/ApacheDSStartStopListener.java
index af3b223..6a3322f 100644
--- a/fit/build-tools/src/main/java/org/apache/syncope/fit/buildtools/ApacheDSStartStopListener.java
+++ b/fit/build-tools/src/main/java/org/apache/syncope/fit/buildtools/ApacheDSStartStopListener.java
@@ -19,17 +19,23 @@
 package org.apache.syncope.fit.buildtools;
 
 import java.io.File;
-import java.util.HashSet;
+import java.io.IOException;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
 import javax.servlet.annotation.WebListener;
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
 import org.apache.directory.api.ldap.model.entry.Entry;
 import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.LdapComparator;
 import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.comparators.NormalizingComparator;
+import org.apache.directory.api.ldap.model.schema.registries.ComparatorRegistry;
 import org.apache.directory.api.ldap.model.schema.registries.SchemaLoader;
 import org.apache.directory.api.ldap.schema.extractor.SchemaLdifExtractor;
 import org.apache.directory.api.ldap.schema.extractor.impl.DefaultSchemaLdifExtractor;
@@ -38,12 +44,12 @@ import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager;
 import org.apache.directory.api.util.exception.Exceptions;
 import org.apache.directory.server.constants.ServerDNConstants;
 import org.apache.directory.server.core.DefaultDirectoryService;
-import org.apache.directory.server.core.api.CacheService;
 import org.apache.directory.server.core.api.DirectoryService;
 import org.apache.directory.server.core.api.DnFactory;
 import org.apache.directory.server.core.api.InstanceLayout;
 import org.apache.directory.server.core.api.partition.Partition;
 import org.apache.directory.server.core.api.schema.SchemaPartition;
+import org.apache.directory.server.core.factory.JdbmPartitionFactory;
 import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmIndex;
 import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition;
 import org.apache.directory.server.core.partition.ldif.LdifPartition;
@@ -78,7 +84,7 @@ public class ApacheDSStartStopListener implements ServletContextListener {
      * @return The newly added partition
      * @throws Exception If the partition can't be added
      */
-    private Partition addPartition(final String partitionId, final String partitionDn, final DnFactory dnFactory)
+    private void addPartition(final String partitionId, final String partitionDn, final DnFactory dnFactory)
             throws Exception {
 
         // Create a new partition with the given partition id
@@ -88,24 +94,11 @@ public class ApacheDSStartStopListener implements ServletContextListener {
         partition.setSuffixDn(new Dn(partitionDn));
         service.addPartition(partition);
 
-        return partition;
-    }
-
-    /**
-     * Add a new set of index on the given attributes.
-     *
-     * @param partition The partition on which we want to add index
-     * @param attrs The list of attributes to index
-     */
-    private static void addIndex(final Partition partition, final String... attrs) {
-        // Index some attributes on the apache partition
-        Set<Index<?, String>> indexedAttributes = new HashSet<>();
-
-        for (String attribute : attrs) {
-            indexedAttributes.add(new JdbmIndex<String>(attribute, false));
-        }
-
-        ((JdbmPartition) partition).setIndexedAttributes(indexedAttributes);
+        Set<Index<?, String>> indexedAttributes = Stream.of(
+                SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.OU_AT,
+                SchemaConstants.UID_AT, SchemaConstants.CN_AT).
+                map(attr -> new JdbmIndex<String>(attr, false)).collect(Collectors.toSet());
+        partition.setIndexedAttributes(indexedAttributes);
     }
 
     /**
@@ -114,41 +107,63 @@ public class ApacheDSStartStopListener implements ServletContextListener {
      * @throws Exception if the schema LDIF files are not found on the classpath
      */
     private void initSchemaPartition() throws Exception {
-        InstanceLayout instanceLayout = service.getInstanceLayout();
-
-        File schemaPartitionDirectory = new File(instanceLayout.getPartitionsDirectory(), "schema");
+        File workingDirectory = service.getInstanceLayout().getPartitionsDirectory();
 
         // Extract the schema on disk (a brand new one) and load the registries
-        if (schemaPartitionDirectory.exists()) {
-            LOG.debug("schema partition already exists, skipping schema extraction");
-        } else {
-            SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor(instanceLayout.getPartitionsDirectory());
+        File schemaRepository = new File(workingDirectory, "schema");
+        SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor(workingDirectory);
+        try {
             extractor.extractOrCopy();
+        } catch (IOException ioe) {
+            // The schema has already been extracted, bypass
         }
 
-        SchemaLoader loader = new LdifSchemaLoader(schemaPartitionDirectory);
+        SchemaLoader loader = new LdifSchemaLoader(schemaRepository);
         SchemaManager schemaManager = new DefaultSchemaManager(loader);
 
         // We have to load the schema now, otherwise we won't be able
-        // to initialize the Partitions, as we won't be able to parse
+        // to initialize the Partitions, as we won't be able to parse 
         // and normalize their suffix Dn
         schemaManager.loadAllEnabled();
 
+        // Tell all the normalizer comparators that they should not normalize anything
+        ComparatorRegistry comparatorRegistry = schemaManager.getComparatorRegistry();
+        for (LdapComparator<?> comparator : comparatorRegistry) {
+            if (comparator instanceof NormalizingComparator) {
+                ((NormalizingComparator) comparator).setOnServer();
+            }
+        }
+
+        service.setSchemaManager(schemaManager);
+
+        // Init the LdifPartition
+        LdifPartition ldifPartition = new LdifPartition(schemaManager, service.getDnFactory());
+        ldifPartition.setPartitionPath(new File(workingDirectory, "schema").toURI());
+        SchemaPartition schemaPartition = new SchemaPartition(schemaManager);
+        schemaPartition.setWrappedPartition(ldifPartition);
+        service.setSchemaPartition(schemaPartition);
+
         List<Throwable> errors = schemaManager.getErrors();
         if (!errors.isEmpty()) {
             throw new IllegalStateException(I18n.err(I18n.ERR_317, Exceptions.printErrors(errors)));
         }
+    }
 
-        service.setSchemaManager(schemaManager);
+    private void initSystemPartition() throws Exception {
+        JdbmPartitionFactory partitionFactory = new JdbmPartitionFactory();
 
-        // Init the LdifPartition with schema
-        LdifPartition schemaLdifPartition = new LdifPartition(schemaManager, service.getDnFactory());
-        schemaLdifPartition.setPartitionPath(schemaPartitionDirectory.toURI());
+        Partition systemPartition = partitionFactory.createPartition(
+                service.getSchemaManager(),
+                service.getDnFactory(),
+                "system",
+                ServerDNConstants.SYSTEM_DN,
+                500,
+                new File(service.getInstanceLayout().getPartitionsDirectory(), "system"));
+        systemPartition.setSchemaManager(service.getSchemaManager());
 
-        // The schema partition
-        SchemaPartition schemaPartition = new SchemaPartition(schemaManager);
-        schemaPartition.setWrappedPartition(schemaLdifPartition);
-        service.setSchemaPartition(schemaPartition);
+        partitionFactory.addIndex(systemPartition, SchemaConstants.OBJECT_CLASS_AT, 100);
+
+        service.setSystemPartition(systemPartition);
     }
 
     /**
@@ -166,38 +181,18 @@ public class ApacheDSStartStopListener implements ServletContextListener {
         service = new DefaultDirectoryService();
         service.setInstanceLayout(new InstanceLayout(workDir));
 
-        CacheService cacheService = new CacheService();
-        cacheService.initialize(service.getInstanceLayout());
-
-        service.setCacheService(cacheService);
-
         // first load the schema
         initSchemaPartition();
 
         // then the system partition
-        // this is a MANDATORY partition
-        // DO NOT add this via addPartition() method, trunk code complains about duplicate partition
-        // while initializing
-        JdbmPartition systemPartition = new JdbmPartition(service.getSchemaManager(), service.getDnFactory());
-        systemPartition.setId("system");
-        systemPartition.setPartitionPath(
-                new File(service.getInstanceLayout().getPartitionsDirectory(), systemPartition.getId()).toURI());
-        systemPartition.setSuffixDn(new Dn(ServerDNConstants.SYSTEM_DN));
-        systemPartition.setSchemaManager(service.getSchemaManager());
-
-        // mandatory to call this method to set the system partition
-        // Note: this system partition might be removed from trunk
-        service.setSystemPartition(systemPartition);
+        initSystemPartition();
 
         // Disable the ChangeLog system
         service.getChangeLog().setEnabled(false);
         service.setDenormalizeOpAttrsEnabled(true);
 
         // Now we can create as many partitions as we need
-        Partition ispPartition = addPartition("isp", "o=isp", service.getDnFactory());
-
-        // Index some attributes on the apache partition
-        addIndex(ispPartition, "objectClass", "ou", "uid");
+        addPartition("isp", "o=isp", service.getDnFactory());
 
         // And start the service
         service.startup();
diff --git a/pom.xml b/pom.xml
index 40c59fc..900830b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -434,8 +434,8 @@ under the License.
 
     <elasticsearch.version>7.6.1</elasticsearch.version>
 
-    <apacheds.version>2.0.0.AM25</apacheds.version>
-    <apachedirapi.version>2.0.0.AM2</apachedirapi.version>
+    <apacheds.version>2.0.0.AM26</apacheds.version>
+    <apachedirapi.version>2.0.0</apachedirapi.version>
 
     <log4j.version>2.13.1</log4j.version>
     <disruptor.version>3.4.2</disruptor.version>
@@ -1288,6 +1288,11 @@ under the License.
       </dependency>
       <dependency>
         <groupId>org.apache.directory.server</groupId>
+        <artifactId>apacheds-core-annotations</artifactId>
+        <version>${apacheds.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.directory.server</groupId>
         <artifactId>apacheds-service-builder</artifactId>
         <version>${apacheds.version}</version>
         <exclusions>
@@ -1302,21 +1307,6 @@ under the License.
         <artifactId>api-ldap-codec-standalone</artifactId>
         <version>${apachedirapi.version}</version>
       </dependency>
-      <dependency>
-        <groupId>org.apache.directory.api</groupId>
-        <artifactId>api-ldap-model</artifactId>
-        <version>${apachedirapi.version}</version>
-      </dependency>
-      <dependency>
-        <groupId>org.apache.directory.api</groupId>
-        <artifactId>api-ldap-schema-data</artifactId>
-        <version>${apachedirapi.version}</version>
-      </dependency>
-      <dependency>
-        <groupId>org.apache.directory.api</groupId>
-        <artifactId>api-util</artifactId>
-        <version>${apachedirapi.version}</version>
-      </dependency>
 
       <dependency>
         <groupId>com.icegreen</groupId>