diff --git a/src/main/java/io/kamax/mxisd/backend/ldap/LdapAuthProvider.java b/src/main/java/io/kamax/mxisd/backend/ldap/LdapAuthProvider.java
index 64f38bc..73c3ade 100644
--- a/src/main/java/io/kamax/mxisd/backend/ldap/LdapAuthProvider.java
+++ b/src/main/java/io/kamax/mxisd/backend/ldap/LdapAuthProvider.java
@@ -24,6 +24,8 @@ import io.kamax.matrix._MatrixID;
import io.kamax.mxisd.UserIdType;
import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
import io.kamax.mxisd.auth.provider.BackendAuthResult;
+import io.kamax.mxisd.config.MatrixConfig;
+import io.kamax.mxisd.config.ldap.LdapConfig;
import org.apache.commons.lang.StringUtils;
import org.apache.directory.api.ldap.model.cursor.CursorException;
import org.apache.directory.api.ldap.model.cursor.CursorLdapReferralException;
@@ -35,6 +37,7 @@ 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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
@@ -44,8 +47,9 @@ public class LdapAuthProvider extends LdapGenericBackend implements Authenticato
private Logger log = LoggerFactory.getLogger(LdapAuthProvider.class);
- private String getUidAttribute() {
- return getCfg().getAttribute().getUid().getValue();
+ @Autowired
+ public LdapAuthProvider(LdapConfig cfg, MatrixConfig mxCfg) {
+ super(cfg, mxCfg);
}
@Override
@@ -57,37 +61,34 @@ public class LdapAuthProvider extends LdapGenericBackend implements Authenticato
public BackendAuthResult authenticate(_MatrixID mxid, String password) {
log.info("Performing auth for {}", mxid);
- LdapConnection conn = getConn();
- try {
+
+ try (LdapConnection conn = getConn()) {
bind(conn);
- String uidType = getCfg().getAttribute().getUid().getType();
- String userFilterValue = StringUtils.equals(LdapThreePidProvider.UID, uidType) ? mxid.getLocalPart() : mxid.getId();
+ String uidType = getAt().getUid().getType();
+ String userFilterValue = StringUtils.equals(LdapGenericBackend.UID, uidType) ? mxid.getLocalPart() : mxid.getId();
if (StringUtils.isBlank(userFilterValue)) {
log.warn("Username is empty, failing auth");
return BackendAuthResult.failure();
}
String userFilter = "(" + getCfg().getAttribute().getUid().getValue() + "=" + userFilterValue + ")";
- if (!StringUtils.isBlank(getCfg().getAuth().getFilter())) {
- userFilter = "(&" + getCfg().getAuth().getFilter() + userFilter + ")";
- }
- EntryCursor cursor = conn.search(getCfg().getConn().getBaseDn(), userFilter, SearchScope.SUBTREE, getUidAttribute(), getCfg().getAttribute().getName());
- try {
+ userFilter = buildWithFilter(userFilter, getCfg().getAuth().getFilter());
+ try (EntryCursor cursor = conn.search(getBaseDn(), userFilter, SearchScope.SUBTREE, getUidAtt(), getAt().getName())) {
while (cursor.next()) {
Entry entry = cursor.get();
String dn = entry.getDn().getName();
log.info("Checking possible match, DN: {}", dn);
- Attribute attribute = entry.get(getUidAttribute());
+ Attribute attribute = entry.get(getUidAtt());
if (attribute == null) {
- log.info("DN {}: no attribute {}, skpping", dn, getUidAttribute());
+ log.info("DN {}: no attribute {}, skpping", dn, getUidAtt());
continue;
}
String data = attribute.get().toString();
if (data.length() < 1) {
- log.info("DN {}: empty attribute {}, skipping", getUidAttribute());
+ log.info("DN {}: empty attribute {}, skipping", getUidAtt());
continue;
}
@@ -99,7 +100,7 @@ public class LdapAuthProvider extends LdapGenericBackend implements Authenticato
return BackendAuthResult.failure();
}
- Attribute nameAttribute = entry.get(getCfg().getAttribute().getName());
+ Attribute nameAttribute = entry.get(getAt().getName());
String name = nameAttribute != null ? nameAttribute.get().toString() : null;
log.info("Authentication successful for {}", entry.getDn().getName());
@@ -110,20 +111,12 @@ public class LdapAuthProvider extends LdapGenericBackend implements Authenticato
}
} catch (CursorLdapReferralException e) {
log.warn("Entity for {} is only available via referral, skipping", mxid);
- } finally {
- cursor.close();
}
log.info("No match were found for {}", mxid);
return BackendAuthResult.failure();
} catch (LdapException | IOException | CursorException e) {
throw new RuntimeException(e);
- } finally {
- try {
- conn.close();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
}
}
diff --git a/src/main/java/io/kamax/mxisd/backend/ldap/LdapDirectoryProvider.java b/src/main/java/io/kamax/mxisd/backend/ldap/LdapDirectoryProvider.java
new file mode 100644
index 0000000..2c25b3f
--- /dev/null
+++ b/src/main/java/io/kamax/mxisd/backend/ldap/LdapDirectoryProvider.java
@@ -0,0 +1,116 @@
+/*
+ * mxisd - Matrix Identity Server Daemon
+ * Copyright (C) 2017 Maxime Dor
+ *
+ * https://max.kamax.io/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package io.kamax.mxisd.backend.ldap;
+
+import io.kamax.mxisd.config.MatrixConfig;
+import io.kamax.mxisd.config.ldap.LdapAttributeConfig;
+import io.kamax.mxisd.config.ldap.LdapConfig;
+import io.kamax.mxisd.controller.directory.io.UserDirectorySearchResult;
+import io.kamax.mxisd.directory.IDirectoryProvider;
+import io.kamax.mxisd.exception.InternalServerError;
+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;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+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.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Component
+public class LdapDirectoryProvider extends LdapGenericBackend implements IDirectoryProvider {
+
+ private Logger log = LoggerFactory.getLogger(LdapDirectoryProvider.class);
+
+ @Autowired
+ public LdapDirectoryProvider(LdapConfig cfg, MatrixConfig mxCfg) {
+ super(cfg, mxCfg);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return getCfg().isEnabled();
+ }
+
+ protected UserDirectorySearchResult search(String query, List attributes) {
+ UserDirectorySearchResult result = new UserDirectorySearchResult();
+ result.setLimited(false);
+
+ try (LdapConnection conn = getConn()) {
+ bind(conn);
+
+ LdapAttributeConfig atCfg = getCfg().getAttribute();
+
+ attributes = new ArrayList<>(attributes);
+ attributes.add(getUidAtt());
+ String[] attArray = new String[attributes.size()];
+ attributes.toArray(attArray);
+
+ String searchQuery = buildOrQueryWithFilter(getCfg().getDirectory().getFilter(), "*" + query + "*", attArray);
+ try (EntryCursor cursor = conn.search(getBaseDn(), searchQuery, SearchScope.SUBTREE, attArray)) {
+ while (cursor.next()) {
+ Entry entry = cursor.get();
+ log.info("Found possible match, DN: {}", entry.getDn().getName());
+ getAttribute(entry, getUidAtt()).ifPresent(uid -> {
+ log.info("DN {} is a valid match", entry.getDn().getName());
+ try {
+ UserDirectorySearchResult.Result entryResult = new UserDirectorySearchResult.Result();
+ entryResult.setUserId(buildMatrixIdFromUid(uid));
+ getAttribute(entry, atCfg.getName()).ifPresent(entryResult::setDisplayName);
+ result.addResult(entryResult);
+ } catch (IllegalArgumentException e) {
+ log.warn("Bind was found but type {} is not supported", atCfg.getUid().getType());
+ }
+ });
+ }
+ }
+ } catch (CursorLdapReferralException e) {
+ log.warn("An entry is only available via referral, skipping");
+ } catch (IOException | LdapException | CursorException e) {
+ throw new InternalServerError(e);
+ }
+
+ return result;
+ }
+
+ @Override
+ public UserDirectorySearchResult searchByDisplayName(String query) {
+ log.info("Performing LDAP directory search on display name using '{}'", query);
+ return search(query, Collections.singletonList(getCfg().getAttribute().getName()));
+ }
+
+ @Override
+ public UserDirectorySearchResult searchBy3pid(String query) {
+ log.info("Performing LDAP directory search on 3PIDs using '{}'", query);
+ List attributes = new ArrayList<>();
+ getCfg().getAttribute().getThreepid().forEach((k, v) -> attributes.addAll(v));
+ return search(query, attributes);
+ }
+
+}
diff --git a/src/main/java/io/kamax/mxisd/backend/ldap/LdapGenericBackend.java b/src/main/java/io/kamax/mxisd/backend/ldap/LdapGenericBackend.java
index ff9a7de..b87d503 100644
--- a/src/main/java/io/kamax/mxisd/backend/ldap/LdapGenericBackend.java
+++ b/src/main/java/io/kamax/mxisd/backend/ldap/LdapGenericBackend.java
@@ -20,38 +20,112 @@
package io.kamax.mxisd.backend.ldap;
+import io.kamax.mxisd.config.MatrixConfig;
+import io.kamax.mxisd.config.ldap.LdapAttributeConfig;
import io.kamax.mxisd.config.ldap.LdapConfig;
import org.apache.commons.lang.StringUtils;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
import org.apache.directory.api.ldap.model.exception.LdapException;
import org.apache.directory.ldap.client.api.LdapConnection;
import org.apache.directory.ldap.client.api.LdapNetworkConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-@Component
-public class LdapGenericBackend {
+import java.util.Arrays;
+import java.util.Optional;
+
+public abstract class LdapGenericBackend {
+
+ public static final String UID = "uid";
+ public static final String MATRIX_ID = "mxid";
private Logger log = LoggerFactory.getLogger(LdapGenericBackend.class);
- @Autowired
- private LdapConfig ldapCfg;
+ private LdapConfig cfg;
+ private MatrixConfig mxCfg;
- protected LdapConnection getConn() {
- return new LdapNetworkConnection(ldapCfg.getConn().getHost(), ldapCfg.getConn().getPort(), ldapCfg.getConn().isTls());
- }
-
- protected void bind(LdapConnection conn) throws LdapException {
- if (StringUtils.isBlank(ldapCfg.getConn().getBindDn()) && StringUtils.isBlank(ldapCfg.getConn().getBindPassword())) {
- conn.anonymousBind();
- } else {
- conn.bind(ldapCfg.getConn().getBindDn(), ldapCfg.getConn().getBindPassword());
- }
+ public LdapGenericBackend(LdapConfig cfg, MatrixConfig mxCfg) {
+ this.cfg = cfg;
+ this.mxCfg = mxCfg;
}
protected LdapConfig getCfg() {
- return ldapCfg;
+ return cfg;
+ }
+
+ protected String getBaseDn() {
+ return cfg.getConn().getBaseDn();
+ }
+
+ protected LdapAttributeConfig getAt() {
+ return cfg.getAttribute();
+ }
+
+ protected String getUidAtt() {
+ return getAt().getUid().getValue();
+ }
+
+ protected LdapConnection getConn() {
+ return new LdapNetworkConnection(cfg.getConn().getHost(), cfg.getConn().getPort(), cfg.getConn().isTls());
+ }
+
+ protected void bind(LdapConnection conn) throws LdapException {
+ if (StringUtils.isBlank(cfg.getConn().getBindDn()) && StringUtils.isBlank(cfg.getConn().getBindPassword())) {
+ conn.anonymousBind();
+ } else {
+ conn.bind(cfg.getConn().getBindDn(), cfg.getConn().getBindPassword());
+ }
+ }
+
+ protected String buildWithFilter(String base, String filter) {
+ if (StringUtils.isBlank(filter)) {
+ return base;
+ } else {
+ return "(&" + filter + base + ")";
+ }
+ }
+
+ public static String buildOrQuery(String value, String... attributes) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("(|");
+ Arrays.stream(attributes).forEach(s -> {
+ builder.append("(");
+ builder.append(s).append("=").append(value).append(")");
+ });
+ builder.append(")");
+ return builder.toString();
+ }
+
+ public String buildOrQueryWithFilter(String filter, String value, String... attributes) {
+ return buildWithFilter(buildOrQuery(value, attributes), filter);
+ }
+
+ public String buildMatrixIdFromUid(String uid) {
+ String uidType = getCfg().getAttribute().getUid().getType();
+ if (StringUtils.equals(UID, uidType)) {
+ return "@" + uid + ":" + mxCfg.getDomain();
+ } else if (StringUtils.equals(MATRIX_ID, uidType)) {
+ return uid;
+ } else {
+ throw new IllegalArgumentException("Bind type " + uidType + " is not supported");
+ }
+ }
+
+ public Optional getAttribute(Entry entry, String attName) {
+ Attribute attribute = entry.get(attName);
+ if (attribute == null) {
+ log.info("DN {}: no attribute {}, skipping", entry.getDn(), attName);
+ return Optional.empty();
+ }
+
+ String value = attribute.get().toString();
+ if (StringUtils.isBlank(value)) {
+ log.info("DN {}: empty attribute {}, skipping", attName);
+ return Optional.empty();
+ }
+
+ return Optional.of(value);
}
}
diff --git a/src/main/java/io/kamax/mxisd/backend/ldap/LdapThreePidProvider.java b/src/main/java/io/kamax/mxisd/backend/ldap/LdapThreePidProvider.java
index 5dbf139..9715ac4 100644
--- a/src/main/java/io/kamax/mxisd/backend/ldap/LdapThreePidProvider.java
+++ b/src/main/java/io/kamax/mxisd/backend/ldap/LdapThreePidProvider.java
@@ -21,23 +21,21 @@
package io.kamax.mxisd.backend.ldap;
import io.kamax.mxisd.config.MatrixConfig;
+import io.kamax.mxisd.config.ldap.LdapConfig;
import io.kamax.mxisd.exception.InternalServerError;
import io.kamax.mxisd.lookup.SingleLookupReply;
import io.kamax.mxisd.lookup.SingleLookupRequest;
import io.kamax.mxisd.lookup.ThreePidMapping;
import io.kamax.mxisd.lookup.provider.IThreePidProvider;
-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;
-import org.apache.directory.api.ldap.model.entry.Attribute;
import org.apache.directory.api.ldap.model.entry.Entry;
import org.apache.directory.api.ldap.model.exception.LdapException;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
@@ -48,23 +46,17 @@ import java.util.Optional;
@Component
public class LdapThreePidProvider extends LdapGenericBackend implements IThreePidProvider {
- public static final String UID = "uid";
- public static final String MATRIX_ID = "mxid";
-
private Logger log = LoggerFactory.getLogger(LdapThreePidProvider.class);
- @Autowired
- private MatrixConfig mxCfg;
+ public LdapThreePidProvider(LdapConfig cfg, MatrixConfig mxCfg) {
+ super(cfg, mxCfg);
+ }
@Override
public boolean isEnabled() {
return getCfg().isEnabled();
}
- private String getUidAttribute() {
- return getCfg().getAttribute().getUid().getValue();
- }
-
@Override
public boolean isLocal() {
return true;
@@ -76,46 +68,22 @@ public class LdapThreePidProvider extends LdapGenericBackend implements IThreePi
}
private Optional lookup(LdapConnection conn, String medium, String value) {
- String uidAttribute = getUidAttribute();
-
Optional queryOpt = getCfg().getIdentity().getQuery(medium);
if (!queryOpt.isPresent()) {
log.warn("{} is not a configured 3PID type for LDAP lookup", medium);
return Optional.empty();
}
- String searchQuery = queryOpt.get().replaceAll("%3pid", value);
- try (EntryCursor cursor = conn.search(getCfg().getConn().getBaseDn(), searchQuery, SearchScope.SUBTREE, uidAttribute)) {
+ String searchQuery = queryOpt.get().replaceAll(getCfg().getIdentity().getToken(), value);
+ try (EntryCursor cursor = conn.search(getBaseDn(), searchQuery, SearchScope.SUBTREE, getUidAtt())) {
while (cursor.next()) {
Entry entry = cursor.get();
log.info("Found possible match, DN: {}", entry.getDn().getName());
- Attribute attribute = entry.get(uidAttribute);
- if (attribute == null) {
- log.info("DN {}: no attribute {}, skpping", entry.getDn(), getCfg().getAttribute());
- continue;
- }
-
- String data = attribute.get().toString();
- if (data.length() < 1) {
- log.info("DN {}: empty attribute {}, skipping", getCfg().getAttribute());
- continue;
- }
-
- StringBuilder matrixId = new StringBuilder();
- // TODO Should we turn this block into a map of functions?
- String uidType = getCfg().getAttribute().getUid().getType();
- if (StringUtils.equals(UID, uidType)) {
- matrixId.append("@").append(data).append(":").append(mxCfg.getDomain());
- } else if (StringUtils.equals(MATRIX_ID, uidType)) {
- matrixId.append(data);
- } else {
- log.warn("Bind was found but type {} is not supported", uidType);
- continue;
- }
-
- log.info("DN {} is a valid match", entry.getDn().getName());
- return Optional.of(matrixId.toString());
+ getAttribute(entry, getUidAtt()).map(uid -> {
+ log.info("DN {} is a valid match", entry.getDn().getName());
+ return buildMatrixIdFromUid(uid);
+ });
}
} catch (CursorLdapReferralException e) {
log.warn("3PID {} is only available via referral, skipping", value);
@@ -128,15 +96,11 @@ public class LdapThreePidProvider extends LdapGenericBackend implements IThreePi
@Override
public Optional find(SingleLookupRequest request) {
- log.info("Performing LDAP lookup ${request.getThreePid()} of type ${request.getType()}");
+ log.info("Performing LDAP lookup {} of type {}", request.getThreePid(), request.getType());
try (LdapConnection conn = getConn()) {
bind(conn);
-
- Optional mxid = lookup(conn, request.getType(), request.getThreePid());
- if (mxid.isPresent()) {
- return Optional.of(new SingleLookupReply(request, mxid.get()));
- }
+ lookup(conn, request.getType(), request.getThreePid()).map(id -> new SingleLookupReply(request, id));
} catch (LdapException | IOException e) {
throw new InternalServerError(e);
}
@@ -155,11 +119,10 @@ public class LdapThreePidProvider extends LdapGenericBackend implements IThreePi
for (ThreePidMapping mapping : mappings) {
try {
- Optional mxid = lookup(conn, mapping.getMedium(), mapping.getValue());
- if (mxid.isPresent()) {
- mapping.setMxid(mxid.get());
+ lookup(conn, mapping.getMedium(), mapping.getValue()).ifPresent(id -> {
+ mapping.setMxid(id);
mappingsFound.add(mapping);
- }
+ });
} catch (IllegalArgumentException e) {
log.warn("{} is not a supported 3PID type for LDAP lookup", mapping.getMedium());
}
diff --git a/src/main/java/io/kamax/mxisd/config/ldap/LdapAttributeConfig.java b/src/main/java/io/kamax/mxisd/config/ldap/LdapAttributeConfig.java
index 9ef4324..fb01de5 100644
--- a/src/main/java/io/kamax/mxisd/config/ldap/LdapAttributeConfig.java
+++ b/src/main/java/io/kamax/mxisd/config/ldap/LdapAttributeConfig.java
@@ -23,12 +23,17 @@ package io.kamax.mxisd.config.ldap;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
@Configuration
@ConfigurationProperties(prefix = "ldap.attribute")
public class LdapAttributeConfig {
private LdapAttributeUidConfig uid;
private String name;
+ private Map> threepid = new HashMap<>();
public LdapAttributeUidConfig getUid() {
return uid;
@@ -46,4 +51,12 @@ public class LdapAttributeConfig {
this.name = name;
}
+ public Map> getThreepid() {
+ return threepid;
+ }
+
+ public void setThreepid(Map> threepid) {
+ this.threepid = threepid;
+ }
+
}
diff --git a/src/main/java/io/kamax/mxisd/config/ldap/LdapConfig.java b/src/main/java/io/kamax/mxisd/config/ldap/LdapConfig.java
index fa9c72c..9c4f9d7 100644
--- a/src/main/java/io/kamax/mxisd/config/ldap/LdapConfig.java
+++ b/src/main/java/io/kamax/mxisd/config/ldap/LdapConfig.java
@@ -21,7 +21,9 @@
package io.kamax.mxisd.config.ldap;
import com.google.gson.Gson;
-import io.kamax.mxisd.backend.ldap.LdapThreePidProvider;
+import io.kamax.matrix.ThreePidMedium;
+import io.kamax.mxisd.backend.ldap.LdapGenericBackend;
+import io.kamax.mxisd.exception.ConfigurationException;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,16 +37,31 @@ import javax.annotation.PostConstruct;
@ConfigurationProperties(prefix = "ldap")
public class LdapConfig {
+ private Logger log = LoggerFactory.getLogger(LdapConfig.class);
private static Gson gson = new Gson();
- private Logger log = LoggerFactory.getLogger(LdapConfig.class);
-
private boolean enabled;
+ private String filter;
+
+ public static class Directory {
+
+ private String filter;
+
+ public String getFilter() {
+ return filter;
+ }
+
+ public void setFilter(String filter) {
+ this.filter = filter;
+ }
+
+ }
@Autowired
private LdapConnectionConfig conn;
private LdapAttributeConfig attribute;
private LdapAuthConfig auth;
+ private Directory directory;
private LdapIdentityConfig identity;
public boolean isEnabled() {
@@ -55,6 +72,14 @@ public class LdapConfig {
this.enabled = enabled;
}
+ public String getFilter() {
+ return filter;
+ }
+
+ public void setFilter(String filter) {
+ this.filter = filter;
+ }
+
public LdapConnectionConfig getConn() {
return conn;
}
@@ -79,6 +104,14 @@ public class LdapConfig {
this.auth = auth;
}
+ public Directory getDirectory() {
+ return directory;
+ }
+
+ public void setDirectory(Directory directory) {
+ this.directory = directory;
+ }
+
public LdapIdentityConfig getIdentity() {
return identity;
}
@@ -100,7 +133,7 @@ public class LdapConfig {
throw new IllegalStateException("LDAP Host must be configured!");
}
- if (1 > conn.getPort() || 65535 < conn.getPort()) {
+ if (conn.getPort() < 1 || conn.getPort() > 65535) {
throw new IllegalStateException("LDAP port is not valid");
}
@@ -114,10 +147,29 @@ public class LdapConfig {
}
String uidType = attribute.getUid().getType();
- if (!StringUtils.equals(LdapThreePidProvider.UID, uidType) && !StringUtils.equals(LdapThreePidProvider.MATRIX_ID, uidType)) {
+ if (!StringUtils.equals(LdapGenericBackend.UID, uidType) && !StringUtils.equals(LdapGenericBackend.MATRIX_ID, uidType)) {
throw new IllegalArgumentException("Unsupported LDAP UID type: " + uidType);
}
+ if (StringUtils.isBlank(identity.getToken())) {
+ throw new ConfigurationException("ldap.identity.token");
+ }
+
+ // Build queries
+ attribute.getThreepid().forEach((k, v) -> {
+ if (StringUtils.isBlank(identity.getMedium().get(k))) {
+ if (ThreePidMedium.PhoneNumber.is(k)) {
+ identity.getMedium().put(k, LdapGenericBackend.buildOrQuery("+" + getIdentity().getToken()));
+ } else {
+ identity.getMedium().put(k, LdapGenericBackend.buildOrQuery(getIdentity().getToken()));
+ }
+ }
+ });
+
+ getAuth().setFilter(StringUtils.defaultIfBlank(getAuth().getFilter(), getFilter()));
+ getDirectory().setFilter(StringUtils.defaultIfBlank(getDirectory().getFilter(), getFilter()));
+ getIdentity().setFilter(StringUtils.defaultIfBlank(getIdentity().getFilter(), getFilter()));
+
log.info("Host: {}", conn.getHost());
log.info("Port: {}", conn.getPort());
log.info("Bind DN: {}", conn.getBindDn());
@@ -125,6 +177,7 @@ public class LdapConfig {
log.info("Attribute: {}", gson.toJson(attribute));
log.info("Auth: {}", gson.toJson(auth));
+ log.info("Directory: {}", gson.toJson(directory));
log.info("Identity: {}", gson.toJson(identity));
}
diff --git a/src/main/java/io/kamax/mxisd/config/ldap/LdapIdentityConfig.java b/src/main/java/io/kamax/mxisd/config/ldap/LdapIdentityConfig.java
index 749530f..8bc4110 100644
--- a/src/main/java/io/kamax/mxisd/config/ldap/LdapIdentityConfig.java
+++ b/src/main/java/io/kamax/mxisd/config/ldap/LdapIdentityConfig.java
@@ -31,8 +31,26 @@ import java.util.Optional;
@ConfigurationProperties(prefix = "ldap.identity")
public class LdapIdentityConfig {
+ private String filter;
+ private String token = "%3pid";
private Map medium = new HashMap<>();
+ public String getFilter() {
+ return filter;
+ }
+
+ public void setFilter(String filter) {
+ this.filter = filter;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(String token) {
+ this.token = token;
+ }
+
public Map getMedium() {
return medium;
}
diff --git a/src/main/java/io/kamax/mxisd/controller/DefaultExceptionHandler.java b/src/main/java/io/kamax/mxisd/controller/DefaultExceptionHandler.java
index 79b1242..e170f8b 100644
--- a/src/main/java/io/kamax/mxisd/controller/DefaultExceptionHandler.java
+++ b/src/main/java/io/kamax/mxisd/controller/DefaultExceptionHandler.java
@@ -45,65 +45,66 @@ public class DefaultExceptionHandler {
private static Gson gson = new Gson();
- static String handle(String erroCode, String error) {
+ private String handle(HttpServletRequest req, String erroCode, String error) {
JsonObject obj = new JsonObject();
obj.addProperty("errcode", erroCode);
obj.addProperty("error", error);
obj.addProperty("success", false);
+ log.info("Request {} {} - Error {}: {}", req.getMethod(), req.getRequestURL(), erroCode, error);
return gson.toJson(obj);
}
@ExceptionHandler(InternalServerError.class)
- public String handle(InternalServerError e, HttpServletResponse response) {
+ public String handle(HttpServletRequest req, InternalServerError e, HttpServletResponse response) {
if (StringUtils.isNotBlank(e.getInternalReason())) {
log.error("Reference #{} - {}", e.getReference(), e.getInternalReason());
} else {
log.error("Reference #{}", e);
}
- return handleGeneric(e, response);
+ return handleGeneric(req, e, response);
}
@ExceptionHandler(MatrixException.class)
- public String handleGeneric(MatrixException e, HttpServletResponse response) {
+ public String handleGeneric(HttpServletRequest req, MatrixException e, HttpServletResponse response) {
response.setStatus(e.getStatus());
- return handle(e.getErrorCode(), e.getError());
+ return handle(req, e.getErrorCode(), e.getError());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MissingServletRequestParameterException.class)
- public String handle(MissingServletRequestParameterException e) {
- return handle("M_INCOMPLETE_REQUEST", e.getMessage());
+ public String handle(HttpServletRequest req, MissingServletRequestParameterException e) {
+ return handle(req, "M_INCOMPLETE_REQUEST", e.getMessage());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(InvalidResponseJsonException.class)
- public String handle(InvalidResponseJsonException e) {
- return handle("M_INVALID_JSON", e.getMessage());
+ public String handle(HttpServletRequest req, InvalidResponseJsonException e) {
+ return handle(req, "M_INVALID_JSON", e.getMessage());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(JsonSyntaxException.class)
- public String handle(JsonSyntaxException e) {
- return handle("M_INVALID_JSON", e.getMessage());
+ public String handle(HttpServletRequest req, JsonSyntaxException e) {
+ return handle(req, "M_INVALID_JSON", e.getMessage());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(JsonMemberNotFoundException.class)
- public String handle(JsonMemberNotFoundException e) {
- return handle("M_JSON_MISSING_KEYS", e.getMessage());
+ public String handle(HttpServletRequest req, JsonMemberNotFoundException e) {
+ return handle(req, "M_JSON_MISSING_KEYS", e.getMessage());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MappingAlreadyExistsException.class)
- public String handle(MappingAlreadyExistsException e) {
- return handle("M_ALREADY_EXISTS", e.getMessage());
+ public String handle(HttpServletRequest req, MappingAlreadyExistsException e) {
+ return handle(req, "M_ALREADY_EXISTS", e.getMessage());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(BadRequestException.class)
- public String handle(BadRequestException e) {
- return handle("M_BAD_REQUEST", e.getMessage());
+ public String handle(HttpServletRequest req, BadRequestException e) {
+ return handle(req, "M_BAD_REQUEST", e.getMessage());
}
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@@ -111,6 +112,7 @@ public class DefaultExceptionHandler {
public String handle(HttpServletRequest req, RuntimeException e) {
log.error("Unknown error when handling {}", req.getRequestURL(), e);
return handle(
+ req,
"M_UNKNOWN",
StringUtils.defaultIfBlank(
e.getMessage(),
diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml
index 7054d0a..708c83d 100644
--- a/src/main/resources/application.yaml
+++ b/src/main/resources/application.yaml
@@ -44,6 +44,7 @@ rest:
ldap:
enabled: false
+ filter: ''
connection:
tls: false
port: 389
@@ -52,10 +53,27 @@ ldap:
type: 'uid'
value: 'userPrincipalName'
name: 'displayName'
+ threepid:
+ email:
+ - 'mailPrimaryAddress'
+ - 'mail'
+ - 'otherMailbox'
+ msisdn:
+ - 'telephoneNumber'
+ - 'mobile'
+ - 'homePhone'
+ - 'otherTelephone'
+ - 'otherMobile'
+ - 'otherHomePhone'
+ auth:
+ filter: ''
+ directory:
+ filter: ''
identity:
+ filter: ''
medium:
- email: "(|(mailPrimaryAddress=%3pid)(mail=%3pid)(otherMailbox=%3pid))"
- msisdn: "(|(telephoneNumber=+%3pid)(mobile=+%3pid)(homePhone=+%3pid)(otherTelephone=+%3pid)(otherMobile=+%3pid)(otherHomePhone=+%3pid))"
+ email: ''
+ msisdn: ''
firebase:
enabled: false