Support 3PID listing during auth with Google Firebase
This commit is contained in:
@@ -48,4 +48,22 @@ public class ThreePid {
|
||||
return getMedium() + ":" + getAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ThreePid threePid = (ThreePid) o;
|
||||
|
||||
if (!medium.equals(threePid.medium)) return false;
|
||||
return address.equals(threePid.address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = medium.hashCode();
|
||||
result = 31 * result + address.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -71,14 +71,14 @@ public class AuthManager {
|
||||
continue;
|
||||
}
|
||||
|
||||
UserAuthResult authResult = new UserAuthResult().success(mxId, result.getProfile().getDisplayName());
|
||||
UserAuthResult authResult = new UserAuthResult().success(result.getProfile().getDisplayName());
|
||||
for (ThreePid pid : result.getProfile().getThreePids()) {
|
||||
authResult.withThreePid(pid.getMedium(), pid.getAddress());
|
||||
}
|
||||
log.info("{} was authenticated by {}, publishing 3PID mappings, if any", id, provider.getClass().getSimpleName());
|
||||
for (ThreePid pid : authResult.getThreePids()) {
|
||||
log.info("Processing {} for {}", pid, id);
|
||||
invMgr.publishMappingIfInvited(new ThreePidMapping(pid, authResult.getMxid()));
|
||||
invMgr.publishMappingIfInvited(new ThreePidMapping(pid, mxId));
|
||||
}
|
||||
|
||||
invMgr.lookupMappingsForInvites();
|
||||
|
@@ -20,31 +20,30 @@
|
||||
|
||||
package io.kamax.mxisd.auth;
|
||||
|
||||
import io.kamax.matrix.ThreePidMedium;
|
||||
import io.kamax.mxisd.ThreePid;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class UserAuthResult {
|
||||
|
||||
private boolean success;
|
||||
private String mxid;
|
||||
private String displayName;
|
||||
private List<ThreePid> threePids = new ArrayList<>();
|
||||
private String photo;
|
||||
private Set<ThreePid> threePids = new HashSet<>();
|
||||
|
||||
public UserAuthResult failure() {
|
||||
success = false;
|
||||
mxid = null;
|
||||
displayName = null;
|
||||
photo = null;
|
||||
threePids.clear();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public UserAuthResult success(String mxid, String displayName) {
|
||||
public UserAuthResult success(String displayName) {
|
||||
setSuccess(true);
|
||||
setMxid(mxid);
|
||||
setDisplayName(displayName);
|
||||
|
||||
return this;
|
||||
@@ -58,14 +57,6 @@ public class UserAuthResult {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public String getMxid() {
|
||||
return mxid;
|
||||
}
|
||||
|
||||
public void setMxid(String mxid) {
|
||||
this.mxid = mxid;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
@@ -74,8 +65,12 @@ public class UserAuthResult {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public UserAuthResult withThreePid(ThreePidMedium medium, String address) {
|
||||
return withThreePid(medium.getId(), address);
|
||||
public String getPhoto() {
|
||||
return photo;
|
||||
}
|
||||
|
||||
public void setPhoto(String photo) {
|
||||
this.photo = photo;
|
||||
}
|
||||
|
||||
public UserAuthResult withThreePid(String medium, String address) {
|
||||
@@ -84,8 +79,8 @@ public class UserAuthResult {
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<ThreePid> getThreePids() {
|
||||
return Collections.unmodifiableList(threePids);
|
||||
public Set<ThreePid> getThreePids() {
|
||||
return Collections.unmodifiableSet(threePids);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -24,21 +24,21 @@ import io.kamax.mxisd.ThreePid;
|
||||
import io.kamax.mxisd.UserID;
|
||||
import io.kamax.mxisd.UserIdType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class BackendAuthResult {
|
||||
|
||||
public static class BackendAuthProfile {
|
||||
|
||||
private String displayName;
|
||||
private List<ThreePid> threePids = new ArrayList<>();
|
||||
private Set<ThreePid> threePids = new HashSet<>();
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public List<ThreePid> getThreePids() {
|
||||
public Set<ThreePid> getThreePids() {
|
||||
return threePids;
|
||||
}
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@ import com.google.firebase.FirebaseOptions;
|
||||
import com.google.firebase.auth.FirebaseAuth;
|
||||
import com.google.firebase.auth.FirebaseCredential;
|
||||
import com.google.firebase.auth.FirebaseCredentials;
|
||||
import com.google.firebase.auth.UserInfo;
|
||||
import io.kamax.matrix.ThreePidMedium;
|
||||
import io.kamax.matrix._MatrixID;
|
||||
import io.kamax.mxisd.ThreePid;
|
||||
@@ -139,6 +140,17 @@ public class GoogleFirebaseAuthenticator implements AuthenticatorProvider {
|
||||
result.withThreePid(new ThreePid(ThreePidMedium.PhoneNumber.getId(), user.getPhoneNumber()));
|
||||
}
|
||||
|
||||
for (UserInfo info : user.getProviderData()) {
|
||||
if (StringUtils.isNotBlank(info.getEmail())) {
|
||||
result.withThreePid(new ThreePid(ThreePidMedium.Email.getId(), info.getEmail()));
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(info.getPhoneNumber())) {
|
||||
result.withThreePid(new ThreePid(ThreePidMedium.PhoneNumber.getId(), info.getPhoneNumber()));
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Got {} 3PIDs in profile", result.getProfile().getThreePids().size());
|
||||
} finally {
|
||||
userRecordLatch.countDown();
|
||||
}
|
||||
|
@@ -23,10 +23,12 @@ package io.kamax.mxisd.controller.v1;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import io.kamax.mxisd.auth.AuthManager;
|
||||
import io.kamax.mxisd.auth.UserAuthResult;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import io.kamax.mxisd.controller.v1.io.CredentialsValidationResponse;
|
||||
import io.kamax.mxisd.exception.JsonMemberNotFoundException;
|
||||
import io.kamax.mxisd.util.GsonParser;
|
||||
import io.kamax.mxisd.util.GsonUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -38,7 +40,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@@ -47,7 +48,8 @@ public class AuthController {
|
||||
|
||||
private Logger log = LoggerFactory.getLogger(AuthController.class);
|
||||
|
||||
private Gson gson = new Gson();
|
||||
private Gson gson = GsonUtil.build();
|
||||
private GsonParser parser = new GsonParser(gson);
|
||||
|
||||
@Autowired
|
||||
private AuthManager mgr;
|
||||
@@ -55,14 +57,9 @@ public class AuthController {
|
||||
@RequestMapping(value = "/_matrix-internal/identity/v1/check_credentials", method = RequestMethod.POST)
|
||||
public String checkCredentials(HttpServletRequest req) {
|
||||
try {
|
||||
JsonElement el = new JsonParser().parse(IOUtils.toString(req.getInputStream(), StandardCharsets.UTF_8));
|
||||
if (!el.isJsonObject() || !el.getAsJsonObject().has("user")) {
|
||||
throw new IllegalArgumentException("Missing user key");
|
||||
}
|
||||
|
||||
JsonObject authData = el.getAsJsonObject().get("user").getAsJsonObject();
|
||||
JsonObject authData = parser.parse(req.getInputStream(), "user");
|
||||
if (!authData.has("id") || !authData.has("password")) {
|
||||
throw new IllegalArgumentException("Missing id or password keys");
|
||||
throw new JsonMemberNotFoundException("Missing id or password keys");
|
||||
}
|
||||
|
||||
String id = authData.get("id").getAsString();
|
||||
@@ -70,16 +67,17 @@ public class AuthController {
|
||||
String password = authData.get("password").getAsString();
|
||||
|
||||
UserAuthResult result = mgr.authenticate(id, password);
|
||||
CredentialsValidationResponse response = new CredentialsValidationResponse(result.isSuccess());
|
||||
|
||||
JsonObject authObj = new JsonObject();
|
||||
authObj.addProperty("success", result.isSuccess());
|
||||
if (result.isSuccess()) {
|
||||
authObj.addProperty("mxid", result.getMxid());
|
||||
authObj.addProperty("display_name", result.getDisplayName());
|
||||
response.setDisplayName(result.getDisplayName());
|
||||
response.getProfile().setThreePids(result.getThreePids());
|
||||
}
|
||||
JsonObject obj = new JsonObject();
|
||||
JsonElement authObj = gson.toJsonTree(response);
|
||||
|
||||
obj.add("authentication", authObj);
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.add("auth", authObj);
|
||||
obj.add("authentication", authObj); // TODO remove later, legacy support
|
||||
return gson.toJson(obj);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
|
@@ -22,10 +22,7 @@ package io.kamax.mxisd.controller.v1;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import io.kamax.mxisd.exception.BadRequestException;
|
||||
import io.kamax.mxisd.exception.InternalServerError;
|
||||
import io.kamax.mxisd.exception.MappingAlreadyExistsException;
|
||||
import io.kamax.mxisd.exception.MatrixException;
|
||||
import io.kamax.mxisd.exception.*;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -78,6 +75,18 @@ public class DefaultExceptionHandler {
|
||||
return handle("M_INVALID_BODY", e.getMessage());
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler(InvalidResponseJsonException.class)
|
||||
public String handle(InvalidResponseJsonException e) {
|
||||
return handle("M_INVALID_JSON", e.getMessage());
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler(JsonMemberNotFoundException.class)
|
||||
public String handle(JsonMemberNotFoundException e) {
|
||||
return handle("M_JSON_MISSING_KEYS", e.getMessage());
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
@ExceptionHandler(MappingAlreadyExistsException.class)
|
||||
public String handle(MappingAlreadyExistsException e) {
|
||||
|
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.controller.v1.io;
|
||||
|
||||
import io.kamax.mxisd.ThreePid;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class CredentialsValidationResponse {
|
||||
|
||||
public static class Profile {
|
||||
|
||||
private String displayName;
|
||||
private Set<ThreePid> threePids = new HashSet<>();
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public Set<ThreePid> getThreePids() {
|
||||
return threePids;
|
||||
}
|
||||
|
||||
public void setThreePids(Set<ThreePid> threePids) {
|
||||
this.threePids = new HashSet<>(threePids);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean success;
|
||||
private String displayName; // TODO remove later, legacy support
|
||||
private Profile profile = new Profile();
|
||||
|
||||
public CredentialsValidationResponse(boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
this.profile.displayName = displayName;
|
||||
}
|
||||
|
||||
public Profile getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
}
|
33
src/main/java/io/kamax/mxisd/util/GsonUtil.java
Normal file
33
src/main/java/io/kamax/mxisd/util/GsonUtil.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
public class GsonUtil {
|
||||
|
||||
public static Gson build() {
|
||||
return new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user