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

SignalR and Windows Authentication / Kerberos in AWS #18576

Closed
johnnyreilly opened this issue Jan 25, 2020 · 13 comments
Closed

SignalR and Windows Authentication / Kerberos in AWS #18576

johnnyreilly opened this issue Jan 25, 2020 · 13 comments
Labels
area-signalr Includes: SignalR clients and servers
Milestone

Comments

@johnnyreilly
Copy link

Is your feature request related to a problem? Please describe.

Hey all,

Amazing work on SignalR! I'm dropping you a line as I've recently encountered a hard problem.

Hand on heart, I don't know how to solve it. I'm no expert on Auth but I have a feeling that I'm not the first to encounter this. I don't know for sure if I'm even asking good questions, but I thought I'd try. If I'm wasting your time please do forgive me.

Here's the situation: I have an ASP.Net Core 3.1 application which runs in docker + kubernetes on AWS. We've a need to connect our application to a SignalR hub that is hosted on an on-premise server. Our cluster has access to the on-premise network + server. However, that hub is secured via Windows Authentication. (A specific service account is permissioned to use it.) It would be amazing if that SignalR hub supported other Auth but alas that's not the case.

Describe the solution you'd like

So we've been wondering if there's a way to combine SignalR and Kerberos.Net to do this. Or if there's another way that we haven't happened upon yet. It's possible this is already feasible, but despite much searching I haven't found an example of someone doing this.

I'm wondering if this is possible? Again, apologies for a random question from out of the blue. I'm an open source maintainer myself and I know that your time isn't free. If you're able to spend some time answering this that would be amazing. No sweat if not.

I've raised a similar question against the Kerberos.Net project too: dotnet/Kerberos.NET#129

@blowdart
Copy link
Contributor

Windows authentication / kerberos authentication is meant for intranet environments, not for the cloud. I don't believe you'd be able to get a kerberos ticket unless your AWS site had access to your domain controller. @SteveSyfuhs can tell me how horribly wrong I am though :)

@johnnyreilly
Copy link
Author

johnnyreilly commented Jan 25, 2020

Thanks for responding @blowdart. (Amazing to speak to the great Barry Dorrans by the way!)

unless your AWS site had access to your domain controller.

My understanding is that this may be the case. (I'm so not an area in this area it's untrue 😄) I say that as we're able to access our on premise network resources such as databases / APIs. Up until now we've been able to tackle these with username / passwords / tokens. It's the first time we've been faced with attempting to authenticate via a service account.

You know when you'd have a website in IIS with an Application Pool set to the identity of a an Active Directory account (your "service" account)? That's the behaviour we're trying to emulate.

@SteveSyfuhs
Copy link

SteveSyfuhs commented Jan 25, 2020 via email

@johnnyreilly
Copy link
Author

johnnyreilly commented Jan 25, 2020

Hey @SteveSyfuhs - thanks so much for responding! I really appreciate it. That's two amazing people responding on one GitHub issue; wow!

You say Kub on AWS so presumably that's NOT Windows hosts

Exactly right! I've written some code like your example:

var client = new KerberosClient();
var kerbCred = new KerberosPasswordCredential("user@domain.com", "userP@ssw0rd!");
await client.Authenticate(kerbCred);
var ticket = await client.GetServiceTicket("http/yoursignalr.app.com");

I'm successfully requesting a ticket when I run locally on Windows. I can test it in k8s on Monday. (With a little help from a marvellous friend who knows more about k8s / AWS and the networking side that I do.)

Once it has a ticket it can just send it to SignalR and everything works as normal.

Would you be able to expand upon this a little please? What I mean is, if we were deployed on IIS running as our service account we'd be able to connect something like this:

            var connection = new HubConnectionBuilder()
                .WithUrl("https://our.server.com/hub/bub", options =>
                {
                    options.UseDefaultCredentials = true;
                })
                .Build();

Is there a way to attach Kerberos credentials to that connection? I haven't stumbled upon any docs that describe that. I'm guessing that something like this could be possible:

var client = new KerberosClient();
var kerbCred = new KerberosPasswordCredential("user@domain.com", "userP@ssw0rd!");
await client.Authenticate(kerbCred);
var ticket = await client.GetServiceTicket("http/yoursignalr.app.com");

            var connection = new HubConnectionBuilder()
                .WithUrl("https://our.server.com/hub/bub", options =>
                {
                    // how can we use ticket?
                    options.Credentials = // new NetworkCredential(UserName, SecurelyStoredPassword, Domain);
                })
                .Build();

