/******************************************************************************* * Copyright (c) 2008 Cambridge Semantics Incorporated. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * File: $Source$ * Created by: Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com </a>) * Created on: Nov 16, 2008 * Revision: $Id$ * * Contributors: * Cambridge Semantics Incorporated - initial API and implementation *******************************************************************************/ package org.openanzo.ldap.internal; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.net.URL; import java.security.Security; import java.util.Dictionary; import java.util.Hashtable; import java.util.Properties; import java.util.UUID; import javax.naming.Context; import javax.naming.ldap.InitialLdapContext; import org.apache.directory.server.constants.ServerDNConstants; import org.apache.directory.server.core.DefaultDirectoryService; import org.apache.directory.server.core.DirectoryService; import org.apache.directory.server.core.entry.DefaultServerEntry; import org.apache.directory.server.core.entry.ServerEntry; import org.apache.directory.server.core.interceptor.context.AddOperationContext; import org.apache.directory.server.core.jndi.CoreContextFactory; import org.apache.directory.server.core.partition.Partition; import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition; import org.apache.directory.server.protocol.shared.transport.TcpTransport; import org.apache.directory.server.protocol.shared.transport.Transport; import org.apache.directory.shared.ldap.constants.SchemaConstants; import org.apache.directory.shared.ldap.csn.CsnFactory; import org.apache.directory.shared.ldap.ldif.LdifEntry; import org.apache.directory.shared.ldap.ldif.LdifReader; import org.apache.directory.shared.ldap.name.LdapDN; import org.apache.directory.shared.ldap.schema.SchemaUtils; import org.openanzo.exceptions.AnzoRuntimeException; import org.openanzo.exceptions.ExceptionConstants; import org.openanzo.exceptions.LogUtils; import org.openanzo.rdf.Constants.OSGI; import org.openanzo.security.keystore.KeyStoreDictionary; import org.openanzo.services.LDAPDictionary; import org.openanzo.services.ServicesDictionary; import org.osgi.framework.BundleContext; import org.osgi.service.event.Event; import org.osgi.service.event.EventAdmin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; class LdapServer { private static final Logger log = LoggerFactory.getLogger(LdapServer.class); private static final int DEFAULT_TIMEOUT = 30000; private final DefaultDirectoryService directoryService; private final org.apache.directory.server.ldap.LdapServer ldapService; protected LdapServer(final BundleContext context, final Dictionary<? extends Object, ? extends Object> configProperties, EventAdmin eventAdmin) throws Exception { final ClassLoader currentLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); boolean exists = false; final File ldapDirectory = context.getDataFile("ldap-anzo"); exists = ldapDirectory.exists(); final String purge = context.getProperty("purgeLdap"); if (purge != null && Boolean.parseBoolean(purge)) { if (exists) { deleteFile(ldapDirectory); exists = false; } } boolean reqSSL = false; Boolean requireSSL = ServicesDictionary.getRequireSSL(configProperties); if (requireSSL != null) { reqSSL = requireSSL.booleanValue(); } final String searchBaseDN = LDAPDictionary.getSearchBaseDN(configProperties); String id = LDAPDictionary.getId(configProperties); if (id == null) { id = "OpenAnzo"; } final String suffix = LDAPDictionary.getSuffix(configProperties); final String o = LDAPDictionary.getOrganization(configProperties); final String principal = LDAPDictionary.getLdapServerUser(configProperties); final String credentials = LDAPDictionary.getLdapServerPassword(configProperties); final String initFile = LDAPDictionary.getInitFile(configProperties); directoryService = new DefaultDirectoryService(); directoryService.setShutdownHookEnabled(false); directoryService.setWorkingDirectory(ldapDirectory); ldapService = new org.apache.directory.server.ldap.LdapServer(); Transport transports[] = new Transport[1]; transports[0] = new TcpTransport(LDAPDictionary.getPort(configProperties, null)); if (reqSSL) { transports[0].setEnableSSL(true); } ldapService.setTransports(transports); ldapService.setDirectoryService(directoryService); final int timeout = ServicesDictionary.getTimeout(configProperties, DEFAULT_TIMEOUT); ldapService.setMaxTimeLimit(timeout); ldapService.setSearchBaseDn(searchBaseDN); ldapService.setAllowAnonymousAccess(true); if (reqSSL) { Security.setProperty("keystore.type", KeyStoreDictionary.getKeystoreType(configProperties)); ldapService.setKeystoreFile(KeyStoreDictionary.getKeyFileLocation(configProperties)); ldapService.setCertificatePassword(KeyStoreDictionary.getKeyPassword(configProperties)); } directoryService.setExitVmOnShutdown(true); directoryService.setShutdownHookEnabled(true); directoryService.startup(); final Partition partition = new JdbmPartition(); partition.setId(id); partition.setSuffix(suffix); directoryService.addPartition(partition); final LdapDN suffixDn = new LdapDN(suffix); suffixDn.normalize(directoryService.getRegistries().getAttributeTypeRegistry().getNormalizerMapping()); ServerEntry ctxEntry = directoryService.newEntry(suffixDn); //final ServerEntry ctxEntry = new DefaultServerEntry(directoryService.getRegistries(), suffixDn); ctxEntry.put("objectClass", "top", "organization"); ctxEntry.put("o", o); CsnFactory csnFactory = new CsnFactory(0); ctxEntry.add(SchemaConstants.ENTRY_CSN_AT, csnFactory.newInstance().toString()); ctxEntry.add(SchemaConstants.ENTRY_UUID_AT, SchemaUtils.uuidToBytes(UUID.randomUUID())); partition.add(new AddOperationContext(directoryService.getAdminSession(), ctxEntry)); final Hashtable<String, Object> env = new Hashtable<String, Object>(); env.put(DirectoryService.JNDI_KEY, directoryService); env.put(Context.SECURITY_PRINCIPAL, principal); env.put(Context.SECURITY_CREDENTIALS, credentials); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.INITIAL_CONTEXT_FACTORY, CoreContextFactory.class.getName()); final Hashtable<String, Object> envFinal = new Hashtable<String, Object>(env); envFinal.put(Context.PROVIDER_URL, ServerDNConstants.SYSTEM_DN); new InitialLdapContext(envFinal, null); envFinal.put(Context.PROVIDER_URL, ""); directoryService.getAdminSession(); envFinal.put(Context.PROVIDER_URL, ServerDNConstants.OU_SCHEMA_DN); new InitialLdapContext(envFinal, null); if (!exists) { if (initFile != null) { InputStream is = null; if (initFile.startsWith("bundle://")) { final URL inputURL = context.getBundle().getEntry(initFile); is = inputURL.openStream(); } else { is = new FileInputStream(initFile); } try { for (final LdifEntry ldifEntry : new LdifReader(is)) { directoryService.getAdminSession().add(new DefaultServerEntry(directoryService.getRegistries(), ldifEntry.getEntry())); } } finally { is.close(); } } else { LdapDN usersDn = new LdapDN("ou=users," + suffix); ServerEntry usersEntry = directoryService.newEntry(usersDn); usersEntry.put("objectClass", "top", "organizationalUnit"); usersEntry.put("ou", "users"); directoryService.getAdminSession().add(usersEntry); LdapDN groupsDn = new LdapDN("ou=groups," + suffix); ServerEntry groupsEntry = directoryService.newEntry(groupsDn); groupsEntry.put("objectClass", "top", "organizationalUnit"); groupsEntry.put("ou", "groups"); directoryService.getAdminSession().add(groupsEntry); } } ldapService.start(); Thread.currentThread().setContextClassLoader(currentLoader); Dictionary<Object, Object> props = new Properties(); ServicesDictionary.setEnabled(props, true); eventAdmin.postEvent(new Event(OSGI.LDAP_SERVER_TOPIC, props)); context.registerService(LdapServer.class.getName(), this, null); } protected void stop(boolean bundleStopping) { if (directoryService != null) { try { ldapService.stop(); directoryService.shutdown(); } catch (final Exception ie) { log.error(LogUtils.LIFECYCLE_MARKER, "Error stopping the ApacheDS embedded server", ie); throw new AnzoRuntimeException(ExceptionConstants.COMBUS.STOP_BROKER_FAILED, ie); } } } private void deleteFile(final File file) { if (file.isDirectory()) { for (final File subFile : file.listFiles()) { deleteFile(subFile); } } file.delete(); } }