Skip to content

Commit

Permalink
Fixes 3775: apoc.load.ldap doesn't work with SSL
Browse files Browse the repository at this point in the history
  • Loading branch information
vga91 committed Feb 27, 2024
1 parent 17c742d commit 5585b91
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 8 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ subprojects {

ext {
// NB: due to version.json generation by parsing this file, the next line must not have any if/then/else logic
neo4jVersion = "5.18.0"
neo4jVersion = "5.16.0"
// instead we apply the override logic here
neo4jVersionEffective = project.hasProperty("neo4jVersionOverride") ? project.getProperty("neo4jVersionOverride") : neo4jVersion
testContainersVersion = '1.18.3'
Expand Down
179 changes: 172 additions & 7 deletions extended/src/test/java/apoc/load/LoadLdapTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import com.novell.ldap.LDAPEntry;
import com.novell.ldap.LDAPSearchResults;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.util.ssl.SSLUtil;
import com.unboundid.util.ssl.TrustAllTrustManager;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
Expand All @@ -18,9 +20,22 @@
import org.zapodot.junit.ldap.EmbeddedLdapRule;
import org.zapodot.junit.ldap.EmbeddedLdapRuleBuilder;

import javax.naming.Context;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.file.Files;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand All @@ -31,6 +46,10 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;


/**
* $ docker run -p 389:389 -p 636:636 --name my-openldap-container --volume ./ldif:/container/service/slapd/assets/config/bootstrap/ldif/custom --detach osixia/openldap:1.5.0 --copy-service
*/
public class LoadLdapTest {
public static final String BIND_DSN = "uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa";
public static final String BIND_PWD = "testPwd";
Expand All @@ -43,28 +62,139 @@ public class LoadLdapTest {

private static GraphDatabaseService db;

public static class UnsecuredSSLSocketFactory extends SSLSocketFactory
{
private SSLSocketFactory socketFactory;

public UnsecuredSSLSocketFactory()
{
try
{
var sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{new X509TrustManager()
{
@Override
public void checkClientTrusted(X509Certificate[] xcs, String string){}

@Override
public void checkServerTrusted(X509Certificate[] xcs, String string){}

@Override
public X509Certificate[] getAcceptedIssuers()
{
return null;
}
}}, new SecureRandom());
socketFactory = sslContext.getSocketFactory();
}
catch(Exception e)
{
throw new RuntimeException(e);
}
}

@SuppressWarnings("unused")
public static SocketFactory getDefault()
{
return new UnsecuredSSLSocketFactory();
}

@Override
public String[] getDefaultCipherSuites()
{
return socketFactory.getDefaultCipherSuites();
}

@Override
public String[] getSupportedCipherSuites()
{
return socketFactory.getSupportedCipherSuites();
}

@Override
public Socket createSocket(Socket socket, String string, int i, boolean bln) throws IOException
{
return socketFactory.createSocket(socket, string, i, bln);
}

@Override
public Socket createSocket(String string, int i) throws IOException
{
return socketFactory.createSocket(string, i);
}

@Override
public Socket createSocket(String string, int i, InetAddress ia, int i1) throws IOException
{
return socketFactory.createSocket(string, i, ia, i1);
}

@Override
public Socket createSocket(InetAddress ia, int i) throws IOException
{
return socketFactory.createSocket(ia, i);
}

@Override
public Socket createSocket(InetAddress ia, int i, InetAddress ia1, int i1) throws IOException
{
return socketFactory.createSocket(ia, i, ia1, i1);
}

@Override
public Socket createSocket() throws IOException
{
return socketFactory.createSocket();
}
}

@ClassRule
public static EmbeddedLdapRule embeddedLdapRule = EmbeddedLdapRuleBuilder
.newInstance()
.usingBindDSN(BIND_DSN)
.usingBindCredentials(BIND_PWD)
.importingLdifs("ldap/example.ldif")
.build();
public static EmbeddedLdapRule embeddedLdapRule;

static {
try {
// SOCKET_FACTORY

// SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
//
// SSLSocketFactory socketFactory = sslUtil.createSSLSocketFactory();
//SSLContext.getDefault().getSocketFactory();

// env.put("java.naming.ldap.factory.socket", UnsecuredSSLSocketFactory.class.getName());


embeddedLdapRule = EmbeddedLdapRuleBuilder
.newInstance()
.usingBindDSN(BIND_DSN)
.usingBindCredentials(BIND_PWD)

.withSocketFactory(new UnsecuredSSLSocketFactory())
.useTls(true)
// .withSocketFactory(socketFactory)
.importingLdifs("ldap/example.ldif")
.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

@BeforeClass
public static void beforeClass() throws Exception {
DatabaseManagementService dbms = new TestDatabaseManagementServiceBuilder(tempFolder.getRoot().toPath()).build();
db = dbms.database(GraphDatabaseSettings.DEFAULT_DATABASE_NAME);
TestUtil.registerProcedure(db, LoadLdap.class);



ldapConnection = embeddedLdapRule.unsharedLdapConnection();
// Context context = embeddedLdapRule.context();

connParams = Map.of("ldapHost", "localhost:" + ldapConnection.getConnectedPort(),
"loginDN", BIND_DSN,
"loginPW", BIND_PWD);

searchParams = Map.of("searchBase", "dc=example,dc=com",
"searchScope", "SCOPE_ONE",
"searchScope", "SCOPE_SUBTREE",
"searchFilter", "(objectClass=*)",
"attributes", List.of("uid") );
}
Expand All @@ -74,6 +204,41 @@ public static void afterClass() {
ldapConnection.close();
}

@Test
public void testLoadLDAPWithApocConfig1() {
// Map<String, Object> connParams1 = new HashMap<>(connParams);
// connParams1.put("ldapHost", "localhost:636");
int port = 636;
extracted(port);
}

@Test
public void testLoadLDAPWithApocConfig12() {
// Map<String, Object> connParams1 = new HashMap<>(connParams);
// connParams1.put("ldapHost", "localhost:636");
int port = 389;
extracted(port);
}

private static void extracted(int port) {
Map<String, String> conn = Map.of("ldapHost", "localhost:" + port,
"loginDN", "cn=admin,dc=example,dc=org",
"loginPW", "admin");
// Map<String, Object> searchBase = Map.of("searchBase", "dc=example,dc=com",
// "searchScope", "SCOPE_BASE",
// "searchFilter", "(objectclass=*)"/*,
// "attributes", List.of("uid")*/);
Map<String, Object> searchBase = Map.of("searchBase", "dc=example,dc=com",
"searchScope", "SCOPE_SUB");
testCall(db, "call apoc.load.ldap($conn, $search)",
Map.of("conn", conn, "search", searchBase),
r -> {
System.out.println("r = " + r);
});

// javax.naming.CommunicationException: simple bind failed: localhost:61178 [Root exception is javax.net.ssl.SSLException: Unsupported or unrecognized SSL message]
}

@Test
public void testLoadLDAPWithApocConfig() {
String key = "apoc.loadldap.myldap.config";
Expand Down

0 comments on commit 5585b91

Please sign in to comment.