Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authentication with SignalR #1040

Open
mkanakis opened this issue Oct 16, 2019 · 24 comments
Open

Authentication with SignalR #1040

mkanakis opened this issue Oct 16, 2019 · 24 comments
Assignees
Labels
Authentication Ocelot feature: Authentication Authorization Ocelot feature: Authorization SignalR SignalR is Microsoft Websocks technology Websockets Ocelot feature: Websockets

Comments

@mkanakis
Copy link

Thanks for the good work!

New Feature

Is authentication for signalR on the plans? We are using signalR with IdentityServer4, to send data over to authenticated users, but I don't think Ocelot is supporting it currently, as stated in documentation.

Motivation for New Feature

I am not sure of people who would use signalR without user authentication.

@JeanRessouche
Copy link

Definitely interested by it, that's the only issue in my architecture :-(

@mkanakis
Copy link
Author

mkanakis commented Nov 2, 2019

I guess the easiest way up till now, is to abstract SignalR from your service and deploy it as a separate one, without the use of a gateway, since .netcore provides token authentication for SignalR.

@JeanRessouche
Copy link

I do, however, I'm forced to have a second port open on the server, which is complicated on prod. Better have only the 443 to get through the firewall :-(

@Misiu
Copy link

Misiu commented Mar 3, 2020

@zee85 I'm planning architecture for the next project and I want to use Ocelot and SignalR.
So you removed the GetUserId method from your hub's and you are doing authentication logic inside the SignalR project?
Is your code available somewhere? I'd like to see Ocelot, SignalR, IdentityServer, and RabbitMQ working together.

@Misiu
Copy link

Misiu commented Mar 3, 2020

@zee85 thank you for sharing 🙂
I plan to build my project on GitHub so it will be open-sourced as well :) Your code will help me a lot to get started with Ocelot, SignalR, and others.
I always wanted to build a project based on microservices, now I have an opportunity.

I saw in ocelot docs that it doesn't handle authentication for SignalR (WebSockets). Hopefully, someday it will

@TomPallister
Copy link
Member

Can anyone point me to how the identityserver and signal r authentication works? I thought signalr only supported basic auth? :o I might be behind the times as have not worked much in dotnet recently :)

@mkanakis
Copy link
Author

Hi @TomPallister

Here is an example of what I have been using with my Hubs project:

services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
                .AddIdentityServerAuthentication(options =>
                {
                    // base-address of your identityserver
                    options.Authority = Configuration["IdentityServer:Url"];

                    // name of the API resource
                    options.ApiName = Configuration["IdentityServer:APIName"];
                    options.ApiSecret = Configuration["IdentityServer:APISecret"];

                    options.EnableCaching = true;
                    options.CacheDuration = TimeSpan.FromMinutes(10); // that's the default

                    options.RequireHttpsMetadata = Convert.ToBoolean(Configuration["IdentityServer:RequireHttpsMetadata"]);

                    // For SignalR
                    options.TokenRetriever = new Func<HttpRequest, string>(req =>
                    {
                        var fromHeader = TokenRetrieval.FromAuthorizationHeader();
                        var fromQuery = TokenRetrieval.FromQueryString();
                        return fromHeader(req) ?? fromQuery(req);
                    });
                });

Taken from here

Hope this helps.

@mkanakis
Copy link
Author

Any updates?

Best, Marios.

@hsnassaad
Copy link

@mkanakis because this feature is not available right now, and I want to implement a similar thing in my project, did you use any other methods to solve this (like using reverse proxy or other different tools?)

@JeanRessouche
Copy link

@hsnassaad you can use nginx as a reverse proxy, signalR is going through correctly

@alex-pollan
Copy link

alex-pollan commented Dec 21, 2021

