/**
* Copyright (C) 2010-2017 Structr GmbH
*
* This file is part of Structr <http://structr.org>.
*
* Structr is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Structr is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Structr. If not, see <http://www.gnu.org/licenses/>.
*/
package org.structr.ldap;
import java.io.File;
import java.net.URL;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import org.apache.commons.lang.StringUtils;
import org.apache.directory.server.core.CoreSession;
import org.apache.directory.server.core.DefaultDirectoryService;
import org.apache.directory.server.core.DirectoryService;
import org.apache.directory.server.core.InstanceLayout;
import org.apache.directory.server.core.interceptor.context.AddOperationContext;
import org.apache.directory.server.core.interceptor.context.EntryOperationContext;
import org.apache.directory.server.core.partition.Partition;
import org.apache.directory.server.core.schema.SchemaPartition;
import org.apache.directory.server.ldap.LdapServer;
import org.apache.directory.server.protocol.shared.transport.TcpTransport;
import org.apache.directory.shared.ldap.model.entry.DefaultEntry;
import org.apache.directory.shared.ldap.model.entry.Entry;
import org.apache.directory.shared.ldap.model.exception.LdapException;
import org.apache.directory.shared.ldap.model.ldif.LdifEntry;
import org.apache.directory.shared.ldap.model.ldif.LdifReader;
import org.apache.directory.shared.ldap.model.name.Dn;
import org.apache.directory.shared.ldap.model.schema.SchemaManager;
import org.apache.directory.shared.ldap.schemaloader.SchemaEntityFactory;
import org.apache.directory.shared.ldap.schemamanager.impl.DefaultSchemaManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.structr.api.service.Command;
import org.structr.api.service.SingletonService;
import org.structr.api.service.StructrServices;
public class LDAPServerService implements SingletonService {
public static final String LDAP_PARTITION_ROOT_TYPE_PREFIX = "ldap.partition.";
public static final String LDAP_PARTITION_ROOT_TYPE_SUFFIX = ".rootType";
private static final Logger logger = LoggerFactory.getLogger(LDAPServerService.class.getName());
private DirectoryService ds = null;
private LdapServer server = null;
@Override
public boolean isRunning() {
return server.isStarted();
}
@Override
public void injectArguments(Command command) {
}
@Override
public void initialize(final StructrServices services) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
logger.info("Initializing directory service");
try {
ds = new DefaultDirectoryService();
final SchemaManager schemaManager = new DefaultSchemaManager();
final SchemaPartition schemaPartition = new SchemaPartition(schemaManager);
final StructrPartition structrSchemaPartition = new StructrPartition(schemaManager, "schema", new Dn("ou=system"));
schemaPartition.setWrappedPartition(structrSchemaPartition);
ds.setInstanceLayout(new InstanceLayout(new File("/tmp/ldap-test")));
ds.setSchemaPartition(schemaPartition);
ds.setSchemaManager(schemaManager);
ds.setSystemPartition(new StructrPartition(schemaManager, "system", new Dn("ou=system")));
ds.startup();
logger.info("Importing schema..");
initSchema(schemaManager, ds.getAdminSession(), structrSchemaPartition);
server = new LdapServer();
int serverPort = 10389;
server.setTransports(new TcpTransport(serverPort));
server.setDirectoryService(ds);
server.start();
} catch (Throwable t) {
logger.warn("", t);
}
}
@Override
public void shutdown() {
server.stop();
}
@Override
public void initialized() {
try {
// TEST
final DirectoryService service = server.getDirectoryService();
final SchemaManager schemaManager = service.getSchemaManager();
final Dn structrDn = new Dn(schemaManager, "dc=org");
final Partition apachePartition = new StructrPartition(schemaManager, "structr", structrDn);
apachePartition.initialize();
service.addPartition(apachePartition);
try {
service.getAdminSession().lookup(structrDn);
} catch (LdapException lnnfe) {
Entry structrEntry = service.newEntry(structrDn);
structrEntry.add("objectClass", "top", "domain", "extensibleObject");
structrEntry.add("dc", "structr");
service.getAdminSession().add(structrEntry);
}
try {
System.out.println("######: " + service.getAdminSession().lookup(structrDn));
System.out.flush();
} catch (LdapException lnnfe) {
logger.warn("", lnnfe);
}
} catch (Throwable t) {
logger.warn("", t);
}
}
@Override
public String getName() {
return "LDAP Server";
}
@Override
public boolean isVital() {
return false;
}
// ----- private methods -----
private void initSchema(final SchemaManager schemaManager, final CoreSession adminSession, final StructrPartition partition) throws Exception {
final URL url = SchemaEntityFactory.class.getProtectionDomain().getCodeSource().getLocation();
final JarFile jarFile = new JarFile(new File(url.toURI()));
final List<String> names = new LinkedList<>();
for (final Enumeration<JarEntry> e = jarFile.entries(); e.hasMoreElements();) {
final ZipEntry zipEntry = e.nextElement();
final String name = zipEntry.getName();
if (name.startsWith("schema/") && name.endsWith(".ldif")) {
names.add(name);
}
}
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// first sort key: number of slashes (level)
Integer s1 = StringUtils.countMatches(o1, "/");
Integer s2 = StringUtils.countMatches(o2, "/");
if (s1.equals(s2)) {
// secondary sort key: string length
Integer l1 = o1.length();
Integer l2 = o2.length();
if (l1.equals(l2)) {
// tertiary sort key: the string values
return o1.compareTo(o2);
}
return l1.compareTo(l2);
}
return s1.compareTo(s2);
}
});
for (final String name : names) {
try (final LdifReader reader = new LdifReader(jarFile.getInputStream(jarFile.getEntry(name)))) {
for (final LdifEntry entry : reader) {
final Entry schemaEntry = new DefaultEntry(schemaManager, entry.getEntry());
final Dn dn = schemaEntry.getDn();
if (!partition.hasEntry(new EntryOperationContext(adminSession, dn))) {
logger.info("Importing {}...", name);
partition.add(new AddOperationContext(adminSession, schemaEntry));
}
}
}
}
}
}