public async Task ClientCertificates_ValidCertificate_ServerReceivesCertificateAndConnectAsyncSucceeds() { using (X509Certificate2 clientCert = Test.Common.Configuration.Certificates.GetClientCertificate()) { await LoopbackServer.CreateClientAndServerAsync(async uri => { using (var clientSocket = new ClientWebSocket()) using (var cts = new CancellationTokenSource(TimeOutMilliseconds)) { clientSocket.Options.ClientCertificates.Add(clientCert); clientSocket.Options.GetType().GetProperty("RemoteCertificateValidationCallback", BindingFlags.NonPublic | BindingFlags.Instance) .SetValue(clientSocket.Options, new RemoteCertificateValidationCallback(delegate { return(true); })); // TODO: #12038: Simplify once property is public. await clientSocket.ConnectAsync(uri, cts.Token); } }, server => server.AcceptConnectionAsync(async connection => { // Validate that the client certificate received by the server matches the one configured on // the client-side socket. SslStream sslStream = Assert.IsType <SslStream>(connection.Stream); Assert.NotNull(sslStream.RemoteCertificate); Assert.Equal(clientCert, new X509Certificate2(sslStream.RemoteCertificate)); // Complete the WebSocket upgrade over the secure channel. After this is done, the client-side // ConnectAsync should complete. Assert.True(await LoopbackHelper.WebSocketHandshakeAsync(connection)); }), new LoopbackServer.Options { UseSsl = true, WebSocketEndpoint = true }); } }
public async Task ClientCertificates_ValidCertificate_ServerReceivesCertificateAndConnectAsyncSucceeds() { if (PlatformDetection.IsWindows7) { return; // [ActiveIssue(27846)] } using (X509Certificate2 clientCert = Test.Common.Configuration.Certificates.GetClientCertificate()) { await LoopbackServer.CreateClientAndServerAsync(async uri => { using (var clientSocket = new ClientWebSocket()) using (var cts = new CancellationTokenSource(TimeOutMilliseconds)) { clientSocket.Options.ClientCertificates.Add(clientCert); clientSocket.Options.RemoteCertificateValidationCallback = delegate { return(true); }; await clientSocket.ConnectAsync(uri, cts.Token); } }, server => server.AcceptConnectionAsync(async connection => { // Validate that the client certificate received by the server matches the one configured on // the client-side socket. SslStream sslStream = Assert.IsType <SslStream>(connection.Stream); Assert.NotNull(sslStream.RemoteCertificate); Assert.Equal(clientCert, new X509Certificate2(sslStream.RemoteCertificate)); // Complete the WebSocket upgrade over the secure channel. After this is done, the client-side // ConnectAsync should complete. Assert.True(await LoopbackHelper.WebSocketHandshakeAsync(connection)); }), new LoopbackServer.Options { UseSsl = true, WebSocketEndpoint = true }); } }
public async Task RemoteCertificateValidationCallback_PassedRemoteCertificateInfo(bool secure) { if (PlatformDetection.IsWindows7) { return; // [ActiveIssue(27846)] } bool callbackInvoked = false; await LoopbackServer.CreateClientAndServerAsync(async uri => { using (var cws = new ClientWebSocket()) using (var cts = new CancellationTokenSource(TimeOutMilliseconds)) { cws.Options.RemoteCertificateValidationCallback = (source, cert, chain, errors) => { Assert.NotNull(source); Assert.NotNull(cert); Assert.NotNull(chain); Assert.NotEqual(SslPolicyErrors.None, errors); callbackInvoked = true; return(true); }; await cws.ConnectAsync(uri, cts.Token); } }, server => server.AcceptConnectionAsync(async connection => { Assert.True(await LoopbackHelper.WebSocketHandshakeAsync(connection)); }), new LoopbackServer.Options { UseSsl = secure, WebSocketEndpoint = true }); Assert.Equal(secure, callbackInvoked); }
public async Task ConnectAsync_NonStandardRequestHeaders_HeadersAddedWithoutValidation() { await LoopbackServer.CreateClientAndServerAsync(async uri => { using (var clientSocket = new ClientWebSocket()) using (var cts = new CancellationTokenSource(TimeOutMilliseconds)) { clientSocket.Options.SetRequestHeader("Authorization", "AWS4-HMAC-SHA256 Credential=PLACEHOLDER /20190301/us-east-2/neptune-db/aws4_request, SignedHeaders=host;x-amz-date, Signature=b8155de54d9faab00000000000000000000000000a07e0d7dda49902e4d9202"); await ConnectAsync(clientSocket, uri, cts.Token); } }, server => server.AcceptConnectionAsync(async connection => { Assert.NotNull(await LoopbackHelper.WebSocketHandshakeAsync(connection)); }), new LoopbackServer.Options { WebSocketEndpoint = true }); }
public async Task PerMessageDeflateHeaders(int clientWindowBits, bool clientContextTakeover, int serverWindowBits, bool serverContextTakover, string expected) { await LoopbackServer.CreateClientAndServerAsync(async uri => { using var client = new ClientWebSocket(); using var cancellation = new CancellationTokenSource(TimeOutMilliseconds); client.Options.DangerousDeflateOptions = new WebSocketDeflateOptions { ClientMaxWindowBits = clientWindowBits, ClientContextTakeover = clientContextTakeover, ServerMaxWindowBits = serverWindowBits, ServerContextTakeover = serverContextTakover }; await client.ConnectAsync(uri, cancellation.Token); object webSocketHandle = client.GetType().GetField("_innerWebSocket", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(client); WebSocketDeflateOptions negotiatedDeflateOptions = (WebSocketDeflateOptions)webSocketHandle.GetType() .GetField("_negotiatedDeflateOptions", BindingFlags.NonPublic | BindingFlags.Instance) .GetValue(webSocketHandle); Assert.Equal(clientWindowBits - 1, negotiatedDeflateOptions.ClientMaxWindowBits); Assert.Equal(clientContextTakeover, negotiatedDeflateOptions.ClientContextTakeover); Assert.Equal(serverWindowBits - 1, negotiatedDeflateOptions.ServerMaxWindowBits); Assert.Equal(serverContextTakover, negotiatedDeflateOptions.ServerContextTakeover); }, server => server.AcceptConnectionAsync(async connection => { var extensionsReply = CreateDeflateOptionsHeader(new WebSocketDeflateOptions { ClientMaxWindowBits = clientWindowBits - 1, ClientContextTakeover = clientContextTakeover, ServerMaxWindowBits = serverWindowBits - 1, ServerContextTakeover = serverContextTakover }); Dictionary <string, string> headers = await LoopbackHelper.WebSocketHandshakeAsync(connection, extensionsReply); Assert.NotNull(headers); Assert.True(headers.TryGetValue("Sec-WebSocket-Extensions", out string extensions)); Assert.Equal(expected, extensions); }), new LoopbackServer.Options { WebSocketEndpoint = true }); }
public async Task ConnectAsync_NonStandardRequestHeaders_HeadersAddedWithoutValidation() { await LoopbackServer.CreateClientAndServerAsync(async uri => { using (var clientSocket = new ClientWebSocket()) using (var cts = new CancellationTokenSource(TimeOutMilliseconds)) { // [SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Unit test dummy authorisation header.")] clientSocket.Options.SetRequestHeader("Authorization", "AWS4-HMAC-SHA256 Credential= AKIAXXXXXXXXXXXYSZA /20190301/us-east-2/neptune-db/aws4_request, SignedHeaders=host;x-amz-date, Signature=b8155de54d9faab00000000000000000000000000a07e0d7dda49902e4d9202"); await clientSocket.ConnectAsync(uri, cts.Token); } }, server => server.AcceptConnectionAsync(async connection => { Assert.NotNull(await LoopbackHelper.WebSocketHandshakeAsync(connection)); }), new LoopbackServer.Options { WebSocketEndpoint = true }); }
public async Task ClientCertificates_ValidCertificate_ServerReceivesCertificateAndConnectAsyncSucceeds() { var options = new LoopbackServer.Options { UseSsl = true, WebSocketEndpoint = true }; Func <ClientWebSocket, LoopbackServer, Uri, X509Certificate2, Task> connectToServerWithClientCert = async(clientSocket, server, url, clientCert) => { // Start listening for incoming connections on the server side. Task acceptTask = server.AcceptConnectionAsync(async connection => { // Validate that the client certificate received by the server matches the one configured on // the client-side socket. SslStream sslStream = Assert.IsType <SslStream>(connection.Stream); Assert.NotNull(sslStream.RemoteCertificate); Assert.Equal(clientCert, new X509Certificate2(sslStream.RemoteCertificate)); // Complete the WebSocket upgrade over the secure channel. After this is done, the client-side // ConnectAsync should complete. Assert.True(await LoopbackHelper.WebSocketHandshakeAsync(connection)); }); // Initiate a connection attempt with a client certificate configured on the socket. clientSocket.Options.ClientCertificates.Add(clientCert); var cts = new CancellationTokenSource(TimeOutMilliseconds); await clientSocket.ConnectAsync(url, cts.Token); acceptTask.Wait(cts.Token); }; await LoopbackServer.CreateServerAsync(async (server, url) => { using (X509Certificate2 clientCert = Test.Common.Configuration.Certificates.GetClientCertificate()) { using (ClientWebSocket clientSocket = new ClientWebSocket()) { await connectToServerWithClientCert(clientSocket, server, url, clientCert); } } }, options); }
public async Task ConnectAsync_HttpResponseDetailsCollectedOnSuccess_Extensions() { await LoopbackServer.CreateClientAndServerAsync(async uri => { using (var clientWebSocket = new ClientWebSocket()) using (var cts = new CancellationTokenSource(TimeOutMilliseconds)) { clientWebSocket.Options.CollectHttpResponseDetails = true; await ConnectAsync(clientWebSocket, uri, cts.Token); Assert.Equal(HttpStatusCode.SwitchingProtocols, clientWebSocket.HttpStatusCode); Assert.NotEmpty(clientWebSocket.HttpResponseHeaders); Assert.Contains("Sec-WebSocket-Extensions", clientWebSocket.HttpResponseHeaders); } }, server => server.AcceptConnectionAsync(async connection => { Dictionary <string, string> headers = await LoopbackHelper.WebSocketHandshakeAsync(connection, "X-CustomHeader1"); }), new LoopbackServer.Options { WebSocketEndpoint = true }); }
public async Task CloseAsync_CancelableEvenWhenPendingReceive_Throws() { var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); await LoopbackServer.CreateClientAndServerAsync(async uri => { try { using (var cws = new ClientWebSocket()) using (var cts = new CancellationTokenSource(TimeOutMilliseconds)) { await cws.ConnectAsync(uri, cts.Token); Task receiveTask = cws.ReceiveAsync(new byte[1], CancellationToken.None); var cancelCloseCts = new CancellationTokenSource(); await Assert.ThrowsAnyAsync <OperationCanceledException>(async() => { Task t = cws.CloseAsync(WebSocketCloseStatus.NormalClosure, null, cancelCloseCts.Token); cancelCloseCts.Cancel(); await t; }); await Assert.ThrowsAnyAsync <OperationCanceledException>(() => receiveTask); } } finally { tcs.SetResult(); } }, server => server.AcceptConnectionAsync(async connection => { Dictionary <string, string> headers = await LoopbackHelper.WebSocketHandshakeAsync(connection); Assert.NotNull(headers); await tcs.Task; }), new LoopbackServer.Options { WebSocketEndpoint = true }); }
public async Task ConnectAsync_AddHostHeader_Success() { string expectedHost = null; await LoopbackServer.CreateClientAndServerAsync(async uri => { expectedHost = "subdomain." + uri.Host; using (var cws = new ClientWebSocket()) using (var cts = new CancellationTokenSource(TimeOutMilliseconds)) { cws.Options.SetRequestHeader("Host", expectedHost); await ConnectAsync(cws, uri, cts.Token); } }, server => server.AcceptConnectionAsync(async connection => { Dictionary <string, string> headers = await LoopbackHelper.WebSocketHandshakeAsync(connection); Assert.NotNull(headers); Assert.True(headers.TryGetValue("Host", out string host)); Assert.Equal(expectedHost, host); }), new LoopbackServer.Options { WebSocketEndpoint = true }); }
public async Task SendReceive_ConnectionClosedPrematurely_ReceiveAsyncFailsAndWebSocketStateUpdated() { var options = new LoopbackServer.Options { WebSocketEndpoint = true }; Func <ClientWebSocket, LoopbackServer, Uri, Task> connectToServerThatAbortsConnection = async(clientSocket, server, url) => { var pendingReceiveAsyncPosted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); // Start listening for incoming connections on the server side. Task acceptTask = server.AcceptConnectionAsync(async connection => { // Complete the WebSocket upgrade. After this is done, the client-side ConnectAsync should complete. Assert.NotNull(await LoopbackHelper.WebSocketHandshakeAsync(connection)); // Wait for client-side ConnectAsync to complete and for a pending ReceiveAsync to be posted. await pendingReceiveAsyncPosted.Task.WaitAsync(TimeSpan.FromMilliseconds(TimeOutMilliseconds)); // Close the underlying connection prematurely (without sending a WebSocket Close frame). connection.Socket.Shutdown(SocketShutdown.Both); connection.Socket.Close(); }); // Initiate a connection attempt. var cts = new CancellationTokenSource(TimeOutMilliseconds); await clientSocket.ConnectAsync(url, cts.Token); // Post a pending ReceiveAsync before the TCP connection is torn down. var recvBuffer = new byte[100]; var recvSegment = new ArraySegment <byte>(recvBuffer); Task pendingReceiveAsync = ReceiveAsync(clientSocket, recvSegment, cts.Token); pendingReceiveAsyncPosted.SetResult(); // Wait for the server to close the underlying connection. await acceptTask.WaitAsync(cts.Token); WebSocketException pendingReceiveException = await Assert.ThrowsAsync <WebSocketException>(() => pendingReceiveAsync); Assert.Equal(WebSocketError.ConnectionClosedPrematurely, pendingReceiveException.WebSocketErrorCode); if (PlatformDetection.IsInAppContainer) { const uint WININET_E_CONNECTION_ABORTED = 0x80072EFE; Assert.NotNull(pendingReceiveException.InnerException); Assert.Equal(WININET_E_CONNECTION_ABORTED, (uint)pendingReceiveException.InnerException.HResult); } WebSocketException newReceiveException = await Assert.ThrowsAsync <WebSocketException>(() => ReceiveAsync(clientSocket, recvSegment, cts.Token)); Assert.Equal( ResourceHelper.GetExceptionMessage("net_WebSockets_InvalidState", "Aborted", "Open, CloseSent"), newReceiveException.Message); Assert.Equal(WebSocketState.Aborted, clientSocket.State); Assert.Null(clientSocket.CloseStatus); }; await LoopbackServer.CreateServerAsync(async (server, url) => { using (ClientWebSocket clientSocket = new ClientWebSocket()) { await connectToServerThatAbortsConnection(clientSocket, server, url); } }, options); }