Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 0257e6c

Browse files
authored
Enable digest test runs on CurlHandler. (#28571)
Now that the authentication test failures have been diagnosed, re-enable most of the Digest authentication test cases on CurlHandler. Four additional cases had to be moved to the SocketsHttpHandler only tests, since they fail on CurlHandler and do not have fixes yet. The digest test cases have to use credentials without a domain when run against CurlHandler. This is because Curl does not allow us to set the realm parameter used to send the domain along with a digest authorization header.
1 parent 15a2915 commit 0257e6c

File tree

2 files changed

+23
-13
lines changed

2 files changed

+23
-13
lines changed

src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public abstract class HttpClientHandler_Authentication_Test : HttpClientTestBase
1818
private const string Domain = "testdomain";
1919

2020
private static readonly NetworkCredential s_credentials = new NetworkCredential(Username, Password, Domain);
21+
private static readonly NetworkCredential s_credentialsNoDomain = new NetworkCredential(Username, Password);
2122

2223
private static readonly Func<HttpClientHandler, Uri, HttpStatusCode, ICredentials, Task> s_createAndValidateRequest = async (handler, url, expectedStatusCode, credentials) =>
2324
{
@@ -34,12 +35,17 @@ public abstract class HttpClientHandler_Authentication_Test : HttpClientTestBase
3435
[MemberData(nameof(Authentication_TestData))]
3536
public async Task HttpClientHandler_Authentication_Succeeds(string authenticateHeader, bool result)
3637
{
37-
if (PlatformDetection.IsWindowsNanoServer || (IsCurlHandler && authenticateHeader.ToLowerInvariant().Contains("digest")))
38+
if (PlatformDetection.IsWindowsNanoServer)
3839
{
3940
// TODO: #28065: Fix failing authentication test cases on different httpclienthandlers.
4041
return;
4142
}
4243

44+
// Digest authentication does not work with domain credentials on CurlHandler. This is blocked by the behavior of LibCurl.
45+
NetworkCredential credentials = (IsCurlHandler && authenticateHeader.ToLowerInvariant().Contains("digest")) ?
46+
s_credentialsNoDomain :
47+
s_credentials;
48+
4349
var options = new LoopbackServer.Options { Domain = Domain, Username = Username, Password = Password };
4450
await LoopbackServer.CreateServerAsync(async (server, url) =>
4551
{
@@ -50,7 +56,7 @@ await LoopbackServer.CreateServerAsync(async (server, url) =>
5056
server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Unauthorized, serverAuthenticateHeader);
5157

5258
await TestHelper.WhenAllCompletedOrAnyFailedWithTimeout(TestHelper.PassingTestTimeoutMilliseconds,
53-
s_createAndValidateRequest(handler, url, result ? HttpStatusCode.OK : HttpStatusCode.Unauthorized, s_credentials), serverTask);
59+
s_createAndValidateRequest(handler, url, result ? HttpStatusCode.OK : HttpStatusCode.Unauthorized, credentials), serverTask);
5460
}, options);
5561
}
5662

@@ -139,21 +145,13 @@ public static IEnumerable<object[]> Authentication_TestData()
139145
yield return new object[] { "bAsiC ", true };
140146
yield return new object[] { "basic", true };
141147

142-
// Add digest tests fail on CurlHandler.
143-
// TODO: #28065: Fix failing authentication test cases on different httpclienthandlers.
144-
yield return new object[] { "Digest realm=\"testrealm\" nonce=\"testnonce\"", false };
145148
yield return new object[] { $"Digest realm=\"testrealm\", nonce=\"{Convert.ToBase64String(Encoding.UTF8.GetBytes($"{DateTimeOffset.UtcNow}:XMh;z+$5|`i6Hx}}\", qop=auth-int, algorithm=MD5"))}\"", true };
146-
yield return new object[] { "Digest realm=\"api@example.org\", qop=\"auth\", algorithm=MD5-sess, nonce=\"5TsQWLVdgBdmrQ0XsxbDODV+57QdFR34I9HAbC/RVvkK\", " +
147-
"opaque=\"HRPCssKJSGjCrkzDg8OhwpzCiGPChXYjwrI2QmXDnsOS\", charset=UTF-8, userhash=true", true };
148-
yield return new object[] { "dIgEsT realm=\"api@example.org\", qop=\"auth\", algorithm=MD5-sess, nonce=\"5TsQWLVdgBdmrQ0XsxbDODV+57QdFR34I9HAbC/RVvkK\", " +
149-
"opaque=\"HRPCssKJSGjCrkzDg8OhwpzCiGPChXYjwrI2QmXDnsOS\", charset=UTF-8, userhash=true", true };
150149
yield return new object[] { $"Basic realm=\"testrealm\", " +
151150
$"Digest realm=\"testrealm\", nonce=\"{Convert.ToBase64String(Encoding.UTF8.GetBytes($"{DateTimeOffset.UtcNow}:XMh;z+$5|`i6Hx}}"))}\", algorithm=MD5", true };
152151

