Properly handle v1 of 3pid/bind

This commit is contained in:
Max Dor
2019-01-15 10:08:01 +01:00
parent 6da68298b0
commit 4ec05f518e
4 changed files with 125 additions and 9 deletions

View File

@@ -0,0 +1,67 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2019 Kamax Sarl
*
* https://www.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.http.io.identity;
import com.google.gson.annotations.SerializedName;
public class BindRequest {
public static class Keys {
public static final String SessionID = "sid";
public static final String Secret = "client_secret";
public static final String UserID = "mxid";
}
@SerializedName(Keys.SessionID)
private String sid;
@SerializedName(Keys.Secret)
private String secret;
@SerializedName(Keys.UserID)
private String userId;
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
}

View File

@@ -30,6 +30,7 @@ import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.HttpString;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -38,7 +39,10 @@ import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Deque;
import java.util.LinkedList;
import java.util.Map;
import java.util.Optional;
public abstract class BasicHttpHandler implements HttpHandler {
@@ -49,8 +53,16 @@ public abstract class BasicHttpHandler implements HttpHandler {
}
protected String getQueryParameter(HttpServerExchange exchange, String name) {
return getQueryParameter(exchange.getQueryParameters(), name);
}
protected String getQueryParameter(Map<String, Deque<String>> parms, String name) {
try {
String raw = exchange.getQueryParameters().getOrDefault(name, new LinkedList<>()).peekFirst();
String raw = parms.getOrDefault(name, new LinkedList<>()).peekFirst();
if (StringUtils.isEmpty(raw)) {
return raw;
}
return URLDecoder.decode(raw, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
throw new InternalServerError(e);
@@ -61,22 +73,33 @@ public abstract class BasicHttpHandler implements HttpHandler {
return getQueryParameter(exchange, name);
}
protected Optional<String> getContentType(HttpServerExchange exchange) {
return Optional.ofNullable(exchange.getRequestHeaders().getFirst("Content-Type"));
}
protected void writeBodyAsUtf8(HttpServerExchange exchange, String body) {
exchange.getResponseSender().send(body, StandardCharsets.UTF_8);
}
protected <T> T parseJsonTo(HttpServerExchange exchange, Class<T> type) {
protected String getBodyUtf8(HttpServerExchange exchange) {
try {
return GsonUtil.get().fromJson(IOUtils.toString(exchange.getInputStream(), StandardCharsets.UTF_8), type);
return IOUtils.toString(exchange.getInputStream(), StandardCharsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
protected <T> T parseJsonTo(HttpServerExchange exchange, Class<T> type) {
return GsonUtil.get().fromJson(getBodyUtf8(exchange), type);
}
protected JsonObject parseJsonObject(HttpServerExchange exchange, String key) {
return GsonUtil.getObj(parseJsonObject(exchange), key);
}
protected JsonObject parseJsonObject(HttpServerExchange exchange) {
try {
JsonObject base = GsonUtil.parseObj(IOUtils.toString(exchange.getInputStream(), StandardCharsets.UTF_8));
return GsonUtil.getObj(base, key);
return GsonUtil.parseObj(IOUtils.toString(exchange.getInputStream(), StandardCharsets.UTF_8));
} catch (IOException e) {
throw new RuntimeException(e);
}

View File

@@ -23,14 +23,21 @@ package io.kamax.mxisd.http.undertow.handler.identity.v1;
import com.google.gson.JsonObject;
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.undertow.handler.BasicHttpHandler;
import io.kamax.mxisd.invitation.InvitationManager;
import io.kamax.mxisd.session.SessionMananger;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.QueryParameterUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.util.Deque;
import java.util.Map;
public class SessionTpidBindHandler extends BasicHttpHandler {
public static final String Path = IsAPIv1.Base + "/3pid/bind";
@@ -47,12 +54,27 @@ public class SessionTpidBindHandler extends BasicHttpHandler {
@Override
public void handleRequest(HttpServerExchange exchange) {
String sid = getQueryParameter(exchange, "sid");
String secret = getQueryParameter(exchange, "client_secret");
String mxid = getQueryParameter(exchange, "mxid");
BindRequest bindReq = new BindRequest();
bindReq.setSid(getQueryParameter(exchange, BindRequest.Keys.SessionID));
bindReq.setSecret(getQueryParameter(exchange, BindRequest.Keys.Secret));
bindReq.setUserId(getQueryParameter(exchange, BindRequest.Keys.UserID));
String reqContentType = getContentType(exchange).orElse("application/octet-stream");
if (StringUtils.equals("application/x-www-form-urlencoded", reqContentType)) {
String body = getBodyUtf8(exchange);
Map<String, Deque<String>> parms = QueryParameterUtils.parseQueryString(body, StandardCharsets.UTF_8.name());
bindReq.setSid(getQueryParameter(parms, BindRequest.Keys.SessionID));
bindReq.setSecret(getQueryParameter(parms, BindRequest.Keys.Secret));
bindReq.setUserId(getQueryParameter(parms, BindRequest.Keys.UserID));
} else if (StringUtils.equals("application/json", reqContentType)) {
bindReq = parseJsonTo(exchange, BindRequest.class);
} else {
log.warn("Unknown encoding in 3PID session bind: {}", reqContentType);
log.warn("The request will most likely fail");
}
try {
mgr.bind(sid, secret, mxid);
mgr.bind(bindReq.getSid(), bindReq.getSecret(), bindReq.getUserId());
respond(exchange, new JsonObject());
} catch (BadRequestException e) {
log.info("requested session was not validated");

View File

@@ -214,6 +214,10 @@ public class SessionMananger {
}
public void bind(String sid, String secret, String mxidRaw) {
if (StringUtils.isEmpty(mxidRaw)) {
throw new IllegalArgumentException("No Matrix User ID provided");
}
_MatrixID mxid = MatrixID.asAcceptable(mxidRaw);
ThreePidSession session = getSessionIfValidated(sid, secret);