I managed to have my Websocket endpoint authenticated by copying some extension classes from the Ocelot project to my project in order to be able to include the Authentication and Authorization middlewares in the WebSocket middleware sub-pipeline

       public static RequestDelegate BuildOcelotPipeline(this IApplicationBuilder app,
            OcelotPipelineConfiguration pipelineConfiguration)
        {
            ...

            app.MapWhen(httpContext => httpContext.WebSockets.IsWebSocketRequest,
                wenSocketsApp =>
                {
                    wenSocketsApp.UseDownstreamRouteFinderMiddleware();
                    wenSocketsApp.UseMultiplexingMiddleware();
                    wenSocketsApp.UseDownstreamRequestInitialiser();

                    //added this here
                    wenSocketsApp.UseAuthenticationMiddleware();
                    wenSocketsApp.UseAuthorisationMiddleware();

                    wenSocketsApp.UseLoadBalancingMiddleware();
                    wenSocketsApp.UseDownstreamUrlCreatorMiddleware();
                    wenSocketsApp.UseWebSocketsProxyMiddleware();  // Notice that the request processing ends here!!!
                });
                ...
        }

Also, I need to introduce some custom middleware to return 401 on Authentication/Authorization errors because the current pipeline returns 200, which is obviously not correct.

I'm curious about why this functionality is not included as the Websocket endpoint is a regular HTTP endpoint. It might be that I'm looking at it with my specific case in mind and don't get the whole picture.

@MohMehrnia
Copy link

@alex-pollan please upload complete code

@alex-pollan
Copy link

alex-pollan commented Feb 2, 2022

The code I'm working on below. Ocelot version 16.0.1.

ocelot.json

  "Routes": [
    {
      "UpstreamPathTemplate": "/hub/update/{deviceName}",
      "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE", "OPTIONS" ],
      "DownstreamScheme": "ws",
      "DownstreamPathTemplate": "/update",
      "DownstreamHostAndPorts": [ { "Host": "{SignalRService}" } ],
      "RouteIsCaseSensitive": false,
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "Bearer",
        "AllowedScopes": [ "the_scope" ]
      },
      "RouteClaimsRequirement": {
        "client_id": "{deviceName}"
      }
    }]

Startup.cs

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            ...
            app.UseAuthentication();
            app.UseAuthorization();
            ...
            app.UseOcelotWebSockets();
            app.UseOcelot().Wait();
        }

Some extension methods class

        public static IApplicationBuilder UseOcelotWebSockets(this IApplicationBuilder appBuilder)
        {
            appBuilder.UseWebSockets();

            //Override Ocelot Websockets pipeline to support authentication and authorization
            appBuilder.MapWhen(httpContext => httpContext.WebSockets.IsWebSocketRequest,
                wenSocketsApp =>
                {
                    wenSocketsApp.UseDownstreamContextMiddleware();
                    wenSocketsApp.UseExceptionHandlerMiddleware();
                    wenSocketsApp.UseResponderMiddleware();
                    wenSocketsApp.UseDownstreamRouteFinderMiddleware();
                    wenSocketsApp.UseMultiplexingMiddleware();
                    wenSocketsApp.UseHttpHeadersTransformationMiddleware();
                    wenSocketsApp.UseDownstreamRequestInitialiser();
                    wenSocketsApp.UseAuthenticationMiddleware();
                    wenSocketsApp.UseClaimsToClaimsMiddleware();
                    wenSocketsApp.UseAuthorisationMiddleware();
                    wenSocketsApp.UseClaimsToHeadersMiddleware();
                    wenSocketsApp.UseClaimsToQueryStringMiddleware();
                    wenSocketsApp.UseClaimsToDownstreamPathMiddleware();
                    wenSocketsApp.UseLoadBalancingMiddleware();
                    wenSocketsApp.UseDownstreamUrlCreatorMiddleware();
                    wenSocketsApp.UseWebSocketsProxyMiddleware();
                });
            return appBuilder;
        }

@AmitManchanda
Copy link

Waiting for this feature. Please provide me any alternate as I need to pass access token to my signal R app.

@raman-m
Copy link
Member

raman-m commented Mar 17, 2024

@alex-pollan commented on Feb 2, 2022

Our current WS pipeline is quite short ))) No authentication at all 🤣

// If the request is for websockets upgrade we fork into a different pipeline
app.MapWhen(httpContext => httpContext.WebSockets.IsWebSocketRequest,
wenSocketsApp =>
{
wenSocketsApp.UseDownstreamRouteFinderMiddleware();
wenSocketsApp.UseMultiplexingMiddleware();
wenSocketsApp.UseDownstreamRequestInitialiser();
wenSocketsApp.UseLoadBalancingMiddleware();
wenSocketsApp.UseDownstreamUrlCreatorMiddleware();
wenSocketsApp.UseWebSocketsProxyMiddleware();
});

