Code-Sharp / WampSharp

A C# implementation of WAMP (The Web Application Messaging Protocol)
http://wampsharp.net
Other
385 stars 84 forks source link

HTTP/1.1 101 Switching Protocols when throwing WampAuthenticationException or UnauthorizedAccessException from GetSessionAuthenticator method #327

Closed SudheeraC closed 3 years ago

SudheeraC commented 3 years ago

Hi,

I am trying to validate the request header "origin" value when authenticating the request for establishing WAMP connection in GetSessionAuthenticator method by implementing IWampSessionAuthenticatorFactory interface. If request origin header value is not valid(as per my validation rules) then I am throwing WampAuthenticationException or UnauthorizedAccessException from GetSessionAuthenticator method. However, the switching of protocols from HTTP to WebSocket is still happening which is not expected. PFA for the sample request and response. Please confirm if its expected to have the protocol switch event if authentication fails.

WAMP_SwitchingProtocols_Issue

darkl commented 3 years ago

This is the expected behavior because the authentication process happens over the WAMP transport (after a HELLO message was sent) and therefore after the Websocket connection has been established.

If you want to filter out illegal origins, you'll have to do it at the level of the transport. It should be possible to do this for ASP.NET Core for instance by adding a handle that throws an exception.

Elad

On Tue, Nov 24, 2020, 03:28 SudheeraC notifications@github.com wrote:

Hi,

I am trying to validate the request header "origin" value when authenticating the request for establishing WAMP connection in GetSessionAuthenticator method by implementing IWampSessionAuthenticatorFactory interface. If request origin header value is not valid(as per my validation rules) then I am throwing WampAuthenticationException or UnauthorizedAccessException from GetSessionAuthenticator method. However, the switching of protocols from HTTP to WebSocket is still happening which is not expected. PFA for the sample request and response. Please confirm if its expected to have the protocol switch event if authentication fails.

[image: WAMP_SwitchingProtocols_Issue] https://user-images.githubusercontent.com/15993610/100067345-26567000-2e5c-11eb-90d3-97b641fc8d76.png

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/Code-Sharp/WampSharp/issues/327, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIS75WRASTUSGYIQWG2RO3SRNVETANCNFSM4UARVCEA .

SudheeraC commented 3 years ago

Hi Elad,

Thanks for the quick reply. Could you please share sample code for filtering out illegal origins and throw exception? I am using WAMPSharp.dll version="20.1.1"

darkl commented 3 years ago

See an example of something similar in this article:

https://www.textcontrol.com/blog/2020/05/28/adding-a-websocket-security-middleware-to-aspnet-core/

On Tue, Nov 24, 2020, 04:40 SudheeraC notifications@github.com wrote:

Hi Elad,

Thanks for the quick reply. Could you please share sample code for filtering out illegal origins and throw exception? I am using WAMPSharp.dll version="20.1.1"

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/Code-Sharp/WampSharp/issues/327#issuecomment-732778048, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIS75WVS2UX6IDCHW43OMDSRN5RBANCNFSM4UARVCEA .

SudheeraC commented 3 years ago

Thank you.. I am using a MVC application as client and a C# windows service as WAMP server. My requirement is if any request that comes to my WAMP server then filtering out of the origin should happen on the WAMP server end itself. The sample reference link that you shared talks about middleware between client and server. I am trying to implement on the server side filtering.

My sample code is below. Please suggest if the below approach is fine or if any other better way. public IWampSessionAuthenticator GetSessionAuthenticator(WampPendingClientDetails details, IWampSessionAuthenticator transportAuthenticator) { HelloDetails helloDetails = details.HelloDetails; string transprtDetailsSerialized = JsonConvert.SerializeObject(details.HelloDetails.TransportDetails); ConnectionTransportDetails transportDetails = JsonConvert.DeserializeObject(transprtDetailsSerialized); var originHeader = transportDetails.http_headers.Where(h => string.Equals(h.Key, "origin", StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); if (originHeader.Key != null) { Uri originURI = new Uri(originHeader.Value); string host = originURI.Host; if (!allowedHeaders.Contains(host)) { throw new UnauthorizedAccessException("Illegal origin"); } } }

darkl commented 3 years ago

A middleware is a code that runs on the server side. You're supposed to run that code in your Startup.cs file (add a line app.UseMiddleware() in your Configure method). I think the article I linked to is informative enough to explain how to do something in that fashion.

Your code runs on the WAMP transport level so it will run after the WebSocket connection has already been established, which is not what you wanted.

Elad

On Tue, Nov 24, 2020 at 5:12 AM SudheeraC notifications@github.com wrote:

Thank you.. I am using a MVC application as client and a C# windows service as WAMP server. My requirement is if any request that comes to my WAMP server then filtering out of the origin should happen on the WAMP server end itself. The sample reference link that you shared talks about middleware between client and server. I am trying to implement on the server side filtering.

My sample code is below. Please suggest if the below approach is fine or if any other better way. public IWampSessionAuthenticator GetSessionAuthenticator(WampPendingClientDetails details, IWampSessionAuthenticator transportAuthenticator) { HelloDetails helloDetails = details.HelloDetails; string transprtDetailsSerialized = JsonConvert.SerializeObject(details.HelloDetails.TransportDetails); ConnectionTransportDetails transportDetails = JsonConvert.DeserializeObject(transprtDetailsSerialized); var originHeader = transportDetails.http_headers.Where(h => string.Equals(h.Key, "origin", StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); if (originHeader.Key != null) { Uri originURI = new Uri(originHeader.Value); string host = originURI.Host; if (!allowedHeaders.Contains(host)) { throw new UnauthorizedAccessException("Illegal origin"); } } }

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/Code-Sharp/WampSharp/issues/327#issuecomment-732797491, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIS75TCUPIEMR7QMAJFNQLSROBKFANCNFSM4UARVCEA .

SudheeraC commented 3 years ago

Thank you Elad.. Mine is windows service. Could you please suggest on how to do in windows service?

darkl commented 3 years ago

My comments have nothing to do with whether you run your code in a Console Application/Windows Service/IIS/Windows Form/etc.

This functionality seems to be built-in in ASP.NET Core. See here. Recall that a WampHost registration for ASP.NET Core looks like this

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        WampHost host = new WampHost();

        app.Map("/ws", builder =>
        {
            builder.UseWebSockets();

            host.RegisterTransport(new AspNetCoreWebSocketTransport(builder),
                                   new JTokenJsonBinding(),
                                   new JTokenMsgpackBinding());
        });

        host.Open();
    }

You should call UseWebSockets with your desired allowed origins:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        WampHost host = new WampHost();

        var webSocketOptions = new WebSocketOptions();
        webSocketOptions.AllowedOrigins.Add("https://client.com");
        webSocketOptions.AllowedOrigins.Add("https://www.client.com");

        app.Map("/ws", builder =>
        {
            builder.UseWebSockets(webSocketOptions);

            host.RegisterTransport(new AspNetCoreWebSocketTransport(builder),
                                   new JTokenJsonBinding(),
                                   new JTokenMsgpackBinding());
        });

        host.Open();
    }

Elad