From 4c549ea6ae01b714b82fded6c6c49727cd46da43 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Tue, 22 Feb 2022 23:49:42 +0100 Subject: [PATCH 1/3] support WindowsPrincipal in HttpListenerWebSocketContext --- .../HttpListenerWebSocketContext.cs | 8 +++++ .../tests/HttpListenerFactory.cs | 9 +++-- .../tests/HttpListenerWebSocketTests.cs | 36 +++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpListenerWebSocketContext.cs b/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpListenerWebSocketContext.cs index 31134051bf0e6c..67d163605d98b7 100644 --- a/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpListenerWebSocketContext.cs +++ b/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpListenerWebSocketContext.cs @@ -101,7 +101,15 @@ internal HttpListenerWebSocketContext( else { // AuthenticationSchemes.Digest, AuthenticationSchemes.Negotiate, AuthenticationSchemes.NTLM. +#if (WINDOWS) + if (user.Identity is WindowsIdentity windowsIdentity) + { + return new WindowsPrincipal(new WindowsIdentity(windowsIdentity.Token, windowsIdentity.AuthenticationType!, WindowsAccountType.Normal, true)); + } +#else throw new PlatformNotSupportedException(); +#endif + } } diff --git a/src/libraries/System.Net.HttpListener/tests/HttpListenerFactory.cs b/src/libraries/System.Net.HttpListener/tests/HttpListenerFactory.cs index dbc147592ce19a..d8528ae3f8a42e 100644 --- a/src/libraries/System.Net.HttpListener/tests/HttpListenerFactory.cs +++ b/src/libraries/System.Net.HttpListener/tests/HttpListenerFactory.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Linq; using System.Net.Sockets; -using System.Runtime.InteropServices; using System.Text; namespace System.Net.Tests @@ -24,7 +23,7 @@ public class HttpListenerFactory : IDisposable private readonly string _path; private readonly int _port; - internal HttpListenerFactory(string hostname = "localhost", string path = null) + internal HttpListenerFactory(string hostname = "localhost", string path = null, AuthenticationSchemes? authenticationSchemes = null) { // Find a URL prefix that is not in use on this machine *and* uses a port that's not in use. // Once we find this prefix, keep a listener on it for the duration of the process, so other processes @@ -42,6 +41,12 @@ internal HttpListenerFactory(string hostname = "localhost", string path = null) try { listener.Prefixes.Add(prefix); + + if (authenticationSchemes != null) + { + listener.AuthenticationSchemes = authenticationSchemes.Value; + } + listener.Start(); _processPrefixListener = listener; diff --git a/src/libraries/System.Net.HttpListener/tests/HttpListenerWebSocketTests.cs b/src/libraries/System.Net.HttpListener/tests/HttpListenerWebSocketTests.cs index f9838ff2efe2f4..d195d944247636 100644 --- a/src/libraries/System.Net.HttpListener/tests/HttpListenerWebSocketTests.cs +++ b/src/libraries/System.Net.HttpListener/tests/HttpListenerWebSocketTests.cs @@ -16,6 +16,7 @@ public class HttpListenerWebSocketTests : IDisposable { public static bool IsNotWindows7 { get; } = !PlatformDetection.IsWindows7; public static bool IsNotWindows7AndIsWindowsImplementation => IsNotWindows7 && Helpers.IsWindowsImplementation; + public static bool IsWindows8OrLater { get; } = PlatformDetection.IsWindows8xOrLater; private HttpListenerFactory Factory { get; } private HttpListener Listener { get; } @@ -363,6 +364,41 @@ public async Task Abort_CallAfterAborted_Nop() Assert.Equal(WebSocketState.Aborted, context.WebSocket.State); } + [ConditionalFact(nameof(IsWindows8OrLater))] + public async Task ReceiveAsync_ReadBuffer_WithWindowsAuthScheme_Success() + { + HttpListenerFactory factory = new HttpListenerFactory(authenticationSchemes: AuthenticationSchemes.IntegratedWindowsAuthentication); + var uriBuilder = new UriBuilder(factory.ListeningUrl) { Scheme = "ws" }; + Task serverContextTask = factory.GetListener().GetContextAsync(); + ClientWebSocket client = new ClientWebSocket(); + client.Options.Credentials = CredentialCache.DefaultCredentials; + + Task clientConnectTask = client.ConnectAsync(uriBuilder.Uri, CancellationToken.None); + if (clientConnectTask == await Task.WhenAny(serverContextTask, clientConnectTask)) + { + await clientConnectTask; + Assert.True(false, "Client should not have completed prior to server sending response"); + } + + HttpListenerContext context = await serverContextTask; + HttpListenerWebSocketContext wsContext = await context.AcceptWebSocketAsync(null); + await clientConnectTask; + + const string Text = "Hello Web Socket"; + byte[] sentBytes = Encoding.ASCII.GetBytes(Text); + + await client.SendAsync(new ArraySegment(sentBytes), WebSocketMessageType.Text, true, new CancellationToken()); + + byte[] receivedBytes = new byte[sentBytes.Length]; + WebSocketReceiveResult result = await ReceiveAllAsync(wsContext.WebSocket, receivedBytes.Length, receivedBytes); + Assert.Equal(WebSocketMessageType.Text, result.MessageType); + Assert.True(result.EndOfMessage); + Assert.Null(result.CloseStatus); + Assert.Null(result.CloseStatusDescription); + + Assert.Equal(Text, Encoding.ASCII.GetString(receivedBytes)); + } + private static async Task ReceiveAllAsync(WebSocket webSocket, int expectedBytes, byte[] buffer) { int totalReceived = 0; From e7516a554fb0faa5e0fffe619ff997ddce2fe694 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Thu, 24 Feb 2022 18:33:47 +0100 Subject: [PATCH 2/3] user Identity is known as instance of WindowsIdentity --- .../System/Net/WebSockets/HttpListenerWebSocketContext.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpListenerWebSocketContext.cs b/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpListenerWebSocketContext.cs index 67d163605d98b7..28c65290ebaef1 100644 --- a/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpListenerWebSocketContext.cs +++ b/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpListenerWebSocketContext.cs @@ -102,10 +102,8 @@ internal HttpListenerWebSocketContext( { // AuthenticationSchemes.Digest, AuthenticationSchemes.Negotiate, AuthenticationSchemes.NTLM. #if (WINDOWS) - if (user.Identity is WindowsIdentity windowsIdentity) - { - return new WindowsPrincipal(new WindowsIdentity(windowsIdentity.Token, windowsIdentity.AuthenticationType!, WindowsAccountType.Normal, true)); - } + WindowsIdentity windowsIdentity = (WindowsIdentity)user.Identity!; + return new WindowsPrincipal(new WindowsIdentity(windowsIdentity.Token, windowsIdentity.AuthenticationType!, WindowsAccountType.Normal, true)); #else throw new PlatformNotSupportedException(); #endif From 14477d31bcd5b0600b50b3e9115c3ff3c9735c92 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Fri, 25 Feb 2022 09:14:38 +0100 Subject: [PATCH 3/3] use TARGET_WINDOWS preprocessor --- .../System.Net.HttpListener/src/System.Net.HttpListener.csproj | 3 ++- .../src/System/Net/WebSockets/HttpListenerWebSocketContext.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Net.HttpListener/src/System.Net.HttpListener.csproj b/src/libraries/System.Net.HttpListener/src/System.Net.HttpListener.csproj index f50c50e9eed6c8..9e837ad5169406 100644 --- a/src/libraries/System.Net.HttpListener/src/System.Net.HttpListener.csproj +++ b/src/libraries/System.Net.HttpListener/src/System.Net.HttpListener.csproj @@ -1,4 +1,4 @@ - + true false @@ -9,6 +9,7 @@ $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) SR.SystemNetHttpListener_PlatformNotSupported + $(DefineConstants);TARGET_WINDOWS diff --git a/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpListenerWebSocketContext.cs b/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpListenerWebSocketContext.cs index 28c65290ebaef1..bfde65878f4eb2 100644 --- a/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpListenerWebSocketContext.cs +++ b/src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpListenerWebSocketContext.cs @@ -101,7 +101,7 @@ internal HttpListenerWebSocketContext( else { // AuthenticationSchemes.Digest, AuthenticationSchemes.Negotiate, AuthenticationSchemes.NTLM. -#if (WINDOWS) +#if TARGET_WINDOWS WindowsIdentity windowsIdentity = (WindowsIdentity)user.Identity!; return new WindowsPrincipal(new WindowsIdentity(windowsIdentity.Token, windowsIdentity.AuthenticationType!, WindowsAccountType.Normal, true)); #else