KEYCLOAK-14162 Uplifted Apache DS version for LDAPEmbeddedServer
Signed-off-by: Tero Saarni <tero.saarni@est.tech>
This commit is contained in:
parent
bae802bcfa
commit
bf8316eefa
7 changed files with 70 additions and 579 deletions
16
pom.xml
16
pom.xml
|
@ -98,7 +98,7 @@
|
||||||
<xmlsec.version>2.1.4</xmlsec.version>
|
<xmlsec.version>2.1.4</xmlsec.version>
|
||||||
<glassfish.json.version>1.1.6</glassfish.json.version>
|
<glassfish.json.version>1.1.6</glassfish.json.version>
|
||||||
<wildfly.common.version>1.5.2.Final</wildfly.common.version>
|
<wildfly.common.version>1.5.2.Final</wildfly.common.version>
|
||||||
<ua-parser.version>1.4.3</ua-parser.version>
|
<ua-parser.version>1.4.3</ua-parser.version>
|
||||||
<picketbox.version>5.0.3.Final</picketbox.version>
|
<picketbox.version>5.0.3.Final</picketbox.version>
|
||||||
<google.guava.version>25.0-jre</google.guava.version>
|
<google.guava.version>25.0-jre</google.guava.version>
|
||||||
|
|
||||||
|
@ -109,8 +109,8 @@
|
||||||
<commons-lang.version>2.6</commons-lang.version>
|
<commons-lang.version>2.6</commons-lang.version>
|
||||||
<commons-lang3.version>3.9</commons-lang3.version>
|
<commons-lang3.version>3.9</commons-lang3.version>
|
||||||
<commons-io.version>2.6</commons-io.version>
|
<commons-io.version>2.6</commons-io.version>
|
||||||
<apacheds.version>2.0.0-M24</apacheds.version>
|
<apacheds.version>2.0.0.AM26</apacheds.version>
|
||||||
<apacheds.codec.version>1.0.0</apacheds.codec.version>
|
<apacheds.codec.version>2.0.0</apacheds.codec.version>
|
||||||
<google.zxing.version>3.4.0</google.zxing.version>
|
<google.zxing.version>3.4.0</google.zxing.version>
|
||||||
<freemarker.version>2.3.29</freemarker.version>
|
<freemarker.version>2.3.29</freemarker.version>
|
||||||
|
|
||||||
|
@ -579,6 +579,16 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Apache DS -->
|
<!-- Apache DS -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.directory.server</groupId>
|
||||||
|
<artifactId>apacheds-core</artifactId>
|
||||||
|
<version>${apacheds.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.directory.server</groupId>
|
||||||
|
<artifactId>apacheds-core-api</artifactId>
|
||||||
|
<version>${apacheds.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.directory.server</groupId>
|
<groupId>org.apache.directory.server</groupId>
|
||||||
<artifactId>apacheds-core-annotations</artifactId>
|
<artifactId>apacheds-core-annotations</artifactId>
|
||||||
|
|
|
@ -39,6 +39,14 @@
|
||||||
<groupId>commons-io</groupId>
|
<groupId>commons-io</groupId>
|
||||||
<artifactId>commons-io</artifactId>
|
<artifactId>commons-io</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-lang</groupId>
|
||||||
|
<artifactId>commons-lang</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.logging</groupId>
|
<groupId>org.jboss.logging</groupId>
|
||||||
<artifactId>jboss-logging</artifactId>
|
<artifactId>jboss-logging</artifactId>
|
||||||
|
@ -82,6 +90,14 @@
|
||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.directory.server</groupId>
|
||||||
|
<artifactId>apacheds-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.directory.server</groupId>
|
||||||
|
<artifactId>apacheds-core-api</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.directory.api</groupId>
|
<groupId>org.apache.directory.api</groupId>
|
||||||
<artifactId>api-ldap-codec-standalone</artifactId>
|
<artifactId>api-ldap-codec-standalone</artifactId>
|
||||||
|
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
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<? extends PartitionFactory> type = ( Class<? extends PartitionFactory> ) 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<Throwable> 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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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-<code>null</code>
|
|
||||||
* @param partitionFactory must be not-<code>null</code>
|
|
||||||
*/
|
|
||||||
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<Throwable> 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<Interceptor> 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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<String, Boolean> resMap = ResourceMap.getResources(Pattern.compile("schema[/\\Q\\\\E]ou=schema.*"));
|
|
||||||
for (String resourcePath : new TreeSet<String>(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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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.ldif.LdifReader;
|
||||||
import org.apache.directory.api.ldap.model.schema.SchemaManager;
|
import org.apache.directory.api.ldap.model.schema.SchemaManager;
|
||||||
import org.apache.directory.server.core.api.DirectoryService;
|
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.api.partition.Partition;
|
||||||
import org.apache.directory.server.core.factory.DirectoryServiceFactory;
|
import org.apache.directory.server.core.factory.AvlPartitionFactory;
|
||||||
import org.apache.directory.server.core.factory.PartitionFactory;
|
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.ldap.LdapServer;
|
||||||
import org.apache.directory.server.protocol.shared.transport.TcpTransport;
|
import org.apache.directory.server.protocol.shared.transport.TcpTransport;
|
||||||
import org.apache.directory.server.protocol.shared.transport.Transport;
|
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.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
@ -48,6 +52,7 @@ import java.util.Properties;
|
||||||
public class LDAPEmbeddedServer {
|
public class LDAPEmbeddedServer {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(LDAPEmbeddedServer.class);
|
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_BASE_DN = "ldap.baseDN";
|
||||||
public static final String PROPERTY_BIND_HOST = "ldap.host";
|
public static final String PROPERTY_BIND_HOST = "ldap.host";
|
||||||
|
@ -171,15 +176,15 @@ public class LDAPEmbeddedServer {
|
||||||
String dcName = baseDN.split(",")[0];
|
String dcName = baseDN.split(",")[0];
|
||||||
dcName = dcName.substring(dcName.indexOf("=") + 1);
|
dcName = dcName.substring(dcName.indexOf("=") + 1);
|
||||||
|
|
||||||
DirectoryServiceFactory dsf;
|
|
||||||
if (this.directoryServiceFactory.equals(DSF_INMEMORY)) {
|
if (this.directoryServiceFactory.equals(DSF_INMEMORY)) {
|
||||||
dsf = new InMemoryDirectoryServiceFactory();
|
System.setProperty( "apacheds.partition.factory", AvlPartitionFactory.class.getName());
|
||||||
} else if (this.directoryServiceFactory.equals(DSF_FILE)) {
|
} else if (this.directoryServiceFactory.equals(DSF_FILE)) {
|
||||||
dsf = new FileDirectoryServiceFactory();
|
System.setProperty( "apacheds.partition.factory", JdbmPartitionFactory.class.getName());
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Unknown value of directoryServiceFactory: " + this.directoryServiceFactory);
|
throw new IllegalStateException("Unknown value of directoryServiceFactory: " + this.directoryServiceFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DefaultDirectoryServiceFactory dsf = new DefaultDirectoryServiceFactory();
|
||||||
DirectoryService service = dsf.getDirectoryService();
|
DirectoryService service = dsf.getDirectoryService();
|
||||||
service.setAccessControlEnabled(false);
|
service.setAccessControlEnabled(false);
|
||||||
service.setAllowAnonymousAccess(false);
|
service.setAllowAnonymousAccess(false);
|
||||||
|
@ -187,20 +192,16 @@ public class LDAPEmbeddedServer {
|
||||||
|
|
||||||
dsf.init(dcName + "DS");
|
dsf.init(dcName + "DS");
|
||||||
|
|
||||||
SchemaManager schemaManager = service.getSchemaManager();
|
Partition partition = dsf.getPartitionFactory().createPartition(
|
||||||
|
service.getSchemaManager(),
|
||||||
PartitionFactory partitionFactory = dsf.getPartitionFactory();
|
service.getDnFactory(),
|
||||||
Partition partition = partitionFactory.createPartition(
|
dcName,
|
||||||
schemaManager,
|
this.baseDN,
|
||||||
service.getDnFactory(),
|
1000,
|
||||||
dcName,
|
new File(service.getInstanceLayout().getPartitionsDirectory(), dcName));
|
||||||
this.baseDN,
|
|
||||||
1000,
|
|
||||||
new File(service.getInstanceLayout().getPartitionsDirectory(), dcName));
|
|
||||||
partition.setCacheService( service.getCacheService() );
|
|
||||||
partition.initialize();
|
partition.initialize();
|
||||||
|
|
||||||
partition.setSchemaManager( schemaManager );
|
partition.setSchemaManager(service.getSchemaManager());
|
||||||
|
|
||||||
// Inject the partition into the DirectoryService
|
// Inject the partition into the DirectoryService
|
||||||
service.addPartition( partition );
|
service.addPartition( partition );
|
||||||
|
@ -213,6 +214,23 @@ public class LDAPEmbeddedServer {
|
||||||
"objectClass: domain\n\n";
|
"objectClass: domain\n\n";
|
||||||
importLdifContent(service, entryLdif);
|
importLdifContent(service, entryLdif);
|
||||||
|
|
||||||
|
|
||||||
|
if (this.directoryServiceFactory.equals(DSF_INMEMORY)) {
|
||||||
|
// Find Normalization interceptor in chain and add our range emulated interceptor
|
||||||
|
List<Interceptor> 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;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ import org.apache.directory.server.core.api.interceptor.context.SearchOperationC
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Ranged interceptor to emulate the behavior of AD. AD has a limit in
|
* <p>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:</p>
|
* See this MS link for AD limits:</p>
|
||||||
*
|
*
|
||||||
* https://support.microsoft.com/en-us/help/315071/how-to-view-and-set-ldap-policy-in-active-directory-by-using-ntdsutil
|
* 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;
|
int end = (max != null && max < attr.size() - 1)? max : attr.size() - 1;
|
||||||
if (start != 0 || end != attr.size() - 1) {
|
if (start != 0 || end != attr.size() - 1) {
|
||||||
// some values should be stripped out
|
// some values should be stripped out
|
||||||
Iterator<Value<?>> it = attr.iterator();
|
Iterator<Value> it = attr.iterator();
|
||||||
Set<Value<?>> valuesToRemove = new HashSet<>(end - start + 1);
|
Set<Value> valuesToRemove = new HashSet<>(end - start + 1);
|
||||||
for (int i = 0; i < attr.size(); i++) {
|
for (int i = 0; i < attr.size(); i++) {
|
||||||
Value<?> v = it.next();
|
Value v = it.next();
|
||||||
if (i < start || i > end) {
|
if (i < start || i > end) {
|
||||||
valuesToRemove.add(v);
|
valuesToRemove.add(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
attr.setUpId(attr.getUpId() + ";range=" + start + "-" + ((end == attr.size() - 1)? "*" : end));
|
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) {
|
} else if (min != null) {
|
||||||
// range explicitly requested although no value stripped
|
// range explicitly requested although no value stripped
|
||||||
attr.setUpId(attr.getUpId() + ";range=0-*");
|
attr.setUpId(attr.getUpId() + ";range=0-*");
|
||||||
|
@ -256,4 +256,4 @@ public class RangedAttributeInterceptor extends BaseInterceptor {
|
||||||
}
|
}
|
||||||
return new RangedEntryFilteringCursor(super.next(sc), name, lmin, lmax);
|
return new RangedEntryFilteringCursor(super.next(sc), name, lmin, lmax);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue