Compare commits
6 Commits
v0.3.0-rc.
...
v0.3.0-rc.
Author | SHA1 | Date | |
---|---|---|---|
|
61addd297a | ||
|
1de0951733 | ||
|
d348ebd813 | ||
|
0499c10a2c | ||
|
13e248c71e | ||
|
d221b2c5de |
@@ -171,7 +171,8 @@ systemctl start mxisd
|
|||||||
After following the specific instructions to create a config file from the sample:
|
After following the specific instructions to create a config file from the sample:
|
||||||
1. Set the `matrix.domain` value to the domain value used in your Home Server configuration
|
1. Set the `matrix.domain` value to the domain value used in your Home Server configuration
|
||||||
2. Set an absolute location for the signing keys using `key.path`
|
2. Set an absolute location for the signing keys using `key.path`
|
||||||
3. Configure the E-mail invite sender with items starting in `invite.sender.email`
|
3. Configure the E-mail notification sender following [the documentation](docs/threepids/medium/email/smtp-connector.md)
|
||||||
|
4. If you would like to support Phone number validation, see the [Twilio configuration](docs/threepids/medium/msisdn/twilio-connector.md)
|
||||||
|
|
||||||
In case your IS public domain does not match your Matrix domain, see `server.name` and `server.publicUrl`
|
In case your IS public domain does not match your Matrix domain, see `server.name` and `server.publicUrl`
|
||||||
config items.
|
config items.
|
||||||
|
@@ -301,18 +301,19 @@ key.path: '/path/to/sign.key'
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#############################
|
###################################
|
||||||
# 3PID invites config items #
|
# 3PID notifications config items #
|
||||||
#############################
|
###################################
|
||||||
|
# If you would like to change the content, see https://github.com/kamax-io/mxisd/blob/master/docs/threepids/notifications/template-generator.md
|
||||||
#
|
#
|
||||||
#### E-mail invite sender
|
#### E-mail invite sender
|
||||||
#
|
#
|
||||||
# SMTP host
|
# SMTP host
|
||||||
invite.sender.email.host: "smtp.example.org"
|
threepid.medium.email.connectors.smtp.host: "smtp.example.org"
|
||||||
|
|
||||||
|
|
||||||
# SMTP port
|
# SMTP port
|
||||||
invite.sender.email.port: 587
|
threepid.medium.email.connectors.smtp.port: 587
|
||||||
|
|
||||||
|
|
||||||
# TLS mode for the connection.
|
# TLS mode for the connection.
|
||||||
@@ -322,51 +323,19 @@ invite.sender.email.port: 587
|
|||||||
# 1 Enable TLS if supported by server
|
# 1 Enable TLS if supported by server
|
||||||
# 2 Force TLS and fail if not available
|
# 2 Force TLS and fail if not available
|
||||||
#
|
#
|
||||||
#invite.sender.email.tls: 1
|
#threepid.medium.email.connectors.smtp.tls: 1
|
||||||
|
|
||||||
|
|
||||||
# Login for SMTP
|
# Login for SMTP
|
||||||
invite.sender.email.login: "matrix-identity@example.org"
|
threepid.medium.email.connectors.smtp.login: "matrix-identity@example.org"
|
||||||
|
|
||||||
|
|
||||||
# Password for the account
|
# Password for the account
|
||||||
invite.sender.email.password: "ThePassword"
|
threepid.medium.email.connectors.smtp.password: "ThePassword"
|
||||||
|
|
||||||
|
|
||||||
# The e-mail to send as. If empty, will be the same as login
|
# The e-mail to send as. If empty, will be the same as login
|
||||||
invite.sender.email.email: "matrix-identity@example.org"
|
threepid.medium.email.identity.from: "matrix-identity@example.org"
|
||||||
|
|
||||||
|
|
||||||
# The display name used in the e-mail
|
|
||||||
#
|
|
||||||
#invite.sender.email.name: "mxisd Identity Server"
|
|
||||||
|
|
||||||
|
|
||||||
# The E-mail template to use, using built-in template by default
|
|
||||||
#
|
|
||||||
# The template is expected to be a full e-mail body, including client headers, using MIME and UTF-8 encoding.
|
|
||||||
# The following headers will be set by mxisd directly and should not be present in the template:
|
|
||||||
# - From
|
|
||||||
# - To
|
|
||||||
# - Date
|
|
||||||
# - Message-Id
|
|
||||||
# - X-Mailer
|
|
||||||
#
|
|
||||||
# The following placeholders are available:
|
|
||||||
# - %DOMAIN% Domain name as per server.name config item
|
|
||||||
# - %DOMAIN_PRETTY% Word capitalize version of the domain. e.g. example.org -> Example.org
|
|
||||||
# - %FROM_EMAIL% Value of this section's email config item
|
|
||||||
# - %FROM_NAME% Value of this section's name config item
|
|
||||||
# - %SENDER_ID% Matrix ID of the invitation sender
|
|
||||||
# - %SENDER_NAME% Display name of the invitation sender, empty if not available
|
|
||||||
# - %SENDER_NAME_OR_ID% Value of %SENDER_NAME% or, if empty, value of %SENDER_ID%
|
|
||||||
# - %INVITE_MEDIUM% Medium of the invite (e.g. email, msisdn)
|
|
||||||
# - %INVITE_ADDRESS% Address used to invite
|
|
||||||
# - %ROOM_ID% ID of the room where the invitation took place
|
|
||||||
# - %ROOM_NAME% Name of the room, empty if not available
|
|
||||||
# - %ROOM_NAME_OR_ID% Value of %ROOM_NAME% or, if empty, value of %ROOM_ID%
|
|
||||||
#
|
|
||||||
#invite.sender.email.template: "/absolute/path/to/file"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -24,7 +24,7 @@ import org.springframework.boot.SpringApplication;
|
|||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
class MatrixIdentityServerApplication {
|
public class MatrixIdentityServerApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(MatrixIdentityServerApplication.class, args);
|
SpringApplication.run(MatrixIdentityServerApplication.class, args);
|
||||||
|
@@ -48,4 +48,22 @@ public class ThreePid {
|
|||||||
return getMedium() + ":" + getAddress();
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserAuthResult authResult = new UserAuthResult().success(mxId, result.getProfile().getDisplayName());
|
UserAuthResult authResult = new UserAuthResult().success(result.getProfile().getDisplayName());
|
||||||
for (ThreePid pid : result.getProfile().getThreePids()) {
|
for (ThreePid pid : result.getProfile().getThreePids()) {
|
||||||
authResult.withThreePid(pid.getMedium(), pid.getAddress());
|
authResult.withThreePid(pid.getMedium(), pid.getAddress());
|
||||||
}
|
}
|
||||||
log.info("{} was authenticated by {}, publishing 3PID mappings, if any", id, provider.getClass().getSimpleName());
|
log.info("{} was authenticated by {}, publishing 3PID mappings, if any", id, provider.getClass().getSimpleName());
|
||||||
for (ThreePid pid : authResult.getThreePids()) {
|
for (ThreePid pid : authResult.getThreePids()) {
|
||||||
log.info("Processing {} for {}", pid, id);
|
log.info("Processing {} for {}", pid, id);
|
||||||
invMgr.publishMappingIfInvited(new ThreePidMapping(pid, authResult.getMxid()));
|
invMgr.publishMappingIfInvited(new ThreePidMapping(pid, mxId));
|
||||||
}
|
}
|
||||||
|
|
||||||
invMgr.lookupMappingsForInvites();
|
invMgr.lookupMappingsForInvites();
|
||||||
|
@@ -20,31 +20,30 @@
|
|||||||
|
|
||||||
package io.kamax.mxisd.auth;
|
package io.kamax.mxisd.auth;
|
||||||
|
|
||||||
import io.kamax.matrix.ThreePidMedium;
|
|
||||||
import io.kamax.mxisd.ThreePid;
|
import io.kamax.mxisd.ThreePid;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class UserAuthResult {
|
public class UserAuthResult {
|
||||||
|
|
||||||
private boolean success;
|
private boolean success;
|
||||||
private String mxid;
|
|
||||||
private String displayName;
|
private String displayName;
|
||||||
private List<ThreePid> threePids = new ArrayList<>();
|
private String photo;
|
||||||
|
private Set<ThreePid> threePids = new HashSet<>();
|
||||||
|
|
||||||
public UserAuthResult failure() {
|
public UserAuthResult failure() {
|
||||||
success = false;
|
success = false;
|
||||||
mxid = null;
|
|
||||||
displayName = null;
|
displayName = null;
|
||||||
|
photo = null;
|
||||||
|
threePids.clear();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserAuthResult success(String mxid, String displayName) {
|
public UserAuthResult success(String displayName) {
|
||||||
setSuccess(true);
|
setSuccess(true);
|
||||||
setMxid(mxid);
|
|
||||||
setDisplayName(displayName);
|
setDisplayName(displayName);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@@ -58,14 +57,6 @@ public class UserAuthResult {
|
|||||||
this.success = success;
|
this.success = success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMxid() {
|
|
||||||
return mxid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMxid(String mxid) {
|
|
||||||
this.mxid = mxid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDisplayName() {
|
public String getDisplayName() {
|
||||||
return displayName;
|
return displayName;
|
||||||
}
|
}
|
||||||
@@ -74,8 +65,12 @@ public class UserAuthResult {
|
|||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserAuthResult withThreePid(ThreePidMedium medium, String address) {
|
public String getPhoto() {
|
||||||
return withThreePid(medium.getId(), address);
|
return photo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPhoto(String photo) {
|
||||||
|
this.photo = photo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserAuthResult withThreePid(String medium, String address) {
|
public UserAuthResult withThreePid(String medium, String address) {
|
||||||
@@ -84,8 +79,8 @@ public class UserAuthResult {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ThreePid> getThreePids() {
|
public Set<ThreePid> getThreePids() {
|
||||||
return Collections.unmodifiableList(threePids);
|
return Collections.unmodifiableSet(threePids);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -24,21 +24,21 @@ import io.kamax.mxisd.ThreePid;
|
|||||||
import io.kamax.mxisd.UserID;
|
import io.kamax.mxisd.UserID;
|
||||||
import io.kamax.mxisd.UserIdType;
|
import io.kamax.mxisd.UserIdType;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
public class BackendAuthResult {
|
public class BackendAuthResult {
|
||||||
|
|
||||||
public static class BackendAuthProfile {
|
public static class BackendAuthProfile {
|
||||||
|
|
||||||
private String displayName;
|
private String displayName;
|
||||||
private List<ThreePid> threePids = new ArrayList<>();
|
private Set<ThreePid> threePids = new HashSet<>();
|
||||||
|
|
||||||
public String getDisplayName() {
|
public String getDisplayName() {
|
||||||
return displayName;
|
return displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ThreePid> getThreePids() {
|
public Set<ThreePid> getThreePids() {
|
||||||
return threePids;
|
return threePids;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,9 @@ import com.google.firebase.FirebaseOptions;
|
|||||||
import com.google.firebase.auth.FirebaseAuth;
|
import com.google.firebase.auth.FirebaseAuth;
|
||||||
import com.google.firebase.auth.FirebaseCredential;
|
import com.google.firebase.auth.FirebaseCredential;
|
||||||
import com.google.firebase.auth.FirebaseCredentials;
|
import com.google.firebase.auth.FirebaseCredentials;
|
||||||
|
import com.google.firebase.auth.UserInfo;
|
||||||
|
import com.google.i18n.phonenumbers.NumberParseException;
|
||||||
|
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||||
import io.kamax.matrix.ThreePidMedium;
|
import io.kamax.matrix.ThreePidMedium;
|
||||||
import io.kamax.matrix._MatrixID;
|
import io.kamax.matrix._MatrixID;
|
||||||
import io.kamax.mxisd.ThreePid;
|
import io.kamax.mxisd.ThreePid;
|
||||||
@@ -48,14 +51,7 @@ public class GoogleFirebaseAuthenticator implements AuthenticatorProvider {
|
|||||||
private FirebaseApp fbApp;
|
private FirebaseApp fbApp;
|
||||||
private FirebaseAuth fbAuth;
|
private FirebaseAuth fbAuth;
|
||||||
|
|
||||||
private void waitOnLatch(BackendAuthResult result, CountDownLatch l, String purpose) {
|
private PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
|
||||||
try {
|
|
||||||
l.await(30, TimeUnit.SECONDS);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
log.warn("Interrupted while waiting for " + purpose);
|
|
||||||
result.fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public GoogleFirebaseAuthenticator(boolean isEnabled) {
|
public GoogleFirebaseAuthenticator(boolean isEnabled) {
|
||||||
this.isEnabled = isEnabled;
|
this.isEnabled = isEnabled;
|
||||||
@@ -73,6 +69,42 @@ public class GoogleFirebaseAuthenticator implements AuthenticatorProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void waitOnLatch(BackendAuthResult result, CountDownLatch l, String purpose) {
|
||||||
|
try {
|
||||||
|
l.await(30, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.warn("Interrupted while waiting for " + purpose);
|
||||||
|
result.fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toEmail(BackendAuthResult result, String email) {
|
||||||
|
if (StringUtils.isBlank(email)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.withThreePid(new ThreePid(ThreePidMedium.Email.getId(), email));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toMsisdn(BackendAuthResult result, String phoneNumber) {
|
||||||
|
if (StringUtils.isBlank(phoneNumber)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String number = phoneUtil.format(
|
||||||
|
phoneUtil.parse(
|
||||||
|
phoneNumber,
|
||||||
|
null // No default region
|
||||||
|
),
|
||||||
|
PhoneNumberUtil.PhoneNumberFormat.E164
|
||||||
|
).substring(1); // We want without the leading +
|
||||||
|
result.withThreePid(new ThreePid(ThreePidMedium.PhoneNumber.getId(), number));
|
||||||
|
} catch (NumberParseException e) {
|
||||||
|
log.warn("Invalid phone number: {}", phoneNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private FirebaseCredential getCreds(String credsPath) throws IOException {
|
private FirebaseCredential getCreds(String credsPath) throws IOException {
|
||||||
if (StringUtils.isNotBlank(credsPath)) {
|
if (StringUtils.isNotBlank(credsPath)) {
|
||||||
return FirebaseCredentials.fromCertificate(new FileInputStream(credsPath));
|
return FirebaseCredentials.fromCertificate(new FileInputStream(credsPath));
|
||||||
@@ -131,14 +163,15 @@ public class GoogleFirebaseAuthenticator implements AuthenticatorProvider {
|
|||||||
CountDownLatch userRecordLatch = new CountDownLatch(1);
|
CountDownLatch userRecordLatch = new CountDownLatch(1);
|
||||||
fbAuth.getUser(token.getUid()).addOnSuccessListener(user -> {
|
fbAuth.getUser(token.getUid()).addOnSuccessListener(user -> {
|
||||||
try {
|
try {
|
||||||
if (StringUtils.isNotBlank(user.getEmail())) {
|
toEmail(result, user.getEmail());
|
||||||
result.withThreePid(new ThreePid(ThreePidMedium.Email.getId(), user.getEmail()));
|
toMsisdn(result, user.getPhoneNumber());
|
||||||
}
|
|
||||||
|
for (UserInfo info : user.getProviderData()) {
|
||||||
if (StringUtils.isNotBlank(user.getPhoneNumber())) {
|
toEmail(result, info.getEmail());
|
||||||
result.withThreePid(new ThreePid(ThreePidMedium.PhoneNumber.getId(), user.getPhoneNumber()));
|
toMsisdn(result, info.getPhoneNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.info("Got {} 3PIDs in profile", result.getProfile().getThreePids().size());
|
||||||
} finally {
|
} finally {
|
||||||
userRecordLatch.countDown();
|
userRecordLatch.countDown();
|
||||||
}
|
}
|
||||||
|
@@ -20,8 +20,6 @@
|
|||||||
|
|
||||||
package io.kamax.mxisd.config.threepid.connector;
|
package io.kamax.mxisd.config.threepid.connector;
|
||||||
|
|
||||||
import io.kamax.mxisd.exception.ConfigurationException;
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
@@ -68,19 +66,6 @@ public class PhoneTwilioConfig {
|
|||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void build() {
|
public void build() {
|
||||||
log.info("--- Phone SMS Twilio connector config ---");
|
log.info("--- Phone SMS Twilio connector config ---");
|
||||||
|
|
||||||
if (StringUtils.isBlank(getAccountSid())) {
|
|
||||||
throw new ConfigurationException(NAMESPACE + ".accountSid");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isBlank(getAuthToken())) {
|
|
||||||
throw new ConfigurationException(NAMESPACE + ".authToken");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isBlank(getNumber())) {
|
|
||||||
throw new ConfigurationException(NAMESPACE + ".number");
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("Account SID: {}", getAccountSid());
|
log.info("Account SID: {}", getAccountSid());
|
||||||
log.info("Sender number: {}", getNumber());
|
log.info("Sender number: {}", getNumber());
|
||||||
}
|
}
|
||||||
|
@@ -23,10 +23,12 @@ package io.kamax.mxisd.controller.v1;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import io.kamax.mxisd.auth.AuthManager;
|
import io.kamax.mxisd.auth.AuthManager;
|
||||||
import io.kamax.mxisd.auth.UserAuthResult;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -38,7 +40,6 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@CrossOrigin
|
@CrossOrigin
|
||||||
@@ -47,7 +48,8 @@ public class AuthController {
|
|||||||
|
|
||||||
private Logger log = LoggerFactory.getLogger(AuthController.class);
|
private Logger log = LoggerFactory.getLogger(AuthController.class);
|
||||||
|
|
||||||
private Gson gson = new Gson();
|
private Gson gson = GsonUtil.build();
|
||||||
|
private GsonParser parser = new GsonParser(gson);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AuthManager mgr;
|
private AuthManager mgr;
|
||||||
@@ -55,14 +57,9 @@ public class AuthController {
|
|||||||
@RequestMapping(value = "/_matrix-internal/identity/v1/check_credentials", method = RequestMethod.POST)
|
@RequestMapping(value = "/_matrix-internal/identity/v1/check_credentials", method = RequestMethod.POST)
|
||||||
public String checkCredentials(HttpServletRequest req) {
|
public String checkCredentials(HttpServletRequest req) {
|
||||||
try {
|
try {
|
||||||
JsonElement el = new JsonParser().parse(IOUtils.toString(req.getInputStream(), StandardCharsets.UTF_8));
|
JsonObject authData = parser.parse(req.getInputStream(), "user");
|
||||||
if (!el.isJsonObject() || !el.getAsJsonObject().has("user")) {
|
|
||||||
throw new IllegalArgumentException("Missing user key");
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonObject authData = el.getAsJsonObject().get("user").getAsJsonObject();
|
|
||||||
if (!authData.has("id") || !authData.has("password")) {
|
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();
|
String id = authData.get("id").getAsString();
|
||||||
@@ -70,16 +67,17 @@ public class AuthController {
|
|||||||
String password = authData.get("password").getAsString();
|
String password = authData.get("password").getAsString();
|
||||||
|
|
||||||
UserAuthResult result = mgr.authenticate(id, password);
|
UserAuthResult result = mgr.authenticate(id, password);
|
||||||
|
CredentialsValidationResponse response = new CredentialsValidationResponse(result.isSuccess());
|
||||||
|
|
||||||
JsonObject authObj = new JsonObject();
|
|
||||||
authObj.addProperty("success", result.isSuccess());
|
|
||||||
if (result.isSuccess()) {
|
if (result.isSuccess()) {
|
||||||
authObj.addProperty("mxid", result.getMxid());
|
response.setDisplayName(result.getDisplayName());
|
||||||
authObj.addProperty("display_name", 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);
|
return gson.toJson(obj);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
@@ -22,10 +22,7 @@ package io.kamax.mxisd.controller.v1;
|
|||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import io.kamax.mxisd.exception.BadRequestException;
|
import io.kamax.mxisd.exception.*;
|
||||||
import io.kamax.mxisd.exception.InternalServerError;
|
|
||||||
import io.kamax.mxisd.exception.MappingAlreadyExistsException;
|
|
||||||
import io.kamax.mxisd.exception.MatrixException;
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -78,6 +75,18 @@ public class DefaultExceptionHandler {
|
|||||||
return handle("M_INVALID_BODY", e.getMessage());
|
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)
|
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||||
@ExceptionHandler(MappingAlreadyExistsException.class)
|
@ExceptionHandler(MappingAlreadyExistsException.class)
|
||||||
public String handle(MappingAlreadyExistsException e) {
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -24,6 +24,8 @@ import com.twilio.Twilio;
|
|||||||
import com.twilio.rest.api.v2010.account.Message;
|
import com.twilio.rest.api.v2010.account.Message;
|
||||||
import com.twilio.type.PhoneNumber;
|
import com.twilio.type.PhoneNumber;
|
||||||
import io.kamax.mxisd.config.threepid.connector.PhoneTwilioConfig;
|
import io.kamax.mxisd.config.threepid.connector.PhoneTwilioConfig;
|
||||||
|
import io.kamax.mxisd.exception.BadRequestException;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
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.beans.factory.annotation.Autowired;
|
||||||
@@ -51,6 +53,10 @@ public class PhoneSmsTwilioConnector implements IPhoneConnector {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void send(String recipient, String content) {
|
public void send(String recipient, String content) {
|
||||||
|
if (StringUtils.isBlank(cfg.getAccountSid()) || StringUtils.isBlank(cfg.getAuthToken()) || StringUtils.isBlank(cfg.getNumber())) {
|
||||||
|
throw new BadRequestException("Phone numbers cannot be validated at this time. Contact your administrator.");
|
||||||
|
}
|
||||||
|
|
||||||
recipient = "+" + recipient;
|
recipient = "+" + recipient;
|
||||||
log.info("Sending SMS notification from {} to {} with {} characters", cfg.getNumber(), recipient, content.length());
|
log.info("Sending SMS notification from {} to {} with {} characters", cfg.getNumber(), recipient, content.length());
|
||||||
Message.creator(new PhoneNumber("+" + recipient), new PhoneNumber(cfg.getNumber()), content).create();
|
Message.creator(new PhoneNumber("+" + recipient), new PhoneNumber(cfg.getNumber()), content).create();
|
||||||
|
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