public void CannotRegisterAListenerWithoutASubProtocol()
        {
            IWebSocketListener listener = this._SubprotocolListener(null);
            var registry = new WebSocketListenerRegistry();

            Assert.Throws <ArgumentNullException>(() => registry.TryRegister(listener));
        }
        public void CanRegisterAListener()
        {
            IWebSocketListener listener = this._SubprotocolListener("abc");
            var registry = new WebSocketListenerRegistry();

            Assert.True(registry.TryRegister(listener));
        }
        async Task ProcessRequestAsync(HttpContext context, IWebSocketListener listener, string correlationId)
        {
            Preconditions.CheckNotNull(context, nameof(context));
            Preconditions.CheckNotNull(context.Connection, nameof(context.Connection));
            Preconditions.CheckNotNull(context.Connection.RemoteIpAddress, nameof(context.Connection.RemoteIpAddress));
            Preconditions.CheckNotNull(correlationId, nameof(correlationId));

            Events.WebSocketSubProtocolSelected(context.TraceIdentifier, listener.SubProtocol, correlationId);

            WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(listener.SubProtocol);

            Option <EndPoint> localEndPoint = Option.None <EndPoint>();

            if (context.Connection.LocalIpAddress != null)
            {
                localEndPoint = Option.Some <EndPoint>(new IPEndPoint(context.Connection.LocalIpAddress, context.Connection.LocalPort));
            }

            var remoteEndPoint = new IPEndPoint(context.Connection.RemoteIpAddress, context.Connection.RemotePort);

            X509Certificate2 cert = await context.Connection.GetClientCertificateAsync();

            if (cert != null)
            {
                IList <X509Certificate2> certChain = context.GetClientCertificateChain();
                await listener.ProcessWebSocketRequestAsync(webSocket, localEndPoint, remoteEndPoint, correlationId, cert, certChain);
            }
            else
            {
                await listener.ProcessWebSocketRequestAsync(webSocket, localEndPoint, remoteEndPoint, correlationId);
            }

            Events.WebSocketRequestCompleted(context.TraceIdentifier, correlationId);
        }
        public void CannotRegisterTheSameListenerTwice()
        {
            IWebSocketListener listener = this._SubprotocolListener("abc");
            var registry = new WebSocketListenerRegistry();

            registry.TryRegister(listener);
            Assert.False(registry.TryRegister(listener));
        }
        public void CanUnregisterAListener()
        {
            IWebSocketListener inListener = this._SubprotocolListener("abc");
            var registry = new WebSocketListenerRegistry();

            registry.TryRegister(inListener);

            Assert.True(registry.TryUnregister("abc", out IWebSocketListener outListener));
            Assert.Equal(inListener, outListener);
        }
        async Task ProcessRequestAsync(HttpContext context, IWebSocketListener listener, string correlationId)
        {
            Preconditions.CheckNotNull(context, nameof(context));
            Preconditions.CheckNotNull(context.Connection, nameof(context.Connection));
            Preconditions.CheckNotNull(context.Connection.RemoteIpAddress, nameof(context.Connection.RemoteIpAddress));
            Preconditions.CheckNotNull(correlationId, nameof(correlationId));

            Events.WebSocketSubProtocolSelected(context.TraceIdentifier, listener.SubProtocol, correlationId);

            WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(listener.SubProtocol);

            Option <EndPoint> localEndPoint = Option.None <EndPoint>();

            if (context.Connection.LocalIpAddress != null)
            {
                localEndPoint = Option.Some <EndPoint>(new IPEndPoint(context.Connection.LocalIpAddress, context.Connection.LocalPort));
            }

            var remoteEndPoint = new IPEndPoint(context.Connection.RemoteIpAddress, context.Connection.RemotePort);

            X509Certificate2 cert = await context.Connection.GetClientCertificateAsync();

            IAuthenticator proxyAuthenticator = null;

            if (cert == null)
            {
                try
                {
                    var certExtractor = await this.httpProxiedCertificateExtractorProvider;
                    // if not certificate in header it returns null, no api proxy authentication needed in this case
                    // if certificate was set in header it means it was forwarded by api proxy and authenticates api proxy by sas token
                    // and throws AuthenticationException if api proxy was not authenticated or returns the certificate if api proxy authentication succeeded
                    cert = (await certExtractor.GetClientCertificate(context)).OrDefault();
                }
                catch (AuthenticationException ex)
                {
                    Events.AuthenticationApiProxyFailed(remoteEndPoint.ToString(), ex);
                    // Set authenticator to unauthorize the call from subprotocol level (Mqtt or Amqp)
                    proxyAuthenticator = new NullAuthenticator();
                    cert = context.GetForwardedCertificate();
                }
            }

            if (cert != null)
            {
                IList <X509Certificate2> certChain = context.GetClientCertificateChain();
                await listener.ProcessWebSocketRequestAsync(webSocket, localEndPoint, remoteEndPoint, correlationId, cert, certChain, proxyAuthenticator);
            }
            else
            {
                await listener.ProcessWebSocketRequestAsync(webSocket, localEndPoint, remoteEndPoint, correlationId);
            }

            Events.WebSocketRequestCompleted(context.TraceIdentifier, correlationId);
        }
        public void CannotUnregisterAListenerWithANullOrWhitespaceSubProtocol()
        {
            IWebSocketListener inListener = this._SubprotocolListener("abc");
            var registry = new WebSocketListenerRegistry();

            registry.TryRegister(inListener);

            Assert.Throws <ArgumentException>(() => registry.TryUnregister(null, out IWebSocketListener _));
            Assert.Throws <ArgumentException>(() => registry.TryUnregister(string.Empty, out IWebSocketListener _));
            Assert.Throws <ArgumentException>(() => registry.TryUnregister("  ", out IWebSocketListener _));
        }
        public async Task AlwaysInvokesTheFirstMatchingListener()
        {
            IWebSocketListener abcListener = this._SubprotocolListener("abc");
            IWebSocketListener xyzListener = this._SubprotocolListener("xyz");

            var registry = new WebSocketListenerRegistry();

            registry.TryRegister(abcListener);
            registry.TryRegister(xyzListener);

            HttpContext httpContext = this._ContextWithRequestedSubprotocols("xyz", "abc");

            Assert.True(await registry.InvokeAsync(httpContext, "123"));
            Mock.Get(xyzListener).Verify(wsl => wsl.ProcessWebSocketRequestAsync(httpContext, "123"));
        }
        public void AlwaysInvokesTheFirstMatchingListener()
        {
            IWebSocketListener abcListener = this._SubprotocolListener("abc");
            IWebSocketListener xyzListener = this._SubprotocolListener("xyz");

            var registry = new WebSocketListenerRegistry();

            registry.TryRegister(abcListener);
            registry.TryRegister(xyzListener);

            HttpContext httpContext = this._ContextWithRequestedSubprotocols("xyz", "abc");

            var listener = registry.GetListener(httpContext.WebSockets.WebSocketRequestedProtocols);

            Assert.True(listener.HasValue);
            listener.ForEach(l => Assert.Equal(l.SubProtocol, "xyz"));
            //Mock.Get(xyzListener).Verify(wsl => wsl.ProcessWebSocketRequestAsync(It.IsAny<WebSocket>(), It.IsAny<string>(), It.IsAny<EndPoint>(), It.IsAny<EndPoint>(), It.IsAny<string>()));
        }
