package org.apereo.cas.util;
import com.unboundid.ldap.sdk.AddRequest;
import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.LDAPConnection;
import org.ldaptive.AttributeModification;
import org.ldaptive.AttributeModificationType;
import org.ldaptive.Connection;
import org.ldaptive.DefaultConnectionFactory;
import org.ldaptive.LdapAttribute;
import org.ldaptive.LdapEntry;
import org.ldaptive.ModifyOperation;
import org.ldaptive.ModifyRequest;
import org.ldaptive.io.LdifReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.stream.Collectors;
/**
* Utility class used by all tests that provision and deprovision LDAP test data.
*
* @author Marvin S. Addison
* @since 4.0.0
*/
public final class LdapTestUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(LdapTestUtils.class);
/**
* Placeholder for base DN in LDIF files.
*/
private static final String BASE_DN_PLACEHOLDER = "${ldapBaseDn}";
/**
* System-wide newline character string.
*/
private static final String NEWLINE = System.getProperty("line.separator");
/**
* Private constructor of utility class.
*/
private LdapTestUtils() {
}
/**
* Reads an LDIF into a collection of LDAP entries. The components performs a simple property
* replacement in the LDIF data where <pre>${ldapBaseDn}</pre> is replaced with the environment-specific base
* DN.
*
* @param ldif LDIF resource, typically a file on filesystem or classpath.
* @param baseDn The directory branch where the entry resides.
* @return LDAP entries contained in the LDIF.
* @throws IOException On IO errors reading LDIF.
*/
public static Collection<LdapEntry> readLdif(final InputStream ldif, final String baseDn) throws IOException {
final String ldapString;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(ldif))) {
ldapString = reader.lines()
.map(line -> {
if (line.contains(BASE_DN_PLACEHOLDER)) {
return line.replace(BASE_DN_PLACEHOLDER, baseDn);
}
return line;
})
.collect(Collectors.joining(NEWLINE));
}
return new LdifReader(new StringReader(ldapString)).read().getEntries();
}
/**
* Creates the given LDAP entries.
*
* @param connection Open LDAP connection used to connect to directory.
* @param entries Collection of LDAP entries.
* @throws Exception On LDAP errors.
*/
public static void createLdapEntries(final LDAPConnection connection, final Collection<LdapEntry> entries) throws Exception {
try {
for (final LdapEntry entry : entries) {
final Collection<Attribute> attrs = new ArrayList<>(entry.getAttributeNames().length);
attrs.addAll(entry.getAttributes().stream()
.map(a -> new Attribute(a.getName(), a.getStringValues())).collect(Collectors.toList()));
final AddRequest ad = new AddRequest(entry.getDn(), attrs);
connection.add(ad);
}
} catch (final Exception e) {
LOGGER.warn(e.getLocalizedMessage());
}
}
/**
* Modify ldap entry.
*
* @param serverCon the server con
* @param dn the dn
* @param attr the attr
* @param add the add
*/
public static void modifyLdapEntry(final LDAPConnection serverCon, final String dn, final LdapAttribute attr,
final AttributeModificationType add) {
try {
final String address = "ldap://" + serverCon.getConnectedAddress() + ':' + serverCon.getConnectedPort();
try (Connection conn = DefaultConnectionFactory.getConnection(address)) {
try {
conn.open();
final ModifyOperation modify = new ModifyOperation(conn);
modify.execute(new ModifyRequest(dn, new AttributeModification(add, attr)));
} catch (final Exception e) {
LOGGER.debug(e.getMessage(), e);
}
}
} finally {
serverCon.close();
}
}
/**
* Modify ldap entry.
*
* @param serverCon the server con
* @param dn the dn
* @param attr the attr
*/
public static void modifyLdapEntry(final LDAPConnection serverCon, final LdapEntry dn, final LdapAttribute attr) {
modifyLdapEntry(serverCon, dn.getDn(), attr, AttributeModificationType.ADD);
}
}