package io.lumify.ldap;
import io.lumify.core.exception.LumifyException;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.SearchResultEntry;
import com.unboundid.ldif.LDIFException;
import com.unboundid.ldif.LDIFReader;
import com.unboundid.util.ssl.KeyStoreKeyManager;
import com.unboundid.util.ssl.SSLUtil;
import com.unboundid.util.ssl.TrustAllTrustManager;
import com.unboundid.util.ssl.TrustStoreTrustManager;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Set;
import static org.junit.Assert.*;
public class LdapSearchServiceTest {
private static final String BIND_DN = "cn=root,dc=lumify,dc=io";
private static final String BIND_PASSWORD = "lumify";
private static InMemoryDirectoryServer ldapServer;
@BeforeClass
public static void setUp() throws Exception {
ldapServer = configureInMemoryDirectoryServer();
ldapServer.startListening();
}
public static InMemoryDirectoryServer configureInMemoryDirectoryServer() throws Exception {
KeyStoreKeyManager ksManager = new KeyStoreKeyManager(classpathResource("/keystore.jks"), "password".toCharArray());
TrustStoreTrustManager tsManager = new TrustStoreTrustManager(classpathResource("/truststore.jks"));
SSLUtil serverSslUtil = new SSLUtil(ksManager, tsManager);
SSLUtil clientSslUtil = new SSLUtil(new TrustAllTrustManager());
InMemoryListenerConfig sslConfig = InMemoryListenerConfig.createLDAPSConfig(
"LDAPS",
null,
4636,
serverSslUtil.createSSLServerSocketFactory(),
clientSslUtil.createSSLSocketFactory()
);
InMemoryDirectoryServerConfig ldapConfig = new InMemoryDirectoryServerConfig("dc=lumify,dc=io");
ldapConfig.addAdditionalBindCredentials(BIND_DN, BIND_PASSWORD);
ldapConfig.setListenerConfigs(sslConfig);
ldapConfig.setSchema(null);
InMemoryDirectoryServer ldapServer = new InMemoryDirectoryServer(ldapConfig);
ldapServer.importFromLDIF(false, classpathResource("/init.ldif"));
ldapServer.importFromLDIF(false, classpathResource("/people.ldif"));
ldapServer.importFromLDIF(false, classpathResource("/people-alice.ldif"));
ldapServer.importFromLDIF(false, classpathResource("/people-bob.ldif"));
ldapServer.importFromLDIF(false, classpathResource("/people-carlos.ldif"));
ldapServer.importFromLDIF(false, classpathResource("/groups.ldif"));
ldapServer.importFromLDIF(false, classpathResource("/groups-admins.ldif"));
ldapServer.importFromLDIF(false, classpathResource("/groups-managers.ldif"));
return ldapServer;
}
@AfterClass
public static void tearDown() {
ldapServer.shutDown(true);
}
@Test
public void searchForAliceWithMatchingCert() throws Exception {
LdapSearchService service = new LdapSearchServiceImpl(getServerConfig(ldapServer), getSearchConfig());
SearchResultEntry result = service.searchPeople(getPersonCertificate("alice"));
assertNotNull(result);
assertEquals("cn=Alice,ou=people,dc=lumify,dc=io", result.getDN());
assertEquals("Alice Smith-Y-", result.getAttributeValue("displayName"));
assertEquals("3", result.getAttributeValue("employeeNumber"));
assertArrayEquals(getPersonCertificate("alice").getEncoded(), result.getAttributeValueBytes("userCertificate;binary"));
Set<String> groups = service.searchGroups(result);
assertNotNull(groups);
assertEquals(2, groups.size());
assertTrue(groups.contains("admins"));
assertTrue(groups.contains("managers"));
System.out.println("groups = " + groups);
System.out.println(result.toLDIFString());
}
@Test
public void searchForBob() throws Exception {
LdapSearchService service = new LdapSearchServiceImpl(getServerConfig(ldapServer), getSearchConfig());
SearchResultEntry result = service.searchPeople(getPersonCertificate("bob"));
assertNotNull(result);
assertEquals("cn=Bob,ou=people,dc=lumify,dc=io", result.getDN());
assertEquals("Bob Maluga-Y-", result.getAttributeValue("displayName"));
assertEquals("4", result.getAttributeValue("employeeNumber"));
Set<String> groups = service.searchGroups(result);
assertNotNull(groups);
assertEquals(1, groups.size());
assertTrue(groups.contains("admins"));
System.out.println("groups = " + groups);
System.out.println(result.toLDIFString());
}
@Test(expected = LumifyException.class)
public void searchForNonExistentPerson() throws Exception {
LdapSearchService service = new LdapSearchServiceImpl(getServerConfig(ldapServer), getSearchConfig());
service.searchPeople(getPersonCertificate("diane"));
}
private static String classpathResource(String name) {
return LdapSearchServiceTest.class.getResource(name).getPath();
}
public static LdapServerConfiguration getServerConfig(InMemoryDirectoryServer ldapServer) throws LDAPException {
LdapServerConfiguration serverConfig = new LdapServerConfiguration();
serverConfig.setPrimaryLdapServerHostname(ldapServer.getConnection().getConnectedAddress());
serverConfig.setPrimaryLdapServerPort(ldapServer.getListenPort("LDAPS"));
serverConfig.setMaxConnections(1);
serverConfig.setBindDn(BIND_DN);
serverConfig.setBindPassword(BIND_PASSWORD);
serverConfig.setTrustStore(classpathResource("/truststore.jks"));
serverConfig.setTrustStorePassword("password");
return serverConfig;
}
public static LdapSearchConfiguration getSearchConfig() {
LdapSearchConfiguration searchConfig = new LdapSearchConfiguration();
searchConfig.setUserSearchBase("dc=lumify,dc=io");
searchConfig.setUserSearchScope("sub");
searchConfig.setUserAttributes("displayName,employeeNumber,telephoneNumber");
searchConfig.setUserCertificateAttribute("userCertificate;binary");
searchConfig.setGroupSearchBase("dc=lumify,dc=io");
searchConfig.setGroupSearchScope("sub");
searchConfig.setUserSearchFilter("(cn=${cn})");
searchConfig.setGroupNameAttribute("cn");
searchConfig.setGroupSearchBase("ou=groups,dc=lumify,dc=io");
searchConfig.setGroupSearchFilter("(uniqueMember=${dn})");
searchConfig.setGroupSearchScope("sub");
return searchConfig;
}
public static X509Certificate getPersonCertificate(String personName) throws IOException, LDIFException, CertificateException {
LDIFReader reader = new LDIFReader(classpathResource("/people-" + personName + ".ldif"));
Attribute certAttr = reader.readEntry().getAttribute(getSearchConfig().getUserCertificateAttribute());
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
return (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(certAttr.getValueByteArray()));
}
}