diff --git a/whois-api/src/main/java/net/ripe/db/whois/api/mail/dequeue/BouncedMessageParser.java b/whois-api/src/main/java/net/ripe/db/whois/api/mail/dequeue/BouncedMessageParser.java index 5217be8f55..7b201a3e93 100644 --- a/whois-api/src/main/java/net/ripe/db/whois/api/mail/dequeue/BouncedMessageParser.java +++ b/whois-api/src/main/java/net/ripe/db/whois/api/mail/dequeue/BouncedMessageParser.java @@ -11,6 +11,8 @@ import jakarta.mail.internet.MimeMultipart; import net.ripe.db.whois.api.mail.EmailMessageInfo; import net.ripe.db.whois.api.mail.exception.MailParsingException; +import net.ripe.db.whois.common.rpsl.AttributeParser; +import net.ripe.db.whois.common.rpsl.attrs.AttributeParseException; import org.apache.commons.compress.utils.Lists; import org.eclipse.angus.mail.dsn.DeliveryStatus; import org.eclipse.angus.mail.dsn.MultipartReport; @@ -40,6 +42,7 @@ public class BouncedMessageParser { private static final Pattern FINAL_RECIPIENT_MATCHER = Pattern.compile("(?i)^(rfc822;)\s?(.+@.+$)"); + private static final AttributeParser.EmailParser EMAIL_PARSER = new AttributeParser.EmailParser(); @Autowired public BouncedMessageParser(@Value("${mail.smtp.from:}") final String smtpFrom) { @@ -183,11 +186,23 @@ private List extractRecipients(final DeliveryStatus deliveryStatus) { LOGGER.error("Wrong formatted recipient {}", recipient); continue; } - recipients.add(finalRecipientMatcher.group(2)); + final String email = finalRecipientMatcher.group(2); + if (isValidEmail(email)) { + recipients.add(email); + } } return recipients; } + private boolean isValidEmail(final String email){ + try { + EMAIL_PARSER.parse(email); + return true; + } catch (AttributeParseException ex){ + return false; + } + } + private boolean isFailed(final DeliveryStatus deliveryStatus) { for (int dsn = 0; dsn < deliveryStatus.getRecipientDSNCount(); dsn++) { if ("failed".equals(getHeaderValue(deliveryStatus.getRecipientDSN(dsn), "Action"))) { diff --git a/whois-api/src/test/java/net/ripe/db/whois/api/mail/dequeue/BouncedMessageParserTest.java b/whois-api/src/test/java/net/ripe/db/whois/api/mail/dequeue/BouncedMessageParserTest.java index 7818e46bd4..bbe5d17d58 100644 --- a/whois-api/src/test/java/net/ripe/db/whois/api/mail/dequeue/BouncedMessageParserTest.java +++ b/whois-api/src/test/java/net/ripe/db/whois/api/mail/dequeue/BouncedMessageParserTest.java @@ -87,6 +87,14 @@ public void parse_permanent_delivery_failure_message_rfc822_headers_real() throw assertThat(bouncedMessage.emailAddresses(), containsInAnyOrder("testing4@ripe.net")); } + @Test + public void parse_permanent_delivery_failure_to_a_too_long_recipient_then_recipient_ignored() throws Exception { + final EmailMessageInfo bouncedMessage = subject.parse(MimeMessageProvider.getUpdateMessage("permanentFailureMessageRfc822TooLongAddress.mail")); + + assertThat(bouncedMessage.messageId(), is("XXXXXXXX-5AE3-4C58-8E3F-860327BA955D@ripe.net")); + assertThat(bouncedMessage.emailAddresses(), containsInAnyOrder("First.Person@host.org")); + } + @Test public void parse_permanent_delivery_failure_without_message_id() { final MailParsingException e = assertThrows(MailParsingException.class, () -> { diff --git a/whois-api/src/test/java/net/ripe/db/whois/api/mail/dequeue/MailBounceTestIntegration.java b/whois-api/src/test/java/net/ripe/db/whois/api/mail/dequeue/MailBounceTestIntegration.java index 4eabe89ece..a7de485f3a 100644 --- a/whois-api/src/test/java/net/ripe/db/whois/api/mail/dequeue/MailBounceTestIntegration.java +++ b/whois-api/src/test/java/net/ripe/db/whois/api/mail/dequeue/MailBounceTestIntegration.java @@ -178,6 +178,21 @@ public void permanent_delivery_failure_to_one_recipient_multiple_final_recipient } + @Test + public void permanent_delivery_failure_to_one_recipient_too_long_address_then_delete_message_without_marking_undeliverable_address() { + insertOutgoingMessageId("XXXXXXXX-5AE3-4C58-8E3F-860327BA955D@ripe.net", "noc@host.org"); + final MimeMessage message = MimeMessageProvider.getUpdateMessage("permanentFailureMessageRfc822JustOneTooLongAddress.mail"); + insertIncomingMessage(message); + + // wait for incoming message to be processed + Awaitility.waitAtMost(10L, TimeUnit.SECONDS).until(() -> (! anyIncomingMessages())); + + // delayed message has been processed but address is not set to undeliverable + assertThat(isUndeliverableAddress("noc@host.org"), is(false)); + assertThat(isUndeliverableAddress("G=noreply/S=noreply/O=noreplynoreplynorepl/P=AA/A=ripe.net/C=SP/@noreply.ripe.net"), is(false)); + } + + @Test public void delayed_delivery_is_not_permanently_undeliverable() { // insert delayed response diff --git a/whois-api/src/test/java/net/ripe/db/whois/api/rest/WhoisRestServiceTestIntegration.java b/whois-api/src/test/java/net/ripe/db/whois/api/rest/WhoisRestServiceTestIntegration.java index 08c50b96d9..af6f91c0bb 100644 --- a/whois-api/src/test/java/net/ripe/db/whois/api/rest/WhoisRestServiceTestIntegration.java +++ b/whois-api/src/test/java/net/ripe/db/whois/api/rest/WhoisRestServiceTestIntegration.java @@ -5823,6 +5823,31 @@ public void undeliverable_notify_user_gets_warn_when_updating() { undeliverableEmail, EmailStatus.UNDELIVERABLE.getValue()); } + + @Test + public void create_too_big_address_then_error() { + final RpslObject PAULETH_PALTHEN_LONG_EMAIL = RpslObject.parse("" + + "person: Pauleth Palthen\n" + + "address: Singel 258\n" + + "phone: +31-1234567890\n" + + "e-mail: G=noreply/S=noreply/O=noreplynoreplynorepl/P=AA/A=ripe.net/C=SP/@noreply.ripe.net\n" + + "mnt-by: OWNER-MNT\n" + + "nic-hdl: PP1-TEST\n" + + "remarks: remark\n" + + "source: TEST\n"); + + final BadRequestException badRequestException = assertThrows(BadRequestException.class, () -> { + RestTest.target(getPort(), "whois/test/person?password=test") + .request() + .post(Entity.entity(map(PAULETH_PALTHEN_LONG_EMAIL), MediaType.APPLICATION_JSON_TYPE), WhoisResources.class); + }); + + assertThat(badRequestException.getMessage(), is("HTTP 400 Bad Request")); + final WhoisResources whoisResources = RestTest.mapClientException(badRequestException); + RestTest.assertErrorCount(whoisResources, 1); + RestTest.assertErrorMessage(whoisResources, 0, "Error", "Syntax error in %s", "G=noreply/S=noreply/O=noreplynoreplynorepl/P=AA/A=ripe.net/C=SP/@noreply.ripe.net"); + } + // helper methods private String encode(final String input) { diff --git a/whois-api/src/test/resources/testMail/permanentFailureMessageRfc822JustOneTooLongAddress.mail b/whois-api/src/test/resources/testMail/permanentFailureMessageRfc822JustOneTooLongAddress.mail new file mode 100644 index 0000000000..5195b21d50 --- /dev/null +++ b/whois-api/src/test/resources/testMail/permanentFailureMessageRfc822JustOneTooLongAddress.mail @@ -0,0 +1,81 @@ +Return-path: <> +Envelope-to: test-dbm@ripe.net +Delivery-date: Fri, 23 Feb 2024 17:29:29 +0200 +Received: from mahimahi.ripe.net ([193.0.19.1]) + by allealle.ripe.net with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + (Exim 4.94) + id xxxxxx-0004d4-OF + for test-dbm@ripe.net; Fri, 23 Feb 2024 17:29:29 +0200 +Received: from abc1.host.org ([68.232.147.154]:21686) + by mahimahi.ripe.net with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + (Exim 4.94.2) + id xxxxxx-0009P6-50 + for test-dbm@ripe.net; Fri, 23 Feb 2024 17:29:29 +0200 +Received: from localhost by abc1.host.org; + 23 Feb 2024 11:29:19 -0400 +Message-Id: +Date: 23 Feb 2024 11:29:19 -0400 +To: test-dbm@ripe.net +From: "Mail Delivery System" +Subject: Delivery Status Notification (Failure) +MIME-Version: 1.0 +Content-Type: multipart/report; report-type=delivery-status; boundary="6KTYe.5maleLdVv.5/WobWlHy4k.7vnm51B" +Delivered-To: test-dbm@ripe.net + +--6KTYe.5maleLdVv.5/WobWlHy4k.7vnm51B +content-type: text/plain; + charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +The following message to was undeliverable. +The reason for the problem: +5.1.0 - Unknown address error 550-'5.4.1 Recipient address rejected: Access= + denied. AS(3333) [xxx.protection.outlook.com= +]' + +--6KTYe.5maleLdVv.5/WobWlHy4k.7vnm51B +Content-Type: message/delivery-status + +Reporting-MTA: dns; mx0.host.org +Received-From-MTA: DNS; mx0.host.org +Arrival-Date: Thu, 4 Apr 2024 09:26:37 +0300 + +Original-Recipient: rfc822;G=noreply/S=noreply/O=noreplynoreplynorepl/P=AA/A=ripe.net/C=SP/@noreply.ripe.net +Final-Recipient: RFC822; G=noreply/S=noreply/O=noreplynoreplynorepl/P=AA/A=ripe.net/C=SP/@noreply.ripe.net +Action: failed +Status: 5.7.1 +Remote-MTA: DNS; mx0.host.org +Diagnostic-Code: SMTP; 550 5.7.1 This message is blocked due to security reason +Last-Attempt-Date: Thu, 4 Apr 2024 09:26:40 +0300 + +--6KTYe.5maleLdVv.5/WobWlHy4k.7vnm51B +content-type: message/rfc822 + +Received: from mahimahi.ripe.net ([193.0.19.1]) + by abc1.host.org with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Feb 2024 11:29:15 -0400 +Received: from allealle.ripe.net ([193.0.23.2]:38580) + by mahimahi.ripe.net with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + (Exim 4.94.2) + (envelope-from ) + id xxxxxx-0009Oo-Ib + for nonexistant@host.org; Fri, 23 Feb 2024 17:29:13 +0200 +Received: from whois.ipv6.ripe.net ([2001:67c:2e8:9::1234] helo=smtpclient.apple) + by allealle.ripe.net with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + (Exim 4.94) + (envelope-from ) + id xxxxxx-0004cV-FW + for nonexistant@host.org; Fri, 23 Feb 2024 17:29:13 +0200 +From: Test DBM +Reply-To: test-dbm@ripe.net +Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.80.0.2.43\)) +Subject: Test Message +Message-Id: +Date: Fri, 23 Feb 2024 17:29:10 +0200 +To: noc@host.org +X-Mailer: Apple Mail (2.3654.80.0.2.43) +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: base64 + +--6KTYe.5maleLdVv.5/WobWlHy4k.7vnm51B-- + + diff --git a/whois-api/src/test/resources/testMail/permanentFailureMessageRfc822TooLongAddress.mail b/whois-api/src/test/resources/testMail/permanentFailureMessageRfc822TooLongAddress.mail new file mode 100644 index 0000000000..8b6ae5ecaa --- /dev/null +++ b/whois-api/src/test/resources/testMail/permanentFailureMessageRfc822TooLongAddress.mail @@ -0,0 +1,89 @@ +Return-path: <> +Envelope-to: test-dbm@ripe.net +Delivery-date: Fri, 23 Feb 2024 17:29:29 +0200 +Received: from mahimahi.ripe.net ([193.0.19.1]) + by allealle.ripe.net with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + (Exim 4.94) + id xxxxxx-0004d4-OF + for test-dbm@ripe.net; Fri, 23 Feb 2024 17:29:29 +0200 +Received: from abc1.host.org ([68.232.147.154]:21686) + by mahimahi.ripe.net with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + (Exim 4.94.2) + id xxxxxx-0009P6-50 + for test-dbm@ripe.net; Fri, 23 Feb 2024 17:29:29 +0200 +Received: from localhost by abc1.host.org; + 23 Feb 2024 11:29:19 -0400 +Message-Id: +Date: 23 Feb 2024 11:29:19 -0400 +To: test-dbm@ripe.net +From: "Mail Delivery System" +Subject: Delivery Status Notification (Failure) +MIME-Version: 1.0 +Content-Type: multipart/report; report-type=delivery-status; boundary="6KTYe.5maleLdVv.5/WobWlHy4k.7vnm51B" +Delivered-To: test-dbm@ripe.net + +--6KTYe.5maleLdVv.5/WobWlHy4k.7vnm51B +content-type: text/plain; + charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +The following message to was undeliverable. +The reason for the problem: +5.1.0 - Unknown address error 550-'5.4.1 Recipient address rejected: Access= + denied. AS(3333) [xxx.protection.outlook.com= +]' + +--6KTYe.5maleLdVv.5/WobWlHy4k.7vnm51B +Content-Type: message/delivery-status + +Reporting-MTA: dns; mx0.host.org +Received-From-MTA: DNS; mx0.host.org +Arrival-Date: Thu, 4 Apr 2024 09:26:37 +0300 + +Original-Recipient: rfc822;noc@host.org +Final-Recipient: RFC822; First.Person@host.org +Action: failed +Status: 5.7.1 +Remote-MTA: DNS; mx0.host.org +Diagnostic-Code: SMTP; 550 5.7.1 This message is blocked due to security reason +Last-Attempt-Date: Thu, 4 Apr 2024 09:26:40 +0300 + +Original-Recipient: rfc822;G=noreply/S=noreply/O=noreplynoreplynorepl/P=AA/A=ripe.net/C=SP/@noreply.ripe.net +Final-Recipient: RFC822; G=noreply/S=noreply/O=noreplynoreplynorepl/P=AA/A=ripe.net/C=SP/@noreply.ripe.net +Action: failed +Status: 5.7.1 +Remote-MTA: DNS; mx0.host.org +Diagnostic-Code: SMTP; 550 5.7.1 This message is blocked due to security reason +Last-Attempt-Date: Thu, 4 Apr 2024 09:26:40 +0300 + +--6KTYe.5maleLdVv.5/WobWlHy4k.7vnm51B +content-type: message/rfc822 + +Received: from mahimahi.ripe.net ([193.0.19.1]) + by abc1.host.org with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Feb 2024 11:29:15 -0400 +Received: from allealle.ripe.net ([193.0.23.2]:38580) + by mahimahi.ripe.net with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + (Exim 4.94.2) + (envelope-from ) + id xxxxxx-0009Oo-Ib + for nonexistant@host.org; Fri, 23 Feb 2024 17:29:13 +0200 +Received: from whois.ipv6.ripe.net ([2001:67c:2e8:9::1234] helo=smtpclient.apple) + by allealle.ripe.net with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + (Exim 4.94) + (envelope-from ) + id xxxxxx-0004cV-FW + for nonexistant@host.org; Fri, 23 Feb 2024 17:29:13 +0200 +From: Test DBM +Reply-To: test-dbm@ripe.net +Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.80.0.2.43\)) +Subject: Test Message +Message-Id: +Date: Fri, 23 Feb 2024 17:29:10 +0200 +To: noc@host.org +X-Mailer: Apple Mail (2.3654.80.0.2.43) +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: base64 + +--6KTYe.5maleLdVv.5/WobWlHy4k.7vnm51B-- + + diff --git a/whois-rpsl/src/main/java/net/ripe/db/whois/common/rpsl/AttributeParser.java b/whois-rpsl/src/main/java/net/ripe/db/whois/common/rpsl/AttributeParser.java index 2cf60f7be8..6f29bf0824 100644 --- a/whois-rpsl/src/main/java/net/ripe/db/whois/common/rpsl/AttributeParser.java +++ b/whois-rpsl/src/main/java/net/ripe/db/whois/common/rpsl/AttributeParser.java @@ -180,6 +180,8 @@ public String parse(final String s) { final class EmailParser implements AttributeParser { + private static final int MAXIMUM_LENGTH = 80; + @Override public InternetAddress parse(final String s) { final InternetAddress[] parsed; @@ -199,6 +201,11 @@ public InternetAddress parse(final String s) { final String address = parsed[0].getAddress(); final String localPart = address.substring(0, address.indexOf('@')); + if (address.length() > MAXIMUM_LENGTH){ + throw new AttributeParseException(String.format("Illegal address length, maximum supported length is %d", + MAXIMUM_LENGTH), s); + } + if (!StandardCharsets.US_ASCII.newEncoder().canEncode(localPart)) { throw new AttributeParseException("Address contains non ASCII characters (%s)", s); } diff --git a/whois-rpsl/src/test/java/net/ripe/db/whois/common/rpsl/AttributeSyntaxTest.java b/whois-rpsl/src/test/java/net/ripe/db/whois/common/rpsl/AttributeSyntaxTest.java index dae94d9b00..31a05dc6e8 100644 --- a/whois-rpsl/src/test/java/net/ripe/db/whois/common/rpsl/AttributeSyntaxTest.java +++ b/whois-rpsl/src/test/java/net/ripe/db/whois/common/rpsl/AttributeSyntaxTest.java @@ -239,12 +239,13 @@ public void email() { verifyFailure(ObjectType.PERSON, AttributeType.E_MAIL, "user@host.org 20180529"); verifyFailure(ObjectType.PERSON, AttributeType.E_MAIL, "a.a.a"); verifyFailure(ObjectType.PERSON, AttributeType.E_MAIL, "user"); + verifyFailure(ObjectType.PERSON, AttributeType.E_MAIL, "0@2.45678901234567890123456789012345678901234567890123456789012345678901234567890"); //To large email verifySuccess(ObjectType.PERSON, AttributeType.E_MAIL, "a@a"); verifySuccess(ObjectType.PERSON, AttributeType.E_MAIL, "user@host.org"); verifySuccess(ObjectType.PERSON, AttributeType.E_MAIL, "Any User "); verifySuccess(ObjectType.PERSON, AttributeType.E_MAIL, "a@a.a"); - verifySuccess(ObjectType.PERSON, AttributeType.E_MAIL, "0@2.45678901234567890123456789012345678901234567890123456789012345678901234567890"); + verifySuccess(ObjectType.PERSON, AttributeType.E_MAIL, "0@2.4567890123456789012345678901234567890123456789012345678901234567890123456789"); verifySuccess(ObjectType.PERSON, AttributeType.E_MAIL, "test@ümlaut.email"); }