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:
authorFilip Navara <navara@emclient.com>2022-06-16 09:45:07 +0300
committerGitHub <noreply@github.com>2022-06-16 09:45:07 +0300
commit3c33b4293107c607ae8669545114d6f9891432cb (patch)
tree48bb56dbc737c96c6165d92c177d13d5cf8b7e89
parent24bbfbfb925d1d71d6c2f52d521aab00c65446a9 (diff)
Add end-to-end test for NTLM/Negotiate authentication against fake server (#70630)
* Add end-to-end test for NTLM/Negotiate authentication against fake server * Simplify the test since HttpClientHandler is always SocketsHttpHandler for the test environment * Fix test condition * Remove extra comment
-rw-r--r--src/libraries/Common/tests/System/Net/Security/FakeNegotiateServer.cs (renamed from src/libraries/System.Net.Security/tests/UnitTests/Fakes/FakeNegotiateServer.cs)0
-rw-r--r--src/libraries/Common/tests/System/Net/Security/FakeNtlmServer.cs (renamed from src/libraries/System.Net.Security/tests/UnitTests/Fakes/FakeNtlmServer.cs)0
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/NtAuthTests.FakeServer.cs140
-rw-r--r--src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj12
-rw-r--r--src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj6
5 files changed, 156 insertions, 2 deletions
diff --git a/src/libraries/System.Net.Security/tests/UnitTests/Fakes/FakeNegotiateServer.cs b/src/libraries/Common/tests/System/Net/Security/FakeNegotiateServer.cs
index 91149e7779f..91149e7779f 100644
--- a/src/libraries/System.Net.Security/tests/UnitTests/Fakes/FakeNegotiateServer.cs
+++ b/src/libraries/Common/tests/System/Net/Security/FakeNegotiateServer.cs
diff --git a/src/libraries/System.Net.Security/tests/UnitTests/Fakes/FakeNtlmServer.cs b/src/libraries/Common/tests/System/Net/Security/FakeNtlmServer.cs
index e4cfba2e544..e4cfba2e544 100644
--- a/src/libraries/System.Net.Security/tests/UnitTests/Fakes/FakeNtlmServer.cs
+++ b/src/libraries/Common/tests/System/Net/Security/FakeNtlmServer.cs
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/NtAuthTests.FakeServer.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/NtAuthTests.FakeServer.cs
new file mode 100644
index 00000000000..881555d67ff
--- /dev/null
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/NtAuthTests.FakeServer.cs
@@ -0,0 +1,140 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Linq;
+using System.Net.Security;
+using System.Net.Test.Common;
+using System.Security.Principal;
+using System.Threading.Tasks;
+
+using Xunit;
+using Xunit.Abstractions;
+
+namespace System.Net.Http.Functional.Tests
+{
+ public partial class NtAuthTests : IClassFixture<NtAuthServers>
+ {
+ public static bool IsNtlmAvailable =>
+ Capability.IsNtlmInstalled() || OperatingSystem.IsAndroid() || OperatingSystem.IsTvOS();
+
+ private static NetworkCredential s_testCredentialRight = new NetworkCredential("rightusername", "rightpassword");
+
+ internal static async Task HandleAuthenticationRequestWithFakeServer(LoopbackServer.Connection connection, bool useNtlm)
+ {
+ HttpRequestData request = await connection.ReadRequestDataAsync();
+ FakeNtlmServer? fakeNtlmServer = null;
+ FakeNegotiateServer? fakeNegotiateServer = null;
+ string authHeader = null;
+
+ foreach (HttpHeaderData header in request.Headers)
+ {
+ if (header.Name == "Authorization")
+ {
+ authHeader = header.Value;
+ break;
+ }
+ }
+
+ if (string.IsNullOrEmpty(authHeader))
+ {
+ // This is initial request, we reject with showing supported mechanisms.
+ if (useNtlm)
+ {
+ authHeader = "WWW-Authenticate: NTLM\r\n";
+ }
+ else
+ {
+ authHeader = "WWW-Authenticate: Negotiate\r\n";
+ }
+
+ await connection.SendResponseAsync(HttpStatusCode.Unauthorized, authHeader).ConfigureAwait(false);
+ connection.CompleteRequestProcessing();
+
+ // Read next requests and fall-back to loop bellow to process it.
+ request = await connection.ReadRequestDataAsync();
+ }
+
+ bool isAuthenticated = false;
+ do
+ {
+ foreach (HttpHeaderData header in request.Headers)
+ {
+ if (header.Name == "Authorization")
+ {
+ authHeader = header.Value;
+ break;
+ }
+ }
+
+ Assert.NotNull(authHeader);
+ var tokens = authHeader.Split(' ', 2, StringSplitOptions.TrimEntries);
+ // Should be type and base64 encoded blob
+ Assert.Equal(2, tokens.Length);
+
+ if (fakeNtlmServer == null)
+ {
+ fakeNtlmServer = new FakeNtlmServer(s_testCredentialRight) { ForceNegotiateVersion = true };
+ if (!useNtlm)
+ {
+ fakeNegotiateServer = new FakeNegotiateServer(fakeNtlmServer);
+ }
+ }
+
+ byte[]? outBlob;
+
+ if (fakeNegotiateServer != null)
+ {
+ outBlob = fakeNegotiateServer.GetOutgoingBlob(Convert.FromBase64String(tokens[1]));
+ isAuthenticated = fakeNegotiateServer.IsAuthenticated;
+ }
+ else
+ {
+ outBlob = fakeNtlmServer.GetOutgoingBlob(Convert.FromBase64String(tokens[1]));
+ isAuthenticated = fakeNtlmServer.IsAuthenticated;
+ }
+
+ if (outBlob != null)
+ {
+ authHeader = $"WWW-Authenticate: {tokens[0]} {Convert.ToBase64String(outBlob)}\r\n";
+ await connection.SendResponseAsync(isAuthenticated ? HttpStatusCode.OK : HttpStatusCode.Unauthorized, authHeader);
+ connection.CompleteRequestProcessing();
+
+ if (!isAuthenticated)
+ {
+ request = await connection.ReadRequestDataAsync();
+ }
+ }
+ }
+ while (!isAuthenticated);
+
+ await connection.SendResponseAsync(HttpStatusCode.OK);
+ }
+
+ [ConditionalTheory(nameof(IsNtlmAvailable))]
+ [InlineData(true)]
+ [InlineData(false)]
+ public async Task DefaultHandler_FakeServer_Success(bool useNtlm)
+ {
+ await LoopbackServer.CreateClientAndServerAsync(
+ async uri =>
+ {
+ HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, uri);
+ requestMessage.Version = new Version(1, 1);
+
+ HttpMessageHandler handler = new HttpClientHandler() { Credentials = s_testCredentialRight };
+ using (var client = new HttpClient(handler))
+ {
+ HttpResponseMessage response = await client.SendAsync(requestMessage);
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ }
+ },
+ async server =>
+ {
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ await HandleAuthenticationRequestWithFakeServer(connection, useNtlm);
+ }).ConfigureAwait(false);
+ });
+ }
+ }
+}
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
index 59a84cb1826..e5da76698df 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
@@ -352,6 +352,7 @@
Link="Common\System\Net\Http\HttpClientHandlerTest.Decompression.cs" />
<Compile Include="HttpClientMiniStressTest.cs" />
<Compile Include="NtAuthTests.cs" />
+ <Compile Include="NtAuthTests.FakeServer.cs" />
<Compile Include="ReadOnlyMemoryContentTest.cs" />
<Compile Include="SocketsHttpHandlerTest.cs" />
<Compile Include="$(CommonTestPath)System\Net\Http\Http2Frames.cs"
@@ -379,6 +380,17 @@
<Compile Include="LoopbackSocksServer.cs" />
<Compile Include="SocksProxyTest.cs" />
</ItemGroup>
+ <!-- NTLM/Negotiate authentication fakes -->
+ <ItemGroup>
+ <Compile Include="$(CommonPath)System\Net\Security\MD4.cs"
+ Link="Common\System\Net\Security\MD4.cs" />
+ <Compile Include="$(CommonPath)System\Net\Security\RC4.cs"
+ Link="Common\System\Net\Security\RC4.cs" />
+ <Compile Include="$(CommonTestPath)System\Net\Security\FakeNtlmServer.cs"
+ Link="Common\System\Net\Security\FakeNtlmServer.cs" />
+ <Compile Include="$(CommonTestPath)System\Net\Security\FakeNegotiateServer.cs"
+ Link="Common\System\Net\Security\FakeNegotiateServer.cs" />
+ </ItemGroup>
<ItemGroup>
<EmbeddedResource Include="SelectedSitesTest.txt">
<Link>SelectedSitesTest.txt</Link>
diff --git a/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj b/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj
index 55df154298e..3f61524d58c 100644
--- a/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj
+++ b/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj
@@ -30,8 +30,10 @@
<!-- Fakes -->
<Compile Include="Fakes\FakeSslStream.Implementation.cs" />
<Compile Include="Fakes\FakeAuthenticatedStream.cs" />
- <Compile Include="Fakes\FakeNtlmServer.cs" />
- <Compile Include="Fakes\FakeNegotiateServer.cs" />
+ <Compile Include="$(CommonTestPath)System\Net\Security\FakeNtlmServer.cs"
+ Link="Common\System\Net\Security\FakeNtlmServer.cs" />
+ <Compile Include="$(CommonTestPath)System\Net\Security\FakeNegotiateServer.cs"
+ Link="Common\System\Net\Security\FakeNegotiateServer.cs" />
<!-- Common test files -->
<Compile Include="$(CommonPath)DisableRuntimeMarshalling.cs"
Link="Common\DisableRuntimeMarshalling.cs" />