Index: pom.xml =================================================================== --- pom.xml (Revision 1876050) +++ pom.xml (Arbeitskopie) @@ -35,8 +35,8 @@ 2.0.0-M24 false - 0.85 - 0.72 + 0.81 + 0.67 @@ -44,6 +44,7 @@ org.apache.felix maven-bundle-plugin + true @@ -50,12 +51,15 @@ !org.dom4j.*, !org.xmlpull.v1, !sun.net.util, + !net.sf.cglib.proxy, + !antlr, + !antlr.collections.impl, + !org.apache.mina.*, * - api-all,commons-pool,commons-lang,mina-core,antlr + api-all,commons-pool2,commons-collections4,mina-core,org.apache.servicemix.bundles.antlr - true @@ -71,67 +75,37 @@ - - - - disable-ldap-integration - - - 1.6 - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - **/LdapProviderTest.class - **/DefaultLdapLoginModuleTest.class - **/GuestTokenDefaultLdapLoginModuleTest.class - **/LdapDefaultLoginModuleTest.class - **/LdapLoginStandaloneTest.class - **/TokenDefaultLdapLoginModuleTest.class - **/LargeLdapProviderTest.class - - - - - - - - - org.apache.directory.api api-all - 1.0.0 - provided + 2.0.1 - commons-pool - commons-pool - 1.6 - provided + org.apache.commons + commons-pool2 + 2.8.0 - commons-lang - commons-lang - 2.6 - provided + org.apache.commons + commons-collections4 + 4.4 org.apache.mina mina-core - 2.0.16 - provided + 2.1.3 - antlr - antlr - 2.7.7 + org.apache.servicemix.bundles + org.apache.servicemix.bundles.antlr + 2.7.7_5 + + + org.apache.commons + commons-lang3 + 3.9 provided @@ -241,179 +215,23 @@ test - - - org.apache.directory.server - apacheds-core - ${apacheds.test.version} + org.apache.sling + org.apache.sling.testing.osgi-mock test - - - org.apache.directory.api - * - - - org.apache.directory.server - apacheds-core-annotations - ${apacheds.test.version} + org.mockito + mockito-core test - - - org.apache.directory.api - * - - + + org.apache.directory.server - apacheds-core-api + apacheds-all ${apacheds.test.version} test - - - org.apache.directory.api - * - - - - org.apache.directory.server - apacheds-core-avl - ${apacheds.test.version} - test - - - org.apache.directory.server - apacheds-core-constants - ${apacheds.test.version} - test - - - org.apache.directory.server - apacheds-core-jndi - ${apacheds.test.version} - test - - - org.apache.directory.server - apacheds-interceptor-kerberos - ${apacheds.test.version} - test - - - org.apache.directory.server - apacheds-kerberos-codec - ${apacheds.test.version} - test - - - org.apache.directory.server - apacheds-ldif-partition - ${apacheds.test.version} - test - - - org.apache.directory.api - * - - - - - org.apache.directory.server - apacheds-protocol-dhcp - ${apacheds.test.version} - test - - - org.apache.directory.server - apacheds-protocol-dns - ${apacheds.test.version} - test - - - org.apache.directory.server - apacheds-protocol-kerberos - ${apacheds.test.version} - test - - - org.apache.directory.server - apacheds-protocol-ldap - ${apacheds.test.version} - test - - - org.apache.directory.api - * - - - - - org.apache.directory.server - apacheds-protocol-ntp - ${apacheds.test.version} - test - - - org.apache.directory.server - apacheds-protocol-shared - ${apacheds.test.version} - test - - - org.apache.directory.server - apacheds-server-annotations - ${apacheds.test.version} - test - - - org.apache.directory.server - apacheds-server-config - ${apacheds.test.version} - test - - - org.apache.directory.api - * - - - - - org.apache.directory.server - apacheds-server-jndi - ${apacheds.test.version} - test - - - org.apache.directory.api - * - - - - - org.apache.directory.server - apacheds-xdbm-partition - ${apacheds.test.version} - test - - - org.apache.directory.api - * - - - - - org.apache.sling - org.apache.sling.testing.osgi-mock - test - - - org.mockito - mockito-core - test - Index: src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapIdentityProvider.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapIdentityProvider.java (Revision 1876050) +++ src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapIdentityProvider.java (Arbeitskopie) @@ -32,8 +32,8 @@ import javax.net.ssl.SSLContext; import javax.security.auth.login.LoginException; -import org.apache.commons.pool.impl.GenericObjectPool; -import org.apache.directory.api.ldap.codec.controls.search.pagedSearch.PagedResultsDecorator; +import org.apache.commons.pool2.impl.DefaultPooledObject; +import org.apache.directory.api.ldap.codec.BasicControlDecorator; import org.apache.directory.api.ldap.model.constants.SchemaConstants; import org.apache.directory.api.ldap.model.cursor.CursorException; import org.apache.directory.api.ldap.model.cursor.SearchCursor; @@ -51,6 +51,7 @@ import org.apache.directory.api.ldap.model.message.SearchResultEntry; import org.apache.directory.api.ldap.model.message.SearchScope; import org.apache.directory.api.ldap.model.message.controls.PagedResults; +import org.apache.directory.api.ldap.model.message.controls.PagedResultsImpl; import org.apache.directory.api.ldap.model.name.Dn; import org.apache.directory.api.ldap.model.name.Rdn; import org.apache.directory.ldap.client.api.AbstractPoolableLdapConnectionFactory; @@ -366,7 +367,7 @@ try { DebugTimer timer = new DebugTimer(); if (userPool == null) { - connection = userConnectionFactory.makeObject(); + connection = userConnectionFactory.create(); } else { connection = userPool.getConnection(); } @@ -538,8 +539,8 @@ if (config.getAdminPoolConfig().getMaxActive() != 0) { adminPool = new LdapConnectionPool(adminConnectionFactory); adminPool.setTestOnBorrow(true); - adminPool.setMaxActive(config.getAdminPoolConfig().getMaxActive()); - adminPool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); +// adminPool.setMaxActive(config.getAdminPoolConfig().getMaxActive()); +// adminPool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); } // setup unbound connection pool. let's create a new version of the config @@ -554,8 +555,8 @@ if (config.getUserPoolConfig().getMaxActive() != 0) { userPool = new UnboundLdapConnectionPool(userConnectionFactory); userPool.setTestOnBorrow(true); - userPool.setMaxActive(config.getUserPoolConfig().getMaxActive()); - userPool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); +// userPool.setMaxActive(config.getUserPoolConfig().getMaxActive()); +// userPool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); } log.info("LdapIdentityProvider initialized: {}", config); @@ -722,10 +723,11 @@ req.setBase(new Dn(idConfig.getBaseDN())); req.setFilter(searchFilter); - PagedResults pagedSearchControl = new PagedResultsDecorator(connection.getCodecService()); // do paged searches (OAK-2874) - pagedSearchControl.setSize(1000); - pagedSearchControl.setCookie(cookie); + PagedResultsImpl pagedResults = new PagedResultsImpl(); + pagedResults.setSize(1000); + pagedResults.setCookie(cookie); + BasicControlDecorator pagedSearchControl = new BasicControlDecorator(connection.getCodecService(), pagedResults); req.addControl(pagedSearchControl); return req; @@ -843,7 +845,7 @@ // for multivalue properties, store as collection if (attr.size() > 1) { List values = new ArrayList(); - for (Value value : attr) { + for (Value value : attr) { values.add(value.getString()); } propValue = values; @@ -859,7 +861,7 @@ private LdapConnection connect() throws ExternalIdentityException { try { if (adminPool == null) { - return adminConnectionFactory.makeObject(); + return adminConnectionFactory.makeObject().getObject(); } else { return adminPool.getConnection(); } @@ -874,7 +876,7 @@ try { if (connection != null) { if (adminPool == null) { - adminConnectionFactory.destroyObject(connection); + adminConnectionFactory.destroyObject(new DefaultPooledObject<>(connection)); } else { adminPool.releaseConnection(connection); } Index: src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapProviderConfig.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapProviderConfig.java (Revision 1876050) +++ src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapProviderConfig.java (Arbeitskopie) @@ -620,7 +620,7 @@ /** * Defines the configuration of a connection pool. Currently we only define the max size. - * (documentation copied from {@link org.apache.commons.pool.impl.GenericObjectPool}) + * (documentation copied from {@link org.apache.commons.pool2.impl.GenericObjectPool}) */ public static class PoolConfig { Index: src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/PoolableUnboundConnectionFactory.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/PoolableUnboundConnectionFactory.java (Revision 1876050) +++ src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/PoolableUnboundConnectionFactory.java (Arbeitskopie) @@ -18,7 +18,9 @@ import java.io.IOException; -import org.apache.commons.pool.PoolableObjectFactory; +import org.apache.commons.pool2.BasePooledObjectFactory; +import org.apache.commons.pool2.PooledObject; +import org.apache.commons.pool2.impl.DefaultPooledObject; import org.apache.directory.api.ldap.model.exception.LdapException; import org.apache.directory.ldap.client.api.LdapConnection; import org.apache.directory.ldap.client.api.LdapConnectionConfig; @@ -32,7 +34,7 @@ /** * A factory for creating unbound LdapConnection objects managed by LdapConnectionPool. */ -public class PoolableUnboundConnectionFactory implements PoolableObjectFactory { +public class PoolableUnboundConnectionFactory extends BasePooledObjectFactory { /** * default logger @@ -90,11 +92,10 @@ connection.close(); } - /** * {@inheritDoc} */ - public LdapConnection makeObject() throws LdapException { + public LdapConnection create() throws LdapException { LdapNetworkConnection connection = config.isUseTls() ? new TlsGuardingConnection(config) : new LdapNetworkConnection(config); @@ -103,6 +104,9 @@ return connection; } + public PooledObject wrap(LdapConnection foo) { + return new DefaultPooledObject<>(foo); + } /** * {@inheritDoc} Index: src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/UnboundLdapConnectionPool.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/UnboundLdapConnectionPool.java (Revision 1876050) +++ src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/UnboundLdapConnectionPool.java (Arbeitskopie) @@ -16,7 +16,7 @@ */ package org.apache.jackrabbit.oak.security.authentication.ldap.impl; -import org.apache.commons.pool.impl.GenericObjectPool; +import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.directory.ldap.client.api.LdapConnection; /** Index: src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/AbstractServer.java =================================================================== --- src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/AbstractServer.java (Revision 1876050) +++ src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/AbstractServer.java (Arbeitskopie) @@ -24,9 +24,11 @@ import java.io.ByteArrayInputStream; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.BindException; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -39,7 +41,6 @@ import javax.naming.ldap.InitialLdapContext; import javax.naming.ldap.LdapContext; -import org.apache.commons.io.FileUtils; import org.apache.directory.api.ldap.model.constants.SupportedSaslMechanisms; import org.apache.directory.api.ldap.model.entry.DefaultEntry; import org.apache.directory.api.ldap.model.entry.Entry; @@ -114,7 +115,7 @@ * @return a list of entries added to the server in the order they were added * @throws NamingException of the load fails */ - protected List loadLdif(InputStream in) throws Exception { + public List loadLdif(InputStream in) throws Exception { if (in == null) { return EMPTY_LIST; } @@ -122,7 +123,7 @@ return loadLdif(ldifReader); } - protected List loadLdif(LdifReader ldifReader) throws Exception { + public List loadLdif(LdifReader ldifReader) throws Exception { List entries = new ArrayList(); for (LdifEntry ldifEntry : ldifReader) { Dn dn = ldifEntry.getDn(); @@ -339,7 +340,7 @@ protected void doDelete(File wkdir) throws IOException { if (doDelete) { if (wkdir.exists()) { - FileUtils.deleteDirectory(wkdir); + deleteDirectory(wkdir); } if (wkdir.exists()) { @@ -348,7 +349,85 @@ } } +//----------------------------------------------------------------------------- + public static void deleteDirectory(File directory) throws IOException { + if (directory.exists()) { + if (!isSymlink(directory)) { + cleanDirectory(directory); + } + + if (!directory.delete()) { + String message = "Unable to delete directory " + directory + "."; + throw new IOException(message); + } + } + } + + public static boolean isSymlink(File file) throws IOException { + if (file == null) { + throw new NullPointerException("File must not be null"); + } else { + return Files.isSymbolicLink(file.toPath()); + } + } + + public static void cleanDirectory(File directory) throws IOException { + File[] files = verifiedListFiles(directory); + IOException exception = null; + File[] var3 = files; + int var4 = files.length; + + for(int var5 = 0; var5 < var4; ++var5) { + File file = var3[var5]; + + try { + forceDelete(file); + } catch (IOException var8) { + exception = var8; + } + } + + if (null != exception) { + throw exception; + } + } + + private static File[] verifiedListFiles(File directory) throws IOException { + String message; + if (!directory.exists()) { + message = directory + " does not exist"; + throw new IllegalArgumentException(message); + } else if (!directory.isDirectory()) { + message = directory + " is not a directory"; + throw new IllegalArgumentException(message); + } else { + File[] files = directory.listFiles(); + if (files == null) { + throw new IOException("Failed to list contents of " + directory); + } else { + return files; + } + } + } + + public static void forceDelete(File file) throws IOException { + if (file.isDirectory()) { + deleteDirectory(file); + } else { + boolean filePresent = file.exists(); + if (!file.delete()) { + if (!filePresent) { + throw new FileNotFoundException("File does not exist: " + file); + } + + String message = "Unable to delete file: " + file; + throw new IOException(message); + } + } + } + +//----------------------------------------------------------------------------- /** * Sets the contexts for this base class. Values of user and password used to * set the respective JNDI properties. These values can be overriden by the Index: src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/InternalLdapServer.java =================================================================== --- src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/InternalLdapServer.java (Revision 1876050) +++ src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/InternalLdapServer.java (Arbeitskopie) @@ -22,7 +22,7 @@ import javax.naming.directory.DirContext; import javax.naming.ldap.LdapContext; -class InternalLdapServer extends AbstractServer { +public class InternalLdapServer extends AbstractServer { public static final String GROUP_MEMBER_ATTR = "member"; public static final String GROUP_CLASS_ATTR = "groupOfNames"; @@ -29,6 +29,10 @@ public static final String ADMIN_PW = "secret"; + public InternalLdapServer() { + super(); + } + public void setUp() throws Exception { super.setUp(); doDelete = true; Index: src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LargeLdapProviderTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LargeLdapProviderTest.java (Revision 1876050) +++ src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LargeLdapProviderTest.java (Arbeitskopie) @@ -43,58 +43,53 @@ public class LargeLdapProviderTest { - protected static final InternalLdapServer LDAP_SERVER = new InternalLdapServer(); + //loaded by a separate ClassLoader unavailable to the client (needed because the server is using old libraries) + protected static LdapServerClassLoader.Proxy proxy; - //initialize LDAP server only once (fast, but might turn out to be not sufficiently flexible in the future) - protected static final boolean USE_COMMON_LDAP_FIXTURE = false; - public static final String IDP_NAME = "ldap"; - protected static final String GROUP_NAME = "foobargroup"; protected static String GROUP_DN; - protected static String[] TEST_MEMBERS; - protected static int NUM_USERS = 2222; - protected static int SIZE_LIMIT = 50; - protected LdapIdentityProvider idp; + protected static LdapIdentityProvider idp; + protected static LdapProviderConfig providerConfig; - protected LdapProviderConfig providerConfig; - @BeforeClass public static void beforeClass() throws Exception { - if (USE_COMMON_LDAP_FIXTURE) { - LDAP_SERVER.setUp(); - LDAP_SERVER.setMaxSizeLimit(SIZE_LIMIT); - initLdapFixture(LDAP_SERVER); + LdapServerClassLoader serverClassLoader = LdapServerClassLoader.createServerClassLoader(); + proxy = serverClassLoader.createAndSetupServer(); + idp = createIDP(); + proxy.setMaxSizeLimit(SIZE_LIMIT); + USER_DN = proxy.addUser(USER_FIRSTNAME, USER_LASTNAME, USER_ID, USER_PWD); + GROUP_DN = proxy.addGroup(GROUP_NAME, USER_DN); + ArrayList members = new ArrayList<>(); + members.add(USER_DN); + List userDNs = new ArrayList(); + for (int i = 0; i < NUM_USERS; i++) { + final String userId = "user-" + i; + String userDN = proxy.addUser(userId, "test", userId, "test"); + userDNs.add(userDN); + members.add(userDN); } + proxy.addMembers(GROUP_DN, userDNs); + TEST_MEMBERS = members.toArray(new String[members.size()]); } @AfterClass public static void afterClass() throws Exception { - if (USE_COMMON_LDAP_FIXTURE) { - LDAP_SERVER.tearDown(); - } + proxy.tearDown(); } @Before public void before() throws Exception { - if (!USE_COMMON_LDAP_FIXTURE) { - LDAP_SERVER.setUp(); - LDAP_SERVER.setMaxSizeLimit(SIZE_LIMIT); - initLdapFixture(LDAP_SERVER); - } idp = createIDP(); } @After public void after() throws Exception { - if (!USE_COMMON_LDAP_FIXTURE) { - LDAP_SERVER.tearDown(); - } if (idp != null) { idp.close(); idp = null; @@ -101,11 +96,11 @@ } } - protected LdapIdentityProvider createIDP() { + protected static LdapIdentityProvider createIDP() { providerConfig = new LdapProviderConfig() .setName(IDP_NAME) .setHostname("127.0.0.1") - .setPort(LDAP_SERVER.getPort()) + .setPort(proxy.port) .setBindDN(USER_DN) .setBindPassword(USER_PWD) .setGroupMemberAttribute("member"); @@ -130,25 +125,6 @@ protected static String USER_DN; - protected static void initLdapFixture(InternalLdapServer server) throws Exception { - ArrayList members = new ArrayList(); - - USER_DN = LDAP_SERVER.addUser(USER_FIRSTNAME, USER_LASTNAME, USER_ID, USER_PWD); - GROUP_DN = server.addGroup(GROUP_NAME, USER_DN); - members.add(USER_DN); - - List userDNs = new ArrayList(); - for (int i = 0; i < NUM_USERS; i++) { - final String userId = "user-" + i; - String userDN = server.addUser(userId, "test", userId, "test"); - userDNs.add(userDN); - members.add(userDN); - } - LDAP_SERVER.addMembers(GROUP_DN, userDNs); - TEST_MEMBERS = members.toArray(new String[members.size()]); - } - - @Test public void testGetMembers() throws Exception { ExternalIdentityRef ref = new ExternalIdentityRef(GROUP_DN, IDP_NAME); Index: src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapLoginTestBase.java =================================================================== --- src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapLoginTestBase.java (Revision 1876050) +++ src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapLoginTestBase.java (Arbeitskopie) @@ -16,6 +16,11 @@ */ package org.apache.jackrabbit.oak.security.authentication.ldap; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.net.URL; +import java.net.URLClassLoader; import java.security.Principal; import java.util.ArrayList; import java.util.List; @@ -58,7 +63,8 @@ public abstract class LdapLoginTestBase extends ExternalLoginTestBase { - protected static final InternalLdapServer LDAP_SERVER = new InternalLdapServer(); + //loaded by a separate ClassLoader unavailable to the client (needed because the server is using old libraries) + protected static LdapServerClassLoader.Proxy proxy; protected static final String USER_ID = "foobar"; protected static final String USER_PWD = "foobar"; @@ -74,35 +80,34 @@ private static String[] CONCURRENT_TEST_USERS = new String[NUM_CONCURRENT_LOGINS]; private static String[] CONCURRENT_GROUP_TEST_USERS = new String[NUM_CONCURRENT_LOGINS]; - //initialize LDAP server only once (fast, but might turn out to be not sufficiently flexible in the future) - protected static final boolean USE_COMMON_LDAP_FIXTURE = true; - protected UserManager userManager; @BeforeClass public static void beforeClass() throws Exception { - if (USE_COMMON_LDAP_FIXTURE) { - LDAP_SERVER.setUp(); - createLdapFixture(); + LdapServerClassLoader serverClassLoader = LdapServerClassLoader.createServerClassLoader(); + proxy = serverClassLoader.createAndSetupServer(); + String userDN = proxy.addUser(USER_FIRSTNAME, USER_LASTNAME, USER_ID, USER_PWD); + GROUP_DN = proxy.addGroup(GROUP_NAME, userDN); + for (int i = 0; i < NUM_CONCURRENT_LOGINS * 2; i++) { + final String userId = "user-" + i; + userDN = proxy.addUser(userId, "test", userId, USER_PWD); + if (i%2 == 0) { + CONCURRENT_GROUP_TEST_USERS[i/2] = userId; + proxy.addMember(GROUP_DN, userDN); + } else { + CONCURRENT_TEST_USERS[i/2] = userId; + } } - } + } @AfterClass public static void afterClass() throws Exception { - if (USE_COMMON_LDAP_FIXTURE) { - LDAP_SERVER.tearDown(); - } + proxy.tearDown(); } @Before public void before() throws Exception { super.before(); - - if (!USE_COMMON_LDAP_FIXTURE) { - LDAP_SERVER.setUp(); - createLdapFixture(); - } - UserConfiguration uc = securityProvider.getConfiguration(UserConfiguration.class); userManager = uc.getUserManager(root, NamePathMapper.DEFAULT); } @@ -109,11 +114,6 @@ @After public void after() throws Exception { - - if (!USE_COMMON_LDAP_FIXTURE) { - LDAP_SERVER.tearDown(); - } - try { Authorizable a = userManager.getAuthorizable(USER_ID); if (a != null) { @@ -146,7 +146,7 @@ LdapProviderConfig cfg = new LdapProviderConfig() .setName("ldap") .setHostname("127.0.0.1") - .setPort(LDAP_SERVER.getPort()) + .setPort(proxy.port) .setBindDN(ServerDNConstants.ADMIN_SYSTEM_DN) .setBindPassword(InternalLdapServer.ADMIN_PW) .setGroupMemberAttribute(InternalLdapServer.GROUP_MEMBER_ATTR); @@ -392,19 +392,4 @@ throw exceptions.get(0); } } - - protected static void createLdapFixture() throws Exception { - String userDN = LDAP_SERVER.addUser(USER_FIRSTNAME, USER_LASTNAME, USER_ID, USER_PWD); - GROUP_DN = LDAP_SERVER.addGroup(GROUP_NAME, userDN); - for (int i = 0; i < NUM_CONCURRENT_LOGINS * 2; i++) { - final String userId = "user-" + i; - userDN = LDAP_SERVER.addUser(userId, "test", userId, USER_PWD); - if (i%2 == 0) { - CONCURRENT_GROUP_TEST_USERS[i/2] = userId; - LDAP_SERVER.addMember(GROUP_DN, userDN); - } else { - CONCURRENT_TEST_USERS[i/2] = userId; - } - } - } } Index: src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapProviderTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapProviderTest.java (Revision 1876050) +++ src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapProviderTest.java (Arbeitskopie) @@ -26,6 +26,13 @@ import static org.junit.Assert.fail; import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URI; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -39,6 +46,7 @@ import org.apache.directory.api.util.Strings; import org.apache.directory.server.constants.ServerDNConstants; +import org.apache.directory.server.ldap.LdapServer; import org.apache.jackrabbit.oak.security.authentication.ldap.impl.LdapIdentity; import org.apache.jackrabbit.oak.security.authentication.ldap.impl.LdapIdentityProvider; import org.apache.jackrabbit.oak.security.authentication.ldap.impl.LdapProviderConfig; @@ -58,50 +66,27 @@ public class LdapProviderTest { - protected static final InternalLdapServer LDAP_SERVER = new InternalLdapServer(); + //loaded by a separate ClassLoader unavailable to the client (needed because the server is using old libraries) + protected LdapServerClassLoader.Proxy proxy; - //initialize LDAP server only once (fast, but might turn out to be not sufficiently flexible in the future) - protected static final boolean USE_COMMON_LDAP_FIXTURE = false; - private static final String TUTORIAL_LDIF = "apache-ds-tutorial.ldif"; - private static final String ERRONEOUS_LDIF = "erroneous.ldif"; - public static final String IDP_NAME = "ldap"; protected LdapIdentityProvider idp; - protected LdapProviderConfig providerConfig; - @BeforeClass - public static void beforeClass() throws Exception { - if (USE_COMMON_LDAP_FIXTURE) { - LDAP_SERVER.setUp(); - initLdapFixture(LDAP_SERVER); - } - } - - @AfterClass - public static void afterClass() throws Exception { - if (USE_COMMON_LDAP_FIXTURE) { - LDAP_SERVER.tearDown(); - } - } - @Before public void before() throws Exception { - if (!USE_COMMON_LDAP_FIXTURE) { - LDAP_SERVER.setUp(); - initLdapFixture(LDAP_SERVER); - } + LdapServerClassLoader serverClassLoader = LdapServerClassLoader.createServerClassLoader(); + proxy = serverClassLoader.createAndSetupServer(); + proxy.loadLdif(getClass().getResourceAsStream(TUTORIAL_LDIF)); idp = createIDP(); } @After public void after() throws Exception { - if (!USE_COMMON_LDAP_FIXTURE) { - LDAP_SERVER.tearDown(); - } + proxy.tearDown(); if (idp != null) { idp.close(); idp = null; @@ -117,7 +102,7 @@ providerConfig = new LdapProviderConfig() .setName(IDP_NAME) .setHostname("127.0.0.1") - .setPort(LDAP_SERVER.getPort()) + .setPort(proxy.port) .setBindDN(ServerDNConstants.ADMIN_SYSTEM_DN) .setBindPassword(InternalLdapServer.ADMIN_PW) .setGroupMemberAttribute("uniquemember") @@ -135,11 +120,6 @@ return new LdapIdentityProvider(providerConfig); } - protected static void initLdapFixture(InternalLdapServer server) throws Exception { - InputStream tutorialLDIF = LdapProviderTest.class.getResourceAsStream(TUTORIAL_LDIF); - server.loadLdif(tutorialLDIF); - } - public static final String TEST_USER0_DN = "cn=Rat Ratterson,ou=users,ou=system"; public static final String TEST_USER0_UID = "ratty"; @@ -192,8 +172,7 @@ @Test public void testListUsersWithMissingUid() throws Exception { // the ERRONEOUS_LDIF contains an entry without uid - InputStream erroneousDIF = LdapProviderTest.class.getResourceAsStream(ERRONEOUS_LDIF); - LDAP_SERVER.loadLdif(erroneousDIF); + proxy.loadLdif(getClass().getResourceAsStream(ERRONEOUS_LDIF)); Iterator users = idp.listUsers(); // without the LdapInvalidAttributeValueException a NPE would result here: while(users.hasNext()) { Index: src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapServerClassLoader.java =================================================================== --- src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapServerClassLoader.java (nicht existent) +++ src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapServerClassLoader.java (Arbeitskopie) @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file 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 org.apache.jackrabbit.oak.security.authentication.ldap; + +import com.google.common.io.ByteStreams; +import org.apache.directory.server.ldap.LdapServer; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.ProtectionDomain; + +public class LdapServerClassLoader extends URLClassLoader { + + private final byte[] serverClassResource; + private final byte[] serverBaseClassResource; + + public LdapServerClassLoader(URL[] urls, Class serverClass, Class serverBaseClass) throws IOException { + super(urls, null); + this.serverClassResource = ByteStreams.toByteArray( + serverClass.getResourceAsStream("/".concat(serverClass.getCanonicalName()).replace('.', '/').concat(".class"))); + this.serverBaseClassResource = ByteStreams.toByteArray( + serverBaseClass.getResourceAsStream("/".concat(serverBaseClass.getCanonicalName()).replace('.', '/').concat(".class"))); + } + + public static LdapServerClassLoader createServerClassLoader() throws URISyntaxException, ClassNotFoundException, IOException { + ClassLoader appClassLoader = LdapServerClassLoader.class.getClassLoader(); + String apacheDsUrl = appClassLoader.getResource( + LdapServer.class.getCanonicalName().replace(".", "/").concat(".class")) + .toURI() + .getRawSchemeSpecificPart(); + apacheDsUrl = apacheDsUrl.substring(0, apacheDsUrl.lastIndexOf('!')); + Class sc = appClassLoader.loadClass(InternalLdapServer.class.getCanonicalName()); + Class sbc = appClassLoader.loadClass(AbstractServer.class.getCanonicalName()); + return new LdapServerClassLoader(new URL[] { new URI(apacheDsUrl).toURL() }, sc, sbc); + } + + public Proxy createAndSetupServer() throws Exception { + final Proxy proxy = new Proxy(); + final Exception[] ex = new Exception[] { null }; + Runnable r = () -> { + try { + proxy.serverClass = loadClass(InternalLdapServer.class.getCanonicalName()); + Constructor constructor = proxy.serverClass.getConstructor(new Class[0]); + proxy.server = constructor.newInstance(new Object[0]); + proxy.serverClass.getMethod("setUp", new Class[0]).invoke(proxy.server); + proxy.port = (int) proxy.serverClass.getMethod("getPort", new Class[0]).invoke(proxy.server); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + ex[0] = e; + } + }; + Thread t = new Thread(r); + t.setContextClassLoader(this); + t.start(); + t.join(); + if (ex[0] != null) { + throw ex[0]; + } + return proxy; + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (InternalLdapServer.class.getCanonicalName().equals(name)) { + return defineClass(name, serverClassResource, 0, serverClassResource.length, (ProtectionDomain) null); + } + if (AbstractServer.class.getCanonicalName().equals(name)) { + return defineClass(name, serverBaseClassResource, 0, serverBaseClassResource.length, (ProtectionDomain) null); + } + return super.findClass(name); + } + + public static class Proxy { + + //Proxy class for InternalLdapServer, using the correct ClassLoader. If marshalling of complex types is + //involved in a method call, a new thread with the correct context ClassLoader will execute the call to + //avoid casting issues (objects of identical types might not be castable across ClassLoaders). + + public static Class serverClass; + public Object server; + public int port; + + public void tearDown() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + serverClass.getMethod("tearDown", new Class[0]).invoke(server); + } + + public void setMaxSizeLimit(long limit) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + serverClass.getMethod("setMaxSizeLimit", new Class[] { Long.TYPE }).invoke(server, limit); + } + + public void loadLdif(InputStream in) throws Exception { + final Exception[] ex = new Exception[] { null }; + Runnable r = () -> { + try { + serverClass.getMethod("loadLdif", new Class[] {InputStream.class}).invoke(server, in); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + ex[0] = e; + } + + }; + Thread t = new Thread(r); + t.setContextClassLoader(serverClass.getClassLoader()); + t.start(); + t.join(); + if (ex[0] != null) { + throw ex[0]; + } + } + + public String addUser(String firstName, String lastName, String userId, String password) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + return (String) serverClass.getMethod("addUser", new Class[] {String.class, String.class, String.class, String.class}).invoke(server, firstName, lastName, userId, password); + } + + public String addGroup(String name, String member) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + return (String) serverClass.getMethod("addGroup", new Class[] {String.class, String.class}).invoke(server, name, member); + } + + public void addMember(String groupDN, String memberDN) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + serverClass.getMethod("addMember", new Class[] {String.class, String.class}).invoke(server, groupDN, memberDN); + } + + public void addMembers(String name, Iterable members) throws Exception { + final Exception[] ex = new Exception[] { null }; + Runnable r = () -> { + try { + serverClass.getMethod("addMembers", new Class[] {String.class, Iterable.class}).invoke(server, name, members); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + ex[0] = e; + } + + }; + Thread t = new Thread(r); + t.setContextClassLoader(serverClass.getClassLoader()); + t.start(); + t.join(); + if (ex[0] != null) { + throw ex[0]; + } + } + } +}