Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attribute Parser Should return an error if Email is longer than 80 characters #1492

Merged
merged 8 commits into from
Jul 9, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -183,11 +186,23 @@ private List<String> 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);
eshryane marked this conversation as resolved.
Show resolved Hide resolved
}
}
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"))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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, () -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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: <xxxxxx$353m5e@abc1.host.org>
Date: 23 Feb 2024 11:29:19 -0400
To: test-dbm@ripe.net
From: "Mail Delivery System" <noreply@ces.cisco.com>
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 <nonexistant@host.org> 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 <test-dbm@ripe.net>)
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 <test-dbm@ripe.net>)
id xxxxxx-0004cV-FW
for nonexistant@host.org; Fri, 23 Feb 2024 17:29:13 +0200
From: Test DBM <test-dbm@ripe.net>
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: <XXXXXXXX-5AE3-4C58-8E3F-860327BA955D@ripe.net>
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--


Original file line number Diff line number Diff line change
@@ -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: <xxxxxx$353m5e@abc1.host.org>
Date: 23 Feb 2024 11:29:19 -0400
To: test-dbm@ripe.net
From: "Mail Delivery System" <noreply@ces.cisco.com>
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 <nonexistant@host.org> 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 <test-dbm@ripe.net>)
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 <test-dbm@ripe.net>)
id xxxxxx-0004cV-FW
for nonexistant@host.org; Fri, 23 Feb 2024 17:29:13 +0200
From: Test DBM <test-dbm@ripe.net>
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: <XXXXXXXX-5AE3-4C58-8E3F-860327BA955D@ripe.net>
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--


Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ public String parse(final String s) {

final class EmailParser implements AttributeParser<InternetAddress> {

private static final int MAXIMUM_LENGTH = 80;

@Override
public InternetAddress parse(final String s) {
final InternetAddress[] parsed;
Expand All @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <user@host.org>");
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");
}

Expand Down