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
|
# 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)
|
# Example: (memberOf=CN=Matrix Users,CN=Users,DC=example,DC=org)
|
||||||
|
#
|
||||||
|
# /!\ Currently NOT supported due to a possible bug in LDAP library /!\
|
||||||
filter: ''
|
filter: ''
|
||||||
|
|
||||||
# Configuration section relating to identity lookups
|
# Configuration section relating to identity lookups
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ dependencies {
|
|||||||
compile 'org.springframework.boot:spring-boot-starter-web:1.5.3.RELEASE'
|
compile 'org.springframework.boot:spring-boot-starter-web:1.5.3.RELEASE'
|
||||||
|
|
||||||
// Matrix Java SDK
|
// Matrix Java SDK
|
||||||
compile 'io.kamax:matrix-java-sdk:0.0.1'
|
compile 'io.kamax:matrix-java-sdk:0.0.2'
|
||||||
|
|
||||||
// ed25519 handling
|
// ed25519 handling
|
||||||
compile 'net.i2p.crypto:eddsa:0.1.0'
|
compile 'net.i2p.crypto:eddsa:0.1.0'
|
||||||
|
|||||||
@@ -14,10 +14,12 @@ public class UserAuthResult {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void success(String mxid, String displayName) {
|
public UserAuthResult success(String mxid, String displayName) {
|
||||||
setSuccess(true);
|
setSuccess(true);
|
||||||
setMxid(mxid);
|
setMxid(mxid);
|
||||||
setDisplayName(displayName);
|
setDisplayName(displayName);
|
||||||
|
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSuccess() {
|
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;
|
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.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConfigurationProperties(prefix = "ldap.attribute.uid")
|
@ConfigurationProperties(prefix = "ldap.attribute.uid")
|
||||||
public class LdapAttributeUidConfig {
|
public class LdapAttributeUidConfig {
|
||||||
@@ -26,4 +30,11 @@ public class LdapAttributeUidConfig {
|
|||||||
this.value = value;
|
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
|
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.ServerConfig
|
||||||
import io.kamax.mxisd.config.ldap.LdapConfig
|
import io.kamax.mxisd.config.ldap.LdapConfig
|
||||||
import io.kamax.mxisd.lookup.SingleLookupRequest
|
import io.kamax.mxisd.lookup.SingleLookupRequest
|
||||||
@@ -40,7 +38,7 @@ import org.springframework.beans.factory.annotation.Autowired
|
|||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class LdapProvider implements IThreePidProvider, AuthenticatorProvider {
|
class LdapProvider implements IThreePidProvider {
|
||||||
|
|
||||||
public static final String UID = "uid"
|
public static final String UID = "uid"
|
||||||
public static final String MATRIX_ID = "mxid"
|
public static final String MATRIX_ID = "mxid"
|
||||||
@@ -66,17 +64,8 @@ class LdapProvider implements IThreePidProvider, AuthenticatorProvider {
|
|||||||
conn.bind(ldapCfg.getConn().getBindDn(), ldapCfg.getConn().getBindPassword())
|
conn.bind(ldapCfg.getConn().getBindDn(), ldapCfg.getConn().getBindPassword())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private String getUidAttribute() {
|
||||||
UserAuthResult authenticate(String id, String password) {
|
return ldapCfg.getAttribute().getUid().getValue();
|
||||||
LdapConnection conn = getConn()
|
|
||||||
try {
|
|
||||||
bind(conn)
|
|
||||||
|
|
||||||
// TODO finish this
|
|
||||||
return new UserAuthResult().failure()
|
|
||||||
} finally {
|
|
||||||
conn.close()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -90,7 +79,7 @@ class LdapProvider implements IThreePidProvider, AuthenticatorProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Optional<String> lookup(LdapConnection conn, String medium, String value) {
|
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)
|
Optional<String> queryOpt = ldapCfg.getIdentity().getQuery(medium)
|
||||||
if (!queryOpt.isPresent()) {
|
if (!queryOpt.isPresent()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user