diff --git a/src/main/groovy/io/kamax/mxisd/config/SessionConfig.java b/src/main/groovy/io/kamax/mxisd/config/SessionConfig.java index fd20b1e..e72a5fc 100644 --- a/src/main/groovy/io/kamax/mxisd/config/SessionConfig.java +++ b/src/main/groovy/io/kamax/mxisd/config/SessionConfig.java @@ -42,6 +42,7 @@ public class SessionConfig { public static class PolicySource { private boolean enabled; + private boolean alwaysValidate; private boolean toLocal; private boolean toRemote; @@ -53,6 +54,14 @@ public class SessionConfig { this.enabled = enabled; } + public boolean isAlwaysValidate() { + return alwaysValidate; + } + + public void setAlwaysValidate(boolean alwaysValidate) { + this.alwaysValidate = alwaysValidate; + } + public boolean toLocal() { return toLocal; } @@ -98,6 +107,10 @@ public class SessionConfig { public PolicySource forRemote() { return forRemote; } + + public PolicySource forIf(boolean isLocal) { + return isLocal ? forLocal : forRemote; + } } private PolicyTemplate bind = new PolicyTemplate(); diff --git a/src/main/groovy/io/kamax/mxisd/config/threepid/medium/EmailTemplateConfig.java b/src/main/groovy/io/kamax/mxisd/config/threepid/medium/EmailTemplateConfig.java index 4054dd7..a426dc4 100644 --- a/src/main/groovy/io/kamax/mxisd/config/threepid/medium/EmailTemplateConfig.java +++ b/src/main/groovy/io/kamax/mxisd/config/threepid/medium/EmailTemplateConfig.java @@ -45,13 +45,36 @@ public class EmailTemplateConfig { public static class Session { - private String validation; + public static class SessionValidation { - public String getValidation() { + private String local; + private String remote; + + public String getLocal() { + return local; + } + + public void setLocal(String local) { + this.local = local; + } + + public String getRemote() { + return remote; + } + + public void setRemote(String remote) { + this.remote = remote; + } + + } + + private SessionValidation validation; + + public SessionValidation getValidation() { return validation; } - public void setValidation(String validation) { + public void setValidation(SessionValidation validation) { this.validation = validation; } @@ -76,7 +99,9 @@ public class EmailTemplateConfig { public void build() { log.info("--- E-mail Generator templates config ---"); log.info("Invite: {}", getName(getInvite())); - log.info("Session validation: {}", getName(getSession().getValidation())); + log.info("Session validation:"); + log.info("\tLocal: {}", getName(getSession().getValidation().getLocal())); + log.info("\tRemote: {}", getName(getSession().getValidation().getRemote())); } } diff --git a/src/main/groovy/io/kamax/mxisd/controller/v1/remote/RemoteIdentityAPIv1.java b/src/main/groovy/io/kamax/mxisd/controller/v1/remote/RemoteIdentityAPIv1.java new file mode 100644 index 0000000..d451736 --- /dev/null +++ b/src/main/groovy/io/kamax/mxisd/controller/v1/remote/RemoteIdentityAPIv1.java @@ -0,0 +1,27 @@ +/* + * 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 . + */ + +package io.kamax.mxisd.controller.v1.remote; + +public class RemoteIdentityAPIv1 { + + public static final String BASE = "/_matrix/identity-remote/api/v1"; + +} diff --git a/src/main/groovy/io/kamax/mxisd/exception/NotAllowedException.java b/src/main/groovy/io/kamax/mxisd/exception/NotAllowedException.java index b3a1f77..068127d 100644 --- a/src/main/groovy/io/kamax/mxisd/exception/NotAllowedException.java +++ b/src/main/groovy/io/kamax/mxisd/exception/NotAllowedException.java @@ -20,14 +20,13 @@ package io.kamax.mxisd.exception; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; -@ResponseStatus(value = HttpStatus.FORBIDDEN) -public class NotAllowedException extends RuntimeException { +import org.apache.http.HttpStatus; + +public class NotAllowedException extends MatrixException { public NotAllowedException(String s) { - super(s); + super(HttpStatus.SC_FORBIDDEN, "M_FORBIDDEN", s); } } diff --git a/src/main/groovy/io/kamax/mxisd/notification/INotificationHandler.java b/src/main/groovy/io/kamax/mxisd/notification/INotificationHandler.java index 6138784..e42735f 100644 --- a/src/main/groovy/io/kamax/mxisd/notification/INotificationHandler.java +++ b/src/main/groovy/io/kamax/mxisd/notification/INotificationHandler.java @@ -31,4 +31,6 @@ public interface INotificationHandler { void sendForValidation(IThreePidSession session); + void sendForRemoteValidation(IThreePidSession session); + } diff --git a/src/main/groovy/io/kamax/mxisd/notification/NotificationManager.java b/src/main/groovy/io/kamax/mxisd/notification/NotificationManager.java index 2178530..78a38a2 100644 --- a/src/main/groovy/io/kamax/mxisd/notification/NotificationManager.java +++ b/src/main/groovy/io/kamax/mxisd/notification/NotificationManager.java @@ -63,7 +63,7 @@ public class NotificationManager { } public void sendforRemoteValidation(IThreePidSession session) { - throw new NotImplementedException("Remote publish of 3PID bind"); + ensureMedium(session.getThreePid().getMedium()).sendForRemoteValidation(session); } } diff --git a/src/main/groovy/io/kamax/mxisd/session/SessionMananger.java b/src/main/groovy/io/kamax/mxisd/session/SessionMananger.java index 0273062..47c58b7 100644 --- a/src/main/groovy/io/kamax/mxisd/session/SessionMananger.java +++ b/src/main/groovy/io/kamax/mxisd/session/SessionMananger.java @@ -114,24 +114,14 @@ public class SessionMananger { } else { log.info("No existing session for {}", tpid); - boolean isLocalDomain = isLocal(tpid); - log.info("Is 3PID bound to local domain? {}", isLocalDomain); + boolean isLocal = isLocal(tpid); + log.info("Is 3PID bound to local domain? {}", isLocal); - if (isLocalDomain && (!policy.forLocal().isEnabled() || !policy.forLocal().toLocal())) { - throw new NotAllowedException("Validating local 3PID is not allowed"); - } - - // We lookup if the 3PID is already known locally. - boolean knownLocal = isKnownLocal(tpid); - log.info("Mapping with {} is " + (knownLocal ? "already" : "not") + " known locally", tpid); - - if (!isLocalDomain && ( - !policy.forRemote().isEnabled() || ( - !policy.forRemote().toLocal() && - !policy.forRemote().toRemote() - ) - )) { - throw new NotAllowedException("Validating unknown remote 3PID is not allowed"); + // This might need a configuration by medium type? + SessionConfig.Policy.PolicyTemplate.PolicySource policySource = policy.forIf(isLocal); + if (!policySource.isEnabled() || (!policySource.toLocal() && !policySource.toRemote())) { + log.info("Session for {}: cancelled due to policy", tpid); + throw new NotAllowedException("Validating " + (isLocal ? "local" : "remote") + " 3PID is not allowed"); } String sessionId; @@ -144,14 +134,12 @@ public class SessionMananger { log.info("Generated new session {} to validate {} from server {}", sessionId, tpid, server); // This might need a configuration by medium type? - if (!isLocalDomain) { - if (policy.forRemote().toLocal() && policy.forRemote().toRemote()) { - log.info("Session {} for {}: sending local validation notification", sessionId, tpid); - notifMgr.sendForValidation(session); - } else { - log.info("Session {} for {}: sending remote-only validation notification", sessionId, tpid); - notifMgr.sendforRemoteValidation(session); - } + if (policySource.toLocal()) { + log.info("Session {} for {}: sending local validation notification", sessionId, tpid); + notifMgr.sendForValidation(session); + } else { + log.info("Session {} for {}: sending remote-only validation notification", sessionId, tpid); + notifMgr.sendforRemoteValidation(session); } storage.insertThreePidSession(session.getDao()); diff --git a/src/main/groovy/io/kamax/mxisd/threepid/notification/INotificationGenerator.java b/src/main/groovy/io/kamax/mxisd/threepid/notification/INotificationGenerator.java index c61dba8..ad429ed 100644 --- a/src/main/groovy/io/kamax/mxisd/threepid/notification/INotificationGenerator.java +++ b/src/main/groovy/io/kamax/mxisd/threepid/notification/INotificationGenerator.java @@ -33,6 +33,6 @@ public interface INotificationGenerator { String getForValidation(IThreePidSession session); - String getForRemotePublishingValidation(IThreePidSession session); + String getForRemoteValidation(IThreePidSession session); } diff --git a/src/main/groovy/io/kamax/mxisd/threepid/notification/email/EmailNotificationGenerator.java b/src/main/groovy/io/kamax/mxisd/threepid/notification/email/EmailNotificationGenerator.java index 6ed62c3..57977a2 100644 --- a/src/main/groovy/io/kamax/mxisd/threepid/notification/email/EmailNotificationGenerator.java +++ b/src/main/groovy/io/kamax/mxisd/threepid/notification/email/EmailNotificationGenerator.java @@ -26,8 +26,8 @@ import io.kamax.mxisd.config.ServerConfig; import io.kamax.mxisd.config.threepid.medium.EmailConfig; import io.kamax.mxisd.config.threepid.medium.EmailTemplateConfig; import io.kamax.mxisd.controller.v1.IdentityAPIv1; +import io.kamax.mxisd.controller.v1.remote.RemoteIdentityAPIv1; import io.kamax.mxisd.exception.InternalServerError; -import io.kamax.mxisd.exception.NotImplementedException; import io.kamax.mxisd.invitation.IThreePidInviteReply; import io.kamax.mxisd.threepid.session.IThreePidSession; import org.apache.commons.io.IOUtils; @@ -121,8 +121,9 @@ public class EmailNotificationGenerator implements IEmailNotificationGenerator { @Override public String getForValidation(IThreePidSession session) { log.info("Generating notification content for 3PID Session validation"); - String templateBody = getTemplateAndPopulate(templateCfg.getSession().getValidation(), session.getThreePid()); + String templateBody = getTemplateAndPopulate(templateCfg.getSession().getValidation().getLocal(), session.getThreePid()); + // FIXME should have a global link builder, most likely in the SDK? String validationLink = srvCfg.getPublicUrl() + IdentityAPIv1.BASE + "/validate/" + session.getThreePid().getMedium() + "/submitToken?sid=" + session.getId() + "&client_secret=" + session.getSecret() + @@ -135,8 +136,19 @@ public class EmailNotificationGenerator implements IEmailNotificationGenerator { } @Override - public String getForRemotePublishingValidation(IThreePidSession session) { - throw new NotImplementedException(""); + public String getForRemoteValidation(IThreePidSession session) { + log.info("Generating notification content for 3PID Session validation"); + String templateBody = getTemplateAndPopulate(templateCfg.getSession().getValidation().getLocal(), session.getThreePid()); + + // FIXME should have a global link builder, specific to mxisd + String nextStepLink = srvCfg.getPublicUrl() + RemoteIdentityAPIv1.BASE + + "/validate/requestToken?sid=" + session.getId() + "&client_secret=" + session.getSecret(); + + templateBody = templateBody.replace("%SESSION_ID%", session.getId()); + templateBody = templateBody.replace("%SESSION_SECRET%", session.getSecret()); + templateBody = templateBody.replace("%NEXT_STEP_LINK%", nextStepLink); + + return templateBody; } } diff --git a/src/main/groovy/io/kamax/mxisd/threepid/notification/email/EmailNotificationHandler.java b/src/main/groovy/io/kamax/mxisd/threepid/notification/email/EmailNotificationHandler.java index 024c6ec..46c4b2e 100644 --- a/src/main/groovy/io/kamax/mxisd/threepid/notification/email/EmailNotificationHandler.java +++ b/src/main/groovy/io/kamax/mxisd/threepid/notification/email/EmailNotificationHandler.java @@ -43,6 +43,7 @@ public class EmailNotificationHandler implements INotificationHandler { @Autowired public EmailNotificationHandler(EmailConfig cfg, List generators, List connectors) { this.cfg = cfg; + generator = generators.stream() .filter(o -> StringUtils.equals(cfg.getGenerator(), o.getId())) .findFirst() @@ -59,24 +60,28 @@ public class EmailNotificationHandler implements INotificationHandler { return ThreePidMedium.Email.getId(); } - @Override - public void sendForInvite(IThreePidInviteReply invite) { + private void send(String recipient, String content) { connector.send( cfg.getIdentity().getFrom(), cfg.getIdentity().getName(), - invite.getInvite().getAddress(), - generator.getForInvite(invite) + recipient, + content ); } + @Override + public void sendForInvite(IThreePidInviteReply invite) { + send(invite.getInvite().getAddress(), generator.getForInvite(invite)); + } + @Override public void sendForValidation(IThreePidSession session) { - connector.send( - cfg.getIdentity().getFrom(), - cfg.getIdentity().getName(), - session.getThreePid().getAddress(), - generator.getForValidation(session) - ); + send(session.getThreePid().getAddress(), generator.getForValidation(session)); + } + + @Override + public void sendForRemoteValidation(IThreePidSession session) { + send(session.getThreePid().getAddress(), generator.getForRemoteValidation(session)); } } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 31e8c59..d717262 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -81,17 +81,19 @@ threepid: template: invite: 'classpath:email/invite-template.eml' session: - validation: 'classpath:email/validate-template.eml' + validation: + local: 'classpath:email/validate-local-template.eml' + remote: 'classpath:email/validate-remote-template.eml' session.policy.validation: enabled: true forLocal: enabled: true - toLocal: true + toLocal: true # This should not be changed unless you know exactly the implications! toRemote: true forRemote: enabled: true - toLocal: true # This should not be changed unless you know exactly the implications! + toLocal: true toRemote: true storage: diff --git a/src/main/resources/email/validate-local-template.eml b/src/main/resources/email/validate-local-template.eml new file mode 100644 index 0000000..08b4f60 --- /dev/null +++ b/src/main/resources/email/validate-local-template.eml @@ -0,0 +1,91 @@ +Subject: Your Matrix Validation Token +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ" + +--7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ +Content-Type: text/plain; charset=UTF-8 +Content-Disposition: inline + +Hello there! + +We have received a request to link this email address with your Matrix account. + +If it was really you who made this request, you can click on the following link to +complete the verification of your email address: + + %VALIDATION_LINK% + +If you didn't make this request, you can safely disregard this email. + +Thanks! + +%DOMAIN_PRETTY% Admins + +--7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ +Content-Type: multipart/related; + boundary="M3yzHl5YZehm9v4bAM8sKEdcOoVnRnKR"; + type="text/html" + +--M3yzHl5YZehm9v4bAM8sKEdcOoVnRnKR +Content-Type: text/html; charset=UTF-8 +Content-Disposition: inline + + + + + + + + + + + + + +
+

Hello there!

+ +

We have received a request to link this email address with your Matrix account.

+ +

If it was really you who made this request, you can click on the following link to + complete the verification of your email address:

+ +

Complete email verification

+ +

If you didn't make this request, you can safely disregard this email.

+ +

Thanks!

+ +

%DOMAIN_PRETTY% Admins

+
+ + +--M3yzHl5YZehm9v4bAM8sKEdcOoVnRnKR-- + +--7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ-- diff --git a/src/main/resources/email/validate-template.eml b/src/main/resources/email/validate-template.eml deleted file mode 100644 index e5b1346..0000000 --- a/src/main/resources/email/validate-template.eml +++ /dev/null @@ -1,66 +0,0 @@ -Subject: Your Matrix Validation Token -MIME-Version: 1.0 -Content-Type: multipart/alternative; - boundary="7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ" - ---7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ -Content-Type: text/plain; charset=UTF-8 -Content-Disposition: inline - -Hello, - -We have received a request to link this email address with a Matrix account. -If this was you who made this request, you may use the following link to complete the verification of your email address: - - %VALIDATION_LINK% - -If your client requires a code, the code is %VALIDATION_TOKEN% - -If you aren't aware of making such a request, please disregard this email. - -Regards, -%DOMAIN_PRETTY% Admins - ---7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ -Content-Type: text/html; charset=UTF-8 -Content-Disposition: inline - - - - - - - - - -

Hello,

- -

We have received a request to link this email address with a Matrix account. - If this was you who made this request, you may use the following link to - complete the verification of your email address:

- -

Complete email verification

- -

...or copy this link into your web browser:

- -

%VALIDATION_LINK%

- -

If your client requires a code, the code is %VALIDATION_TOKEN%

- -

If you aren't aware of making such a request, please disregard this -email.

- -
-

Regards,
- %DOMAIN_PRETTY% Admins

- - - - ---7REaIwWQCioQ6NaBlAQlg8ztbUQj6PKJ--