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