Directory integration prototype using Google Firebase auth + Synapse SQL
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.sql;
|
||||
|
||||
import com.mchange.v2.c3p0.ComboPooledDataSource;
|
||||
import io.kamax.mxisd.config.sql.SqlProviderConfig;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
@Component
|
||||
public class SqlConnectionPool {
|
||||
|
||||
private ComboPooledDataSource ds;
|
||||
|
||||
public SqlConnectionPool(SqlProviderConfig cfg) {
|
||||
ds = new ComboPooledDataSource();
|
||||
ds.setJdbcUrl("jdbc:" + cfg.getType() + ":" + cfg.getConnection());
|
||||
ds.setMinPoolSize(1);
|
||||
ds.setMaxPoolSize(10);
|
||||
ds.setAcquireIncrement(2);
|
||||
}
|
||||
|
||||
public Connection get() throws SQLException {
|
||||
return ds.getConnection();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.kamax.mxisd.backend.sql;
|
||||
|
||||
import io.kamax.mxisd.config.MatrixConfig;
|
||||
import io.kamax.mxisd.config.sql.SqlProviderConfig;
|
||||
import io.kamax.mxisd.controller.directory.io.UserDirectorySearchResult;
|
||||
import io.kamax.mxisd.directory.IDirectoryProvider;
|
||||
import io.kamax.mxisd.exception.InternalServerError;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
|
||||
import static io.kamax.mxisd.controller.directory.io.UserDirectorySearchResult.Result;
|
||||
|
||||
|
||||
@Component
|
||||
public class SqlDirectoryProvider implements IDirectoryProvider {
|
||||
|
||||
private Logger log = LoggerFactory.getLogger(SqlDirectoryProvider.class);
|
||||
|
||||
protected SqlProviderConfig cfg;
|
||||
private MatrixConfig mxCfg;
|
||||
|
||||
private SqlConnectionPool pool;
|
||||
|
||||
@Autowired
|
||||
public SqlDirectoryProvider(SqlProviderConfig cfg, MatrixConfig mxCfg, SqlConnectionPool pool) {
|
||||
this.cfg = cfg;
|
||||
this.pool = pool;
|
||||
this.mxCfg = mxCfg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return cfg.isEnabled();
|
||||
}
|
||||
|
||||
protected void setParameters(PreparedStatement stmt, String searchTerm) throws SQLException {
|
||||
for (int i = 1; i <= stmt.getParameterMetaData().getParameterCount(); i++) {
|
||||
stmt.setString(i, searchTerm);
|
||||
}
|
||||
}
|
||||
|
||||
protected Optional<Result> processRow(ResultSet rSet) throws SQLException {
|
||||
Result item = new Result();
|
||||
item.setUserId(rSet.getString(1));
|
||||
item.setDisplayName(rSet.getString(2));
|
||||
return Optional.of(item);
|
||||
}
|
||||
|
||||
public UserDirectorySearchResult search(String searchTerm, SqlProviderConfig.Query query) {
|
||||
try (Connection conn = pool.get()) {
|
||||
try (PreparedStatement stmt = conn.prepareStatement(query.getValue())) {
|
||||
setParameters(stmt, searchTerm);
|
||||
|
||||
try (ResultSet rSet = stmt.executeQuery()) {
|
||||
UserDirectorySearchResult result = new UserDirectorySearchResult();
|
||||
result.setLimited(false);
|
||||
|
||||
while (rSet.next()) {
|
||||
processRow(rSet).ifPresent(e -> {
|
||||
if (StringUtils.equalsIgnoreCase("localpart", query.getType())) {
|
||||
e.setUserId("@" + e.getUserId() + mxCfg.getDomain());
|
||||
}
|
||||
result.addResult(e);
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new InternalServerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDirectorySearchResult searchByDisplayName(String searchTerm) {
|
||||
log.info("Searching users by display name using '{}'", searchTerm);
|
||||
return search(searchTerm, cfg.getDirectory().getQuery().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDirectorySearchResult searchBy3pid(String searchTerm) {
|
||||
log.info("Searching users by 3PID using '{}'", searchTerm);
|
||||
return search(searchTerm, cfg.getDirectory().getQuery().getThreepid());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,7 +33,10 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.sql.*;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -43,11 +46,17 @@ public class SqlThreePidProvider implements IThreePidProvider {
|
||||
|
||||
private Logger log = LoggerFactory.getLogger(SqlThreePidProvider.class);
|
||||
|
||||
@Autowired
|
||||
private SqlProviderConfig cfg;
|
||||
private MatrixConfig mxCfg;
|
||||
|
||||
private SqlConnectionPool pool;
|
||||
|
||||
@Autowired
|
||||
private SqlProviderConfig cfg;
|
||||
public SqlThreePidProvider(SqlProviderConfig cfg, MatrixConfig mxCfg, SqlConnectionPool pool) {
|
||||
this.cfg = cfg;
|
||||
this.pool = pool;
|
||||
this.mxCfg = mxCfg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
@@ -64,37 +73,36 @@ public class SqlThreePidProvider implements IThreePidProvider {
|
||||
return 20;
|
||||
}
|
||||
|
||||
private Connection getConn() throws SQLException {
|
||||
return DriverManager.getConnection("jdbc:" + cfg.getType() + ":" + cfg.getConnection());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<SingleLookupReply> find(SingleLookupRequest request) {
|
||||
log.info("SQL lookup");
|
||||
String stmtSql = StringUtils.defaultIfBlank(cfg.getIdentity().getMedium().get(request.getType()), cfg.getIdentity().getQuery());
|
||||
log.info("SQL query: {}", stmtSql);
|
||||
try (PreparedStatement stmt = getConn().prepareStatement(stmtSql)) {
|
||||
stmt.setString(1, request.getType().toLowerCase());
|
||||
stmt.setString(2, request.getThreePid().toLowerCase());
|
||||
try (Connection conn = pool.get()) {
|
||||
try (PreparedStatement stmt = conn.prepareStatement(stmtSql)) {
|
||||
stmt.setString(1, request.getType().toLowerCase());
|
||||
stmt.setString(2, request.getThreePid().toLowerCase());
|
||||
|
||||
ResultSet rSet = stmt.executeQuery();
|
||||
while (rSet.next()) {
|
||||
String uid = rSet.getString("uid");
|
||||
log.info("Found match: {}", uid);
|
||||
if (StringUtils.equals("uid", cfg.getIdentity().getType())) {
|
||||
log.info("Resolving as localpart");
|
||||
return Optional.of(new SingleLookupReply(request, new MatrixID(uid, mxCfg.getDomain())));
|
||||
}
|
||||
if (StringUtils.equals("mxid", cfg.getIdentity().getType())) {
|
||||
log.info("Resolving as MXID");
|
||||
return Optional.of(new SingleLookupReply(request, new MatrixID(uid)));
|
||||
}
|
||||
try (ResultSet rSet = stmt.executeQuery()) {
|
||||
while (rSet.next()) {
|
||||
String uid = rSet.getString("uid");
|
||||
log.info("Found match: {}", uid);
|
||||
if (StringUtils.equals("uid", cfg.getIdentity().getType())) {
|
||||
log.info("Resolving as localpart");
|
||||
return Optional.of(new SingleLookupReply(request, new MatrixID(uid, mxCfg.getDomain())));
|
||||
}
|
||||
if (StringUtils.equals("mxid", cfg.getIdentity().getType())) {
|
||||
log.info("Resolving as MXID");
|
||||
return Optional.of(new SingleLookupReply(request, new MatrixID(uid)));
|
||||
}
|
||||
|
||||
log.info("Identity type is unknown, skipping");
|
||||
log.info("Identity type is unknown, skipping");
|
||||
}
|
||||
|
||||
log.info("No match found in SQL");
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
log.info("No match found in SQL");
|
||||
return Optional.empty();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.sql;
|
||||
|
||||
import io.kamax.mxisd.config.MatrixConfig;
|
||||
import io.kamax.mxisd.config.sql.SqlProviderConfig;
|
||||
import io.kamax.mxisd.config.sql.synapse.SynapseSqlProviderConfig;
|
||||
import io.kamax.mxisd.exception.ConfigurationException;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
@Component
|
||||
public class SynapseSqliteDirectoryProvider extends SqlDirectoryProvider {
|
||||
|
||||
private SynapseSqlProviderConfig cfg;
|
||||
|
||||
@Autowired
|
||||
public SynapseSqliteDirectoryProvider(SynapseSqlProviderConfig cfg, MatrixConfig mxCfg, SqlConnectionPool pool) {
|
||||
super(cfg, mxCfg, pool);
|
||||
|
||||
if (StringUtils.equals("sqlite", cfg.getType())) {
|
||||
String userId = "'@' || p.user_id || ':" + mxCfg.getDomain() + "'";
|
||||
SqlProviderConfig.Type queries = cfg.getDirectory().getQuery();
|
||||
queries.getName().setValue(
|
||||
"select " + userId + ", displayname from profiles p where displayname like ?");
|
||||
queries.getThreepid().setValue(
|
||||
"select t.user_id, p.displayname " +
|
||||
"from user_threepids t JOIN profiles p on t.user_id = " + userId + " " +
|
||||
"where t.address like ?");
|
||||
} else if (StringUtils.equals("postgresql", cfg.getType())) {
|
||||
String userId = "concat('@',p.user_id,':" + mxCfg.getDomain() + "')";
|
||||
SqlProviderConfig.Type queries = cfg.getDirectory().getQuery();
|
||||
queries.getName().setValue(
|
||||
"select " + userId + ", displayname from profiles p where displayname ilike ?");
|
||||
queries.getThreepid().setValue(
|
||||
"select t.user_id, p.displayname " +
|
||||
"from user_threepids t JOIN profiles p on t.user_id = " + userId + " " +
|
||||
"where t.address ilike ?");
|
||||
} else {
|
||||
throw new ConfigurationException("Invalid SQL type");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setParameters(PreparedStatement stmt, String searchTerm) throws SQLException {
|
||||
stmt.setString(1, "%" + searchTerm + "%");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user