package com.constellio.app.modules.es.connectors.ldap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.Control;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.PagedResultsControl;
import javax.naming.ldap.PagedResultsResponseControl;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import com.constellio.app.modules.es.model.connectors.ldap.enums.DirectoryType;
import com.constellio.model.conf.ldap.RegexFilter;
import com.constellio.model.conf.ldap.services.LDAPServicesImpl;
public class ConnectorLDAPServicesImpl implements ConnectorLDAPServices {
private static final Logger LOGGER = LogManager.getLogger(ConnectorLDAPServicesImpl.class);
@Override
public ConnectorLDAPSearchResult getAllObjectsUsingFilter(LdapContext ctx, String objectClass, String objectCategory,
Set<String> searchContextsNames, RegexFilter filter) {
Set<String> usersIds = new HashSet<>();
String userIdAttributeName = "cn";
String searchFilter = computeSearchFilter(objectCategory, objectClass);
boolean errorDuringSearch = false;
/////////////////////////////
try {
for (String currentContext : searchContextsNames) {
ConnectorLDAPSearchResult currentResult = getAllObjectsUsingFilter(ctx, filter, searchFilter, userIdAttributeName,
currentContext);
if(currentResult.isErrorDuringSearch()){
errorDuringSearch = true;
}
usersIds.addAll(currentResult.getDocumentIds());
}
} catch (Exception e) {
errorDuringSearch = true;
LOGGER.warn("PagedSearch failed.", e);
}
return new ConnectorLDAPSearchResult().setDocumentIds(usersIds).setErrorDuringSearch(errorDuringSearch);
}
ConnectorLDAPSearchResult getAllObjectsUsingFilter(LdapContext ctx, RegexFilter filter, String searchFilter,
String userIdAttributeName,
String contextName) {
Set<String> objectsIds = new HashSet<>();
/////////////////////////////
Boolean errorDuringSearch = false;
try {
int pageSize = 100;
byte[] cookie = null;
ctx.setRequestControls(new Control[] { new PagedResultsControl(pageSize, Control.NONCRITICAL) });
do {
//Query
SearchControls searchCtls = new SearchControls();
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
String[] returnAttributes = { userIdAttributeName };
searchCtls.setReturningAttributes(returnAttributes);
NamingEnumeration results = ctx.search(contextName, searchFilter, searchCtls);
/* for each entry print out name + all attrs and values */
while (results != null && results.hasMore()) {
SearchResult entry = (SearchResult) results.next();
String currentUserId = entry.getNameInNamespace();
if (StringUtils.isNotBlank(currentUserId)) {
if (filter != null) {
if (filter.isAccepted(getSimpleName(currentUserId.toLowerCase()))) {
objectsIds.add(currentUserId);
}
} else {
objectsIds.add(currentUserId);
}
}
}
// Examine the paged results control response
Control[] controls = ctx.getResponseControls();
if (controls != null) {
for (int i = 0; i < controls.length; i++) {
if (controls[i] instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
cookie = prrc.getCookie();
}
}
} else {
LOGGER.warn("No controls were sent from the server");
}
// Re-activate paged results
ctx.setRequestControls(new Control[] { new PagedResultsControl(pageSize, cookie, Control.CRITICAL) });
} while (cookie != null);
} catch (Exception e) {
errorDuringSearch = true;
LOGGER.error("PagedSearch failed.", e);
}
return new ConnectorLDAPSearchResult().setDocumentIds(objectsIds).setErrorDuringSearch(errorDuringSearch);
}
static String getSimpleName(String userId) {
String userNameEndingWithCommaAndOtherString = StringUtils.substringBetween(userId, "=", "=");
return StringUtils.substringBeforeLast(userNameEndingWithCommaAndOtherString, ",");
}
private Set<String> getMainContextes(LdapContext ctx)
throws NamingException {
Set<String> returnContextes = new HashSet<>();
Attributes attributes = ctx.getAttributes("", new String[] { "namingContexts" });
Attribute attribute = attributes.get("namingContexts");
NamingEnumeration<?> all = attribute.getAll();
while (all.hasMore()) {
String next = (String) all.next();
String nextWithoutCaps = next.toLowerCase();
if (nextWithoutCaps.startsWith("ou") || nextWithoutCaps.startsWith("dc")) {
returnContextes.add(next);
}
}
return returnContextes;
}
static String computeSearchFilter(String objectCategory, String objectClass) {
if (StringUtils.isNotBlank(objectClass)) {
if (StringUtils.isNotBlank(objectCategory)) {
return "(&(objectCategory=" + objectCategory + ")(objectClass=" + objectClass + "))";
} else {
return "(objectClass=" + objectClass + ")";
}
} else {
if (StringUtils.isNotBlank(objectCategory)) {
return "(objectCategory=" + objectCategory + ")";
}
}
LOGGER.error("Should specify at least one of objectClass, objectCategory; given values were : " + objectClass
+ objectCategory);
throw new InvalidSearchFilterRuntimeException(objectClass, objectCategory);
}
@Override
public Map<String, LDAPObjectAttributes> getObjectsAttributes(LdapContext ctx, Set<String> objectsIds) {
Map<String, LDAPObjectAttributes> returnMap = new HashMap<>();
for (String objectId : objectsIds) {
returnMap.put(objectId, getObjectAttributes(ctx, objectId));
}
return returnMap;
}
@Override
public LDAPObjectAttributes getObjectAttributes(LdapContext ctx, String objectsId) {
Attributes attrs;
try {
attrs = ctx.getAttributes(objectsId, null);
return new LDAPObjectAttributes(attrs);
} catch (NamingException e) {
//TODO
throw new RuntimeException(e);
}
}
@Override
public LdapContext connectToLDAP(String url, String user, String password, Boolean followReferences,
boolean activeDirectory) {
return new LDAPServicesImpl().connectToLDAP(new ArrayList<String>(), url, user, password, followReferences, activeDirectory);
}
@Override
public boolean isObjectEnabled(LDAPObjectAttributes object, DirectoryType directoryType) {
return false;
}
public static class InvalidSearchFilterRuntimeException extends RuntimeException {
public InvalidSearchFilterRuntimeException(
String objectClass, String objectCategory) {
super("Should specify at least one of objectClass, objectCategory; given values were : " + objectClass
+ objectCategory);
}
}
}