Compare commits

...

6 Commits

Author SHA1 Message Date
Max Dor
b613415dc4 Fix doc layout (cosmetic) 2018-05-18 01:47:43 +02:00
Max Dor
0549d23d21 Add LDAP TLS config value in logs 2018-05-16 15:42:24 +02:00
Max Dor
b493ccd479 De-duplicate results from Identity stores in Directory searches 2018-04-26 01:45:04 +02:00
Max Dor
03e72ba155 Use the correct domain (server name) for signatures 2018-04-22 19:27:52 +02:00
Max Dor
32a3444a9e Document the correct property for SQL usernames 2018-04-22 00:39:18 +02:00
Max Dor
78a25c21ba Code maintenance
- Switch to HttpClient for remote fetcher
- Don't fail for remote binding on matrix.org
2018-04-13 08:14:09 +02:00
10 changed files with 88 additions and 37 deletions

View File

@@ -44,7 +44,7 @@ Example: `/path/to/sqlite/file.db`
#### Others #### Others
```yaml ```yaml
sql.connection: //<HOST[:PORT]/DB?username=USER&password=PASS sql.connection: //<HOST[:PORT]/DB?user=USER&password=PASS
``` ```
Set the connection info for the database by replacing the following values: Set the connection info for the database by replacing the following values:
- `HOST`: Hostname of the SQL server - `HOST`: Hostname of the SQL server

View File

@@ -35,7 +35,7 @@ Example: `/path/to/synapse/sqliteFile.db`
### PostgreSQL ### PostgreSQL
```yaml ```yaml
synapseSql.connection: //<HOST[:PORT]/DB?username=USER&password=PASS synapseSql.connection: //<HOST[:PORT]/DB?user=USER&password=PASS
``` ```
Set the connection info for the database by replacing the following values: Set the connection info for the database by replacing the following values:
- `HOST`: Hostname of the SQL server - `HOST`: Hostname of the SQL server

View File

@@ -117,6 +117,7 @@ The following example of configuration (incomplete extract) shows which items ar
**IMPORTANT:** Most configuration items shown have default values and should not be included in your own configuration **IMPORTANT:** Most configuration items shown have default values and should not be included in your own configuration
file unless you want to specifically overwrite them. file unless you want to specifically overwrite them.
```yaml ```yaml
# CONFIGURATION EXAMPLE
# DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION # DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION
session.policy.validation.enabled: true session.policy.validation.enabled: true
session.policy.validation.forLocal: session.policy.validation.forLocal:
@@ -132,6 +133,7 @@ session.policy.validation.forRemote:
enabled: true enabled: true
server: 'configExample' # Not to be included in config! Already present in default config! server: 'configExample' # Not to be included in config! Already present in default config!
# DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION # DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION
# CONFIGURATION EXAMPLE
``` ```
`session.policy.validation` is the core configuration to control what users configured to use your Identity server `session.policy.validation` is the core configuration to control what users configured to use your Identity server
@@ -144,7 +146,7 @@ Each scope is divided into three parts:
- global on/off switch for 3PID sessions using `.enabled` - global on/off switch for 3PID sessions using `.enabled`
- `toLocal` allowing or not local 3PID session validations - `toLocal` allowing or not local 3PID session validations
- `toRemote` allowing or not remote 3PID session validations and to which server such sessions should be sent. - `toRemote` allowing or not remote 3PID session validations and to which server such sessions should be sent.
`.server` takes a Matrix Identity server list label. Only the first server in the list is currently used. `.server` takes a Matrix Identity server list label. Only the first server in the list is currently used.
If both `toLocal` and `toRemote` are enabled, the user will be offered to initiate a remote session once their 3PID If both `toLocal` and `toRemote` are enabled, the user will be offered to initiate a remote session once their 3PID
locally validated. locally validated.

View File

