Research code for #14

This commit is contained in:
Max Dor
2019-03-08 23:25:49 +01:00
parent 57c7e4a91d
commit 795798ee06
3 changed files with 111 additions and 7 deletions

View File

@@ -72,7 +72,11 @@ public abstract class LdapBackend {
}
protected synchronized LdapConnection getConn() {
return new LdapNetworkConnection(cfg.getConnection().getHost(), cfg.getConnection().getPort(), cfg.getConnection().isTls());
return getConn(cfg.getConnection().getHost());
}
protected synchronized LdapConnection getConn(String host) {
return new LdapNetworkConnection(host, cfg.getConnection().getPort(), cfg.getConnection().isTls());
}
protected void bind(LdapConnection conn) throws LdapException {

View File

@@ -28,6 +28,7 @@ import io.kamax.mxisd.lookup.SingleLookupRequest;
import io.kamax.mxisd.lookup.ThreePidMapping;
import io.kamax.mxisd.lookup.provider.IThreePidProvider;
import io.kamax.mxisd.util.GsonUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.directory.api.ldap.model.cursor.CursorException;
import org.apache.directory.api.ldap.model.cursor.CursorLdapReferralException;
import org.apache.directory.api.ldap.model.cursor.EntryCursor;
@@ -37,8 +38,10 @@ import org.apache.directory.api.ldap.model.message.SearchScope;
import org.apache.directory.ldap.client.api.LdapConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xbill.DNS.*;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -91,7 +94,10 @@ public class LdapThreePidProvider extends LdapBackend implements IThreePidProvid
return Optional.of(buildMatrixIdFromUid(data.get()));
}
} catch (CursorLdapReferralException e) {
log.warn("3PID {} is only available via referral, skipping", value);
log.info("Got referral info: {}", e.getReferralInfo());
return followReferral(medium, value, e.getReferralInfo());
//log.warn("3PID {} is only available via referral, skipping", value);
} catch (IOException | LdapException | CursorException e) {
throw new InternalServerError(e);
}
@@ -104,12 +110,50 @@ public class LdapThreePidProvider extends LdapBackend implements IThreePidProvid
public Optional<SingleLookupReply> find(SingleLookupRequest request) {
log.info("Performing LDAP lookup {} of type {}", request.getThreePid(), request.getType());
try (LdapConnection conn = getConn()) {
bind(conn);
return lookup(conn, request.getType(), request.getThreePid()).map(id -> new SingleLookupReply(request, id));
} catch (LdapException | IOException e) {
throw new InternalServerError(e);
List<String> hosts = new ArrayList<>();
String domain = getCfg().getConnection().getDomain();
if (StringUtils.isNotBlank(domain)) {
try {
Record[] records = new Lookup("_ldap._tcp.DomainDnsZones." + domain, Type.SRV).run();
if (records == null || records.length == 0) {
log.warn("No LDAP server found for domain {}", domain);
return Optional.empty();
}
for (Record record : records) {
if (record instanceof SRVRecord) {
SRVRecord srvRec = (SRVRecord) record;
hosts.add(srvRec.getTarget().toString(true));
}
}
if (hosts.isEmpty()) {
return Optional.empty();
}
} catch (TextParseException e) {
throw new RuntimeException(e);
}
} else {
hosts.add(getCfg().getConnection().getHost());
}
for (String host : hosts) {
log.info("Trying host {}", host);
try (LdapConnection conn = getConn(host)) {
bind(conn);
Optional<SingleLookupReply> reply = lookup(conn, request.getType(), request.getThreePid()).map(id -> new SingleLookupReply(request, id));
if (reply.isPresent()) return reply;
} catch (LdapException | IOException e) {
if (hosts.size() == 1) {
throw new InternalServerError(e);
} else {
log.warn("Unable to query {}: {}", host, e.getMessage());
}
}
}
return Optional.empty();
}
@Override
@@ -137,4 +181,51 @@ public class LdapThreePidProvider extends LdapBackend implements IThreePidProvid
return mappingsFound;
}
private Optional<String> followReferral(String medium, String value, String ref) {
URI uri = URI.create(ref);
Optional<String> tPidQueryOpt = getCfg().getIdentity().getQuery(medium);
if (!tPidQueryOpt.isPresent()) {
log.warn("{} is not a configured 3PID type for LDAP lookup", medium);
return Optional.empty();
}
LdapConnection conn = getConn(uri.getHost());
try {
bind(conn);
} catch (LdapException e) {
throw new RuntimeException(e);
}
// we merge 3PID specific query with global/specific filter, if one exists.
String tPidQuery = tPidQueryOpt.get().replaceAll(getCfg().getIdentity().getToken(), value);
String searchQuery = buildWithFilter(tPidQuery, getCfg().getIdentity().getFilter());
log.debug("Query: {}", searchQuery);
log.debug("Attributes: {}", GsonUtil.build().toJson(getUidAtt()));
try (EntryCursor cursor = conn.search(uri.getPath().substring(1), searchQuery, SearchScope.SUBTREE, getUidAtt())) {
while (cursor.next()) {
Entry entry = cursor.get();
log.info("Found possible match, DN: {}", entry.getDn().getName());
Optional<String> data = getAttribute(entry, getUidAtt());
if (!data.isPresent()) {
continue;
}
log.info("DN {} is a valid match", entry.getDn().getName());
return Optional.of(buildMatrixIdFromUid(data.get()));
}
return Optional.empty();
} catch (CursorLdapReferralException e) {
log.info("Got referral info: {}", e.getReferralInfo());
return followReferral(medium, value, e.getReferralInfo());
//log.warn("3PID {} is only available via referral, skipping", value);
} catch (IOException | LdapException | CursorException e) {
throw new InternalServerError(e);
}
}
}

View File

@@ -125,6 +125,7 @@ public abstract class LdapConfig {
private boolean tls = false;
private String host;
private String domain;
private int port = 389;
private String bindDn;
private String bindPassword;
@@ -147,6 +148,14 @@ public abstract class LdapConfig {
this.host = host;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
public int getPort() {
return port;
}