diff --git a/spring-ldap-tiger/.classpath b/spring-ldap-tiger/.classpath new file mode 100644 index 00000000..b4efd0bf --- /dev/null +++ b/spring-ldap-tiger/.classpath @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-ldap-tiger/.project b/spring-ldap-tiger/.project new file mode 100644 index 00000000..43534cf2 --- /dev/null +++ b/spring-ldap-tiger/.project @@ -0,0 +1,17 @@ + + + spring-ldap-tiger + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/spring-ldap-tiger/build.xml b/spring-ldap-tiger/build.xml new file mode 100644 index 00000000..d339e115 --- /dev/null +++ b/spring-ldap-tiger/build.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Unit test report has been generated. +The HTML report is ${target.testresults.html.dir}/index.html + + + + + diff --git a/spring-ldap-tiger/ivy.xml b/spring-ldap-tiger/ivy.xml new file mode 100644 index 00000000..c68c6f26 --- /dev/null +++ b/spring-ldap-tiger/ivy.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-ldap-tiger/project.properties b/spring-ldap-tiger/project.properties new file mode 100644 index 00000000..b2aa8f52 --- /dev/null +++ b/spring-ldap-tiger/project.properties @@ -0,0 +1,14 @@ +# properties defined in this file are overridable by a local build.properties in this project dir + +# The location of the common build system +common.build.dir=${basedir}/../common-build + +project.base.version=1.2-RC2 +#project.version=${project.base.version} +#ivy.status=release + +javac.source=1.5 +javac.target=1.5 + +# extend common-build with source capability +main.build.configs=global,buildtime,test,source diff --git a/spring-ldap-tiger/src/itest/java/conf/apacheDsContext.xml b/spring-ldap-tiger/src/itest/java/conf/apacheDsContext.xml new file mode 100644 index 00000000..52694704 --- /dev/null +++ b/spring-ldap-tiger/src/itest/java/conf/apacheDsContext.xml @@ -0,0 +1,84 @@ + + + + + + + + + + simple + + + ${userDn} + + + ${password} + + + + + + + + + + + + + + + + + + + + + objectClass: top + objectClass: domain + objectClass: extensibleObject + dc: jayway + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-ldap-tiger/src/itest/java/conf/ldap.properties b/spring-ldap-tiger/src/itest/java/conf/ldap.properties new file mode 100644 index 00000000..8843f1f1 --- /dev/null +++ b/spring-ldap-tiger/src/itest/java/conf/ldap.properties @@ -0,0 +1,4 @@ +urls=ldap://127.0.0.1:3900 +userDn=uid=admin,ou=system +password=secret +base=dc=jayway,dc=se diff --git a/spring-ldap-tiger/src/itest/java/conf/ldapTemplateTestContext.xml b/spring-ldap-tiger/src/itest/java/conf/ldapTemplateTestContext.xml new file mode 100644 index 00000000..78027383 --- /dev/null +++ b/spring-ldap-tiger/src/itest/java/conf/ldapTemplateTestContext.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-ldap-tiger/src/itest/java/log4j.properties b/spring-ldap-tiger/src/itest/java/log4j.properties new file mode 100644 index 00000000..f57302e8 --- /dev/null +++ b/spring-ldap-tiger/src/itest/java/log4j.properties @@ -0,0 +1,9 @@ +log4j.rootCategory=WARN, stdout + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n + +#Enable debug logging +log4j.category.net.sf.ldaptemplate=INFO +log4j.category.net.sf.ldaptemplate.LdapTemplate=DEBUG diff --git a/spring-ldap-tiger/src/itest/java/org/springframework/ldap/AbstractLdapTemplateIntegrationTest.java b/spring-ldap-tiger/src/itest/java/org/springframework/ldap/AbstractLdapTemplateIntegrationTest.java new file mode 100644 index 00000000..cc18bb95 --- /dev/null +++ b/spring-ldap-tiger/src/itest/java/org/springframework/ldap/AbstractLdapTemplateIntegrationTest.java @@ -0,0 +1,33 @@ +/* + * Copyright 2005-2007 the original author or authors. + * + * 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.springframework.ldap; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +public abstract class AbstractLdapTemplateIntegrationTest extends AbstractDependencyInjectionSpringContextTests { + + private LdapServerManager ldapServerManager; + + protected void onSetUp() throws Exception { + super.onSetUp(); + + ldapServerManager.cleanAndSetup("setup_data.ldif"); + } + + public void setLdapServerManager(LdapServerManager ldapServerManager) { + this.ldapServerManager = ldapServerManager; + } +} diff --git a/spring-ldap-tiger/src/itest/java/org/springframework/ldap/ConfigEnvHelper.java b/spring-ldap-tiger/src/itest/java/org/springframework/ldap/ConfigEnvHelper.java new file mode 100644 index 00000000..9db90b99 --- /dev/null +++ b/spring-ldap-tiger/src/itest/java/org/springframework/ldap/ConfigEnvHelper.java @@ -0,0 +1,58 @@ +/* + * Copyright 2005-2007 the original author or authors. + * + * 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.springframework.ldap; + +import java.io.File; +import java.util.Hashtable; + +import javax.naming.Context; + +import org.apache.directory.server.configuration.MutableServerStartupConfiguration; +import org.apache.directory.server.jndi.ServerContextFactory; +import org.springframework.beans.factory.InitializingBean; + +/** + * Helper class to simplify Spring configuration of ApacheDS. + * + * @author Mattias Arthursson + */ +public class ConfigEnvHelper implements InitializingBean { + private final MutableServerStartupConfiguration configuration; + + private final Hashtable initialEnv; + + private final File workingDir = new File(System + .getProperty("java.io.tmpdir") + + File.separator + "ldaptemplate_apacheds"); + + public ConfigEnvHelper(Hashtable initialEnv, + MutableServerStartupConfiguration configuration) { + + this.initialEnv = initialEnv; + this.configuration = configuration; + } + + public Hashtable getEnv() { + return initialEnv; + } + + public void afterPropertiesSet() throws Exception { + initialEnv.put(Context.INITIAL_CONTEXT_FACTORY, ServerContextFactory.class.getName()); + configuration.setWorkingDirectory(workingDir); + initialEnv.putAll(configuration.toJndiEnvironment()); + } +} diff --git a/spring-ldap-tiger/src/itest/java/org/springframework/ldap/LdapServerManager.java b/spring-ldap-tiger/src/itest/java/org/springframework/ldap/LdapServerManager.java new file mode 100644 index 00000000..937e14fe --- /dev/null +++ b/spring-ldap-tiger/src/itest/java/org/springframework/ldap/LdapServerManager.java @@ -0,0 +1,126 @@ +/* + * Copyright 2005-2007 the original author or authors. + * + * 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.springframework.ldap; + +import java.util.Properties; + +import javax.naming.Binding; +import javax.naming.Context; +import javax.naming.ContextNotEmptyException; +import javax.naming.InitialContext; +import javax.naming.Name; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.directory.server.core.configuration.ShutdownConfiguration; +import org.apache.directory.server.jndi.ServerContextFactory; +import org.apache.directory.server.protocol.shared.store.LdifFileLoader; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.DistinguishedName; +import org.springframework.ldap.core.support.DefaultDirObjectFactory; + +/** + * Utility class to initialize the apache directory server for use in the + * integration tests. + * + * @author Mattias Arthursson + * + */ +public class LdapServerManager implements DisposableBean { + private static Log log = LogFactory.getLog(LdapServerManager.class); + + private ContextSource contextSource; + + public void setContextSource(ContextSource contextSource) { + this.contextSource = contextSource; + } + + public void destroy() throws Exception { + Properties env = new Properties(); + env.setProperty(Context.INITIAL_CONTEXT_FACTORY, + ServerContextFactory.class.getName()); + env.setProperty(Context.SECURITY_AUTHENTICATION, "simple"); + env.setProperty(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system"); + env.setProperty(Context.SECURITY_CREDENTIALS, "secret"); + + ShutdownConfiguration configuration = new ShutdownConfiguration(); + env.putAll(configuration.toJndiEnvironment()); + + new InitialContext(env); + } + + public void cleanAndSetup(String ldifFile) throws Exception { + DirContext ctx = contextSource.getReadWriteContext(); + + // First of all, make sure the database is empty. + Name startingPoint = null; + + // Different test cases have different base paths. This means that the + // starting point will be different. + if (ctx.getEnvironment().get( + DefaultDirObjectFactory.JNDI_ENV_BASE_PATH_KEY) != null) { + startingPoint = DistinguishedName.EMPTY_PATH; + } else { + startingPoint = new DistinguishedName("dc=jayway,dc=se"); + } + + try { + log.info("Cleaning all present data."); + clearSubContexts(ctx, startingPoint); + // Load the ldif to the recently started server + log.info("Loading setup data"); + LdifFileLoader loader = new LdifFileLoader(ctx, ldifFile); + loader.execute(); + } finally { + ctx.close(); + } + } + + private void clearSubContexts(DirContext ctx, Name name) + throws NamingException { + + NamingEnumeration enumeration = null; + try { + enumeration = ctx.listBindings(name); + while (enumeration.hasMore()) { + Binding element = (Binding) enumeration.next(); + DistinguishedName childName = new DistinguishedName(element + .getName()); + childName.prepend((DistinguishedName) name); + + try { + ctx.destroySubcontext(childName); + } catch (ContextNotEmptyException e) { + clearSubContexts(ctx, childName); + ctx.destroySubcontext(childName); + } + } + } catch (NamingException e) { + e.printStackTrace(); + } finally { + try { + enumeration.close(); + } catch (Exception e) { + // Never mind this + } + } + } +} diff --git a/spring-ldap-tiger/src/itest/java/org/springframework/ldap/core/simple/SimpleLdapTemplateTest.java b/spring-ldap-tiger/src/itest/java/org/springframework/ldap/core/simple/SimpleLdapTemplateTest.java new file mode 100644 index 00000000..08ac5562 --- /dev/null +++ b/spring-ldap-tiger/src/itest/java/org/springframework/ldap/core/simple/SimpleLdapTemplateTest.java @@ -0,0 +1,41 @@ +package org.springframework.ldap.core.simple; + +import java.util.List; + +import org.springframework.ldap.AbstractLdapTemplateIntegrationTest; +import org.springframework.ldap.core.DirContextAdapter; + +public class SimpleLdapTemplateTest extends AbstractLdapTemplateIntegrationTest { + + private SimpleLdapTemplate ldapTemplate; + + protected String[] getConfigLocations() { + return new String[] { "/conf/ldapTemplateTestContext.xml" }; + } + + public void setSimplLdapTemplate(SimpleLdapTemplate ldapTemplate) { + this.ldapTemplate = ldapTemplate; + } + + public void testLookup() { + String result = ldapTemplate.lookup("cn=Some Person,ou=company1,c=Sweden", new CnContextMapper()); + assertEquals("Some Person", result); + } + + public void testSearch1() { + List cns = ldapTemplate.search("", "(&(objectclass=person)(sn=Person3))", new CnContextMapper()); + + assertEquals(1, cns.size()); + assertEquals("Some Person3", cns.get(0)); + } + + private static class CnContextMapper implements ParametrizedContextMapper { + + public String mapFromContext(Object ctx) { + DirContextAdapter adapter = (DirContextAdapter) ctx; + + return adapter.getStringAttribute("cn"); + } + } + +} diff --git a/spring-ldap-tiger/src/itest/java/setup_data.ldif b/spring-ldap-tiger/src/itest/java/setup_data.ldif new file mode 100644 index 00000000..885a8ca4 --- /dev/null +++ b/spring-ldap-tiger/src/itest/java/setup_data.ldif @@ -0,0 +1,110 @@ +dn: ou=groups,dc=jayway,dc=se +objectclass: top +objectclass: organizationalUnit +ou: groups + +dn: cn=ROLE_USER,ou=groups,dc=jayway,dc=se +objectclass: top +objectclass: groupOfUniqueNames +cn: ROLE_USER +uniqueMember: cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se +uniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=jayway,dc=se +uniqueMember: cn=Some Person,ou=company1,c=Norway,dc=jayway,dc=se +uniqueMember: cn=Some Person,ou=company2,c=Sweden,dc=jayway,dc=se +uniqueMember: cn=Some Person3,ou=company1,c=Sweden,dc=jayway,dc=se + +dn: cn=ROLE_ADMIN,ou=groups,dc=jayway,dc=se +objectclass: top +objectclass: groupOfUniqueNames +cn: ROLE_ADMIN +uniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=jayway,dc=se + +dn: c=Sweden,dc=jayway,dc=se +objectclass: top +objectclass: country +c: Sweden +description: The country of Sweden + +dn: c=Norway,dc=jayway,dc=se +objectclass: top +objectclass: country +c: Norway +description: The country of Norway + +dn: ou=company1,c=Sweden,dc=jayway,dc=se +objectclass: top +objectclass: organizationalUnit +ou: company1 +description: First company in Sweden + +dn: ou=company2,c=Sweden,dc=jayway,dc=se +objectclass: top +objectclass: organizationalUnit +ou: company2 +description: Second company in Sweden + +dn: ou=company1,c=Norway,dc=jayway,dc=se +objectclass: top +objectclass: organizationalUnit +ou: company1 +description: First company in Norway + +dn: cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: some.person +userPassword: password +cn: Some Person +sn: Person +description: Sweden, Company1, Some Person +telephoneNumber: +46 555-123456 + +dn: cn=Some Person2,ou=company1,c=Sweden,dc=jayway,dc=se +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: some.person2 +userPassword: password +cn: Some Person2 +sn: Person2 +description: Sweden, Company1, Some Person2 +telephoneNumber: +46 555-654321 + +dn: cn=Some Person3,ou=company1,c=Sweden,dc=jayway,dc=se +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: some.person3 +userPassword: password +cn: Some Person3 +sn: Person3 +description: Sweden, Company1, Some Person3 +telephoneNumber: +46 555-123654 + +dn: cn=Some Person,ou=company2,c=Sweden,dc=jayway,dc=se +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: some.person4 +userPassword: password +cn: Some Person +sn: Person +description: Sweden, Company2, Some Person +telephoneNumber: +46 555-456321 + +dn: cn=Some Person+sn=Person,ou=company1,c=Norway,dc=jayway,dc=se +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +uid: some.norwegian +userPassword: password +cn: Some Person +sn: Person +description: Norway, Company1, Some Person+Person +telephoneNumber: +45 555-654123 diff --git a/spring-ldap-tiger/src/main/java/org/springframework/ldap/core/simple/ParametrizedContextMapper.java b/spring-ldap-tiger/src/main/java/org/springframework/ldap/core/simple/ParametrizedContextMapper.java new file mode 100644 index 00000000..d89b8636 --- /dev/null +++ b/spring-ldap-tiger/src/main/java/org/springframework/ldap/core/simple/ParametrizedContextMapper.java @@ -0,0 +1,26 @@ +package org.springframework.ldap.core.simple; + +import javax.naming.Binding; +import javax.naming.directory.SearchResult; + +import org.springframework.ldap.core.ContextMapper; + +/** + * Extension of the {@link ContextMapper} interface. Uses Java 5 covariant + * return types to override the return type of the + * {@link #mapFromContext(Object)} method to be the type parameter T. + * + * @param + */ +public interface ParametrizedContextMapper extends ContextMapper { + + /** + * Map a single LDAP Context to an object. The supplied Object + * ctx is the object from a single {@link SearchResult}, + * {@link Binding}, or a lookup operation. + * + * @param ctx the context to map to an object. + * @return an object built from the data in the context. + */ + public T mapFromContext(Object ctx); +} diff --git a/spring-ldap-tiger/src/main/java/org/springframework/ldap/core/simple/SimpleLdapOperations.java b/spring-ldap-tiger/src/main/java/org/springframework/ldap/core/simple/SimpleLdapOperations.java new file mode 100644 index 00000000..0993cc0e --- /dev/null +++ b/spring-ldap-tiger/src/main/java/org/springframework/ldap/core/simple/SimpleLdapOperations.java @@ -0,0 +1,20 @@ +package org.springframework.ldap.core.simple; + +import java.util.List; + +import javax.naming.directory.SearchControls; + +import org.springframework.ldap.core.DirContextProcessor; +import org.springframework.ldap.core.LdapOperations; + +public interface SimpleLdapOperations { + + LdapOperations getLdapOperations(); + + List search(String base, String filter, ParametrizedContextMapper mapper); + + List search(String base, String filter, SearchControls controls, ParametrizedContextMapper mapper, + DirContextProcessor processor); + + T lookup(String dn, ParametrizedContextMapper mapper); +} diff --git a/spring-ldap-tiger/src/main/java/org/springframework/ldap/core/simple/SimpleLdapTemplate.java b/spring-ldap-tiger/src/main/java/org/springframework/ldap/core/simple/SimpleLdapTemplate.java new file mode 100644 index 00000000..c421dfe3 --- /dev/null +++ b/spring-ldap-tiger/src/main/java/org/springframework/ldap/core/simple/SimpleLdapTemplate.java @@ -0,0 +1,66 @@ +package org.springframework.ldap.core.simple; + +import java.util.List; + +import javax.naming.directory.SearchControls; + +import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.DirContextProcessor; +import org.springframework.ldap.core.LdapOperations; +import org.springframework.ldap.core.LdapTemplate; + +public class SimpleLdapTemplate implements SimpleLdapOperations { + + private LdapOperations ldapOperations; + + public SimpleLdapTemplate(LdapOperations ldapOperations) { + this.ldapOperations = ldapOperations; + } + + public SimpleLdapTemplate(ContextSource contextSource) { + this.ldapOperations = new LdapTemplate(contextSource); + } + + /* + * (non-Javadoc) + * @see org.springframework.ldap.core.simple.SimpleLdapOperations#getLdapOperations() + */ + public LdapOperations getLdapOperations() { + return ldapOperations; + } + + /* + * (non-Javadoc) + * @see org.springframework.ldap.core.simple.SimpleLdapOperations#lookup(java.lang.String, + * org.springframework.ldap.core.simple.ParametrizedContextMapper) + */ + @SuppressWarnings("unchecked") + public T lookup(String dn, ParametrizedContextMapper mapper) { + return (T) ldapOperations.lookup(dn, mapper); + } + + /* + * (non-Javadoc) + * @see org.springframework.ldap.core.simple.SimpleLdapOperations#search(java.lang.String, + * java.lang.String, + * org.springframework.ldap.core.simple.ParametrizedContextMapper) + */ + @SuppressWarnings("unchecked") + public List search(String base, String filter, ParametrizedContextMapper mapper) { + return ldapOperations.search(base, filter, mapper); + } + + /* + * (non-Javadoc) + * @see org.springframework.ldap.core.simple.SimpleLdapOperations#search(java.lang.String, + * java.lang.String, javax.naming.directory.SearchControls, + * org.springframework.ldap.core.simple.ParametrizedContextMapper, + * org.springframework.ldap.core.DirContextProcessor) + */ + @SuppressWarnings("unchecked") + public List search(String base, String filter, SearchControls controls, ParametrizedContextMapper mapper, + DirContextProcessor processor) { + return ldapOperations.search(base, filter, controls, mapper); + } + +}