Could we convert your experience and solution to a PR please?

@raman-m
Copy link
Member

raman-m commented Mar 17, 2024

@mkanakis commented on Mar 30, 2020

Sorry! How can we re-use your solution in Ocelot if it is based on custom setup in AddIdentityServerAuthentication method which is not a part of Ocelot code base?
This solution doesn't use Ocelot functionality at all.
Or, do you propose to wrap TokenRetriever life hack into an useful extension method?

@raman-m raman-m added Websockets Ocelot feature: Websockets Authentication Ocelot feature: Authentication Authorization Ocelot feature: Authorization SignalR SignalR is Microsoft Websocks technology labels Mar 17, 2024
@alex-pollan
Copy link

alex-pollan commented Mar 20, 2024

I just want to clarify that my solution above is for a pure APIGW with Ocelot that proxies the SignalR connection endpoint downstream to another service where I actually implement the SignalR server.

Notice that the authentication / authorization happens and it is terminated at the APIGW layer.

I capture the authenticated principal identity and pass it downstream as HTTP headers to the SignalR service to use it

Here are the final Ocelot routes I needed:

    {
      "UpstreamPathTemplate": "/signalr/negotiate",
      "UpstreamHttpMethod": [ "POST" ],
      "DownstreamScheme": "http",
      "DownstreamPathTemplate": "/devices-hub/negotiate",
      "DownstreamHostAndPorts": [ { "Host": "{DevicesHubApiService}" } ],
      "RouteIsCaseSensitive": false,
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "Bearer",
        "AllowedScopes": [ "myscope" ]
      }
    },
    {
      "UpstreamPathTemplate": "/signalr",
      "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE", "OPTIONS" ],
      "DownstreamScheme": "ws",
      "DownstreamPathTemplate": "/devices-hub",
      "DownstreamHostAndPorts": [ { "Host": "{DevicesHubSignalRService}" } ],
      "RouteIsCaseSensitive": false,
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "Bearer",
        "AllowedScopes": [ "myscope" ]
      }
    },

@raman-m
Copy link
Member

raman-m commented Mar 25, 2024

@alex-pollan commented on Mar 20

Your JSON looks like a life hack to forward anonymous traffic to downstream and be authorized on Ocelot's side.
I propose to developers always to define 2 routes to allow authentication on service's side.

Your previous comments with a solution is good. And I will figure out how to reuse it when started working on #1707

@hogwartsdeveloper
Copy link
Contributor

is this implemented? If not then I'm going to do id.

@raman-m
Copy link
Member

raman-m commented Jun 10, 2024

@hogwartsdeveloper You are assigned!

@raman-m raman-m added the Oct'24 October 2024 release label Jun 12, 2024
@raman-m raman-m added this to the Summer'24 milestone Jun 12, 2024
@raman-m
Copy link
Member

raman-m commented Jun 12, 2024

@hogwartsdeveloper, best of luck to you!
Just so you know, I've assigned the issue to the Summer'24 milestone as I'm uncertain if it can be completed for the Annual 2023 release, which is currently underway. The final decision regarding its delivery will depend on the readiness of the PR.

@raman-m
Copy link
Member

raman-m commented Jun 15, 2024

@hogwartsdeveloper FYI #720 #718

@raman-m
Copy link
Member

raman-m commented Jun 15, 2024

@hogwartsdeveloper FYI #674 #998

@raman-m raman-m removed the Oct'24 October 2024 release label Oct 26, 2024
@raman-m raman-m removed this from the October'24 milestone Oct 26, 2024
@raman-m
Copy link
Member

raman-m commented Oct 26, 2024

Further development after upgrade to .NET 9 ❗

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Authentication Ocelot feature: Authentication Authorization Ocelot feature: Authorization SignalR SignalR is Microsoft Websocks technology Websockets Ocelot feature: Websockets
Projects
None yet
Development

No branches or pull requests

11 participants