Fix response body of /3pid/bind to match spec
- synapse did not check/validate the response as per spec until 0.99.5 it seems - mxisd was never compliant also
This commit is contained in:
@@ -105,7 +105,7 @@ public class HttpMxisd {
|
||||
.get(SessionValidateHandler.Path, SaneHandler.around(new SessionValidationGetHandler(m.getSession(), m.getConfig())))
|
||||
.post(SessionValidateHandler.Path, SaneHandler.around(new SessionValidationPostHandler(m.getSession())))
|
||||
.get(SessionTpidGetValidatedHandler.Path, SaneHandler.around(new SessionTpidGetValidatedHandler(m.getSession())))
|
||||
.post(SessionTpidBindHandler.Path, SaneHandler.around(new SessionTpidBindHandler(m.getSession(), m.getInvite())))
|
||||
.post(SessionTpidBindHandler.Path, SaneHandler.around(new SessionTpidBindHandler(m.getSession(), m.getInvite(), m.getSign())))
|
||||
.post(SessionTpidUnbindHandler.Path, SaneHandler.around(new SessionTpidUnbindHandler(m.getSession())))
|
||||
.post(SignEd25519Handler.Path, SaneHandler.around(new SignEd25519Handler(m.getConfig(), m.getInvite(), m.getSign())))
|
||||
|
||||
|
@@ -107,7 +107,7 @@ public class Mxisd {
|
||||
|
||||
store = new OrmLiteSqlStorage(cfg);
|
||||
keyMgr = CryptoFactory.getKeyManager(cfg.getKey());
|
||||
signMgr = CryptoFactory.getSignatureManager(keyMgr);
|
||||
signMgr = CryptoFactory.getSignatureManager(cfg, keyMgr);
|
||||
clientDns = new ClientDnsOverwrite(cfg.getDns().getOverwrite());
|
||||
|
||||
synapse = new Synapse(cfg.getSynapseSql());
|
||||
|
@@ -83,6 +83,12 @@ public class MxisdConfig {
|
||||
|
||||
}
|
||||
|
||||
public static MxisdConfig forDomain(String domain) {
|
||||
MxisdConfig cfg = new MxisdConfig();
|
||||
cfg.getMatrix().setDomain(domain);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
private AppServiceConfig appsvc = new AppServiceConfig();
|
||||
private AuthenticationConfig auth = new AuthenticationConfig();
|
||||
private DirectoryConfig directory = new DirectoryConfig();
|
||||
@@ -309,6 +315,13 @@ public class MxisdConfig {
|
||||
this.wordpress = wordpress;
|
||||
}
|
||||
|
||||
public MxisdConfig inMemory() {
|
||||
getKey().setPath(":memory:");
|
||||
getStorage().getProvider().getSqlite().setDatabase(":memory:");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MxisdConfig build() {
|
||||
if (StringUtils.isBlank(getServer().getName())) {
|
||||
getServer().setName(getMatrix().getDomain());
|
||||
|
@@ -21,6 +21,7 @@
|
||||
package io.kamax.mxisd.crypto;
|
||||
|
||||
import io.kamax.mxisd.config.KeyConfig;
|
||||
import io.kamax.mxisd.config.MxisdConfig;
|
||||
import io.kamax.mxisd.crypto.ed25519.Ed25519KeyManager;
|
||||
import io.kamax.mxisd.crypto.ed25519.Ed25519SignatureManager;
|
||||
import io.kamax.mxisd.storage.crypto.FileKeyStore;
|
||||
@@ -54,8 +55,8 @@ public class CryptoFactory {
|
||||
return new Ed25519KeyManager(store);
|
||||
}
|
||||
|
||||
public static SignatureManager getSignatureManager(Ed25519KeyManager keyMgr) {
|
||||
return new Ed25519SignatureManager(keyMgr);
|
||||
public static SignatureManager getSignatureManager(MxisdConfig cfg, Ed25519KeyManager keyMgr) {
|
||||
return new Ed25519SignatureManager(cfg, keyMgr);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -30,6 +30,18 @@ import java.util.Objects;
|
||||
|
||||
public interface SignatureManager {
|
||||
|
||||
/**
|
||||
* Sign the message with the default domain and add the signature to the <code>signatures</code> key.
|
||||
* <p>
|
||||
* If the key does not exist yet, it is created. If the key exist, the produced signature will be merged with any
|
||||
* existing ones.
|
||||
*
|
||||
* @param message The message to sign with the default domain and add the produced signature to
|
||||
* @return The provided message with the new signature
|
||||
* @throws IllegalArgumentException If the <code>signatures</code> key exists and its value is not a JSON object
|
||||
*/
|
||||
JsonObject signMessageGson(JsonObject message) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Sign the message and add the signature to the <code>signatures</code> key.
|
||||
* <p>
|
||||
@@ -39,7 +51,7 @@ public interface SignatureManager {
|
||||
* @param domain The domain under which the signature should be added
|
||||
* @param message The message to sign and add the produced signature to
|
||||
* @return The provided message with the new signature
|
||||
* @throws IllegalArgumentException If the <code>signatures</code> value is not a JSON object
|
||||
* @throws IllegalArgumentException If the <code>signatures</code> key exists and its value is not a JSON object
|
||||
*/
|
||||
default JsonObject signMessageGson(String domain, JsonObject message) throws IllegalArgumentException {
|
||||
JsonElement signEl = message.remove(EventKey.Signatures.get());
|
||||
|
@@ -23,6 +23,8 @@ package io.kamax.mxisd.crypto.ed25519;
|
||||
import com.google.gson.JsonObject;
|
||||
import io.kamax.matrix.codec.MxBase64;
|
||||
import io.kamax.matrix.json.MatrixJson;
|
||||
import io.kamax.mxisd.config.MxisdConfig;
|
||||
import io.kamax.mxisd.config.ServerConfig;
|
||||
import io.kamax.mxisd.crypto.KeyIdentifier;
|
||||
import io.kamax.mxisd.crypto.Signature;
|
||||
import io.kamax.mxisd.crypto.SignatureManager;
|
||||
@@ -35,12 +37,19 @@ import java.security.SignatureException;
|
||||
|
||||
public class Ed25519SignatureManager implements SignatureManager {
|
||||
|
||||
private final ServerConfig cfg;
|
||||
private final Ed25519KeyManager keyMgr;
|
||||
|
||||
public Ed25519SignatureManager(Ed25519KeyManager keyMgr) {
|
||||
public Ed25519SignatureManager(MxisdConfig cfg, Ed25519KeyManager keyMgr) {
|
||||
this.cfg = cfg.getServer();
|
||||
this.keyMgr = keyMgr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject signMessageGson(JsonObject message) throws IllegalArgumentException {
|
||||
return signMessageGson(cfg.getName(), message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject signMessageGson(String domain, String message) {
|
||||
Signature sign = sign(message);
|
||||
|
@@ -21,11 +21,15 @@
|
||||
package io.kamax.mxisd.http.undertow.handler.identity.v1;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import io.kamax.matrix.json.GsonUtil;
|
||||
import io.kamax.mxisd.crypto.SignatureManager;
|
||||
import io.kamax.mxisd.exception.BadRequestException;
|
||||
import io.kamax.mxisd.http.IsAPIv1;
|
||||
import io.kamax.mxisd.http.io.identity.BindRequest;
|
||||
import io.kamax.mxisd.http.io.identity.SingeLookupReplyJson;
|
||||
import io.kamax.mxisd.http.undertow.handler.BasicHttpHandler;
|
||||
import io.kamax.mxisd.invitation.InvitationManager;
|
||||
import io.kamax.mxisd.lookup.SingleLookupReply;
|
||||
import io.kamax.mxisd.session.SessionManager;
|
||||
import io.undertow.server.HttpServerExchange;
|
||||
import io.undertow.util.QueryParameterUtils;
|
||||
@@ -42,14 +46,16 @@ public class SessionTpidBindHandler extends BasicHttpHandler {
|
||||
|
||||
public static final String Path = IsAPIv1.Base + "/3pid/bind";
|
||||
|
||||
private transient final Logger log = LoggerFactory.getLogger(SessionTpidBindHandler.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(SessionTpidBindHandler.class);
|
||||
|
||||
private SessionManager mgr;
|
||||
private InvitationManager invMgr;
|
||||
private SignatureManager signMgr;
|
||||
|
||||
public SessionTpidBindHandler(SessionManager mgr, InvitationManager invMgr) {
|
||||
public SessionTpidBindHandler(SessionManager mgr, InvitationManager invMgr, SignatureManager signMgr) {
|
||||
this.mgr = mgr;
|
||||
this.invMgr = invMgr;
|
||||
this.signMgr = signMgr;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -74,8 +80,9 @@ public class SessionTpidBindHandler extends BasicHttpHandler {
|
||||
}
|
||||
|
||||
try {
|
||||
mgr.bind(bindReq.getSid(), bindReq.getSecret(), bindReq.getUserId());
|
||||
respond(exchange, new JsonObject());
|
||||
SingleLookupReply lookup = mgr.bind(bindReq.getSid(), bindReq.getSecret(), bindReq.getUserId());
|
||||
JsonObject response = signMgr.signMessageGson(GsonUtil.makeObj(new SingeLookupReplyJson(lookup)));
|
||||
respond(exchange, response);
|
||||
} catch (BadRequestException e) {
|
||||
log.info("requested session was not validated");
|
||||
|
||||
|
@@ -32,6 +32,7 @@ import io.kamax.mxisd.exception.NotImplementedException;
|
||||
import io.kamax.mxisd.exception.SessionNotValidatedException;
|
||||
import io.kamax.mxisd.exception.SessionUnknownException;
|
||||
import io.kamax.mxisd.lookup.SingleLookupReply;
|
||||
import io.kamax.mxisd.lookup.SingleLookupRequest;
|
||||
import io.kamax.mxisd.lookup.ThreePidValidation;
|
||||
import io.kamax.mxisd.lookup.strategy.LookupStrategy;
|
||||
import io.kamax.mxisd.notification.NotificationManager;
|
||||
@@ -43,6 +44,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
|
||||
import static io.kamax.mxisd.config.SessionConfig.Policy.PolicyTemplate;
|
||||
@@ -151,7 +153,7 @@ public class SessionManager {
|
||||
return new ThreePidValidation(session.getThreePid(), session.getValidationTime());
|
||||
}
|
||||
|
||||
public void bind(String sid, String secret, String mxidRaw) {
|
||||
public SingleLookupReply bind(String sid, String secret, String mxidRaw) {
|
||||
// We make sure we have an acceptable User ID
|
||||
if (StringUtils.isEmpty(mxidRaw)) {
|
||||
throw new IllegalArgumentException("No Matrix User ID provided");
|
||||
@@ -165,11 +167,16 @@ public class SessionManager {
|
||||
|
||||
// Only accept binds if the domain matches our own
|
||||
if (!StringUtils.equalsIgnoreCase(mxCfg.getDomain(), mxid.getDomain())) {
|
||||
throw new NotAllowedException("Only Matrix IDs from domain " + mxCfg + " can be bound");
|
||||
throw new NotAllowedException("Only Matrix IDs from domain " + mxCfg.getDomain() + " can be bound");
|
||||
}
|
||||
|
||||
log.info("Session {}: Binding of {}:{} to Matrix ID {} is accepted",
|
||||
session.getId(), session.getThreePid().getMedium(), session.getThreePid().getAddress(), mxid.getId());
|
||||
|
||||
SingleLookupRequest request = new SingleLookupRequest();
|
||||
request.setType(session.getThreePid().getMedium());
|
||||
request.setThreePid(session.getThreePid().getAddress());
|
||||
return new SingleLookupReply(request, mxid, Instant.now(), Instant.now().minusSeconds(5 * 60), Instant.now().plusSeconds(5 * 60));
|
||||
}
|
||||
|
||||
public void unbind(JsonObject reqData) {
|
||||
|
@@ -33,11 +33,7 @@ public class MxisdDefaultTest {
|
||||
|
||||
@Test
|
||||
public void defaultConfig() {
|
||||
MxisdConfig cfg = new MxisdConfig();
|
||||
cfg.getMatrix().setDomain(domain);
|
||||
cfg.getKey().setPath(":memory:");
|
||||
cfg.getStorage().getProvider().getSqlite().setDatabase(":memory:");
|
||||
|
||||
MxisdConfig cfg = MxisdConfig.forDomain(domain).inMemory();
|
||||
Mxisd m = new Mxisd(cfg);
|
||||
m.start();
|
||||
|
||||
|
@@ -41,10 +41,7 @@ public class MxisdTest {
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
MxisdConfig cfg = new MxisdConfig();
|
||||
cfg.getMatrix().setDomain("localhost");
|
||||
cfg.getKey().setPath(":memory:");
|
||||
cfg.getStorage().getProvider().getSqlite().setDatabase(":memory:");
|
||||
MxisdConfig cfg = MxisdConfig.forDomain("localhost").inMemory();
|
||||
|
||||
MemoryThreePid mem3pid = new MemoryThreePid();
|
||||
mem3pid.setMedium("email");
|
||||
|
@@ -24,6 +24,7 @@ import com.google.gson.JsonObject;
|
||||
import io.kamax.matrix.event.EventKey;
|
||||
import io.kamax.matrix.json.GsonUtil;
|
||||
import io.kamax.matrix.json.MatrixJson;
|
||||
import io.kamax.mxisd.config.MxisdConfig;
|
||||
import io.kamax.mxisd.crypto.Signature;
|
||||
import io.kamax.mxisd.crypto.SignatureManager;
|
||||
import io.kamax.mxisd.crypto.ed25519.Ed25519Key;
|
||||
@@ -52,7 +53,7 @@ public class SignatureManagerTest {
|
||||
KeyStore store = new MemoryKeyStore();
|
||||
store.add(key);
|
||||
|
||||
return new Ed25519SignatureManager(new Ed25519KeyManager(store));
|
||||
return new Ed25519SignatureManager(MxisdConfig.forDomain("localhost").inMemory().build(), new Ed25519KeyManager(store));
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
|
Reference in New Issue
Block a user