mirror of
https://github.com/google/nomulus.git
synced 2025-08-14 21:44:05 +02:00
Send expiring notification emails to admins if no tech emails are on file (#1387)
* Send emails to admin if tech emails are not present * Improve test cases and comments
This commit is contained in:
parent
1a4a31569e
commit
43074ea32f
2 changed files with 182 additions and 121 deletions
|
@ -113,9 +113,11 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of registrars that should receive expiring notification emails. There are two
|
* Returns a list of registrars that should receive expiring notification emails.
|
||||||
* certificates that should be considered (the main certificate and failOver certificate). The
|
*
|
||||||
* registrars should receive notifications if one of the certificate checks returns true.
|
* <p>There are two certificates that should be considered (the main certificate and failOver
|
||||||
|
* certificate). The registrars should receive notifications if one of the certificate checks
|
||||||
|
* returns true.
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
ImmutableList<RegistrarInfo> getRegistrarsWithExpiringCertificates() {
|
ImmutableList<RegistrarInfo> getRegistrarsWithExpiringCertificates() {
|
||||||
|
@ -157,15 +159,17 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ImmutableSet<InternetAddress> recipients = getEmailAddresses(registrar, Type.TECH);
|
ImmutableSet<InternetAddress> recipients = getEmailAddresses(registrar, Type.TECH);
|
||||||
|
ImmutableSet<InternetAddress> ccs = getEmailAddresses(registrar, Type.ADMIN);
|
||||||
Date expirationDate = certificateChecker.getCertificate(certificate.get()).getNotAfter();
|
Date expirationDate = certificateChecker.getCertificate(certificate.get()).getNotAfter();
|
||||||
logger.atInfo().log(
|
logger.atInfo().log(
|
||||||
"Registrar %s should receive an email that its %s SSL certificate will expire on %s.",
|
" %s SSL certificate of registrar '%s' will expire on %s.",
|
||||||
registrar.getRegistrarName(),
|
|
||||||
certificateType.getDisplayName(),
|
certificateType.getDisplayName(),
|
||||||
|
registrar.getRegistrarName(),
|
||||||
expirationDate.toString());
|
expirationDate.toString());
|
||||||
if (recipients.isEmpty()) {
|
if (recipients.isEmpty() && ccs.isEmpty()) {
|
||||||
logger.atWarning().log(
|
logger.atWarning().log(
|
||||||
"Registrar %s contains no email addresses to receive notification email.",
|
"Registrar %s contains no TECH nor ADMIN email addresses to receive notification"
|
||||||
|
+ " email.",
|
||||||
registrar.getRegistrarName());
|
registrar.getRegistrarName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -180,7 +184,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||||
expirationDate,
|
expirationDate,
|
||||||
registrar.getRegistrarId()))
|
registrar.getRegistrarId()))
|
||||||
.setRecipients(recipients)
|
.setRecipients(recipients)
|
||||||
.setCcs(getEmailAddresses(registrar, Type.ADMIN))
|
.setCcs(ccs)
|
||||||
.build());
|
.build());
|
||||||
/*
|
/*
|
||||||
* A duration time offset is used here to ensure that date comparison between two
|
* A duration time offset is used here to ensure that date comparison between two
|
||||||
|
@ -249,30 +253,32 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||||
/** Sends notification emails to registrars with expiring certificates. */
|
/** Sends notification emails to registrars with expiring certificates. */
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
int sendNotificationEmails() {
|
int sendNotificationEmails() {
|
||||||
int emailsSent = 0;
|
int numEmailsSent = 0;
|
||||||
for (RegistrarInfo registrarInfo : getRegistrarsWithExpiringCertificates()) {
|
for (RegistrarInfo registrarInfo : getRegistrarsWithExpiringCertificates()) {
|
||||||
Registrar registrar = registrarInfo.registrar();
|
Registrar registrar = registrarInfo.registrar();
|
||||||
if (registrarInfo.isCertExpiring()) {
|
if (registrarInfo.isCertExpiring()
|
||||||
sendNotificationEmail(
|
&& sendNotificationEmail(
|
||||||
registrar,
|
registrar,
|
||||||
registrar.getLastExpiringCertNotificationSentDate(),
|
registrar.getLastExpiringCertNotificationSentDate(),
|
||||||
CertificateType.PRIMARY,
|
CertificateType.PRIMARY,
|
||||||
registrar.getClientCertificate());
|
registrar.getClientCertificate())) {
|
||||||
emailsSent++;
|
numEmailsSent++;
|
||||||
}
|
}
|
||||||
if (registrarInfo.isFailOverCertExpiring()) {
|
if (registrarInfo.isFailOverCertExpiring()
|
||||||
sendNotificationEmail(
|
&& sendNotificationEmail(
|
||||||
registrar,
|
registrar,
|
||||||
registrar.getLastExpiringFailoverCertNotificationSentDate(),
|
registrar.getLastExpiringFailoverCertNotificationSentDate(),
|
||||||
CertificateType.FAILOVER,
|
CertificateType.FAILOVER,
|
||||||
registrar.getFailoverClientCertificate());
|
registrar.getFailoverClientCertificate())) {
|
||||||
emailsSent++;
|
numEmailsSent++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return emailsSent;
|
return numEmailsSent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a list of email addresses of the registrar that should receive a notification email */
|
/**
|
||||||
|
* Returns a list of email addresses of the registrar that should receive a notification email.
|
||||||
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
ImmutableSet<InternetAddress> getEmailAddresses(Registrar registrar, Type contactType) {
|
ImmutableSet<InternetAddress> getEmailAddresses(Registrar registrar, Type contactType) {
|
||||||
ImmutableSortedSet<RegistrarContact> contacts = registrar.getContactsOfType(contactType);
|
ImmutableSortedSet<RegistrarContact> contacts = registrar.getContactsOfType(contactType);
|
||||||
|
|
|
@ -142,7 +142,7 @@ class SendExpiringCertificateNotificationEmailActionTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestOfyAndSql
|
@TestOfyAndSql
|
||||||
void sendNotificationEmail_returnsTrue() throws Exception {
|
void sendNotificationEmail_techEMailAsRecipient_returnsTrue() throws Exception {
|
||||||
X509Certificate expiringCertificate =
|
X509Certificate expiringCertificate =
|
||||||
SelfSignedCaCertificate.create(
|
SelfSignedCaCertificate.create(
|
||||||
"www.example.tld",
|
"www.example.tld",
|
||||||
|
@ -157,25 +157,64 @@ class SendExpiringCertificateNotificationEmailActionTest {
|
||||||
.asBuilder()
|
.asBuilder()
|
||||||
.setFailoverClientCertificate(cert.get(), clock.nowUtc())
|
.setFailoverClientCertificate(cert.get(), clock.nowUtc())
|
||||||
.build());
|
.build());
|
||||||
ImmutableList<RegistrarContact> contacts =
|
persistSampleContacts(registrar, Type.TECH);
|
||||||
ImmutableList.of(
|
|
||||||
new RegistrarContact.Builder()
|
|
||||||
.setParent(registrar)
|
|
||||||
.setName("Will Doe")
|
|
||||||
.setEmailAddress("will@example-registrar.tld")
|
|
||||||
.setPhoneNumber("+1.3105551213")
|
|
||||||
.setFaxNumber("+1.3105551213")
|
|
||||||
.setTypes(ImmutableSet.of(RegistrarContact.Type.TECH))
|
|
||||||
.setVisibleInWhoisAsAdmin(true)
|
|
||||||
.setVisibleInWhoisAsTech(false)
|
|
||||||
.build());
|
|
||||||
persistSimpleResources(contacts);
|
|
||||||
persistResource(registrar);
|
|
||||||
assertThat(
|
assertThat(
|
||||||
action.sendNotificationEmail(registrar, START_OF_TIME, CertificateType.FAILOVER, cert))
|
action.sendNotificationEmail(registrar, START_OF_TIME, CertificateType.FAILOVER, cert))
|
||||||
.isEqualTo(true);
|
.isEqualTo(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestOfyAndSql
|
||||||
|
void sendNotificationEmail_adminEMailAsRecipient_returnsTrue() throws Exception {
|
||||||
|
X509Certificate expiringCertificate =
|
||||||
|
SelfSignedCaCertificate.create(
|
||||||
|
"www.example.tld",
|
||||||
|
DateTime.parse("2020-09-02T00:00:00Z"),
|
||||||
|
DateTime.parse("2021-06-01T00:00:00Z"))
|
||||||
|
.cert();
|
||||||
|
Optional<String> cert =
|
||||||
|
Optional.of(certificateChecker.serializeCertificate(expiringCertificate));
|
||||||
|
Registrar registrar =
|
||||||
|
persistResource(
|
||||||
|
makeRegistrar1()
|
||||||
|
.asBuilder()
|
||||||
|
.setFailoverClientCertificate(cert.get(), clock.nowUtc())
|
||||||
|
.build());
|
||||||
|
persistSampleContacts(registrar, Type.ADMIN);
|
||||||
|
assertThat(
|
||||||
|
action.sendNotificationEmail(registrar, START_OF_TIME, CertificateType.FAILOVER, cert))
|
||||||
|
.isEqualTo(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestOfyAndSql
|
||||||
|
void sendNotificationEmail_returnsFalse_unsupportedEmailType() throws Exception {
|
||||||
|
Registrar registrar =
|
||||||
|
persistResource(
|
||||||
|
createRegistrar(
|
||||||
|
"testId",
|
||||||
|
"testName",
|
||||||
|
SelfSignedCaCertificate.create(
|
||||||
|
"www.example.tld",
|
||||||
|
DateTime.parse("2020-09-02T00:00:00Z"),
|
||||||
|
DateTime.parse("2021-06-01T00:00:00Z"))
|
||||||
|
.cert(),
|
||||||
|
null)
|
||||||
|
.build());
|
||||||
|
persistSampleContacts(registrar, Type.LEGAL);
|
||||||
|
assertThat(
|
||||||
|
action.sendNotificationEmail(
|
||||||
|
registrar,
|
||||||
|
START_OF_TIME,
|
||||||
|
CertificateType.FAILOVER,
|
||||||
|
Optional.of(
|
||||||
|
certificateChecker.serializeCertificate(
|
||||||
|
SelfSignedCaCertificate.create(
|
||||||
|
"www.example.tld",
|
||||||
|
DateTime.parse("2020-09-02T00:00:00Z"),
|
||||||
|
DateTime.parse("2021-06-01T00:00:00Z"))
|
||||||
|
.cert()))))
|
||||||
|
.isEqualTo(false);
|
||||||
|
}
|
||||||
|
|
||||||
@TestOfyAndSql
|
@TestOfyAndSql
|
||||||
void sendNotificationEmail_returnsFalse_noEmailRecipients() throws Exception {
|
void sendNotificationEmail_returnsFalse_noEmailRecipients() throws Exception {
|
||||||
X509Certificate expiringCertificate =
|
X509Certificate expiringCertificate =
|
||||||
|
@ -247,93 +286,82 @@ class SendExpiringCertificateNotificationEmailActionTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestOfyAndSql
|
@TestOfyAndSql
|
||||||
void sendNotificationEmails_allEmailsBeingAttemptedToSend() throws Exception {
|
void sendNotificationEmails_allEmailsBeingSent_onlyMainCertificates() throws Exception {
|
||||||
X509Certificate expiringCertificate =
|
for (int i = 1; i <= 10; i++) {
|
||||||
SelfSignedCaCertificate.create(
|
Registrar registrar =
|
||||||
"www.example.tld",
|
persistResource(
|
||||||
DateTime.parse("2020-09-02T00:00:00Z"),
|
createRegistrar(
|
||||||
DateTime.parse("2021-06-01T00:00:00Z"))
|
"oldcert" + i,
|
||||||
.cert();
|
"name" + i,
|
||||||
X509Certificate certificate =
|
SelfSignedCaCertificate.create(
|
||||||
SelfSignedCaCertificate.create(
|
"www.example.tld",
|
||||||
"www.example.tld",
|
DateTime.parse("2020-09-02T00:00:00Z"),
|
||||||
DateTime.parse("2020-09-02T00:00:00Z"),
|
DateTime.parse("2021-06-01T00:00:00Z"))
|
||||||
DateTime.parse("2021-10-01T00:00:00Z"))
|
.cert(),
|
||||||
.cert();
|
null)
|
||||||
int numOfRegistrars = 10;
|
.build());
|
||||||
int numOfRegistrarsWithExpiringCertificates = 2;
|
persistSampleContacts(registrar, Type.TECH);
|
||||||
for (int i = 1; i <= numOfRegistrarsWithExpiringCertificates; i++) {
|
|
||||||
persistResource(
|
|
||||||
createRegistrar("oldcert" + i, "name" + i, expiringCertificate, null).build());
|
|
||||||
}
|
}
|
||||||
for (int i = numOfRegistrarsWithExpiringCertificates; i <= numOfRegistrars; i++) {
|
assertThat(action.sendNotificationEmails()).isEqualTo(10);
|
||||||
persistResource(createRegistrar("goodcert" + i, "name" + i, certificate, null).build());
|
|
||||||
}
|
|
||||||
assertThat(action.sendNotificationEmails()).isEqualTo(numOfRegistrarsWithExpiringCertificates);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestOfyAndSql
|
@TestOfyAndSql
|
||||||
void sendNotificationEmails_allEmailsBeingAttemptedToSend_onlyMainCertificates()
|
void sendNotificationEmails_allEmailsBeingSent_onlyFailOverCertificates() throws Exception {
|
||||||
throws Exception {
|
for (int i = 1; i <= 10; i++) {
|
||||||
X509Certificate expiringCertificate =
|
Registrar registrar =
|
||||||
SelfSignedCaCertificate.create(
|
persistResource(
|
||||||
"www.example.tld",
|
createRegistrar(
|
||||||
DateTime.parse("2020-09-02T00:00:00Z"),
|
"oldcert" + i,
|
||||||
DateTime.parse("2021-06-01T00:00:00Z"))
|
"name" + i,
|
||||||
.cert();
|
null,
|
||||||
int numOfRegistrars = 10;
|
SelfSignedCaCertificate.create(
|
||||||
for (int i = 1; i <= numOfRegistrars; i++) {
|
"www.example.tld",
|
||||||
persistResource(
|
DateTime.parse("2020-09-02T00:00:00Z"),
|
||||||
createRegistrar("oldcert" + i, "name" + i, expiringCertificate, null).build());
|
DateTime.parse("2021-06-01T00:00:00Z"))
|
||||||
|
.cert())
|
||||||
|
.build());
|
||||||
|
persistSampleContacts(registrar, Type.TECH);
|
||||||
}
|
}
|
||||||
assertThat(action.sendNotificationEmails()).isEqualTo(numOfRegistrars);
|
assertThat(action.sendNotificationEmails()).isEqualTo(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestOfyAndSql
|
@TestOfyAndSql
|
||||||
void sendNotificationEmails_allEmailsBeingAttemptedToSend_onlyFailOverCertificates()
|
void sendNotificationEmails_allEmailsBeingSent_mixedOfCertificates() throws Exception {
|
||||||
throws Exception {
|
|
||||||
X509Certificate expiringCertificate =
|
X509Certificate expiringCertificate =
|
||||||
SelfSignedCaCertificate.create(
|
SelfSignedCaCertificate.create(
|
||||||
"www.example.tld",
|
"www.example.tld",
|
||||||
DateTime.parse("2020-09-02T00:00:00Z"),
|
DateTime.parse("2020-09-02T00:00:00Z"),
|
||||||
DateTime.parse("2021-06-01T00:00:00Z"))
|
DateTime.parse("2021-06-01T00:00:00Z"))
|
||||||
.cert();
|
.cert();
|
||||||
int numOfRegistrars = 10;
|
|
||||||
for (int i = 1; i <= numOfRegistrars; i++) {
|
|
||||||
persistResource(
|
|
||||||
createRegistrar("oldcert" + i, "name" + i, null, expiringCertificate).build());
|
|
||||||
}
|
|
||||||
assertThat(action.sendNotificationEmails()).isEqualTo(numOfRegistrars);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestOfyAndSql
|
for (int i = 1; i <= 3; i++) {
|
||||||
void sendNotificationEmails_allEmailsBeingAttemptedToSend_mixedOfCertificates() throws Exception {
|
Registrar registrar =
|
||||||
X509Certificate expiringCertificate =
|
persistResource(
|
||||||
SelfSignedCaCertificate.create(
|
createRegistrar(
|
||||||
"www.example.tld",
|
"cl" + i, "regWIthexpiringFailOverOnly" + i, null, expiringCertificate)
|
||||||
DateTime.parse("2020-09-02T00:00:00Z"),
|
.build());
|
||||||
DateTime.parse("2021-06-01T00:00:00Z"))
|
persistSampleContacts(registrar, Type.TECH);
|
||||||
.cert();
|
|
||||||
int numOfRegistrars = 10;
|
|
||||||
int numOfExpiringFailOverOnly = 2;
|
|
||||||
int numOfExpiringPrimaryOnly = 3;
|
|
||||||
for (int i = 1; i <= numOfExpiringFailOverOnly; i++) {
|
|
||||||
persistResource(
|
|
||||||
createRegistrar("cl" + i, "expiringFailOverOnly" + i, null, expiringCertificate).build());
|
|
||||||
}
|
}
|
||||||
for (int i = 1; i <= numOfExpiringPrimaryOnly; i++) {
|
for (int i = 1; i <= 5; i++) {
|
||||||
persistResource(
|
Registrar registrar =
|
||||||
createRegistrar("cli" + i, "expiringPrimaryOnly" + i, expiringCertificate, null).build());
|
persistResource(
|
||||||
|
createRegistrar(
|
||||||
|
"cli" + i, "regWithexpiringPrimaryOnly" + i, expiringCertificate, null)
|
||||||
|
.build());
|
||||||
|
persistSampleContacts(registrar, Type.TECH);
|
||||||
}
|
}
|
||||||
for (int i = numOfExpiringFailOverOnly + numOfExpiringPrimaryOnly + 1;
|
for (int i = 1; i <= 4; i++) {
|
||||||
i <= numOfRegistrars;
|
Registrar registrar =
|
||||||
i++) {
|
persistResource(
|
||||||
persistResource(
|
createRegistrar(
|
||||||
createRegistrar("client" + i, "regularReg" + i, expiringCertificate, expiringCertificate)
|
"client" + i,
|
||||||
.build());
|
"regWithTwoExpiring" + i,
|
||||||
|
expiringCertificate,
|
||||||
|
expiringCertificate)
|
||||||
|
.build());
|
||||||
|
persistSampleContacts(registrar, Type.ADMIN);
|
||||||
}
|
}
|
||||||
assertThat(action.sendNotificationEmails())
|
assertThat(action.sendNotificationEmails()).isEqualTo(16);
|
||||||
.isEqualTo(numOfRegistrars + numOfExpiringFailOverOnly + numOfExpiringPrimaryOnly);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestOfyAndSql
|
@TestOfyAndSql
|
||||||
|
@ -649,17 +677,19 @@ class SendExpiringCertificateNotificationEmailActionTest {
|
||||||
@TestOfyAndSql
|
@TestOfyAndSql
|
||||||
void run_sentEmails_responseStatusIs200() throws Exception {
|
void run_sentEmails_responseStatusIs200() throws Exception {
|
||||||
for (int i = 1; i <= 5; i++) {
|
for (int i = 1; i <= 5; i++) {
|
||||||
persistResource(
|
Registrar registrar =
|
||||||
createRegistrar(
|
persistResource(
|
||||||
"id_" + i,
|
createRegistrar(
|
||||||
"name" + i,
|
"id_" + i,
|
||||||
SelfSignedCaCertificate.create(
|
"name" + i,
|
||||||
"www.example.tld",
|
SelfSignedCaCertificate.create(
|
||||||
DateTime.parse("2020-09-02T00:00:00Z"),
|
"www.example.tld",
|
||||||
DateTime.parse("2021-06-01T00:00:00Z"))
|
DateTime.parse("2020-09-02T00:00:00Z"),
|
||||||
.cert(),
|
DateTime.parse("2021-06-01T00:00:00Z"))
|
||||||
null)
|
.cert(),
|
||||||
.build());
|
null)
|
||||||
|
.build());
|
||||||
|
persistSampleContacts(registrar, Type.TECH);
|
||||||
}
|
}
|
||||||
action.run();
|
action.run();
|
||||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||||
|
@ -667,7 +697,9 @@ class SendExpiringCertificateNotificationEmailActionTest {
|
||||||
.isEqualTo("Done. Sent 5 expiring certificate notification emails in total.");
|
.isEqualTo("Done. Sent 5 expiring certificate notification emails in total.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a sample registrar with a customized registrar name, client id and certificate* */
|
/**
|
||||||
|
* Returns a sample registrar builder with a customized registrar name, client id and certificate.
|
||||||
|
*/
|
||||||
private Registrar.Builder createRegistrar(
|
private Registrar.Builder createRegistrar(
|
||||||
String registrarId,
|
String registrarId,
|
||||||
String registrarName,
|
String registrarName,
|
||||||
|
@ -706,4 +738,27 @@ class SendExpiringCertificateNotificationEmailActionTest {
|
||||||
}
|
}
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns persisted sample contacts with a customized contact email type. */
|
||||||
|
private ImmutableList<RegistrarContact> persistSampleContacts(
|
||||||
|
Registrar registrar, RegistrarContact.Type emailType) {
|
||||||
|
return persistSimpleResources(
|
||||||
|
ImmutableList.of(
|
||||||
|
new RegistrarContact.Builder()
|
||||||
|
.setParent(registrar)
|
||||||
|
.setName("Will Doe")
|
||||||
|
.setEmailAddress("will@example-registrar.tld")
|
||||||
|
.setPhoneNumber("+1.0105551213")
|
||||||
|
.setFaxNumber("+1.0105551213")
|
||||||
|
.setTypes(ImmutableSet.of(emailType))
|
||||||
|
.build(),
|
||||||
|
new RegistrarContact.Builder()
|
||||||
|
.setParent(registrar)
|
||||||
|
.setName("Will Smith")
|
||||||
|
.setEmailAddress("will@test-registrar.tld")
|
||||||
|
.setPhoneNumber("+1.3105551213")
|
||||||
|
.setFaxNumber("+1.3105551213")
|
||||||
|
.setTypes(ImmutableSet.of(emailType))
|
||||||
|
.build()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue