From 0b41741d1711aa73d720671ac01072face063b4e Mon Sep 17 00:00:00 2001 From: Max Kerr Date: Thu, 15 Mar 2018 09:45:51 -0700 Subject: [PATCH 1/5] Initial commit with tests. --- .../src/System/Net/Http/WinHttpAuthHelper.cs | 13 ++++++++---- .../HttpClientHandlerTest.Authentication.cs | 21 ++++++++++++++++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs index 0635ed2ec2eb..d985c46f3eac 100644 --- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs +++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs @@ -102,7 +102,7 @@ public void CheckResponseForAuthentication( // But we can validate with assert. Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER); - serverAuthScheme = ChooseAuthScheme(supportedSchemes); + serverAuthScheme = ChooseAuthScheme(supportedSchemes, state.RequestMessage.RequestUri, state.ServerCredentials); if (serverAuthScheme != 0) { if (SetWinHttpCredential( @@ -155,7 +155,7 @@ public void CheckResponseForAuthentication( // But we can validate with assert. Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY); - proxyAuthScheme = ChooseAuthScheme(supportedSchemes); + proxyAuthScheme = ChooseAuthScheme(supportedSchemes, state.Proxy.GetProxy(state.RequestMessage.RequestUri), proxyCreds); state.RetryRequest = true; break; @@ -371,11 +371,16 @@ private bool SetWinHttpCredential( return true; } - private static uint ChooseAuthScheme(uint supportedSchemes) + private static uint ChooseAuthScheme(uint supportedSchemes, Uri uri, ICredentials credentials) { + if (credentials == null) + { + return 0; + } + foreach (uint authScheme in s_authSchemePriorityOrder) { - if ((supportedSchemes & authScheme) != 0) + if ((supportedSchemes & authScheme) != 0 && credentials.GetCredential(uri, s_authSchemeStringMapping[authScheme]) != null) { return authScheme; } diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs index 0eada261f433..8c7434334f4b 100644 --- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs +++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs @@ -19,7 +19,7 @@ public abstract class HttpClientHandler_Authentication_Test : HttpClientTestBase private static readonly NetworkCredential s_credentials = new NetworkCredential(Username, Password, Domain); - private static readonly Func s_createAndValidateRequest = async (handler, url, expectedStatusCode, credentials) => + private static readonly Func s_createAndValidateRequest = async (handler, url, expectedStatusCode, credentials) => { handler.Credentials = credentials; @@ -90,6 +90,25 @@ await LoopbackServer.CreateServerAsync(async (server, url) => }, options); } + [Theory] + [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: Negotiate\r\nx-identifier: Test\r\n", "Basic")] + [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5\r\nWWW-Authenticate: Negotiate\r\nx-identifier: Test\r\n", "Digest")] + public async Task HttpClientHandler_MultipleAuthenticateHeaders_PicksSupported(string authenticateHeader, string supportedAuth) + { + var options = new LoopbackServer.Options { Domain = Domain, Username = Username, Password = Password }; + await LoopbackServer.CreateServerAsync(async (server, url) => + { + HttpClientHandler handler = CreateHttpClientHandler(); + + var credentials = new CredentialCache(); + credentials.Add(url, supportedAuth, new NetworkCredential(Username, Password, Domain)); + handler.UseDefaultCredentials = false; + + Task serverTask = server.AcceptConnectionPerformAuthenticationAndCloseAsync(authenticateHeader); + await TestHelper.WhenAllCompletedOrAnyFailed(s_createAndValidateRequest(handler, url, HttpStatusCode.OK, credentials), serverTask); + }, options); + } + [Theory] [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\n")] [InlineData("WWW-Authenticate: Digest realm=\"hello\", nonce=\"testnonce\"\r\n")] From 44d59a37c37c9de86be03a7b4dfee6888a225ce6 Mon Sep 17 00:00:00 2001 From: Max Kerr Date: Thu, 15 Mar 2018 10:12:36 -0700 Subject: [PATCH 2/5] Disable test on CurlHandler. --- .../FunctionalTests/HttpClientHandlerTest.Authentication.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs index 8c7434334f4b..326281c57e95 100644 --- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs +++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs @@ -95,6 +95,12 @@ await LoopbackServer.CreateServerAsync(async (server, url) => [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5\r\nWWW-Authenticate: Negotiate\r\nx-identifier: Test\r\n", "Digest")] public async Task HttpClientHandler_MultipleAuthenticateHeaders_PicksSupported(string authenticateHeader, string supportedAuth) { + if (IsCurlHandler && authenticateHeader.Contains("Digest")) + { + // TODO: #27113: Fix failing authentication test cases on different httpclienthandlers. + return; + } + var options = new LoopbackServer.Options { Domain = Domain, Username = Username, Password = Password }; await LoopbackServer.CreateServerAsync(async (server, url) => { From dfa416bbf1f5287b028b0e2a40a7b8c9884be053 Mon Sep 17 00:00:00 2001 From: Max Kerr Date: Thu, 15 Mar 2018 10:47:36 -0700 Subject: [PATCH 3/5] Update issue number. --- .../FunctionalTests/HttpClientHandlerTest.Authentication.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs index 326281c57e95..deae89a52fd9 100644 --- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs +++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs @@ -97,7 +97,7 @@ public async Task HttpClientHandler_MultipleAuthenticateHeaders_PicksSupported(s { if (IsCurlHandler && authenticateHeader.Contains("Digest")) { - // TODO: #27113: Fix failing authentication test cases on different httpclienthandlers. + // TODO: #28065: Fix failing authentication test cases on different httpclienthandlers. return; } From 559e956da8ec7e4ba4ed15dce695d35194ca34dc Mon Sep 17 00:00:00 2001 From: Max Kerr Date: Fri, 16 Mar 2018 17:27:44 +0000 Subject: [PATCH 4/5] Add an authentication scheme that is supported by the client but not the server. --- .../HttpClientHandlerTest.Authentication.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs index deae89a52fd9..b6107f18303c 100644 --- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs +++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs @@ -91,9 +91,9 @@ await LoopbackServer.CreateServerAsync(async (server, url) => } [Theory] - [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: Negotiate\r\nx-identifier: Test\r\n", "Basic")] - [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5\r\nWWW-Authenticate: Negotiate\r\nx-identifier: Test\r\n", "Digest")] - public async Task HttpClientHandler_MultipleAuthenticateHeaders_PicksSupported(string authenticateHeader, string supportedAuth) + [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: NTLM\r\n", "Basic", "Negotiate")] + [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5\r\nWWW-Authenticate: NTLM\r\n", "Digest", "Negotiate")] + public async Task HttpClientHandler_MultipleAuthenticateHeaders_PicksSupported(string authenticateHeader, string supportedAuth, string unsupportedAuth) { if (IsCurlHandler && authenticateHeader.Contains("Digest")) { @@ -105,10 +105,11 @@ public async Task HttpClientHandler_MultipleAuthenticateHeaders_PicksSupported(s await LoopbackServer.CreateServerAsync(async (server, url) => { HttpClientHandler handler = CreateHttpClientHandler(); + handler.UseDefaultCredentials = false; var credentials = new CredentialCache(); credentials.Add(url, supportedAuth, new NetworkCredential(Username, Password, Domain)); - handler.UseDefaultCredentials = false; + credentials.Add(url, unsupportedAuth, new NetworkCredential(Username, Password, Domain)); Task serverTask = server.AcceptConnectionPerformAuthenticationAndCloseAsync(authenticateHeader); await TestHelper.WhenAllCompletedOrAnyFailed(s_createAndValidateRequest(handler, url, HttpStatusCode.OK, credentials), serverTask); From f76c969782ff7e1bff099a1b1755d67b814aca95 Mon Sep 17 00:00:00 2001 From: Max Kerr Date: Fri, 16 Mar 2018 21:31:29 +0000 Subject: [PATCH 5/5] Disable on nano server. --- .../FunctionalTests/HttpClientHandlerTest.Authentication.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs index b6107f18303c..70f7b95a4754 100644 --- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs +++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs @@ -95,7 +95,7 @@ await LoopbackServer.CreateServerAsync(async (server, url) => [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5\r\nWWW-Authenticate: NTLM\r\n", "Digest", "Negotiate")] public async Task HttpClientHandler_MultipleAuthenticateHeaders_PicksSupported(string authenticateHeader, string supportedAuth, string unsupportedAuth) { - if (IsCurlHandler && authenticateHeader.Contains("Digest")) + if (PlatformDetection.IsWindowsNanoServer || (IsCurlHandler && authenticateHeader.Contains("Digest"))) { // TODO: #28065: Fix failing authentication test cases on different httpclienthandlers. return;