Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
698a16ec17 | ||
|
619b70d860 | ||
|
494c9e3941 | ||
|
94441d0446 | ||
|
b4776b50e2 | ||
|
2458b38b75 | ||
|
249e28a8b5 | ||
|
ba9e2d6121 | ||
|
f042b82a50 | ||
|
59071177ad | ||
|
6450cd1f20 | ||
|
90bc244f3e | ||
|
6e52a509db | ||
|
5ca666981a |
@@ -103,8 +103,8 @@ session:
|
||||
validation:
|
||||
enabled: true
|
||||
unbind:
|
||||
notification:
|
||||
enabled: true
|
||||
notifications: true
|
||||
enabled: true
|
||||
|
||||
# DO NOT COPY/PASTE AS-IS IN YOUR CONFIGURATION
|
||||
# CONFIGURATION EXAMPLE
|
||||
@@ -115,7 +115,7 @@ are allowed to do in terms of 3PID sessions. The policy has a global on/off swit
|
||||
|
||||
---
|
||||
|
||||
`unbind` controls warning notifications for 3PID removal.
|
||||
`unbind` controls warning notifications for 3PID removal. Setting `notifications` for `unbind` to false will prevent unbind emails from sending.
|
||||
|
||||
### Web views
|
||||
Once a user click on a validation link, it is taken to the Identity Server validation page where the token is submitted.
|
||||
|
5
gradle/wrapper/gradle-wrapper.properties
vendored
5
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,5 @@
|
||||
#Thu Jul 04 22:47:59 MSK 2019
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
6
gradlew
vendored
6
gradlew
vendored
@@ -7,7 +7,7 @@
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@@ -125,8 +125,8 @@ if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
2
gradlew.bat
vendored
2
gradlew.bat
vendored
@@ -5,7 +5,7 @@
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem http://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@@ -131,7 +131,7 @@ public class Mxisd {
|
||||
dirMgr = new DirectoryManager(cfg.getDirectory(), clientDns, httpClient, DirectoryProviders.get());
|
||||
regMgr = new RegistrationManager(cfg.getRegister(), httpClient, clientDns, invMgr);
|
||||
asHander = new AppSvcManager(this);
|
||||
accMgr = new AccountManager(store, resolver, getHttpClient(), cfg.getAccountConfig(), cfg.getMatrix());
|
||||
accMgr = new AccountManager(store, resolver, cfg.getAccountConfig(), cfg.getMatrix());
|
||||
}
|
||||
|
||||
public MxisdConfig getConfig() {
|
||||
|
@@ -9,7 +9,6 @@ import io.kamax.mxisd.config.PolicyConfig;
|
||||
import io.kamax.mxisd.exception.BadRequestException;
|
||||
import io.kamax.mxisd.exception.InvalidCredentialsException;
|
||||
import io.kamax.mxisd.exception.NotFoundException;
|
||||
import io.kamax.mxisd.http.undertow.handler.auth.v1.LoginGetHandler;
|
||||
import io.kamax.mxisd.matrix.HomeserverFederationResolver;
|
||||
import io.kamax.mxisd.storage.IStorage;
|
||||
import io.kamax.mxisd.storage.ormlite.dao.AccountDao;
|
||||
@@ -17,15 +16,24 @@ import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateParsingException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
public class AccountManager {
|
||||
|
||||
@@ -33,15 +41,12 @@ public class AccountManager {
|
||||
|
||||
private final IStorage storage;
|
||||
private final HomeserverFederationResolver resolver;
|
||||
private final CloseableHttpClient httpClient;
|
||||
private final AccountConfig accountConfig;
|
||||
private final MatrixConfig matrixConfig;
|
||||
|
||||
public AccountManager(IStorage storage, HomeserverFederationResolver resolver,
|
||||
CloseableHttpClient httpClient, AccountConfig accountConfig, MatrixConfig matrixConfig) {
|
||||
public AccountManager(IStorage storage, HomeserverFederationResolver resolver, AccountConfig accountConfig, MatrixConfig matrixConfig) {
|
||||
this.storage = storage;
|
||||
this.resolver = resolver;
|
||||
this.httpClient = httpClient;
|
||||
this.accountConfig = accountConfig;
|
||||
this.matrixConfig = matrixConfig;
|
||||
}
|
||||
@@ -67,24 +72,31 @@ public class AccountManager {
|
||||
}
|
||||
|
||||
private String getUserId(OpenIdToken openIdToken) {
|
||||
String homeserverURL = resolver.resolve(openIdToken.getMatrixServerName()).toString();
|
||||
LOGGER.info("Domain resolved: {} => {}", openIdToken.getMatrixServerName(), homeserverURL);
|
||||
String matrixServerName = openIdToken.getMatrixServerName();
|
||||
String homeserverURL = resolver.resolve(matrixServerName).toString();
|
||||
LOGGER.info("Domain resolved: {} => {}", matrixServerName, homeserverURL);
|
||||
HttpGet getUserInfo = new HttpGet(
|
||||
homeserverURL + "/_matrix/federation/v1/openid/userinfo?access_token=" + openIdToken.getAccessToken());
|
||||
String userId;
|
||||
try (CloseableHttpResponse response = httpClient.execute(getUserInfo)) {
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
if (statusCode == HttpStatus.SC_OK) {
|
||||
String content = EntityUtils.toString(response.getEntity());
|
||||
LOGGER.trace("Response: {}", content);
|
||||
JsonObject body = GsonUtil.parseObj(content);
|
||||
userId = GsonUtil.getStringOrThrow(body, "sub");
|
||||
} else {
|
||||
LOGGER.error("Wrong response status: {}", statusCode);
|
||||
try (CloseableHttpClient httpClient = HttpClientBuilder.create()
|
||||
.setSSLHostnameVerifier(new MatrixHostnameVerifier(matrixServerName)).build()) {
|
||||
try (CloseableHttpResponse response = httpClient.execute(getUserInfo)) {
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
if (statusCode == HttpStatus.SC_OK) {
|
||||
String content = EntityUtils.toString(response.getEntity());
|
||||
LOGGER.trace("Response: {}", content);
|
||||
JsonObject body = GsonUtil.parseObj(content);
|
||||
userId = GsonUtil.getStringOrThrow(body, "sub");
|
||||
} else {
|
||||
LOGGER.error("Wrong response status: {}", statusCode);
|
||||
throw new InvalidCredentialsException();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Unable to get user info.", e);
|
||||
throw new InvalidCredentialsException();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Unable to get user info.", e);
|
||||
LOGGER.error("Unable to create a connection to host: " + homeserverURL, e);
|
||||
throw new InvalidCredentialsException();
|
||||
}
|
||||
|
||||
@@ -157,4 +169,74 @@ public class AccountManager {
|
||||
public MatrixConfig getMatrixConfig() {
|
||||
return matrixConfig;
|
||||
}
|
||||
|
||||
public static class MatrixHostnameVerifier implements HostnameVerifier {
|
||||
|
||||
private static final String ALT_DNS_NAME_TYPE = "2";
|
||||
private static final String ALT_IP_ADDRESS_TYPE = "7";
|
||||
|
||||
private final String matrixHostname;
|
||||
|
||||
public MatrixHostnameVerifier(String matrixHostname) {
|
||||
this.matrixHostname = matrixHostname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
try {
|
||||
Certificate peerCertificate = session.getPeerCertificates()[0];
|
||||
if (peerCertificate instanceof X509Certificate) {
|
||||
X509Certificate x509Certificate = (X509Certificate) peerCertificate;
|
||||
if (x509Certificate.getSubjectAlternativeNames() == null) {
|
||||
return false;
|
||||
}
|
||||
for (String altSubjectName : getAltSubjectNames(x509Certificate)) {
|
||||
if (match(altSubjectName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SSLPeerUnverifiedException | CertificateParsingException e) {
|
||||
LOGGER.error("Unable to check remote host", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<String> getAltSubjectNames(X509Certificate x509Certificate) {
|
||||
List<String> subjectNames = new ArrayList<>();
|
||||
try {
|
||||
for (List<?> subjectAlternativeNames : x509Certificate.getSubjectAlternativeNames()) {
|
||||
if (subjectAlternativeNames == null
|
||||
|| subjectAlternativeNames.size() < 2
|
||||
|| subjectAlternativeNames.get(0) == null
|
||||
|| subjectAlternativeNames.get(1) == null) {
|
||||
continue;
|
||||
}
|
||||
String subjectType = subjectAlternativeNames.get(0).toString();
|
||||
switch (subjectType) {
|
||||
case ALT_DNS_NAME_TYPE:
|
||||
case ALT_IP_ADDRESS_TYPE:
|
||||
subjectNames.add(subjectAlternativeNames.get(1).toString());
|
||||
break;
|
||||
default:
|
||||
LOGGER.trace("Unusable subject type: " + subjectType);
|
||||
}
|
||||
}
|
||||
} catch (CertificateParsingException e) {
|
||||
LOGGER.error("Unable to parse the certificate", e);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return subjectNames;
|
||||
}
|
||||
|
||||
private boolean match(String altSubjectName) {
|
||||
if (altSubjectName.startsWith("*.")) {
|
||||
return altSubjectName.toLowerCase().endsWith(matrixHostname.toLowerCase());
|
||||
} else {
|
||||
return matrixHostname.equalsIgnoreCase(altSubjectName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -140,7 +140,7 @@ public class AuthManager {
|
||||
}
|
||||
|
||||
try {
|
||||
MatrixID.asValid(mxId);
|
||||
MatrixID.asAcceptable(mxId);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("The returned User ID {} is not a valid Matrix ID. Login might fail at the Homeserver level", mxId);
|
||||
}
|
||||
|
@@ -47,6 +47,8 @@ public class SessionConfig {
|
||||
public static class PolicyUnbind {
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
private boolean notifications = true;
|
||||
|
||||
public boolean getEnabled() {
|
||||
return enabled;
|
||||
@@ -55,11 +57,20 @@ public class SessionConfig {
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean shouldNotify() {
|
||||
return notifications;
|
||||
}
|
||||
|
||||
public void setNotifications(boolean notifications) {
|
||||
this.notifications = notifications;
|
||||
}
|
||||
}
|
||||
|
||||
public Policy() {
|
||||
validation.enabled = true;
|
||||
unbind.enabled = true;
|
||||
unbind.notifications = true;
|
||||
}
|
||||
|
||||
private PolicyTemplate validation = new PolicyTemplate();
|
||||
|
@@ -59,6 +59,7 @@ import org.slf4j.LoggerFactory;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.Calendar;
|
||||
@@ -236,7 +237,9 @@ public class SessionManager {
|
||||
}
|
||||
|
||||
log.info("Unbinding of {} {} to {} is accepted", tpid.getMedium(), tpid.getAddress(), mxid.getId());
|
||||
notifMgr.sendForUnbind(tpid);
|
||||
if (cfg.getSession().getPolicy().getUnbind().shouldNotify()) {
|
||||
notifMgr.sendForUnbind(tpid);
|
||||
}
|
||||
}
|
||||
|
||||
private String getDomain(String publicUrl) {
|
||||
|
Reference in New Issue
Block a user