@@ -359,6 +359,7 @@ public abstract class LdapConfig {
log.info("Host: {}", connection.getHost()); log.info("Host: {}", connection.getHost());
log.info("Port: {}", connection.getPort()); log.info("Port: {}", connection.getPort());
log.info("TLS: {}", connection.isTls());
log.info("Bind DN: {}", connection.getBindDn()); log.info("Bind DN: {}", connection.getBindDn());
log.info("Base DN: {}", connection.getBaseDn()); log.info("Base DN: {}", connection.getBaseDn());

View File

@@ -20,8 +20,8 @@
package io.kamax.mxisd.controller.directory.v1.io; package io.kamax.mxisd.controller.directory.v1.io;
import java.util.ArrayList; import java.util.HashSet;
import java.util.List; import java.util.Set;
public class UserDirectorySearchResult { public class UserDirectorySearchResult {
@@ -55,10 +55,31 @@ public class UserDirectorySearchResult {
this.userId = userId; this.userId = userId;
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Result result = (Result) o;
if (displayName != null ? !displayName.equals(result.displayName) : result.displayName != null)
return false;
if (avatarUrl != null ? !avatarUrl.equals(result.avatarUrl) : result.avatarUrl != null) return false;
return userId.equals(result.userId);
}
@Override
public int hashCode() {
int result = displayName != null ? displayName.hashCode() : 0;
result = 31 * result + (avatarUrl != null ? avatarUrl.hashCode() : 0);
result = 31 * result + userId.hashCode();
return result;
}
} }
private boolean limited; private boolean limited;
private List<Result> results = new ArrayList<>(); private Set<Result> results = new HashSet<>();
public boolean isLimited() { public boolean isLimited() {
return limited; return limited;
@@ -68,11 +89,11 @@ public class UserDirectorySearchResult {
this.limited = limited; this.limited = limited;
} }
public List<Result> getResults() { public Set<Result> getResults() {
return results; return results;
} }
public void setResults(List<Result> results) { public void setResults(Set<Result> results) {
this.results = results; this.results = results;
} }

View File

@@ -23,6 +23,7 @@ package io.kamax.mxisd.lookup.provider;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.controller.identity.v1.ClientBulkLookupRequest; import io.kamax.mxisd.controller.identity.v1.ClientBulkLookupRequest;
import io.kamax.mxisd.exception.InvalidResponseJsonException; import io.kamax.mxisd.exception.InvalidResponseJsonException;
import io.kamax.mxisd.lookup.SingleLookupReply; import io.kamax.mxisd.lookup.SingleLookupReply;
@@ -33,18 +34,20 @@ import io.kamax.mxisd.matrix.IdentityServerUtils;
import io.kamax.mxisd.util.GsonParser; import io.kamax.mxisd.util.GsonParser;
import io.kamax.mxisd.util.RestClientUtils; import io.kamax.mxisd.util.RestClientUtils;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection; import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@@ -59,6 +62,9 @@ public class RemoteIdentityServerFetcher implements IRemoteIdentityServerFetcher
private Gson gson = new Gson(); private Gson gson = new Gson();
private GsonParser parser = new GsonParser(gson); private GsonParser parser = new GsonParser(gson);
@Autowired
private CloseableHttpClient client;
@Override @Override
public boolean isUsable(String remote) { public boolean isUsable(String remote) {
return IdentityServerUtils.isUsable(remote); return IdentityServerUtils.isUsable(remote);
@@ -69,24 +75,40 @@ public class RemoteIdentityServerFetcher implements IRemoteIdentityServerFetcher
log.info("Looking up {} 3PID {} using {}", request.getType(), request.getThreePid(), remote); log.info("Looking up {} 3PID {} using {}", request.getType(), request.getThreePid(), remote);
try { try {
HttpURLConnection rootSrvConn = (HttpURLConnection) new URL( URIBuilder b = new URIBuilder(remote);
remote + "/_matrix/identity/api/v1/lookup?medium=" + request.getType() + "&address=" + request.getThreePid() b.setPath("/_matrix/identity/api/v1/lookup");
).openConnection(); b.addParameter("medium", request.getType());
JsonObject obj = parser.parse(rootSrvConn.getInputStream()); b.addParameter("address", request.getThreePid());
if (obj.has("address")) { HttpGet req = new HttpGet(b.build());
log.info("Found 3PID mapping: {}", gson.toJson(obj));
return Optional.of(SingleLookupReply.fromRecursive(request, gson.toJson(obj))); try (CloseableHttpResponse res = client.execute(req)) {
int statusCode = res.getStatusLine().getStatusCode();
String body = EntityUtils.toString(res.getEntity());
if (statusCode != 200) {
log.warn("Remote returned status code {}", statusCode);
log.warn("Body: {}", body);
return Optional.empty();
}
JsonObject obj = GsonUtil.parseObj(body);
if (obj.has("address")) {
log.debug("Found 3PID mapping: {}", gson.toJson(obj));
return Optional.of(SingleLookupReply.fromRecursive(request, gson.toJson(obj)));
}
log.info("Empty 3PID mapping from {}", remote);
return Optional.empty();
} }
log.info("Empty 3PID mapping from {}", remote);
return Optional.empty();
} catch (IOException e) { } catch (IOException e) {
log.warn("Error looking up 3PID mapping {}: {}", request.getThreePid(), e.getMessage()); log.warn("Error looking up 3PID mapping {}: {}", request.getThreePid(), e.getMessage());
return Optional.empty(); return Optional.empty();
} catch (JsonParseException e) { } catch (JsonParseException e) {
log.warn("Invalid JSON answer from {}", remote); log.warn("Invalid JSON answer from {}", remote);
return Optional.empty(); return Optional.empty();
} catch (URISyntaxException e) {
log.warn("Invalid remote address: {}", e.getMessage(), e);
return Optional.empty();
} }
} }
@@ -98,12 +120,15 @@ public class RemoteIdentityServerFetcher implements IRemoteIdentityServerFetcher
mappingRequest.setMappings(mappings); mappingRequest.setMappings(mappings);
String url = remote + "/_matrix/identity/api/v1/bulk_lookup"; String url = remote + "/_matrix/identity/api/v1/bulk_lookup";
CloseableHttpClient client = HttpClients.createDefault();
try { try {
HttpPost request = RestClientUtils.post(url, mappingRequest); HttpPost request = RestClientUtils.post(url, mappingRequest);
try (CloseableHttpResponse response = client.execute(request)) { try (CloseableHttpResponse response = client.execute(request)) {
if (response.getStatusLine().getStatusCode() != 200) { int statusCode = response.getStatusLine().getStatusCode();
log.info("Could not perform lookup at {} due to HTTP return code: {}", url, response.getStatusLine().getStatusCode()); String body = EntityUtils.toString(response.getEntity());
if (statusCode != 200) {
log.warn("Could not perform lookup at {} due to HTTP return code: {}", url, statusCode);
log.warn("Body: {}", body);
return mappingsFound; return mappingsFound;
} }

View File

@@ -277,8 +277,7 @@ public class SessionMananger {
} }
String is = servers.get(0); String is = servers.get(0);
String url = IdentityServerUtils.findIsUrlForDomain(is) String url = IdentityServerUtils.findIsUrlForDomain(is).orElse(is);
.orElseThrow(() -> new InternalServerError(is + " could not be resolved to an Identity server"));
log.info("Will use IS endpoint {}", url); log.info("Will use IS endpoint {}", url);
String remoteSecret = session.isRemote() ? session.getRemoteSecret() : RandomStringUtils.randomAlphanumeric(16); String remoteSecret = session.isRemote() ? session.getRemoteSecret() : RandomStringUtils.randomAlphanumeric(16);

View File

@@ -30,7 +30,11 @@ public class CloseableHttpClientFactory {
@Bean @Bean
public CloseableHttpClient getClient() { public CloseableHttpClient getClient() {
return HttpClients.custom().setUserAgent("mxisd").build(); return HttpClients.custom()
.setUserAgent("mxisd")
.setMaxConnPerRoute(Integer.MAX_VALUE)
.setMaxConnTotal(Integer.MAX_VALUE)
.build();
} }
} }

View File

@@ -24,7 +24,7 @@ import io.kamax.matrix.crypto.KeyFileStore;
import io.kamax.matrix.crypto.KeyManager; import io.kamax.matrix.crypto.KeyManager;
import io.kamax.matrix.crypto.SignatureManager; import io.kamax.matrix.crypto.SignatureManager;
import io.kamax.mxisd.config.KeyConfig; import io.kamax.mxisd.config.KeyConfig;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.ServerConfig;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -50,8 +50,8 @@ public class CryptoFactory {
} }
@Bean @Bean
public SignatureManager getSignatureManager(KeyManager keyMgr, MatrixConfig mxCfg) { public SignatureManager getSignatureManager(KeyManager keyMgr, ServerConfig cfg) {
return new SignatureManager(keyMgr, mxCfg.getDomain()); return new SignatureManager(keyMgr, cfg.getName());
} }
} }

View File

@@ -33,8 +33,7 @@ import org.junit.Test;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import static com.github.tomakehurst.wiremock.client.WireMock.*; import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.*;
import static org.junit.Assert.assertTrue;
public class RestDirectoryProviderTest { public class RestDirectoryProviderTest {
@@ -89,8 +88,8 @@ public class RestDirectoryProviderTest {
UserDirectorySearchResult result = p.searchByDisplayName(byNameSearch); UserDirectorySearchResult result = p.searchByDisplayName(byNameSearch);
assertTrue(!result.isLimited()); assertTrue(!result.isLimited());
assertTrue(result.getResults().size() == 1); assertEquals(1, result.getResults().size());
UserDirectorySearchResult.Result entry = result.getResults().get(0); UserDirectorySearchResult.Result entry = result.getResults().iterator().next();
assertNotNull(entry); assertNotNull(entry);
assertTrue(StringUtils.equals(byNameAvatar, entry.getAvatarUrl())); assertTrue(StringUtils.equals(byNameAvatar, entry.getAvatarUrl()));
assertTrue(StringUtils.equals(byNameDisplay, entry.getDisplayName())); assertTrue(StringUtils.equals(byNameDisplay, entry.getDisplayName()));
@@ -132,8 +131,8 @@ public class RestDirectoryProviderTest {
UserDirectorySearchResult result = p.searchBy3pid(byThreepidSearch); UserDirectorySearchResult result = p.searchBy3pid(byThreepidSearch);
assertTrue(!result.isLimited()); assertTrue(!result.isLimited());
assertTrue(result.getResults().size() == 1); assertEquals(1, result.getResults().size());
UserDirectorySearchResult.Result entry = result.getResults().get(0); UserDirectorySearchResult.Result entry = result.getResults().iterator().next();
assertNotNull(entry); assertNotNull(entry);
assertTrue(StringUtils.equals(byThreepidAvatar, entry.getAvatarUrl())); assertTrue(StringUtils.equals(byThreepidAvatar, entry.getAvatarUrl()));
assertTrue(StringUtils.equals(byThreepidDisplay, entry.getDisplayName())); assertTrue(StringUtils.equals(byThreepidDisplay, entry.getDisplayName()));