diff --git a/mvn-build/test/integration-tests-openldap/README-EC2-tests.txt b/mvn-build/test/integration-tests-openldap/README-EC2-tests.txt new file mode 100644 index 00000000..856c86b5 --- /dev/null +++ b/mvn-build/test/integration-tests-openldap/README-EC2-tests.txt @@ -0,0 +1,7 @@ +To run the automatic open LDAP EC2 instance launching tests, do: +mvn -Daws.key= -Daws.secret.key= test + +You can optionally tune the EC2 launch using the following parameters: +-Daws.ami= +-Daws.key= +-Daws.security.group= diff --git a/mvn-build/test/integration-tests-openldap/etc/lib/typica-1.4.jar b/mvn-build/test/integration-tests-openldap/etc/lib/typica-1.4.jar new file mode 100644 index 00000000..e5665a2b Binary files /dev/null and b/mvn-build/test/integration-tests-openldap/etc/lib/typica-1.4.jar differ diff --git a/mvn-build/test/integration-tests-openldap/pom.xml b/mvn-build/test/integration-tests-openldap/pom.xml index 7b185ea3..21876bd6 100644 --- a/mvn-build/test/integration-tests-openldap/pom.xml +++ b/mvn-build/test/integration-tests-openldap/pom.xml @@ -1,8 +1,6 @@ - - org.springframework.ldap spring-ldap-parent @@ -12,7 +10,6 @@ spring-ldap-openldap-integration-tests jar Spring LDAP Integration Tests (OpenLDAP) - @@ -33,6 +30,97 @@ org.springframework.ldap spring-ldap-core-tiger + + com.xerox.amazonws + typica + 1.3 + system + ${basedir}/etc/lib/typica-1.4.jar + + + commons-logging + commons-logging + 1.1.1 + + + avalon-framework + avalon-framework + + + javax.servlet + servlet-api + + + junit + junit + + + log4j + log4j + + + logkit + logkit + + + junit + junit + + + + + commons-httpclient + commons-httpclient + 3.1 + + + commons-logging + commons-logging + + + junit + junit + + + + + commons-codec + commons-codec + 1.3 + + + + javax.xml + jsr173 + 1.0 + true + + + + javax.activation + activation + 1.1 + true + + + javax.xml + jaxb-api + 2.1 + true + + + javax.xml + jaxb-impl + 2.1 + true + + org.springframework @@ -55,10 +143,16 @@ 4.4 test - - org.springframework - spring-test - test - + + org.springframework + spring-test + test + + + com.sun + ldapbp + 1.0 + test + - + \ No newline at end of file diff --git a/mvn-build/test/integration-tests-openldap/src/main/java/org/springframework/ldap/AbstractEc2InstanceLaunchingFactoryBean.java b/mvn-build/test/integration-tests-openldap/src/main/java/org/springframework/ldap/AbstractEc2InstanceLaunchingFactoryBean.java new file mode 100644 index 00000000..ab787c27 --- /dev/null +++ b/mvn-build/test/integration-tests-openldap/src/main/java/org/springframework/ldap/AbstractEc2InstanceLaunchingFactoryBean.java @@ -0,0 +1,97 @@ +package org.springframework.ldap; + +import java.util.Collections; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.config.AbstractFactoryBean; +import org.springframework.util.Assert; + +import com.xerox.amazonws.ec2.Jec2; +import com.xerox.amazonws.ec2.LaunchConfiguration; +import com.xerox.amazonws.ec2.ReservationDescription; +import com.xerox.amazonws.ec2.ReservationDescription.Instance; + +public abstract class AbstractEc2InstanceLaunchingFactoryBean extends AbstractFactoryBean { + private static final int SLEEP_TIME = 1000; + + private static final Log log = LogFactory.getLog(AbstractEc2InstanceLaunchingFactoryBean.class); + + private String imageName; + + private String awsKey; + + private String awsSecretKey; + + private String keyName; + + private String groupName; + + private Instance instance; + + public void setImageName(String imageName) { + this.imageName = imageName; + } + + public void setAwsKey(String awsKey) { + this.awsKey = awsKey; + } + + public void setAwsSecretKey(String awsSecretKey) { + this.awsSecretKey = awsSecretKey; + } + + public void setKeyName(String keyName) { + this.keyName = keyName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + @Override + protected final Object createInstance() throws Exception { + Assert.hasLength(imageName, "ImageName must be set"); + Assert.hasLength(awsKey, "AwsKey must be set"); + Assert.hasLength(awsSecretKey, "AwsSecretKey must be set"); + Assert.hasLength(keyName, "KeyName must be set"); + Assert.hasLength(groupName, "GroupName must be set"); + + log.info("Launching EC2 instance for image: " + imageName); + + Jec2 jec2 = new Jec2(awsKey, awsSecretKey); + LaunchConfiguration launchConfiguration = new LaunchConfiguration(imageName); + launchConfiguration.setKeyName(keyName); + launchConfiguration.setSecurityGroup(Collections.singletonList(groupName)); + + ReservationDescription reservationDescription = jec2.runInstances(launchConfiguration); + instance = reservationDescription.getInstances().get(0); + while (!instance.isRunning() && !instance.isTerminated()) { + log.info("Instance still starting up; sleeping " + SLEEP_TIME + "ms"); + Thread.sleep(SLEEP_TIME); + reservationDescription = jec2.describeInstances(Collections.singletonList(instance.getInstanceId())).get(0); + instance = reservationDescription.getInstances().get(0); + } + + if (instance.isRunning()) { + log.info("EC2 instance is now running"); + return doCreateInstance(instance.getDnsName()); + } + else { + throw new IllegalStateException("Failed to start a new instance"); + } + + } + + protected abstract Object doCreateInstance(String dnsName) throws Exception; + + @Override + protected void destroyInstance(Object ignored) throws Exception { + if (this.instance != null) { + log.info("Shutting down instance"); + Jec2 jec2 = new Jec2(awsKey, awsSecretKey); + jec2.terminateInstances(Collections.singletonList(this.instance.getInstanceId())); + } + + } +} diff --git a/mvn-build/test/integration-tests-openldap/src/main/java/org/springframework/ldap/ContextSourceEc2InstanceLaunchingFactoryBean.java b/mvn-build/test/integration-tests-openldap/src/main/java/org/springframework/ldap/ContextSourceEc2InstanceLaunchingFactoryBean.java new file mode 100644 index 00000000..b87e6402 --- /dev/null +++ b/mvn-build/test/integration-tests-openldap/src/main/java/org/springframework/ldap/ContextSourceEc2InstanceLaunchingFactoryBean.java @@ -0,0 +1,54 @@ +package org.springframework.ldap; + +import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.support.LdapContextSource; + +public class ContextSourceEc2InstanceLaunchingFactoryBean extends AbstractEc2InstanceLaunchingFactoryBean { + + private String base; + + private String userDn; + + private String password; + + @Override + public final Class getObjectType() { + return ContextSource.class; + } + + @Override + protected final Object doCreateInstance(final String dnsName) throws Exception { + LdapContextSource instance = new LdapContextSource(); + instance.setUrl("ldap://" + dnsName); + instance.setUserDn(userDn); + instance.setPassword(password); + instance.setBase(base); + setAdditionalContextSourceProperties(instance, dnsName); + + instance.afterPropertiesSet(); + return instance; + } + + /** + * Override to set additional properties on the ContextSource. + * + * @param ctx The created instance. + * @param dnsName The dns name of the created Ec2 instance. + */ + protected void setAdditionalContextSourceProperties(LdapContextSource ctx, final String dnsName) { + + } + + public void setBase(String base) { + this.base = base; + } + + public void setUserDn(String userDn) { + this.userDn = userDn; + } + + public void setPassword(String password) { + this.password = password; + } + +} diff --git a/mvn-build/test/integration-tests-openldap/src/main/java/org/springframework/ldap/TlsContextSourceEc2InstanceLaunchingFactoryBean.java b/mvn-build/test/integration-tests-openldap/src/main/java/org/springframework/ldap/TlsContextSourceEc2InstanceLaunchingFactoryBean.java new file mode 100644 index 00000000..5cef2c4b --- /dev/null +++ b/mvn-build/test/integration-tests-openldap/src/main/java/org/springframework/ldap/TlsContextSourceEc2InstanceLaunchingFactoryBean.java @@ -0,0 +1,23 @@ +package org.springframework.ldap; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSession; + +import org.springframework.ldap.core.support.DefaultTlsDirContextAuthenticationStrategy; +import org.springframework.ldap.core.support.LdapContextSource; + +public class TlsContextSourceEc2InstanceLaunchingFactoryBean extends ContextSourceEc2InstanceLaunchingFactoryBean { + + protected void setAdditionalContextSourceProperties(LdapContextSource ctx, final String dnsName) { + DefaultTlsDirContextAuthenticationStrategy authenticationStrategy = new DefaultTlsDirContextAuthenticationStrategy(); + + authenticationStrategy.setHostnameVerifier(new HostnameVerifier() { + public boolean verify(String hostname, SSLSession session) { + return hostname.equals(dnsName); + } + }); + + ctx.setAuthenticationStrategy(authenticationStrategy); + ctx.setPooled(false); + } +} diff --git a/mvn-build/test/integration-tests-openldap/src/main/java/org/springframework/ldap/control/Person.java b/mvn-build/test/integration-tests-openldap/src/main/java/org/springframework/ldap/control/Person.java new file mode 100644 index 00000000..e0a76d7d --- /dev/null +++ b/mvn-build/test/integration-tests-openldap/src/main/java/org/springframework/ldap/control/Person.java @@ -0,0 +1,104 @@ +/* + * 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.control; + +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; + +/** + * Simple class representing a single person. + * + * @author Mattias Arthursson + * @author Ulrik Sandberg + */ +public class Person { + private String fullName; + + private String lastName; + + private String description; + + private String country; + + private String company; + + private String phone; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getCompany() { + return company; + } + + public void setCompany(String company) { + this.company = company; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public boolean equals(Object obj) { + return EqualsBuilder.reflectionEquals( + this, obj); + } + + public int hashCode() { + return HashCodeBuilder + .reflectionHashCode(this); + } + + public String toString() { + return ToStringBuilder.reflectionToString( + this, ToStringStyle.MULTI_LINE_STYLE); + } +} diff --git a/mvn-build/test/integration-tests-openldap/src/test/java/org/springframework/ldap/control/LdapTemplatePagedSearchITest.java b/mvn-build/test/integration-tests-openldap/src/test/java/org/springframework/ldap/control/LdapTemplatePagedSearchITest.java new file mode 100644 index 00000000..ab3db1ca --- /dev/null +++ b/mvn-build/test/integration-tests-openldap/src/test/java/org/springframework/ldap/control/LdapTemplatePagedSearchITest.java @@ -0,0 +1,179 @@ +/* + * 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.control; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; + +import java.util.List; + +import javax.naming.Name; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; +import javax.naming.directory.SearchControls; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.ldap.core.CollectingNameClassPairCallbackHandler; +import org.springframework.ldap.core.ContextMapper; +import org.springframework.ldap.core.ContextMapperCallbackHandler; +import org.springframework.ldap.core.DirContextAdapter; +import org.springframework.ldap.core.DistinguishedName; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.core.SearchExecutor; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; + +/** + * Tests the paged search result capability of LdapTemplate. + *

+ * Note: Currently, ApacheDS does not support paged results controls, so this + * test must be run under another directory server, for example OpenLdap. This + * test will not run under ApacheDS, and the other integration tests assume + * ApacheDS and will probably not run under OpenLdap. + * + * @author Ulrik Sandberg + */ +@ContextConfiguration(locations = { "/conf/ldapTemplateTestContext.xml" }) +public class LdapTemplatePagedSearchITest extends AbstractJUnit4SpringContextTests { + + private static final Name BASE = DistinguishedName.EMPTY_PATH; + + private static final String FILTER_STRING = "(&(objectclass=person))"; + + @Autowired + private LdapTemplate tested; + + private CollectingNameClassPairCallbackHandler callbackHandler; + + private SearchControls searchControls; + + @Before + public void onSetUp() throws Exception { + PersonContextMapper mapper = new PersonContextMapper(); + callbackHandler = new ContextMapperCallbackHandler(mapper); + searchControls = new SearchControls(); + searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); + searchControls.setReturningObjFlag(true); + } + + @After + public void onTearDown() throws Exception { + callbackHandler = null; + tested = null; + searchControls = null; + } + + @Test + public void testSearch_PagedResult() { + SearchExecutor searchExecutor = new SearchExecutor() { + public NamingEnumeration executeSearch(DirContext ctx) throws NamingException { + return ctx.search(BASE, FILTER_STRING, searchControls); + } + }; + Person person; + List list; + PagedResultsCookie cookie; + PagedResultsRequestControl requestControl; + + // Prepare for first search + requestControl = new PagedResultsRequestControl(3); + tested.search(searchExecutor, callbackHandler, requestControl); + cookie = requestControl.getCookie(); + assertNotNull("Cookie should not be null yet", cookie.getCookie()); + list = callbackHandler.getList(); + assertEquals(3, list.size()); + person = (Person) list.get(0); + assertEquals("Some Person", person.getFullName()); + assertEquals("+46 555-123456", person.getPhone()); + person = (Person) list.get(1); + assertEquals("Some Person2", person.getFullName()); + assertEquals("+46 555-654321", person.getPhone()); + person = (Person) list.get(2); + assertEquals("Some Person3", person.getFullName()); + assertEquals("+46 555-123654", person.getPhone()); + + // Prepare for second and last search + requestControl = new PagedResultsRequestControl(3, cookie); + tested.search(searchExecutor, callbackHandler, requestControl); + cookie = requestControl.getCookie(); + assertNull("Cookie should be null now", cookie.getCookie()); + assertEquals(5, list.size()); + person = (Person) list.get(3); + assertEquals("Some Person", person.getFullName()); + assertEquals("+46 555-456321", person.getPhone()); + person = (Person) list.get(4); + assertEquals("Some Person", person.getFullName()); + assertEquals("+45 555-654123", person.getPhone()); + } + + public void testSearch_PagedResult_ConvenienceMethod() { + Person person; + List list; + PagedResultsCookie cookie; + PagedResultsRequestControl requestControl; + + // Prepare for first search + requestControl = new PagedResultsRequestControl(3); + tested.search(BASE, FILTER_STRING, searchControls, callbackHandler, requestControl); + cookie = requestControl.getCookie(); + assertNotNull("Cookie should not be null yet", cookie.getCookie()); + list = callbackHandler.getList(); + assertEquals(3, list.size()); + person = (Person) list.get(0); + assertEquals("Some Person", person.getFullName()); + person = (Person) list.get(1); + assertEquals("Some Person2", person.getFullName()); + person = (Person) list.get(2); + assertEquals("Some Person3", person.getFullName()); + + // Prepare for second and last search + requestControl = new PagedResultsRequestControl(3, cookie); + tested.search(BASE, FILTER_STRING, searchControls, callbackHandler, requestControl); + cookie = requestControl.getCookie(); + assertNull("Cookie should be null now", cookie.getCookie()); + assertEquals(5, list.size()); + person = (Person) list.get(3); + assertEquals("Some Person", person.getFullName()); + person = (Person) list.get(4); + assertEquals("Some Person", person.getFullName()); + } + + private static class PersonContextMapper implements ContextMapper { + + public Object mapFromContext(Object ctx) { + DirContextAdapter context = (DirContextAdapter) ctx; + DistinguishedName dn = new DistinguishedName(context.getDn()); + Person person = new Person(); + person.setCountry(dn.getLdapRdn(0).getComponent().getValue()); + person.setCompany(dn.getLdapRdn(1).getComponent().getValue()); + person.setFullName(context.getStringAttribute("cn")); + person.setLastName(context.getStringAttribute("sn")); + person.setDescription(context.getStringAttribute("description")); + person.setPhone(context.getStringAttribute("telephoneNumber")); + + return person; + } + } + + public void setTested(LdapTemplate tested) { + this.tested = tested; + } +} diff --git a/mvn-build/test/integration-tests-openldap/src/test/java/org/springframework/ldap/core/LdapTemplateSearchResultITest.java b/mvn-build/test/integration-tests-openldap/src/test/java/org/springframework/ldap/core/LdapTemplateSearchResultITest.java index 813f383d..d94eba1b 100644 --- a/mvn-build/test/integration-tests-openldap/src/test/java/org/springframework/ldap/core/LdapTemplateSearchResultITest.java +++ b/mvn-build/test/integration-tests-openldap/src/test/java/org/springframework/ldap/core/LdapTemplateSearchResultITest.java @@ -34,11 +34,11 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; /** - * Verifies that LdapTemplate search methods work against OpenLDAP. + * Verifies that LdapTemplate search methods work against OpenLDAP with TLS. * * @author Mattias Arthursson */ -@ContextConfiguration(locations = { "/conf/ldapTemplateTestContext.xml" }) +@ContextConfiguration(locations = { "/conf/ldapTemplateTestContext-tls.xml" }) public class LdapTemplateSearchResultITest extends AbstractJUnit4SpringContextTests { @Autowired diff --git a/mvn-build/test/integration-tests-openldap/src/test/resources/conf/ldap.properties b/mvn-build/test/integration-tests-openldap/src/test/resources/conf/ldap.properties index b7834cce..9e2df1b3 100644 --- a/mvn-build/test/integration-tests-openldap/src/test/resources/conf/ldap.properties +++ b/mvn-build/test/integration-tests-openldap/src/test/resources/conf/ldap.properties @@ -2,3 +2,7 @@ itest.openldap.serverAddress=spring-ldap-test.dyndns.org userDn=cn=admin,dc=jayway,dc=se password=secret base=dc=jayway,dc=se + +aws.ami=ami-56ec083f +aws.key=spring-ldap-keypair +aws.security.group=spring-ldap \ No newline at end of file diff --git a/mvn-build/test/integration-tests-openldap/src/test/resources/conf/ldapTemplateTestContext-tls.xml b/mvn-build/test/integration-tests-openldap/src/test/resources/conf/ldapTemplateTestContext-tls.xml new file mode 100644 index 00000000..747f8d60 --- /dev/null +++ b/mvn-build/test/integration-tests-openldap/src/test/resources/conf/ldapTemplateTestContext-tls.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mvn-build/test/integration-tests-openldap/src/test/resources/conf/ldapTemplateTestContext.xml b/mvn-build/test/integration-tests-openldap/src/test/resources/conf/ldapTemplateTestContext.xml index b8dbc97b..cca75e41 100644 --- a/mvn-build/test/integration-tests-openldap/src/test/resources/conf/ldapTemplateTestContext.xml +++ b/mvn-build/test/integration-tests-openldap/src/test/resources/conf/ldapTemplateTestContext.xml @@ -9,16 +9,15 @@ - + + + + + + - - - - -