But I'm not sure how you create a NetworkCredential with the acquired Kerberos ticket? Again, my understanding of Kerberos is very far from complete so I might be asking a slight odd question. Hopefully my desired direction of travel makes sense?

Thanks again for your time! I really appreciate you helping; you certainly didn't have to and I'm very grateful.

@blowdart
Copy link
Contributor

There's no support in Core for making a kerb credential like this. That would be a questions for the .net core repo, rather than asp.net, but right now the only plans for kerb are extending it out to get groups and things.

@johnnyreilly
Copy link
Author

johnnyreilly commented Jan 25, 2020

Oh no! Does this mean I can authenticate but then can't actually use that when I work with SignalR? Or you think maybe, but I should check with https://github.com/dotnet/core/issues ?

@blowdart
Copy link
Contributor

That'd be the place. And yea, it looks like you can't do what you want.

Have you considered using ADFS in your domain, and the OIDC service to service? You'd get a JWT that way, and better still you can host way more things in whatever cloud you wish and have auth to your corporate domain. Although obviously you should use Azure as it pays my salary ;)

@blowdart blowdart added the area-signalr Includes: SignalR clients and servers label Jan 25, 2020
@blowdart blowdart added this to the Discussions milestone Jan 25, 2020
@SteveSyfuhs
Copy link

SteveSyfuhs commented Jan 25, 2020 via email

@johnnyreilly
Copy link
Author

johnnyreilly commented Jan 26, 2020

Have you considered using ADFS in your domain, and the OIDC service to service?

@blowdart I'll talk to our DevOps team and see what they say. We use Azure AD already so maybe that's possible?

Although obviously you should use Azure as it pays my salary ;)

😄

@johnnyreilly
Copy link
Author

johnnyreilly commented Jan 26, 2020

@SteveSyfuhs

As Barry says you can't load in a ticket per-se. You would need to manage the

Authorization: negotiate <ticket>

header on your own, but that's not rocket science. What you will need to do is call the EncodeGssApi() method to get a nego ticket (easier to use APIs TBD).

This sounds like something worth exploring! I'm imagining that possibly the approach detailed here could be adopted and tweaked to this end perhaps? Using a custom HttpClientHandler I mean:

var httpHandler = new WrappedHttpMessageHandler();
var connection = new HubConnectionBuilder()
.WithUrl("https://site.name.com")
.WithMessageHandler(httpHandler)
.Build();

private class WrappedHttpMessageHandler : HttpClientHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // Maybe the `Authorization: negotiate <ticket>` can be handled in here somehow?

        var response = await base.SendAsync(request, cancellationToken);

        return response;
    }
}

Are you aware of any example code out there that does this:

What you will need to do is call the EncodeGssApi() method to get a nego ticket

And do you think that plugging into the HttpClientHandler would work? I guess it would only be at the point of the making the initial connection where you'd need to do the Authorization: negotiate <ticket> dance. Looking at Kerberos.NET tests maybe something like this is possible:

var negoTicket = ticket.EncodeGssApi().ToArray();
var negoTicketAsString = Encoding.UTF8.GetString(negoTicket, 0, negoTicket.Length);
var authHeader = $"Authorization: negotiate {negoTicketAsString}"

Though not sure if UTF8stringifying the byte array is quite right...

By the way, I write a tech blog; if we can work out a way to do this I'll definitely plan to write this up so that others can get the benefit as well. I'd lay good money that in enterprise companies the world over there's developers banging their head against this particular wall 😄

Incidentally, the details on this ticket provide some insight as to how you might get NTLM working; not Kerberos though I think.

@blowdart
Copy link
Contributor

@johnnyreilly If you're on Azure AD anyway .. there is service to service auth, but you'd need to have line of site to the Azure AD too. Which may well mean hosting in azure itself, although I'm not 100% on that.

@johnnyreilly
Copy link
Author

Thanks @blowdart - hopefully that's not the case as we're hosting in AWS (sorry!) But if not that could be another possibility to investigate 🤗

@ghost
Copy link

ghost commented Nov 12, 2020

Thank you for contacting us. Due to a lack of activity on this discussion issue we're closing it in an effort to keep our backlog clean. If you believe there is a concern related to the ASP.NET Core framework, which hasn't been addressed yet, please file a new issue.

This issue will be locked after 30 more days of inactivity. If you still wish to discuss this subject after then, please create a new issue!

@ghost ghost closed this as completed Nov 12, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 12, 2020
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-signalr Includes: SignalR clients and servers
Projects
None yet
Development

No branches or pull requests

3 participants