Handle anonymous bind in LDAP backend (Fix #27)
This commit is contained in:
@@ -172,12 +172,14 @@ key.path: '/path/to/sign.key'
|
||||
#ldap.connection.port: 389
|
||||
|
||||
|
||||
# Bind DN to use when performing lookups
|
||||
# Bind DN for the connection.
|
||||
#
|
||||
# If Bind DN and password are empty, anonymous authentication is performed
|
||||
#
|
||||
#ldap.connection.bindDn: 'CN=Matrix Identity Server,CN=Users,DC=example,DC=org'
|
||||
|
||||
|
||||
# Bind password to use
|
||||
# Bind password for the connection.
|
||||
#
|
||||
#ldap.connection.bindPassword: 'password'
|
||||
|
||||
@@ -256,6 +258,9 @@ key.path: '/path/to/sign.key'
|
||||
#sql.enabled: true
|
||||
#sql.type: 'sqlite'
|
||||
#sql.connection: '/var/lib/matrix-synapse/homeserver.db'
|
||||
|
||||
|
||||
# See ldap.attribute.uid.type for more info on possible values
|
||||
#sql.identity.type: 'mxid'
|
||||
#sql.identity.query: 'SELECT user_id AS uid FROM user_threepids WHERE medium = ? AND address = ?'
|
||||
#sql.identity.medium.email: "SELECT user_id AS uid FROM user_threepids WHERE medium = ? AND address = ?"
|
||||
@@ -383,6 +388,7 @@ storage.provider.sqlite.database: '/path/to/mxisd.db'
|
||||
#dns.overwrite.homeserver.type: 'raw'
|
||||
|
||||
|
||||
# The value to use, depending on the type
|
||||
# The value to use, depending on the type.
|
||||
# Protocol will always be HTTPS
|
||||
#
|
||||
#dns.overwrite.homeserver.value: 'localhost:8448'
|
||||
|
@@ -22,7 +22,7 @@ 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.backend.LdapBackend;
|
||||
import io.kamax.mxisd.lookup.provider.LdapProvider;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.directory.api.ldap.model.cursor.CursorException;
|
||||
@@ -33,37 +33,24 @@ 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 {
|
||||
public class LdapAuthProvider extends LdapBackend 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();
|
||||
return getCfg().getAttribute().getUid().getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return ldapCfg.isEnabled();
|
||||
return getCfg().isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -74,11 +61,11 @@ public class LdapAuthProvider implements AuthenticatorProvider {
|
||||
try {
|
||||
bind(conn);
|
||||
|
||||
String uidType = ldapCfg.getAttribute().getUid().getType();
|
||||
String uidType = getCfg().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());
|
||||
String userFilter = "(" + getCfg().getAttribute().getUid().getValue() + "=" + userFilterValue + ")";
|
||||
EntryCursor cursor = conn.search(getCfg().getConn().getBaseDn(), userFilter, SearchScope.SUBTREE, getUidAttribute(), getCfg().getAttribute().getName());
|
||||
try {
|
||||
while (cursor.next()) {
|
||||
Entry entry = cursor.get();
|
||||
@@ -105,7 +92,7 @@ public class LdapAuthProvider implements AuthenticatorProvider {
|
||||
return new UserAuthResult().failure();
|
||||
}
|
||||
|
||||
Attribute nameAttribute = entry.get(ldapCfg.getAttribute().getName());
|
||||
Attribute nameAttribute = entry.get(getCfg().getAttribute().getName());
|
||||
String name = nameAttribute != null ? nameAttribute.get().toString() : null;
|
||||
|
||||
log.info("Authentication successful for {}", entry.getDn().getName());
|
||||
|
57
src/main/groovy/io/kamax/mxisd/backend/LdapBackend.java
Normal file
57
src/main/groovy/io/kamax/mxisd/backend/LdapBackend.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.kamax.mxisd.backend;
|
||||
|
||||
import io.kamax.mxisd.config.ldap.LdapConfig;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
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 LdapBackend {
|
||||
|
||||
private Logger log = LoggerFactory.getLogger(LdapBackend.class);
|
||||
|
||||
@Autowired
|
||||
private LdapConfig ldapCfg;
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
protected LdapConfig getCfg() {
|
||||
return ldapCfg;
|
||||
}
|
||||
|
||||
}
|
@@ -20,8 +20,8 @@
|
||||
|
||||
package io.kamax.mxisd.lookup.provider
|
||||
|
||||
import io.kamax.mxisd.backend.LdapBackend
|
||||
import io.kamax.mxisd.config.MatrixConfig
|
||||
import io.kamax.mxisd.config.ldap.LdapConfig
|
||||
import io.kamax.mxisd.lookup.SingleLookupReply
|
||||
import io.kamax.mxisd.lookup.SingleLookupRequest
|
||||
import io.kamax.mxisd.lookup.ThreePidMapping
|
||||
@@ -32,14 +32,13 @@ 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.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
|
||||
|
||||
@Component
|
||||
class LdapProvider implements IThreePidProvider {
|
||||
class LdapProvider extends LdapBackend implements IThreePidProvider {
|
||||
|
||||
public static final String UID = "uid"
|
||||
public static final String MATRIX_ID = "mxid"
|
||||
@@ -49,24 +48,13 @@ class LdapProvider implements IThreePidProvider {
|
||||
@Autowired
|
||||
private MatrixConfig mxCfg
|
||||
|
||||
@Autowired
|
||||
private LdapConfig ldapCfg
|
||||
|
||||
@Override
|
||||
boolean isEnabled() {
|
||||
return ldapCfg.isEnabled()
|
||||
}
|
||||
|
||||
private LdapConnection getConn() {
|
||||
return new LdapNetworkConnection(ldapCfg.getConn().getHost(), ldapCfg.getConn().getPort(), ldapCfg.getConn().isTls())
|
||||
}
|
||||
|
||||
private void bind(LdapConnection conn) {
|
||||
conn.bind(ldapCfg.getConn().getBindDn(), ldapCfg.getConn().getBindPassword())
|
||||
return getCfg().isEnabled()
|
||||
}
|
||||
|
||||
private String getUidAttribute() {
|
||||
return ldapCfg.getAttribute().getUid().getValue();
|
||||
return getCfg().getAttribute().getUid().getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,14 +70,14 @@ class LdapProvider implements IThreePidProvider {
|
||||
Optional<String> lookup(LdapConnection conn, String medium, String value) {
|
||||
String uidAttribute = getUidAttribute()
|
||||
|
||||
Optional<String> queryOpt = ldapCfg.getIdentity().getQuery(medium)
|
||||
Optional<String> 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)
|
||||
EntryCursor cursor = conn.search(ldapCfg.getConn().getBaseDn(), searchQuery, SearchScope.SUBTREE, uidAttribute)
|
||||
EntryCursor cursor = conn.search(getCfg().getConn().getBaseDn(), searchQuery, SearchScope.SUBTREE, uidAttribute)
|
||||
try {
|
||||
while (cursor.next()) {
|
||||
Entry entry = cursor.get()
|
||||
@@ -97,19 +85,19 @@ class LdapProvider implements IThreePidProvider {
|
||||
|
||||
Attribute attribute = entry.get(uidAttribute)
|
||||
if (attribute == null) {
|
||||
log.info("DN {}: no attribute {}, skpping", entry.getDn(), ldapCfg.getAttribute())
|
||||
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", ldapCfg.getAttribute())
|
||||
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 = ldapCfg.getAttribute().getUid().getType()
|
||||
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)) {
|
||||
|
Reference in New Issue
Block a user