Add LDAP Auth support with synapse REST Auth module
This commit is contained in:
@@ -158,6 +158,8 @@ ldap:
|
||||
# If this value is not set, login check will be performed for all entities within the LDAP
|
||||
#
|
||||
# Example: (memberOf=CN=Matrix Users,CN=Users,DC=example,DC=org)
|
||||
#
|
||||
# /!\ Currently NOT supported due to a possible bug in LDAP library /!\
|
||||
filter: ''
|
||||
|
||||
# Configuration section relating to identity lookups
|
||||
|
@@ -47,7 +47,7 @@ dependencies {
|
||||
compile 'org.springframework.boot:spring-boot-starter-web:1.5.3.RELEASE'
|
||||
|
||||
// Matrix Java SDK
|
||||
compile 'io.kamax:matrix-java-sdk:0.0.1'
|
||||
compile 'io.kamax:matrix-java-sdk:0.0.2'
|
||||
|
||||
// ed25519 handling
|
||||
compile 'net.i2p.crypto:eddsa:0.1.0'
|
||||
|
@@ -14,10 +14,12 @@ public class UserAuthResult {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void success(String mxid, String displayName) {
|
||||
public UserAuthResult success(String mxid, String displayName) {
|
||||
setSuccess(true);
|
||||
setMxid(mxid);
|
||||
setDisplayName(displayName);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
|
@@ -0,0 +1,115 @@
|
||||
package io.kamax.mxisd.auth.provider;
|
||||
|
||||
import io.kamax.matrix.MatrixID;
|
||||
import io.kamax.mxisd.auth.UserAuthResult;
|
||||
import io.kamax.mxisd.config.ldap.LdapConfig;
|
||||
import io.kamax.mxisd.lookup.provider.LdapProvider;
|
||||
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.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;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
public class LdapAuthProvider implements AuthenticatorProvider {
|
||||
|
||||
private Logger log = LoggerFactory.getLogger(LdapAuthProvider.class);
|
||||
|
||||
@Autowired
|
||||
private LdapConfig ldapCfg;
|
||||
|
||||
private LdapConnection getConn() {
|
||||
return new LdapNetworkConnection(ldapCfg.getConn().getHost(), ldapCfg.getConn().getPort(), ldapCfg.getConn().isTls());
|
||||
}
|
||||
|
||||
private void bind(LdapConnection conn) throws LdapException {
|
||||
conn.bind(ldapCfg.getConn().getBindDn(), ldapCfg.getConn().getBindPassword());
|
||||
}
|
||||
|
||||
private String getUidAttribute() {
|
||||
return ldapCfg.getAttribute().getUid().getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return ldapCfg.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserAuthResult authenticate(String id, String password) {
|
||||
log.info("Performing auth for {}", id);
|
||||
|
||||
LdapConnection conn = getConn();
|
||||
try {
|
||||
bind(conn);
|
||||
|
||||
String uidType = ldapCfg.getAttribute().getUid().getType();
|
||||
MatrixID mxIdExt = new MatrixID(id);
|
||||
String userFilterValue = StringUtils.equals(LdapProvider.UID, uidType) ? mxIdExt.getLocalPart() : mxIdExt.getId();
|
||||
String userFilter = "(" + ldapCfg.getAttribute().getUid().getValue() + "=" + userFilterValue + ")";
|
||||
EntryCursor cursor = conn.search(ldapCfg.getConn().getBaseDn(), userFilter, SearchScope.SUBTREE, getUidAttribute(), ldapCfg.getAttribute().getName());
|
||||
try {
|
||||
while (cursor.next()) {
|
||||
Entry entry = cursor.get();
|
||||
String dn = entry.getDn().getName();
|
||||
log.info("Checking possible match, DN: {}", dn);
|
||||
|
||||
Attribute attribute = entry.get(getUidAttribute());
|
||||
if (attribute == null) {
|
||||
log.info("DN {}: no attribute {}, skpping", dn, getUidAttribute());
|
||||
continue;
|
||||
}
|
||||
|
||||
String data = attribute.get().toString();
|
||||
if (data.length() < 1) {
|
||||
log.info("DN {}: empty attribute {}, skipping", getUidAttribute());
|
||||
continue;
|
||||
}
|
||||
|
||||
log.info("Attempting authentication on LDAP for {}", dn);
|
||||
try {
|
||||
conn.bind(entry.getDn(), password);
|
||||
} catch (LdapException e) {
|
||||
log.info("Unable to bind using {} because {}", entry.getDn().getName(), e.getMessage());
|
||||
return new UserAuthResult().failure();
|
||||
}
|
||||
|
||||
Attribute nameAttribute = entry.get(ldapCfg.getAttribute().getName());
|
||||
String name = nameAttribute != null ? nameAttribute.get().toString() : null;
|
||||
|
||||
log.info("Authentication successful for {}", entry.getDn().getName());
|
||||
log.info("DN {} is a valid match", dn);
|
||||
|
||||
return new UserAuthResult().success(mxIdExt.getId(), name);
|
||||
}
|
||||
} catch (CursorLdapReferralException e) {
|
||||
log.warn("Entity for {} is only available via referral, skipping", mxIdExt);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
log.info("No match were found for {}", id);
|
||||
return new UserAuthResult().failure();
|
||||
} catch (LdapException | IOException | CursorException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,8 +1,12 @@
|
||||
package io.kamax.mxisd.config.ldap;
|
||||
|
||||
import io.kamax.mxisd.lookup.provider.LdapProvider;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "ldap.attribute.uid")
|
||||
public class LdapAttributeUidConfig {
|
||||
@@ -26,4 +30,11 @@ public class LdapAttributeUidConfig {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
if (!StringUtils.equals(LdapProvider.UID, getType()) && !StringUtils.equals(LdapProvider.MATRIX_ID, getType())) {
|
||||
throw new IllegalArgumentException("Unsupported LDAP UID type: " + getType());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -20,8 +20,6 @@
|
||||
|
||||
package io.kamax.mxisd.lookup.provider
|
||||
|
||||
import io.kamax.mxisd.auth.UserAuthResult
|
||||
import io.kamax.mxisd.auth.provider.AuthenticatorProvider
|
||||
import io.kamax.mxisd.config.ServerConfig
|
||||
import io.kamax.mxisd.config.ldap.LdapConfig
|
||||
import io.kamax.mxisd.lookup.SingleLookupRequest
|
||||
@@ -40,7 +38,7 @@ import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class LdapProvider implements IThreePidProvider, AuthenticatorProvider {
|
||||
class LdapProvider implements IThreePidProvider {
|
||||
|
||||
public static final String UID = "uid"
|
||||
public static final String MATRIX_ID = "mxid"
|
||||
@@ -66,17 +64,8 @@ class LdapProvider implements IThreePidProvider, AuthenticatorProvider {
|
||||
conn.bind(ldapCfg.getConn().getBindDn(), ldapCfg.getConn().getBindPassword())
|
||||
}
|
||||
|
||||
@Override
|
||||
UserAuthResult authenticate(String id, String password) {
|
||||
LdapConnection conn = getConn()
|
||||
try {
|
||||
bind(conn)
|
||||
|
||||
// TODO finish this
|
||||
return new UserAuthResult().failure()
|
||||
} finally {
|
||||
conn.close()
|
||||
}
|
||||
private String getUidAttribute() {
|
||||
return ldapCfg.getAttribute().getUid().getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -90,7 +79,7 @@ class LdapProvider implements IThreePidProvider, AuthenticatorProvider {
|
||||
}
|
||||
|
||||
Optional<String> lookup(LdapConnection conn, String medium, String value) {
|
||||
String uidAttribute = ldapCfg.getAttribute().getUid().getValue()
|
||||
String uidAttribute = getUidAttribute()
|
||||
|
||||
Optional<String> queryOpt = ldapCfg.getIdentity().getQuery(medium)
|
||||
if (!queryOpt.isPresent()) {
|
||||
|
Reference in New Issue
Block a user