From bf8316eefab4d305ff93135b99c36fccc359da8e Mon Sep 17 00:00:00 2001 From: Tero Saarni Date: Wed, 13 May 2020 15:58:20 +0300 Subject: [PATCH] KEYCLOAK-14162 Uplifted Apache DS version for LDAPEmbeddedServer Signed-off-by: Tero Saarni --- pom.xml | 16 +- util/embedded-ldap/pom.xml | 16 + .../ldap/FileDirectoryServiceFactory.java | 278 ------------------ .../ldap/InMemoryDirectoryServiceFactory.java | 182 ------------ .../util/ldap/InMemorySchemaPartition.java | 93 ------ .../util/ldap/LDAPEmbeddedServer.java | 52 ++-- .../util/ldap/RangedAttributeInterceptor.java | 12 +- 7 files changed, 70 insertions(+), 579 deletions(-) delete mode 100644 util/embedded-ldap/src/main/java/org/keycloak/util/ldap/FileDirectoryServiceFactory.java delete mode 100644 util/embedded-ldap/src/main/java/org/keycloak/util/ldap/InMemoryDirectoryServiceFactory.java delete mode 100644 util/embedded-ldap/src/main/java/org/keycloak/util/ldap/InMemorySchemaPartition.java diff --git a/pom.xml b/pom.xml index 35c79c2291..037fb64d58 100755 --- a/pom.xml +++ b/pom.xml @@ -98,7 +98,7 @@ 2.1.4 1.1.6 1.5.2.Final - 1.4.3 + 1.4.3 5.0.3.Final 25.0-jre @@ -109,8 +109,8 @@ 2.6 3.9 2.6 - 2.0.0-M24 - 1.0.0 + 2.0.0.AM26 + 2.0.0 3.4.0 2.3.29 @@ -579,6 +579,16 @@ + + org.apache.directory.server + apacheds-core + ${apacheds.version} + + + org.apache.directory.server + apacheds-core-api + ${apacheds.version} + org.apache.directory.server apacheds-core-annotations diff --git a/util/embedded-ldap/pom.xml b/util/embedded-ldap/pom.xml index 36747121a7..85deefd127 100644 --- a/util/embedded-ldap/pom.xml +++ b/util/embedded-ldap/pom.xml @@ -39,6 +39,14 @@ commons-io commons-io + + commons-lang + commons-lang + + + org.apache.commons + commons-lang3 + org.jboss.logging jboss-logging @@ -82,6 +90,14 @@ + + org.apache.directory.server + apacheds-core + + + org.apache.directory.server + apacheds-core-api + org.apache.directory.api api-ldap-codec-standalone diff --git a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/FileDirectoryServiceFactory.java b/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/FileDirectoryServiceFactory.java deleted file mode 100644 index 37f975432c..0000000000 --- a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/FileDirectoryServiceFactory.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * 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.keycloak.util.ldap; - -import org.apache.directory.api.ldap.model.constants.SchemaConstants; -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; -import org.apache.directory.api.ldap.schema.loader.LdifSchemaLoader; -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.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.DefaultDirectoryServiceFactory; -import org.apache.directory.server.core.factory.DirectoryServiceFactory; -import org.apache.directory.server.core.factory.LdifPartitionFactory; -import org.apache.directory.server.core.factory.PartitionFactory; -import org.apache.directory.server.core.partition.ldif.LdifPartition; -import org.apache.directory.server.i18n.I18n; -import org.jboss.logging.Logger; - -import java.io.File; -import java.io.IOException; -import java.util.List; - -/** - * Slightly modified version of {@link DefaultDirectoryServiceFactory} which allows persistence among restarts and uses LDIF partitions by default - * - * @author Marek Posolda - */ -class FileDirectoryServiceFactory implements DirectoryServiceFactory { - - /** A logger for this class */ - private static final Logger LOG = Logger.getLogger(FileDirectoryServiceFactory.class); - - /** The directory service. */ - private DirectoryService directoryService; - - /** The partition factory. */ - private PartitionFactory partitionFactory; - - - public FileDirectoryServiceFactory() - { - try - { - // creating the instance here so that - // we we can set some properties like accesscontrol, anon access - // before starting up the service - directoryService = new DefaultDirectoryService(); - - // no need to register a shutdown hook during tests because this - // starts a lot of threads and slows down test execution - directoryService.setShutdownHookEnabled( false ); - } - catch ( Exception e ) - { - throw new RuntimeException( e ); - } - - try - { - String typeName = System.getProperty( "apacheds.partition.factory" ); - - if ( typeName != null ) - { - Class type = ( Class ) Class.forName( typeName ); - partitionFactory = type.newInstance(); - } - else - { - // partitionFactory = new JdbmPartitionFactory(); - partitionFactory = new LdifPartitionFactory(); - } - } - catch ( Exception e ) - { - LOG.error( "Error instantiating custom partiton factory", e ); - throw new RuntimeException( e ); - } - } - - - public FileDirectoryServiceFactory( DirectoryService directoryService, PartitionFactory partitionFactory ) - { - this.directoryService = directoryService; - this.partitionFactory = partitionFactory; - } - - - /** - * {@inheritDoc} - */ - public void init( String name ) throws Exception - { - if ( ( directoryService != null ) && directoryService.isStarted() ) { - return; - } - - build(name); - } - - - /** - * Build the working directory - */ - private void buildInstanceDirectory( String name ) throws IOException - { - String instanceDirectory = System.getProperty( "workingDirectory" ); - - if ( instanceDirectory == null ) - { - instanceDirectory = System.getProperty( "java.io.tmpdir" ) + "/server-work-" + name; - } - - InstanceLayout instanceLayout = new InstanceLayout( instanceDirectory ); - - /*if ( instanceLayout.getInstanceDirectory().exists() ) - { - try - { - FileUtils.deleteDirectory(instanceLayout.getInstanceDirectory()); - } - catch ( IOException e ) - { - LOG.warn( "couldn't delete the instance directory before initializing the DirectoryService", e ); - } - }*/ - - directoryService.setInstanceLayout( instanceLayout ); - } - - - /** - * Inits the schema and schema partition. - */ - private void initSchema() throws Exception - { - File workingDirectory = directoryService.getInstanceLayout().getPartitionsDirectory(); - - // Extract the schema on disk (a brand new one) and load the registries - 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( 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 - // 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(); - } - } - - directoryService.setSchemaManager( schemaManager ); - - // Init the LdifPartition - LdifPartition ldifPartition = new LdifPartition( schemaManager, directoryService.getDnFactory() ); - ldifPartition.setPartitionPath( new File( workingDirectory, "schema" ).toURI() ); - SchemaPartition schemaPartition = new SchemaPartition( schemaManager ); - schemaPartition.setWrappedPartition( ldifPartition ); - directoryService.setSchemaPartition( schemaPartition ); - - List errors = schemaManager.getErrors(); - - if ( errors.size() != 0 ) - { - throw new Exception( I18n.err(I18n.ERR_317, Exceptions.printErrors(errors)) ); - } - } - - - /** - * Inits the system partition. - * - * @throws Exception the exception - */ - private void initSystemPartition() throws Exception - { - // change the working directory to something that is unique - // on the system and somewhere either under target directory - // or somewhere in a temp area of the machine. - - // Inject the System Partition - Partition systemPartition = partitionFactory.createPartition( directoryService.getSchemaManager(), - directoryService.getDnFactory(), - "system", ServerDNConstants.SYSTEM_DN, 500, - new File( directoryService.getInstanceLayout().getPartitionsDirectory(), "system" ) ); - systemPartition.setSchemaManager(directoryService.getSchemaManager()); - - partitionFactory.addIndex(systemPartition, SchemaConstants.OBJECT_CLASS_AT, 100 ); - - directoryService.setSystemPartition( systemPartition ); - } - - - /** - * Builds the directory server instance. - * - * @param name the instance name - */ - private void build( String name ) throws Exception - { - directoryService.setInstanceId( name ); - buildInstanceDirectory( name ); - - CacheService cacheService = new CacheService(); - cacheService.initialize( directoryService.getInstanceLayout() ); - - directoryService.setCacheService( cacheService ); - - // Init the service now - initSchema(); - initSystemPartition(); - - directoryService.startup(); - } - - - /** - * {@inheritDoc} - */ - public DirectoryService getDirectoryService() throws Exception - { - return directoryService; - } - - - /** - * {@inheritDoc} - */ - public PartitionFactory getPartitionFactory() throws Exception - { - return partitionFactory; - } -} diff --git a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/InMemoryDirectoryServiceFactory.java b/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/InMemoryDirectoryServiceFactory.java deleted file mode 100644 index 2b324694ca..0000000000 --- a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/InMemoryDirectoryServiceFactory.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * 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.keycloak.util.ldap; - -import net.sf.ehcache.CacheManager; -import net.sf.ehcache.config.CacheConfiguration; -import net.sf.ehcache.config.Configuration; -import org.apache.commons.io.FileUtils; -import org.apache.directory.api.ldap.model.constants.SchemaConstants; -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.loader.JarLdifSchemaLoader; -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.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.AvlPartitionFactory; -import org.apache.directory.server.core.factory.DirectoryServiceFactory; -import org.apache.directory.server.core.factory.PartitionFactory; -import org.apache.directory.server.i18n.I18n; -import org.jboss.logging.Logger; - -import java.io.File; -import java.io.IOException; -import java.util.List; -import org.apache.directory.server.core.api.interceptor.Interceptor; -import org.apache.directory.server.core.normalization.NormalizationInterceptor; - -/** - * Factory for a fast (mostly in-memory-only) ApacheDS DirectoryService. Use only for tests!! - * - * @author Josef Cacek - */ -class InMemoryDirectoryServiceFactory implements DirectoryServiceFactory { - - private static final Logger log = Logger.getLogger(InMemoryDirectoryServiceFactory.class); - private static final int PAGE_SIZE = 30; - - private final DirectoryService directoryService; - private final PartitionFactory partitionFactory; - - /** - * Default constructor which creates {@link DefaultDirectoryService} instance and configures {@link AvlPartitionFactory} as - * the {@link PartitionFactory} implementation. - */ - public InMemoryDirectoryServiceFactory() { - try { - directoryService = new DefaultDirectoryService(); - } catch (Exception e) { - throw new RuntimeException(e); - } - directoryService.setShutdownHookEnabled(false); - partitionFactory = new AvlPartitionFactory(); - } - - /** - * Constructor which uses provided {@link DirectoryService} and {@link PartitionFactory} implementations. - * - * @param directoryService must be not-null - * @param partitionFactory must be not-null - */ - public InMemoryDirectoryServiceFactory(DirectoryService directoryService, PartitionFactory partitionFactory) { - this.directoryService = directoryService; - this.partitionFactory = partitionFactory; - } - - /** - * {@inheritDoc} - */ - @Override - public void init(String name) throws Exception { - if ((directoryService != null) && directoryService.isStarted()) { - return; - } - directoryService.setInstanceId(name); - - // instance layout - InstanceLayout instanceLayout = new InstanceLayout(System.getProperty("java.io.tmpdir") + "/server-work-inmemory-" + name); - if (instanceLayout.getInstanceDirectory().exists()) { - try { - FileUtils.deleteDirectory(instanceLayout.getInstanceDirectory()); - } catch (IOException e) { - log.warn("couldn't delete the instance directory before initializing the DirectoryService", e); - } - } - directoryService.setInstanceLayout(instanceLayout); - - // EhCache in disabled-like-mode - Configuration ehCacheConfig = new Configuration(); - ehCacheConfig.setName(name); - CacheConfiguration defaultCache = new CacheConfiguration(name + "-default", 1).eternal(false).timeToIdleSeconds(30) - .timeToLiveSeconds(30).overflowToDisk(false); - ehCacheConfig.addDefaultCache(defaultCache); - CacheService cacheService = new CacheService(new CacheManager(ehCacheConfig)); - directoryService.setCacheService(cacheService); - - // Init the schema - // SchemaLoader loader = new SingleLdifSchemaLoader(); - SchemaLoader loader = new JarLdifSchemaLoader(); - SchemaManager schemaManager = new DefaultSchemaManager(loader); - schemaManager.loadAllEnabled(); - ComparatorRegistry comparatorRegistry = schemaManager.getComparatorRegistry(); - for (LdapComparator comparator : comparatorRegistry) { - if (comparator instanceof NormalizingComparator) { - ((NormalizingComparator) comparator).setOnServer(); - } - } - directoryService.setSchemaManager(schemaManager); - InMemorySchemaPartition inMemorySchemaPartition = new InMemorySchemaPartition(schemaManager); - SchemaPartition schemaPartition = new SchemaPartition(schemaManager); - schemaPartition.setWrappedPartition(inMemorySchemaPartition); - directoryService.setSchemaPartition(schemaPartition); - List errors = schemaManager.getErrors(); - if (errors.size() != 0) { - throw new Exception(I18n.err(I18n.ERR_317, Exceptions.printErrors(errors))); - } - - // Init system partition - Partition systemPartition = partitionFactory.createPartition(directoryService.getSchemaManager(), - directoryService.getDnFactory(), "system", - ServerDNConstants.SYSTEM_DN, 500, - new File(directoryService.getInstanceLayout().getPartitionsDirectory(), - "system")); - - systemPartition.setSchemaManager(directoryService.getSchemaManager()); - partitionFactory.addIndex(systemPartition, SchemaConstants.OBJECT_CLASS_AT, 100); - directoryService.setSystemPartition(systemPartition); - - // Find Normalization interceptor in chain and add our range emulated interceptor - List interceptors = directoryService.getInterceptors(); - int insertionPosition = -1; - for (int pos = 0; pos < interceptors.size(); ++pos) { - Interceptor interceptor = interceptors.get(pos); - if (interceptor instanceof NormalizationInterceptor) { - insertionPosition = pos; - } - } - interceptors.add(insertionPosition + 1, new RangedAttributeInterceptor("member", PAGE_SIZE)); - directoryService.setInterceptors(interceptors); - - directoryService.startup(); - } - - /** - * {@inheritDoc} - */ - @Override - public DirectoryService getDirectoryService() throws Exception { - return directoryService; - } - - /** - * {@inheritDoc} - */ - @Override - public PartitionFactory getPartitionFactory() throws Exception { - return partitionFactory; - } -} diff --git a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/InMemorySchemaPartition.java b/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/InMemorySchemaPartition.java deleted file mode 100644 index 320511bbf7..0000000000 --- a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/InMemorySchemaPartition.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * 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.keycloak.util.ldap; - -import org.apache.directory.api.ldap.model.constants.SchemaConstants; -import org.apache.directory.api.ldap.model.entry.DefaultEntry; -import org.apache.directory.api.ldap.model.entry.Entry; -import org.apache.directory.api.ldap.model.ldif.LdifEntry; -import org.apache.directory.api.ldap.model.ldif.LdifReader; -import org.apache.directory.api.ldap.model.schema.SchemaManager; -import org.apache.directory.api.ldap.schema.extractor.impl.DefaultSchemaLdifExtractor; -import org.apache.directory.api.ldap.schema.extractor.impl.ResourceMap; -import org.apache.directory.server.core.api.interceptor.context.AddOperationContext; -import org.apache.directory.server.core.partition.ldif.AbstractLdifPartition; -import org.jboss.logging.Logger; - -import javax.naming.InvalidNameException; -import java.net.URL; -import java.util.Map; -import java.util.TreeSet; -import java.util.UUID; -import java.util.regex.Pattern; - -/** - * In-memory schema-only partition which loads the data in the similar way as the - * {@link org.apache.directory.api.ldap.schemaloader.JarLdifSchemaLoader}. - * - * @author Josef Cacek - */ -class InMemorySchemaPartition extends AbstractLdifPartition { - - private static final Logger log = Logger.getLogger(InMemorySchemaPartition.class); - - /** - * Filesystem path separator pattern, either forward slash or backslash. java.util.regex.Pattern is immutable so only one - * instance is needed for all uses. - */ - public InMemorySchemaPartition(SchemaManager schemaManager) { - super(schemaManager); - } - - /** - * Partition initialization - loads schema entries from the files on classpath. - * - * @see org.apache.directory.server.core.partition.impl.avl.AvlPartition#doInit() - */ - @Override - protected void doInit() throws InvalidNameException, Exception { - if (initialized) - return; - log.debug("Initializing schema partition " + getId()); - suffixDn.apply(schemaManager); - super.doInit(); - - // load schema - final Map resMap = ResourceMap.getResources(Pattern.compile("schema[/\\Q\\\\E]ou=schema.*")); - for (String resourcePath : new TreeSet(resMap.keySet())) { - if (resourcePath.endsWith(".ldif")) { - URL resource = DefaultSchemaLdifExtractor.getUniqueResource(resourcePath, "Schema LDIF file"); - LdifReader reader = new LdifReader(resource.openStream()); - LdifEntry ldifEntry = reader.next(); - reader.close(); - Entry entry = new DefaultEntry(schemaManager, ldifEntry.getEntry()); - - // add mandatory attributes - if (entry.get(SchemaConstants.ENTRY_CSN_AT) == null) { - entry.add(SchemaConstants.ENTRY_CSN_AT, AbstractLdifPartition.defaultCSNFactory.newInstance().toString()); - } - if (entry.get(SchemaConstants.ENTRY_UUID_AT) == null) { - entry.add(SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString()); - } - AddOperationContext addContext = new AddOperationContext(null, entry); - super.add(addContext); - } - } - } - -} diff --git a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/LDAPEmbeddedServer.java b/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/LDAPEmbeddedServer.java index 619dbf2fa8..a155a6b3e3 100644 --- a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/LDAPEmbeddedServer.java +++ b/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/LDAPEmbeddedServer.java @@ -26,9 +26,12 @@ import org.apache.directory.api.ldap.model.ldif.LdifEntry; import org.apache.directory.api.ldap.model.ldif.LdifReader; import org.apache.directory.api.ldap.model.schema.SchemaManager; import org.apache.directory.server.core.api.DirectoryService; +import org.apache.directory.server.core.api.interceptor.Interceptor; import org.apache.directory.server.core.api.partition.Partition; -import org.apache.directory.server.core.factory.DirectoryServiceFactory; -import org.apache.directory.server.core.factory.PartitionFactory; +import org.apache.directory.server.core.factory.AvlPartitionFactory; +import org.apache.directory.server.core.factory.DefaultDirectoryServiceFactory; +import org.apache.directory.server.core.factory.JdbmPartitionFactory; +import org.apache.directory.server.core.normalization.NormalizationInterceptor; import org.apache.directory.server.ldap.LdapServer; import org.apache.directory.server.protocol.shared.transport.TcpTransport; import org.apache.directory.server.protocol.shared.transport.Transport; @@ -39,6 +42,7 @@ import org.keycloak.common.util.StreamUtil; import java.io.File; import java.io.InputStream; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Properties; @@ -48,6 +52,7 @@ import java.util.Properties; public class LDAPEmbeddedServer { private static final Logger log = Logger.getLogger(LDAPEmbeddedServer.class); + private static final int PAGE_SIZE = 30; public static final String PROPERTY_BASE_DN = "ldap.baseDN"; public static final String PROPERTY_BIND_HOST = "ldap.host"; @@ -171,15 +176,15 @@ public class LDAPEmbeddedServer { String dcName = baseDN.split(",")[0]; dcName = dcName.substring(dcName.indexOf("=") + 1); - DirectoryServiceFactory dsf; if (this.directoryServiceFactory.equals(DSF_INMEMORY)) { - dsf = new InMemoryDirectoryServiceFactory(); + System.setProperty( "apacheds.partition.factory", AvlPartitionFactory.class.getName()); } else if (this.directoryServiceFactory.equals(DSF_FILE)) { - dsf = new FileDirectoryServiceFactory(); + System.setProperty( "apacheds.partition.factory", JdbmPartitionFactory.class.getName()); } else { throw new IllegalStateException("Unknown value of directoryServiceFactory: " + this.directoryServiceFactory); } + DefaultDirectoryServiceFactory dsf = new DefaultDirectoryServiceFactory(); DirectoryService service = dsf.getDirectoryService(); service.setAccessControlEnabled(false); service.setAllowAnonymousAccess(false); @@ -187,20 +192,16 @@ public class LDAPEmbeddedServer { dsf.init(dcName + "DS"); - SchemaManager schemaManager = service.getSchemaManager(); - - PartitionFactory partitionFactory = dsf.getPartitionFactory(); - Partition partition = partitionFactory.createPartition( - schemaManager, - service.getDnFactory(), - dcName, - this.baseDN, - 1000, - new File(service.getInstanceLayout().getPartitionsDirectory(), dcName)); - partition.setCacheService( service.getCacheService() ); + Partition partition = dsf.getPartitionFactory().createPartition( + service.getSchemaManager(), + service.getDnFactory(), + dcName, + this.baseDN, + 1000, + new File(service.getInstanceLayout().getPartitionsDirectory(), dcName)); partition.initialize(); - partition.setSchemaManager( schemaManager ); + partition.setSchemaManager(service.getSchemaManager()); // Inject the partition into the DirectoryService service.addPartition( partition ); @@ -213,6 +214,23 @@ public class LDAPEmbeddedServer { "objectClass: domain\n\n"; importLdifContent(service, entryLdif); + + if (this.directoryServiceFactory.equals(DSF_INMEMORY)) { + // Find Normalization interceptor in chain and add our range emulated interceptor + List interceptors = service.getInterceptors(); + int insertionPosition = -1; + for (int pos = 0; pos < interceptors.size(); ++pos) { + Interceptor interceptor = interceptors.get(pos); + if (interceptor instanceof NormalizationInterceptor) { + insertionPosition = pos; + } + } + RangedAttributeInterceptor interceptor = new RangedAttributeInterceptor("member", PAGE_SIZE); + interceptor.init(service); + interceptors.add(insertionPosition + 1, interceptor); + service.setInterceptors(interceptors); + } + return service; } diff --git a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/RangedAttributeInterceptor.java b/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/RangedAttributeInterceptor.java index a0ed01680c..ce29f51b10 100644 --- a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/RangedAttributeInterceptor.java +++ b/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/RangedAttributeInterceptor.java @@ -37,7 +37,7 @@ import org.apache.directory.server.core.api.interceptor.context.SearchOperationC /** *

Ranged interceptor to emulate the behavior of AD. AD has a limit in - * the number of attributes that return (15000 by default in MaxValRange). + * the number of attributes that return (15000 by default in MaxValRange). * See this MS link for AD limits:

* * https://support.microsoft.com/en-us/help/315071/how-to-view-and-set-ldap-policy-in-active-directory-by-using-ntdsutil @@ -73,16 +73,16 @@ public class RangedAttributeInterceptor extends BaseInterceptor { int end = (max != null && max < attr.size() - 1)? max : attr.size() - 1; if (start != 0 || end != attr.size() - 1) { // some values should be stripped out - Iterator> it = attr.iterator(); - Set> valuesToRemove = new HashSet<>(end - start + 1); + Iterator it = attr.iterator(); + Set valuesToRemove = new HashSet<>(end - start + 1); for (int i = 0; i < attr.size(); i++) { - Value v = it.next(); + Value v = it.next(); if (i < start || i > end) { valuesToRemove.add(v); } } attr.setUpId(attr.getUpId() + ";range=" + start + "-" + ((end == attr.size() - 1)? "*" : end)); - attr.remove(valuesToRemove.toArray(new Value[0])); + attr.remove(valuesToRemove.toArray(new Value[0])); } else if (min != null) { // range explicitly requested although no value stripped attr.setUpId(attr.getUpId() + ";range=0-*"); @@ -256,4 +256,4 @@ public class RangedAttributeInterceptor extends BaseInterceptor { } return new RangedEntryFilteringCursor(super.next(sc), name, lmin, lmax); } -} \ No newline at end of file +}