diff options
author | Ola Aunrønning <olaa@yahooinc.com> | 2022-10-27 14:47:25 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-27 14:47:25 +0200 |
commit | 30a93b4910c1de1a10ebccfa545d03e1deac8056 (patch) | |
tree | 48f239e59fd895064f653165652b8d111140d991 /controller-api | |
parent | 0cb3aa286942e998a598c390332466a432b6e956 (diff) | |
parent | c6903a0afe6244587ccf2ae345acaff3b55fb12b (diff) |
Merge pull request #24555 from vespa-engine/olaa/email-verification
Add email verification
Diffstat (limited to 'controller-api')
10 files changed, 183 insertions, 15 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/organization/Mailer.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/organization/Mailer.java index 18662edc85e..27eec34cf4e 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/organization/Mailer.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/organization/Mailer.java @@ -1,6 +1,8 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.api.integration.organization; +import com.yahoo.vespa.hosted.controller.tenant.PendingMailVerification; + /** * Allows sending e-mail from a particular <code>user@domain</code>. * @@ -17,4 +19,6 @@ public interface Mailer { /** Returns the domain this is configured to use. */ String domain(); + void sendVerificationMail(PendingMailVerification pendingMailVerification); + } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockMailer.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockMailer.java index cb2b76d845c..dcfa9b7ea07 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockMailer.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/stubs/MockMailer.java @@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller.api.integration.stubs; import com.yahoo.vespa.hosted.controller.api.integration.organization.Mail; import com.yahoo.vespa.hosted.controller.api.integration.organization.Mailer; +import com.yahoo.vespa.hosted.controller.tenant.PendingMailVerification; import java.util.ArrayList; import java.util.HashMap; @@ -47,6 +48,11 @@ public class MockMailer implements Mailer { return "domain"; } + @Override + public void sendVerificationMail(PendingMailVerification pendingMailVerification) { + send(new Mail(List.of(pendingMailVerification.getMailAddress()), "subject", "message")); + } + /** Returns the list of mails sent to the given recipient. Modifications affect the set of mails stored in this. */ public List<Mail> inbox(String recipient) { return mails.getOrDefault(recipient, List.of()); diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java index c2682334ce0..b8de63b61a9 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java @@ -58,6 +58,7 @@ enum PathGroup { "/application/v4/tenant/{tenant}/info/profile", "/application/v4/tenant/{tenant}/info/billing", "/application/v4/tenant/{tenant}/info/contacts", + "/application/v4/tenant/{tenant}/info/resend-mail-verification", "/application/v4/tenant/{tenant}/notifications", "/routing/v1/status/tenant/{tenant}/{*}"), @@ -255,7 +256,10 @@ enum PathGroup { /** Paths used to approve requests to access tenant resources */ accessRequestApproval(Matcher.tenant, "/application/v4/tenant/{tenant}/access/approve/operator", - "/application/v4/tenant/{tenant}/access/managed/operator"); + "/application/v4/tenant/{tenant}/access/managed/operator"), + + /** Path used for email verification */ + emailVerification("/user/v1/email/verify"); final List<String> pathSpecs; final List<Matcher> matchers; diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java index 91eaec53aa4..2d4f98dfa8d 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java @@ -209,7 +209,11 @@ enum Policy { horizonProxyOperations(Privilege.grant(Action.all()) .on(PathGroup.horizonProxy) - .in(SystemName.PublicCd, SystemName.Public)); + .in(SystemName.PublicCd, SystemName.Public)), + + emailVerification(Privilege.grant(Action.create) + .on(PathGroup.emailVerification) + .in(SystemName.PublicCd, SystemName.Public)); private final Set<Privilege> privileges; diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java index a9d67c2d78a..e40c99a64be 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java @@ -28,7 +28,8 @@ public enum RoleDefinition { everyone(Policy.classifiedRead, Policy.publicRead, Policy.user, - Policy.tenantCreate), + Policy.tenantCreate, + Policy.emailVerification), /** Build service which may submit new applications for continuous deployment. */ buildService(everyone, diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Email.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Email.java new file mode 100644 index 00000000000..ea6e0e9c754 --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Email.java @@ -0,0 +1,56 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.tenant; + +import java.util.Objects; + +/** + * @author olaa + */ +public class Email { + + private final String emailAddress; + private final boolean isVerified; + + public Email(String emailAddress, boolean isVerified) { + this.emailAddress = emailAddress; + this.isVerified = isVerified; + } + + public String getEmailAddress() { + return emailAddress; + } + + public boolean isVerified() { + return isVerified; + } + + public static Email empty() { + return new Email("", true); + } + + public Email withEmailAddress(String emailAddress) { + return new Email(emailAddress, isVerified); + } + + public Email withVerification(boolean isVerified) { + return new Email(emailAddress, isVerified); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Email email = (Email) o; + return isVerified == email.isVerified && Objects.equals(emailAddress, email.emailAddress); + } + + @Override + public int hashCode() { + return Objects.hash(emailAddress, isVerified); + } + + @Override + public String toString() { + return emailAddress; + } +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/PendingMailVerification.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/PendingMailVerification.java new file mode 100644 index 00000000000..af5ae746d22 --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/PendingMailVerification.java @@ -0,0 +1,81 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.tenant; + +import com.yahoo.config.provision.TenantName; + +import java.time.Instant; +import java.util.List; +import java.util.Objects; + +/** + * @author olaa + */ +public class PendingMailVerification { + + private final TenantName tenantName; + private final String mailAddress; + private final String verificationCode; + private final Instant verificationDeadline; + private final MailType mailType; + + public PendingMailVerification(TenantName tenantName, String mailAddress, String verificationCode, Instant verificationDeadline, MailType mailType) { + this.tenantName = tenantName; + this.mailAddress = mailAddress; + this.verificationCode = verificationCode; + this.verificationDeadline = verificationDeadline; + this.mailType = mailType; + } + + public TenantName getTenantName() { + return tenantName; + } + + public String getMailAddress() { + return mailAddress; + } + + public String getVerificationCode() { + return verificationCode; + } + + public Instant getVerificationDeadline() { + return verificationDeadline; + } + + public MailType getMailType() { + return mailType; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PendingMailVerification that = (PendingMailVerification) o; + return Objects.equals(tenantName, that.tenantName) && + Objects.equals(mailAddress, that.mailAddress) && + Objects.equals(verificationCode, that.verificationCode) && + Objects.equals(verificationDeadline, that.verificationDeadline) && + mailType == that.mailType; + } + + @Override + public int hashCode() { + return Objects.hash(tenantName, mailAddress, verificationCode, verificationDeadline, mailType); + } + + @Override + public String toString() { + return "PendingMailVerification{" + + "tenantName=" + tenantName + + ", mailAddress='" + mailAddress + '\'' + + ", verificationCode='" + verificationCode + '\'' + + ", verificationDeadline=" + verificationDeadline + + ", mailType=" + mailType + + '}'; + } + + public enum MailType { + TENANT_CONTACT, + NOTIFICATIONS + } +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantContact.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantContact.java index 3aa5600ed87..482bb26bcf9 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantContact.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantContact.java @@ -8,36 +8,36 @@ import java.util.Objects; */ public class TenantContact { private final String name; - private final String email; + private final Email email; private final String phone; - private TenantContact(String name, String email, String phone) { + private TenantContact(String name, Email email, String phone) { this.name = Objects.requireNonNull(name); this.email = Objects.requireNonNull(email); this.phone = Objects.requireNonNull(phone); } - public static TenantContact from(String name, String email, String phone) { + public static TenantContact from(String name, Email email, String phone) { return new TenantContact(name, email, phone); } - public static TenantContact from(String name, String email) { + public static TenantContact from(String name, Email email) { return TenantContact.from(name, email, ""); } public static TenantContact empty() { - return new TenantContact("", "", ""); + return new TenantContact("", Email.empty(), ""); } public String name() { return name; } - public String email() { return email; } + public Email email() { return email; } public String phone() { return phone; } public TenantContact withName(String name) { return new TenantContact(name, email, phone); } - public TenantContact withEmail(String email) { + public TenantContact withEmail(Email email) { return new TenantContact(name, email, phone); } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantContacts.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantContacts.java index bd8671d814f..7e0fc50660e 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantContacts.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantContacts.java @@ -5,6 +5,7 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; /** * Tenant contacts are targets of the notification system. Sometimes they @@ -35,6 +36,13 @@ public class TenantContacts { return contacts; } + public <T extends Contact> List<T> ofType(Class<T> type) { + return contacts.stream() + .filter(type::isInstance) + .map(type::cast) + .collect(Collectors.toList()); + } + public boolean isEmpty() { return contacts.isEmpty(); } @@ -77,14 +85,18 @@ public class TenantContacts { } public static class EmailContact extends Contact { - private final String email; + private final Email email; - public EmailContact(List<Audience> audiences, String email) { + public EmailContact(List<Audience> audiences, Email email) { super(audiences); this.email = email; } - public String email() { return email; } + public Email email() { return email; } + + public EmailContact withEmail(Email email) { + return new EmailContact(audiences(), email); + } @Override public Type type() { diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfo.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfo.java index 0ca7863fbce..36a302ed0d8 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfo.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantInfo.java @@ -23,7 +23,7 @@ public class TenantInfo { private final TenantBilling billingContact; private final TenantContacts contacts; - TenantInfo(String name, String email, String website, String contactName, String contactEmail, + TenantInfo(String name, String email, String website, String contactName, Email contactEmail, TenantAddress address, TenantBilling billingContact, TenantContacts contacts) { this(name, email, website, TenantContact.from(contactName, contactEmail), address, billingContact, contacts); } @@ -39,7 +39,7 @@ public class TenantInfo { } public static TenantInfo empty() { - return new TenantInfo("", "", "", "", "", TenantAddress.empty(), TenantBilling.empty(), TenantContacts.empty()); + return new TenantInfo("", "", "", "", Email.empty(), TenantAddress.empty(), TenantBilling.empty(), TenantContacts.empty()); } public String name() { |