Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomas Weinfurt <Tomas.Weinfurt@microsoft.com>2022-03-14 19:20:56 +0300
committerMatt Mitchell <mmitche@microsoft.com>2022-03-14 19:20:56 +0300
commitbe98e88c760526452df94ef452fff4602fb5bded (patch)
tree3d82f4be5bb650009ed4de314c6a8c3493c26f49
parent1cb75051f216c1f7ade4d74a5835c7291a3fdfd6 (diff)
Merged PR 21497: [release/6.0] MSRC 68590 - newlines in domain literalsv6.0.4
This add validation for embedded newlines in email addresses. Based on https://dev.azure.com/dnceng/internal/_git/dotnet-runtime/pullrequest/20738 There is opt-in System.Net.Mail.EnableFullDomainLiterals switch to allow previous behavior
-rw-r--r--src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/EmailAddressAttribute.cs8
-rw-r--r--src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/EmailAddressAttributeTests.cs1
-rw-r--r--src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs9
-rw-r--r--src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs59
4 files changed, 77 insertions, 0 deletions
diff --git a/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/EmailAddressAttribute.cs b/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/EmailAddressAttribute.cs
index 2e28b0cb6ac..de5a86a64ac 100644
--- a/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/EmailAddressAttribute.cs
+++ b/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/EmailAddressAttribute.cs
@@ -7,6 +7,9 @@ namespace System.ComponentModel.DataAnnotations
AllowMultiple = false)]
public sealed class EmailAddressAttribute : DataTypeAttribute
{
+ private static bool EnableFullDomainLiterals { get; } =
+ AppContext.TryGetSwitch("System.Net.AllowFullDomainLiterals", out bool enable) ? enable : false;
+
public EmailAddressAttribute()
: base(DataType.EmailAddress)
{
@@ -27,6 +30,11 @@ namespace System.ComponentModel.DataAnnotations
return false;
}
+ if (!EnableFullDomainLiterals && (valueAsString.Contains('\r') || valueAsString.Contains('\n')))
+ {
+ return false;
+ }
+
// only return true if there is only 1 '@' character
// and it is neither the first nor the last character
int index = valueAsString.IndexOf('@');
diff --git a/src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/EmailAddressAttributeTests.cs b/src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/EmailAddressAttributeTests.cs
index a0c67ed7d2b..da80016608e 100644
--- a/src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/EmailAddressAttributeTests.cs
+++ b/src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/EmailAddressAttributeTests.cs
@@ -29,6 +29,7 @@ namespace System.ComponentModel.DataAnnotations.Tests
yield return new TestCase(new EmailAddressAttribute(), 0);
yield return new TestCase(new EmailAddressAttribute(), "");
yield return new TestCase(new EmailAddressAttribute(), " \r \t \n" );
+ yield return new TestCase(new EmailAddressAttribute(), "someName@[\r\n\tsomeDomain]");
yield return new TestCase(new EmailAddressAttribute(), "@someDomain.com");
yield return new TestCase(new EmailAddressAttribute(), "@someDomain@abc.com");
yield return new TestCase(new EmailAddressAttribute(), "someName");
diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs
index f5ea92bf4e8..541deb3c955 100644
--- a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs
+++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs
@@ -15,6 +15,9 @@ namespace System.Net.Mail
//
public partial class MailAddress
{
+ private static bool EnableFullDomainLiterals { get; } =
+ AppContext.TryGetSwitch("System.Net.AllowFullDomainLiterals", out bool enable) ? enable : false;
+
// These components form an e-mail address when assembled as follows:
// "EncodedDisplayname" <userName@host>
private readonly Encoding _displayNameEncoding;
@@ -219,6 +222,12 @@ namespace System.Net.Mail
throw new SmtpException(SR.Format(SR.SmtpInvalidHostName, Address), argEx);
}
}
+
+ if (!EnableFullDomainLiterals && domain.AsSpan().IndexOfAny('\r', '\n') >= 0)
+ {
+ throw new SmtpException(SR.Format(SR.SmtpInvalidHostName, Address));
+ }
+
return domain;
}
diff --git a/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs b/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs
index bd0fb529843..f635b0d67ac 100644
--- a/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs
+++ b/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs
@@ -9,11 +9,15 @@
// (C) 2006 John Luke
//
+using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Net.NetworkInformation;
using System.Net.Sockets;
+using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.DotNet.RemoteExecutor;
using Systen.Net.Mail.Tests;
using Xunit;
@@ -523,5 +527,60 @@ namespace System.Net.Mail.Tests
quitReceived.Wait(TimeSpan.FromSeconds(30));
Assert.True(quitMessageReceived, "QUIT message not received");
}
+
+ [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ [InlineData("foo@[\r\n bar]")]
+ [InlineData("foo@[bar\r\n ]")]
+ [InlineData("foo@[bar\r\n baz]")]
+ public void MultiLineDomainLiterals_Enabled_Success(string input)
+ {
+ RemoteExecutor.Invoke(static (string @input) =>
+ {
+ AppContext.SetSwitch("System.Net.AllowFullDomainLiterals", true);
+
+ var address = new MailAddress(@input);
+
+ // Using address with new line breaks the protocol so we cannot easily use LoopbackSmtpServer
+ // Instead we call internal method that does the extra validation.
+ string? host = (string?)typeof(MailAddress).InvokeMember("GetAddress", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, address, new object[] { true });
+ Assert.Equal(input, host);
+ }, input).Dispose();
+ }
+
+ [Theory]
+ [MemberData(nameof(SendMail_MultiLineDomainLiterals_Data))]
+ public async Task SendMail_MultiLineDomainLiterals_Disabled_Throws(string from, string to, bool asyncSend)
+ {
+ using var server = new LoopbackSmtpServer();
+
+ using SmtpClient client = server.CreateClient();
+ client.Credentials = new NetworkCredential("Foo", "Bar");
+
+ using var msg = new MailMessage(@from, @to, "subject", "body");
+
+ await Assert.ThrowsAsync<SmtpException>(async () =>
+ {
+ if (asyncSend)
+ {
+ await client.SendMailAsync(msg).WaitAsync(TimeSpan.FromSeconds(30));
+ }
+ else
+ {
+ client.Send(msg);
+ }
+ });
+ }
+
+ public static IEnumerable<object[]> SendMail_MultiLineDomainLiterals_Data()
+ {
+ foreach (bool async in new[] { true, false })
+ {
+ foreach (string address in new[] { "foo@[\r\n bar]", "foo@[bar\r\n ]", "foo@[bar\r\n baz]" })
+ {
+ yield return new object[] { address, "foo@example.com", async };
+ yield return new object[] { "foo@example.com", address, async };
+ }
+ }
+ }
}
}