Example #10
0
        public WebSocketDispatcher(Uri locationUri,
                                   ServerEtiquette etiquette,
                                   IWebSocketHandlerFactory handlerFactory,
                                   X509Certificate serverCertificate)
        {
            if (locationUri == null)
            {
                throw new ArgumentNullException("locationUri");
            }
            if (handlerFactory == null)
            {
                throw new ArgumentNullException("handlerFactory");
            }

            this.handlerFactory = handlerFactory;
            clientsByMetadata   = new Dictionary <string, List <IWebSocket> >();

            listener = new WebSocketListener(locationUri, etiquette, serverCertificate);
            listener.Start(OnHandShaken);
        }
 public bool TryUnregister(string subProtocol, out IWebSocketListener webSocketListener)
 {
     Preconditions.CheckNonWhiteSpace(subProtocol, nameof(subProtocol));
     return(this.webSocketListeners.TryRemove(subProtocol, out webSocketListener));
 }
 public bool TryRegister(IWebSocketListener webSocketListener)
 {
     Preconditions.CheckNotNull(webSocketListener, nameof(webSocketListener));
     return(this.webSocketListeners.TryAdd(webSocketListener.SubProtocol, webSocketListener));
 }
        async Task ProcessRequestAsync(HttpContext context, IWebSocketListener listener, string correlationId)
        {
            Preconditions.CheckNotNull(context, nameof(context));
            Preconditions.CheckNotNull(context.Connection, nameof(context.Connection));
            Preconditions.CheckNotNull(context.Connection.RemoteIpAddress, nameof(context.Connection.RemoteIpAddress));
            Preconditions.CheckNotNull(correlationId, nameof(correlationId));

            Events.WebSocketSubProtocolSelected(context.TraceIdentifier, listener.SubProtocol, correlationId);

            WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(listener.SubProtocol);

            Option <EndPoint> localEndPoint = Option.None <EndPoint>();

            if (context.Connection.LocalIpAddress != null)
            {
                localEndPoint = Option.Some <EndPoint>(new IPEndPoint(context.Connection.LocalIpAddress, context.Connection.LocalPort));
            }

            var remoteEndPoint = new IPEndPoint(context.Connection.RemoteIpAddress, context.Connection.RemotePort);

            X509Certificate2 cert = await context.Connection.GetClientCertificateAsync();

            if (cert == null)
            {
                // If the connection came through the API proxy, the client cert
                // would have been forwarded in a custom header. But since TLS
                // termination occurs at the proxy, we can only trust this custom
                // header if the request came through port 8080, which an internal
                // port only accessible within the local Docker vNet.
                if (context.Connection.LocalPort == Constants.ApiProxyPort)
                {
                    if (context.Request.Headers.TryGetValue(Constants.ClientCertificateHeaderKey, out StringValues clientCertHeader) && clientCertHeader.Count > 0)
                    {
                        Events.AuthenticationApiProxy(context.Connection.RemoteIpAddress.ToString());

                        string clientCertString = WebUtility.UrlDecode(clientCertHeader.First());

                        try
                        {
                            var clientCertificateBytes = Encoding.UTF8.GetBytes(clientCertString);
                            cert = new X509Certificate2(clientCertificateBytes);
                        }
                        catch (Exception ex)
                        {
                            Events.InvalidCertificate(ex, remoteEndPoint.ToString());
                            throw;
                        }
                    }
                }
            }

            if (cert != null)
            {
                IList <X509Certificate2> certChain = context.GetClientCertificateChain();
                await listener.ProcessWebSocketRequestAsync(webSocket, localEndPoint, remoteEndPoint, correlationId, cert, certChain);
            }
            else
            {
                await listener.ProcessWebSocketRequestAsync(webSocket, localEndPoint, remoteEndPoint, correlationId);
            }

            Events.WebSocketRequestCompleted(context.TraceIdentifier, correlationId);
        }