blob: e9533e3e4d9c0fce4092ca4203ee01159114a4e7 [file] [log] [blame]
/**
* 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.rampart.util;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.DatagramSocket;
import java.nio.file.Files;
import java.security.Provider;
import java.security.Security;
import java.util.List;
import org.apache.axis2.testutils.PortAllocator;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.directory.api.ldap.model.entry.DefaultEntry;
import org.apache.directory.api.ldap.model.ldif.LdifEntry;
import org.apache.directory.api.ldap.model.ldif.LdifReader;
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.DefaultDirectoryServiceFactory;
import org.apache.directory.server.core.factory.DirectoryServiceFactory;
import org.apache.directory.server.core.factory.PartitionFactory;
import org.apache.directory.server.core.kerberos.KeyDerivationInterceptor;
import org.apache.directory.server.kerberos.KerberosConfig;
import org.apache.directory.server.kerberos.kdc.KdcServer;
import org.apache.directory.server.protocol.shared.transport.Transport;
import org.apache.directory.server.protocol.shared.transport.UdpTransport;
import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
import org.junit.rules.ExternalResource;
/**
* Runs an Apache DS Kerberos server.
*/
public final class KerberosServer extends ExternalResource {
private static final Log log = LogFactory.getLog(KerberosServer.class);
/**
* The used DirectoryService instance
*/
private DirectoryService directoryService;
/**
* The used KdcServer instance
*/
private KdcServer kdcServer;
private Provider provider;
private int providerPos = 2;
private File workDir;
@Override
protected void before() throws Throwable {
int kdcPort = PortAllocator.allocatePort();
DatagramSocket datagramSocket = new DatagramSocket(kdcPort);
datagramSocket.setReuseAddress(true);
datagramSocket.close();
//Ok, apache ds doesn't like the bouncy castle provider at position 2
//Caused by: KrbException: Integrity check on decrypted field failed (31) - Integrity check on decrypted field failed
Provider[] installedProviders = Security.getProviders();
for (int i = 0; i < installedProviders.length; i++) {
Provider installedProvider = installedProviders[i];
if ("BC".equals(installedProvider.getName())) {
provider = installedProvider;
providerPos = i;
Security.removeProvider("BC");
break;
}
}
if (provider != null) {
Security.addProvider(provider);
}
workDir = Files.createTempDirectory("server-work").toFile();
DirectoryServiceFactory directoryServiceFactory = new DefaultDirectoryServiceFactory();
directoryService = directoryServiceFactory.getDirectoryService();
directoryService.setAccessControlEnabled(false);
directoryService.setAllowAnonymousAccess(false);
directoryService.getChangeLog().setEnabled(true);
List<Interceptor> interceptors = directoryService.getInterceptors();
interceptors.add(new KeyDerivationInterceptor());
directoryService.setInterceptors(interceptors);
directoryServiceFactory.init("defaultDS");
PartitionFactory partitionFactory = directoryServiceFactory.getPartitionFactory();
Partition partition = partitionFactory.createPartition(directoryService.getSchemaManager(),
directoryService.getDnFactory(), "example", "dc=example,dc=com", 1000, workDir);
partitionFactory.addIndex(partition, "objectClass", 1000);
partitionFactory.addIndex(partition, "dc", 1000);
partitionFactory.addIndex(partition, "ou", 1000);
partition.setSchemaManager(directoryService.getSchemaManager());
// Inject the partition into the DirectoryService
directoryService.addPartition(partition);
InputStream is = KerberosServer.class.getClassLoader().getResourceAsStream("kerberos/users.ldif");
LdifReader ldifReader = new LdifReader(is);
for (LdifEntry entry : ldifReader) {
directoryService.getAdminSession().add(new DefaultEntry(directoryService.getSchemaManager(), entry.getEntry()));
}
ldifReader.close();
KerberosConfig kerberosConfig = new KerberosConfig();
kerberosConfig.setServicePrincipal("krbtgt/EXAMPLE.COM@EXAMPLE.COM");
kerberosConfig.setPrimaryRealm("EXAMPLE.COM");
kerberosConfig.setSearchBaseDn("dc=example,dc=com");
kerberosConfig.setMaximumTicketLifetime(60000 * 1440);
kerberosConfig.setMaximumRenewableLifetime(60000 * 10080);
kerberosConfig.setEncryptionTypes(new EncryptionType[]{EncryptionType.AES128_CTS_HMAC_SHA1_96});
kdcServer = new KdcServer(kerberosConfig);
kdcServer.setServiceName("DefaultKrbServer");
final String kdcHostname = "localhost";
log.info(String.format("Starting service on %s:%s", kdcHostname, kdcPort));
UdpTransport udp = new UdpTransport(kdcHostname, kdcPort);
kdcServer.addTransports(udp);
kdcServer.setDirectoryService(directoryService);
kdcServer.start();
}
/**
* @return The Apache DS Kerberos server port.
* @throws IllegalArgumentException If server or respective transport are not initialized
*/
public int getPort() throws IllegalArgumentException {
if (kdcServer == null) {
throw new IllegalStateException("Kerberos server is not initialized");
}
Transport[] transports = kdcServer.getTransports();
if (transports == null || transports.length == 0) {
throw new IllegalStateException("Kerberos server does not configure any transports");
}
for (Transport transport : transports) {
if (transport instanceof UdpTransport) {
return transport.getPort();
}
}
throw new IllegalStateException(
String.format("Cannot identify Kerberos server port. List of transports does not contain an %s instance",
UdpTransport.class.getName()));
}
@Override
protected void after() {
log.info("Stop called");
try {
if (directoryService != null) {
try {
directoryService.shutdown();
} catch (Exception ex) {
log.error("Failed to stop server", ex);
} finally {
try {
FileUtils.deleteDirectory(workDir);
}
catch (IOException e) {
log.error("Failed to delete Apache DS working directory: " + workDir.getAbsolutePath() , e);
}
}
directoryService = null;
}
}
finally {
if (kdcServer != null) {
kdcServer.stop();
kdcServer = null;
}
if (provider != null) {
//restore BC position
Security.removeProvider("BC");
Security.insertProviderAt(provider, providerPos);
}
}
}
}