153152
if (PlatformDetection.IsNetCore)
154153
{
155154
// TODO: #28060: Fix failing authentication test cases on Framework run.
156-
yield return new object[] { "Digest realm=\"testrealm1\", nonce=\"testnonce1\" Digest realm=\"testrealm2\", nonce=\"testnonce2\"", false };
157155
yield return new object[] { "Basic something, Digest something", false };
158156
yield return new object[] { $"Digest realm=\"testrealm\", nonce=\"testnonce\", algorithm=MD5 " +
159157
$"Basic realm=\"testrealm\"", false };

src/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -568,13 +568,25 @@ public async void SocketsHttpHandler_Authentication_Succeeds(string authenticate
568568

569569
public static IEnumerable<object[]> Authentication_SocketsHttpHandler_TestData()
570570
{
571-
// These test cases pass on SocketsHttpHandler, fail everywhere else.
572-
// TODO: #28065: Investigate failing authentication test cases on WinHttpHandler & CurlHandler.
571+
// These test cases successfully authenticate on SocketsHttpHandler but fail on the other handlers.
572+
// These are legal as per the the RFC, so authenticating is the expected behavior. See #28521 for details.
573573
yield return new object[] { "Basic realm=\"testrealm1\" basic realm=\"testrealm1\"", true };
574574
yield return new object[] { "Basic something digest something", true };
575+
yield return new object[] { "Digest realm=\"api@example.org\", qop=\"auth\", algorithm=MD5-sess, nonce=\"5TsQWLVdgBdmrQ0XsxbDODV+57QdFR34I9HAbC/RVvkK\", " +
576+
"opaque=\"HRPCssKJSGjCrkzDg8OhwpzCiGPChXYjwrI2QmXDnsOS\", charset=UTF-8, userhash=true", true };
577+
yield return new object[] { "dIgEsT realm=\"api@example.org\", qop=\"auth\", algorithm=MD5-sess, nonce=\"5TsQWLVdgBdmrQ0XsxbDODV+57QdFR34I9HAbC/RVvkK\", " +
578+
"opaque=\"HRPCssKJSGjCrkzDg8OhwpzCiGPChXYjwrI2QmXDnsOS\", charset=UTF-8, userhash=true", true };
579+
580+
// These cases fail on WinHttpHandler because of a behavior in WinHttp that causes requests to be duplicated
581+
// when the digest header has certain parameters. See #28522 for details.
575582
yield return new object[] { "Digest ", false };
576-
yield return new object[] { "Digest realm=withoutquotes, nonce=withoutquotes", false };
577583
yield return new object[] { "Digest realm=\"testrealm\", nonce=\"testnonce\", algorithm=\"myown\"", false };
584+
585+
// These cases fail to authenticate on SocketsHttpHandler, but succeed on the other handlers.
586+
// they are all invalid as per the RFC, so failing is the expected behavior. See #28523 for details.
587+
yield return new object[] { "Digest realm=withoutquotes, nonce=withoutquotes", false };
588+
yield return new object[] { "Digest realm=\"testrealm\" nonce=\"testnonce\"", false };
589+
yield return new object[] { "Digest realm=\"testrealm1\", nonce=\"testnonce1\" Digest realm=\"testrealm2\", nonce=\"testnonce2\"", false };
578590
}
579591
}
580592

0 commit comments

Comments
 (0)