/* * Copyright (c) 2014 Denis Mikhalkin. * * This software is provided 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 com.denismo.apacheds; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.*; import com.denismo.apacheds.auth.AWSIAMAuthenticator; import org.apache.directory.api.ldap.model.constants.SchemaConstants; import org.apache.directory.api.ldap.model.cursor.Cursor; import org.apache.directory.api.ldap.model.cursor.CursorException; 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.exception.LdapException; import org.apache.directory.api.ldap.model.name.Dn; import org.apache.directory.api.ldap.model.name.Rdn; import org.apache.directory.api.ldap.model.schema.SchemaManager; import org.apache.directory.api.ldap.model.schema.registries.SchemaLoader; import org.apache.directory.api.ldap.schemaextractor.SchemaLdifExtractor; import org.apache.directory.api.ldap.schemaextractor.impl.DefaultSchemaLdifExtractor; import org.apache.directory.api.ldap.schemaloader.LdifSchemaLoader; import org.apache.directory.api.ldap.schemamanager.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.interceptor.context.AddOperationContext; import org.apache.directory.server.core.api.partition.Partition; import org.apache.directory.server.core.api.schema.SchemaPartition; import org.apache.directory.server.core.partition.impl.btree.AbstractBTreePartition; import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition; import org.apache.directory.server.core.partition.ldif.LdifPartition; import org.apache.directory.server.core.partition.ldif.SingleFileLdifPartition; import org.apache.directory.server.i18n.I18n; import org.apache.directory.server.ldap.LdapServer; import org.apache.directory.server.protocol.shared.store.LdifFileLoader; import org.apache.directory.server.protocol.shared.transport.TcpTransport; import org.apache.directory.server.xdbm.Index; import org.apache.directory.server.xdbm.IndexEntry; import org.apache.directory.server.xdbm.ParentIdAndRdn; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * User: Denis Mikhalkin * Date: 10/03/14 * Time: 6:02 PM */ public class Runner { private static final Logger IAM_LOG = LoggerFactory.getLogger(Runner.class); private static int serverPort = 10389; private ApacheDSUtils utils; /** The directory service */ private DirectoryService service; // private ApacheDsService service; /** The LDAP server */ private LdapServer server; public Runner(DirectoryService service) { this.service = service; utils = new ApacheDSUtils(service); } public Runner() {} /** * initialize the schema manager and add the schema partition to diectory service * * @throws Exception if the schema LDIF files are not found on the classpath */ private void initSchemaPartition() throws Exception { InstanceLayout instanceLayout = service.getInstanceLayout(); File schemaPartitionDirectory = new File( instanceLayout.getPartitionsDirectory(), "schema" ); // Extract the schema on disk (a brand new one) and load the registries if ( schemaPartitionDirectory.exists() ) { System.out.println( "schema partition already exists, skipping schema extraction" ); } else { SchemaLdifExtractor extractor = new DefaultSchemaLdifExtractor( instanceLayout.getPartitionsDirectory() ); extractor.extractOrCopy(); } SchemaLoader loader = new LdifSchemaLoader( schemaPartitionDirectory ); 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(); List<Throwable> errors = schemaManager.getErrors(); if ( errors.size() != 0 ) { throw new Exception( I18n.err( I18n.ERR_317, Exceptions.printErrors( errors ) ) ); } service.setSchemaManager( schemaManager ); // Init the LdifPartition with schema LdifPartition schemaLdifPartition = new LdifPartition( schemaManager, service.getDnFactory() ); schemaLdifPartition.setPartitionPath( schemaPartitionDirectory.toURI() ); // The schema partition SchemaPartition schemaPartition = new SchemaPartition( schemaManager ); schemaPartition.setWrappedPartition( schemaLdifPartition ); service.setSchemaPartition( schemaPartition ); } /** * Initialize the server. It creates the partition, adds the index, and * injects the context entries for the created partitions. * * @param workDir the directory to be used for storing the data * @throws Exception if there were some problems while initializing the system */ private void initDirectoryService( File workDir ) throws Exception { // Initialize the LDAP service service = new DefaultDirectoryService(); utils = new ApacheDSUtils(service); // service = new ApacheDsService(); // service.start(new InstanceLayout( workDir )); service.setInstanceLayout( new InstanceLayout( workDir ) ); CacheService cacheService = new CacheService(); cacheService.initialize( service.getInstanceLayout() ); service.setCacheService( cacheService ); // first load the schema initSchemaPartition(); // then the system partition // this is a MANDATORY partition // DO NOT add this via addPartition() method, trunk code complains about duplicate partition // while initializing JdbmPartition systemPartition = new JdbmPartition(service.getSchemaManager(), service.getDnFactory()); systemPartition.setId( "system" ); systemPartition.setPartitionPath( new File( service.getInstanceLayout().getPartitionsDirectory(), systemPartition.getId() ).toURI() ); systemPartition.setSuffixDn( new Dn( ServerDNConstants.SYSTEM_DN ) ); systemPartition.setSchemaManager( service.getSchemaManager() ); // mandatory to call this method to set the system partition // Note: this system partition might be removed from trunk service.setSystemPartition( systemPartition ); service.getChangeLog().setEnabled(false); service.setDenormalizeOpAttrsEnabled(true); SingleFileLdifPartition configPartition = new SingleFileLdifPartition(service.getSchemaManager(), service.getDnFactory()); configPartition.setId("config"); configPartition.setPartitionPath(new File(service.getInstanceLayout().getConfDirectory(), "config.ldif").toURI()); configPartition.setSuffixDn(new Dn(service.getSchemaManager(), "ou=config")); configPartition.setSchemaManager(service.getSchemaManager()); configPartition.setCacheService(cacheService); configPartition.initialize(); service.addPartition(configPartition); readIAMProperties(); String rootDN = AWSIAMAuthenticator.getConfig().rootDN; Partition iamPartition = utils.addPartition("iam", rootDN, service.getDnFactory()); // Index some attributes on the apache partition utils.addIndex(iamPartition, "objectClass", "ou", "uid", "gidNumber", "uidNumber", "cn"); // And start the service service.startup(); utils.loadLdif("iam.ldif"); utils.loadLdif("enable_nis.ldif"); utils.loadLdif("auth.ldif"); if (!utils.exists("cn=config,ads-authenticatorid=awsiamauthenticator,ou=authenticators,ads-interceptorId=authenticationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config")) { Entry entryIAM = service.newEntry( service.getDnFactory().create("cn=config,ads-authenticatorid=awsiamauthenticator,ou=authenticators,ads-interceptorId=authenticationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config") ); entryIAM.put("objectClass", "iamauthenticatorconfig", "top"); entryIAM.put(SchemaConstants.ENTRY_CSN_AT, service.getCSN().toString()); entryIAM.put(SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString()); entryIAM.put("cn", "config"); entryIAM.put("idGenerator", "1000"); service.getAdminSession().add(entryIAM); } Dn dnIAM = service.getDnFactory().create(rootDN); if (!service.getAdminSession().exists(dnIAM)) { Entry entryIAM = new DefaultEntry(service.getSchemaManager(), dnIAM, "objectClass: top", "objectClass: domain", "dc: iam", "entryCsn: " + service.getCSN(), SchemaConstants.ENTRY_UUID_AT + ": " + UUID.randomUUID().toString()); iamPartition.add(new AddOperationContext(null, entryIAM)); } } public void createStructure() throws Exception { String rootDN = AWSIAMAuthenticator.getConfig().rootDN; Dn dnIAM = service.getDnFactory().create(rootDN); if (!utils.exists(dnIAM)) { IAM_LOG.info("Creating partition " + rootDN); Partition iamPartition = utils.addPartition("iam", rootDN, service.getDnFactory()); // Index some attributes on the apache partition utils.addIndex(iamPartition, "objectClass", "ou", "uid", "gidNumber", "uidNumber", "cn"); if (!utils.exists(dnIAM)) { IAM_LOG.info("Creating root node " + rootDN); Rdn rdn = dnIAM.getRdn(0); Entry entryIAM = new DefaultEntry(service.getSchemaManager(), dnIAM, "objectClass: top", "objectClass: domain", "entryCsn: " + service.getCSN(), SchemaConstants.ENTRY_UUID_AT + ": " + UUID.randomUUID().toString(), rdn.getType() + ": " + rdn.getValue()); service.getAdminSession().add(entryIAM); checkErrors(); } } service.sync(); } public void checkErrors() { if (!service.getSchemaManager().getErrors().isEmpty()) { throw new RuntimeException("Errors: " + service.getSchemaManager().getErrors()); } } private void readIAMProperties() { String propsPath = System.getProperty("iamLdapPropertiesPath", "/etc/iam_ldap.conf"); File propsFile = new File(propsPath); // Read the config file if exists if (propsFile.exists()) { try { Properties props = new Properties(); props.load(new FileInputStream(propsFile)); AWSIAMAuthenticator.Config config = new AWSIAMAuthenticator.Config(); if (props.containsKey("pollPeriod")) config.pollPeriod = Integer.parseInt(props.getProperty("pollPeriod")); if (props.containsKey("rootDN")) config.rootDN = props.getProperty("rootDN"); AWSIAMAuthenticator.setConfig(config); } catch (IOException e) { IAM_LOG.error("Unable to read IAM LDAP config file"); AWSIAMAuthenticator.setConfig(new AWSIAMAuthenticator.Config()); } } else { // Populate from defaults AWSIAMAuthenticator.setConfig(new AWSIAMAuthenticator.Config()); } } /** * starts the LdapServer * * @throws Exception */ public void startServer() throws Exception { server = new LdapServer(); server.setTransports( new TcpTransport( serverPort ) ); server.setDirectoryService( service ); server.start(); } public static void main(String[] args) throws Exception { System.setProperty("default.controls", "org.apache.directory.api.ldap.codec.controls.cascade.CascadeFactory,org.apache.directory.api.ldap.codec.controls.manageDsaIT.ManageDsaITFactory,org.apache.directory.api.ldap.codec.controls.search.entryChange.EntryChangeFactory,org.apache.directory.api.ldap.codec.controls.search.pagedSearch.PagedResultsFactory,org.apache.directory.api.ldap.codec.controls.search.persistentSearch.PersistentSearchFactory,org.apache.directory.api.ldap.codec.controls.search.subentries.SubentriesFactory"); System.setProperty("extra.controls", "org.apache.directory.api.ldap.extras.controls.ppolicy_impl.PasswordPolicyFactory,org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncDoneValueFactory,org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncInfoValueFactory,org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncRequestValueFactory,org.apache.directory.api.ldap.extras.controls.syncrepl_impl.SyncStateValueFactory"); System.setProperty("default.extendedOperation.requests", "org.apache.directory.api.ldap.extras.extended.ads_impl.cancel.CancelFactory,org.apache.directory.api.ldap.extras.extended.ads_impl.certGeneration.CertGenerationFactory,org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulShutdown.GracefulShutdownFactory,org.apache.directory.api.ldap.extras.extended.ads_impl.storedProcedure.StoredProcedureFactory"); System.setProperty("default.extendedOperation.responses", "org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect.GracefulDisconnectFactory"); Runner runner = new Runner(); runner.initDirectoryService(getDirectoryPath(args)); runner.startServer(); System.out.println("Server started on " + serverPort); } private static File getDirectoryPath(String[] args) { if (args.length > 0) return new File(args[0]); if (!new File("/var").exists()) { return new File(System.getProperty("java.io.tmpdir"), "iam_ldap"); } else { return new File("/var", "iam_ldap"); } } public Partition getPartition(DirectoryService directory, String id) throws LdapException { Set<? extends Partition> partitions = directory.getPartitions(); for (Partition part : partitions) { if (part.getId().equalsIgnoreCase(id)) return part; } throw new LdapException("No partition with the ID " + id); } }