Runtime: Implement Cross-Platform Kerberos for .NET Core

Created on 13 Sep 2018  Â·  42Comments  Â·  Source: dotnet/runtime

Kerberos is a popular authentication protocol that many Windows .NET applications use. We would like .NET Core to add a cross-platform Kerberos implementation, including support for these MIT Kerberos APIs or equivalent functionality:

  • krb5_init_context((krb5_context *)&context);
  • krb5_sname_to_principal(context, (char *) 0, (char *) 0, KRB5_NT_SRV_HST, &server);
  • krb5_get_default_realm(context, &therealm);
  • krb5_cc_resolve(context, CCNm_, &ccache);
  • krb5_cc_get_principal(context, ccache, &client);
  • krb5_auth_con_init(context, &auth_context);
  • krb5_copy_principal(context, server, &creds.server);
  • krb5_copy_principal(context, client, &creds.client);
  • krb5_get_credentials(context, 0, ccache, &creds, &credsp);
  • krb5_mk_req_extended(context, &auth_context, auth_options, &cksum_data, credsp, &outbuf);
api-suggestion area-System.Net.Security

Most helpful comment

Yes, Karelz, Kerberos is definitely used widely throughout the industry as a single sign-on.

Also, I specified the low level libraries, because without high level Kerberos APIs from .NET, that is our only choice. ALSO the low level APIs give the user the ULTIMATE flexibility in terms of handling ALL THE DIFFERENT usage cases that all the different applications may require.

All 42 comments

What are the user scenarios taking advantage of the APIs?
Do you have some API shape in mind?
How should it be integrated into existing networking APIs?

cc @wfurt @davidsh

Basically, we are acquiring client Kerberos credentials, then using them and server side credentials to acquire a TGT for the server DB service, and then generating the associated "authenticator" and sending it to the server. ie, pretty standard for authenticating to a service.

We would prefer that it is NOT integrated into any existing Network APIs, since that gives the API user more flexibility in terms of how to use or send the data to the server...which is the same as how MIT Kerberos5 APIs do it. Specifically, this is not at all associated with a web server or client.

So you are looking for general API for the protocol. Does anything prevent anyone from implementing it as separate library? Why does it need to be in CoreFX / .NET Core? Just convenience?
I assume there are similar APIs in Windows for Kerberos. Is that correct?

.NET already provides some high-level APIs that use Kerberos functionality internally, such as NegotiateStream. It may make sense to expose the low-level APIs in a platform independent way and layer the high level ones on top of them.

We already had to write platform specific versions of the code in order to support Kerberos authentication within the context of SASL authentication, which is in turn used by application protocols such as SMTP, IMAP or LDAP.

Unfortunately the high-level API already provided is not suitable for this use case since we are bound by another protocol standard, where the on-wire representation is different.

If there is room for reuse of APIs even inside .NET Core itself, then it would definitely make sense.
We would need someone familiar with those implementations to help design the right API surface - satisfying the consumer needs & making it reasonable for public consumption.

.NET already provides some high-level APIs that use Kerberos functionality internally, such as NegotiateStream. It may make sense to expose the low-level APIs in a platform independent way and layer the high level ones on top of them.

We already had to write platform specific versions of the code in order to support Kerberos authentication within the context of SASL authentication, which is in turn used by application protocols such as SMTP, IMAP or LDAP.

Unfortunately the high-level API already provided is not suitable for this use case since we are bound by another protocol standard, where the on-wire representation is different.

Yes, this is exactly the problem. The windows APIs and .NET APIs are within the context of very specific upper layer protocols, and often a windows domain instead of a generic KDC.

https://github.com/SteveSyfuhs/Kerberos.NET ?

Steve's package does no authenticator generation, only validation.

So you are looking for general API for the protocol. Does anything prevent anyone from implementing it as separate library? Why does it need to be in CoreFX / .NET Core? Just convenience?
I assume there are similar APIs in Windows for Kerberos. Is that correct?

Yes, it doesn't have to be in .NET/.NET Core. For example, if Steve's package could be extended to do the GENERATION of the authenticator, that would be a great first step.

But yes, it would be a lot "nicer" if it was included in .NET/.NET Core.

For what it's worth, the library has been extended to do generation (and issuance and what not).

@SteveSyfuhs

Does that mean we can generate Kerberos tokens in .net Core now ?
I .net 4.8 we could do it with something like this:

```c#
private string KerberosToken(Uri uri)
{
// Uri uri = new Uri(url);
var serviceName = "HTTP/" + uri.Host + (uri.Port != 80 && uri.Port != 443 ? ":" + uri.Port : "");

        var tokenProvider = new KerberosSecurityTokenProvider(serviceName, TokenImpersonationLevel.Impersonation, CredentialCache.DefaultNetworkCredentials);
        var securityToken = tokenProvider.GetToken(TimeSpan.FromMinutes(1)) as KerberosRequestorSecurityToken;
        return Convert.ToBase64String(securityToken.GetRequest());
    }

```

That class is not available in Core AFAIK. It's also very Windows-specific. The library people are referring to above is 3rd party and is an implementation of the Kerberos protocol. It does not call into GSSAPI, which is probably not the most useful for corefx.

The APIs seem to be too low-level for us to take into the BCL. We think the APIs won't be used by too many people.
It sounds like a good candidate for independent package. Closing.

Whereas it is great that Steve's package has been extended to client side, it doesn't help for the reason that this issue was created, since Steve noted they are only available on Windows. ie, the point here is cross platform (Linux and MacOS Core) support for Kerberos client side functionality.

@ScotMac I think maybe you misinterpreted what I said. KerberosSecurityTokenProvider is Windows-only, and AFAIK doesn't exist in Core in any form. The library I built is cross-platform (or at least intends to be though it's not rigorously tested off Windows).

You can more or less replace calls to KerberosSecurityTokenProvider with KerberosClient, but it doesn't rely on GSSAPI so the behavior and usage is different.

Got it Steve, thanks.

So, your package now DOES handle client side authenticator generation? Can you please give an example of the generation (sorry if you already have it somewhere else).

Also, does your package support BOTH framework and core?

Yes, you can do client side authenticator generation. It's all wrapped in the KerberosClient class. Here's an E2E test that shows how it's done: https://github.com/SteveSyfuhs/Kerberos.NET/blob/master/Tests/Tests.Kerberos.NET/E2EKdcClientTest.cs#L135-L158

The gist of it is:

  1. Create a client (don't pass override KDC unless you need to pin it to a particular DC)
  2. Authenticate the client to get the TGT
  3. Request a service ticket to some SPN for that authenticated user
  4. Send the ticket to some service

It's built as netstandard2.0 so that should in principle work for both framework and core.

Here's the thing though. This doesn't have the same level of security as say Kerberos on Windows through SSPI, because it doesn't rely on LSA protecting it's secrets. This changes the security model significantly and you need to consider whether this is something to account for in your build.

MIT client libraries support BOTH the ability to see/utilize the client authentication via LSA and a Kerberos5 specific local credential cache (kinit/klist and okinit/oklist for Oracle). Are you saying that you don't support the LSA portion, and only support a local credential cache file?

I expect that MIT is just calling SSPI since Windows doesn't expose a way to access cached tickets directly.

My library doesn't touch LSA at all. The cache is rudimentary and doesn't even use a file.


From: ScotMac notifications@github.com
Sent: Monday, September 9, 2019 12:43:58 PM
To: dotnet/corefx corefx@noreply.github.com
Cc: Steve Syfuhs steve@syfuhs.net; Mention mention@noreply.github.com
Subject: Re: [dotnet/corefx] Implement Cross-Platform Kerberos for .NET Core (#32291)

MIT client libraries support BOTH the ability to see/utilize the client authentication via LSA and a Kerberos5 specific local credential cache (kinit/klist and okinit/oklist for Oracle). Are you saying that you don't support the LSA portion, and only support a local credential cache file?

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://github.com/dotnet/corefx/issues/32291?email_source=notifications&email_token=AAJHTYO6GLTCCOSPPPPY5FDQI2RP5A5CNFSM4FVA5RQKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD6IZNTY#issuecomment-529635023, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AAJHTYIXWBCN7QQCIV62DC3QI2RP5ANCNFSM4FVA5RQA.

Sure, they call LSA APIs to acquire the ccache authentication data, after which they use it just like it came from a ccache file. You can read about KFW (KerberosForWindows) and their support for MSLSA here: https://web.mit.edu/kerberos/kfw-4.1/kfw-4.1.html

We would need support for file based, and probably MSLSA, ccache.

Your implementation strictly uses in memory data for the ccache? If so, is a file based transformation possible? ie, read in the file and supply the resultant byte array to your library?

Okay, so that's unsupported on Windows today. The way it queries LSA is not a supported mechanism, is blocked by default, and hard blocked in certain scenarios. SSPI is the only safe way on Windows clients.

The library could be extended easily enough to support a file-based cache. It's not terribly complicated.


From: ScotMac notifications@github.com
Sent: Tuesday, September 10, 2019 4:48:20 PM
To: dotnet/corefx corefx@noreply.github.com
Cc: Steve Syfuhs steve@syfuhs.net; Mention mention@noreply.github.com
Subject: Re: [dotnet/corefx] Implement Cross-Platform Kerberos for .NET Core (#32291)

Sure, they call LSA APIs to acquire the ccache authentication data, after which they use it just like it came from a ccache file. You can read about KFW (KerberosForWindows) and their support for MSLSA here: https://web.mit.edu/kerberos/kfw-4.1/kfw-4.1.html

We would need support for file based, and probably MSLSA, ccache.

Your implementation strictly uses in memory data for the ccache? If so, is a file based transformation possible? ie, read in the file and supply the resultant byte array to your library?

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://github.com/dotnet/corefx/issues/32291?email_source=notifications&email_token=AAJHTYNL6J3U6JM7WGGF6SDQJAW4JA5CNFSM4FVA5RQKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD6M2ELY#issuecomment-530162223, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AAJHTYLPWKQJMMDFD4SOI4LQJAW4JANCNFSM4FVA5RQA.

Note, MIT's KFWindows also has a way of translating MSLSA to the MIT API cache. Here is their description (from the link i gave above):

  • ms2mit.exe behavior has changed to improve the MSLSA: cache experience for UAC-restricted login sessions on an AD domain that runs ms2mit.exe in login scripts:

    • If the TGT is accessible in the LSA ccache, copy the LSA ccache to the API ccache.

    • Set the registry key for the default ccname to "API:" if the copy occurred, or to "MSLSA:" if it didn't occur.

ie, MIT appears to have two ways of handling MSLSA (Windows logon credential) ccache.

Oh, and our MSLSA via MIT Kerberos5 works fine on all Windows versions. ie, is not blocked/hard.blocked.

Guys I am having a similar issue. Here's the problem I am trying to solve:

  1. Running a .net core 3.1 in a container on Openshift (works fine)
  2. Using a keytab file I would like to fetch a kerberos token in order to use for a REST call to a Kerberos protected service

Other teams in the firm have this working in Node and in Java, they are basically accessing the MIT libs and using the Krb5.conf and locally stored keytabs for everything.

So far I have attempted to do this with Kerberos.Net and httpclient but the SPNEGO to that REST service fails.
Is there a native .net core way of doing this?

Thanks

.net only wraps krb5 via GSSPI. So it will respect krb5.conf as well as keytab entries.
It should be certainly possible. look at https://github.com/dotnet/corefx/pull/39933
You can perhaps also look at the test. If that does not help you I would suggest to open a separate issue and provide as many details as you can @undecided2013.

Thanks, I just looked at the test code, I do not see any tests that utilize keytabs. To be more clear, I only have username, keytab, spn of REST service to be hit and the uri for that service.

Is this available in the current previews of Core 5? If so, how do i go about accessing it (what is the class?)? If not, will it be available in a later preview?

The APIs seem to be too low-level for us to take into the BCL. We think the APIs won't be used by too many people.
It sounds like a good candidate for independent package. Closing.

@karelz
These APIs will be used by the Oracle DB .NET Core provider. Without these APIs, Oracle Data Provider for .NET Core developers won't be able to use Kerberos, which would prevent some of them from adopting .NET Core.

I've had customers approach me privately asking for this feature. There have been a couple additional customers asking for support on Oracle forums,
https://community.oracle.com/thread/4288468
https://community.oracle.com/thread/4328912

AND Steve's library will NOT WORK for us and others, since the client side authenticator does not support acquisition of the client credentials via a standard kerberos credential cache NOR via LSA.

So, there IS NO independent package.

@alexkeh there is clear need of .NET Core package with this functionality. It does not mean it has to be part of the platform itself inbox, does it?
Either way, someone has to build the APIs which do not exist today, we are just debating where it lives (in BCL or independent nuget package) and who does it. Or did I misunderstand what you meant?

@ScotMac without understanding technical details -- is it something that can be extended in the existing library? Built on top of? Or is Steve's library entirely irrelevant for what you need?

@karelz
The package doesn't need to be part of the platform. However, commercial customers care very much who owns the package and who provides support.

It's not clear to me what you mean by an independent package. Do you mean a third-party owning the package or another team at Microsoft?

Another item of confusion is that @msftgits added this project to the .NET 5 milestone after you closed the issue. Most of the time when an issue is closed and has been added to a milestone, it means the feature has been added to that product version. However, your comments closing the issue seems to indicate otherwise.

Third-party package means non-Microsoft. .NET Foundation is a way to drive the message that not everything has to be owned and driven by Microsoft. Other large companies, smaller companies, and even communities can produce reliable components. (think Json.NET)

Packages / APIs that have limited usage (i.e. low percentage of developers/libraries), like this one, are great candidates for that -- they can start independently, don't need to be part of the .NET Core, don't need to be owned and driven by Microsoft as they are better served by teams/people who know more about the scenarios where they need to be used. Some of them may be that way for ever, some of them may eventually graduate into the platform, or to have strong Microsoft contributions. It depends on how important and valuable the scenario becomes over time.

Regarding milestones -- milestone reflects WHEN the issue was closed, not the resolution (i.e. WHY) -- if it was Fixed vs. Won't Fix vs. By Design vs. Not Repro (such information is usually clear from the discussion, esp. around the time of the closure).

"Added this to the 5.0 milestone on Jan 31"

A milestone is almost always a positive event that you achieved. And the wording "Added this to the 5.0 milestone" strongly implies it is part of the 5.0 release, and says nothing about closing it. All and all, that is extremely misleading and should not be used to designate that this was just closed.

@ScotMac in your line of reasoning milestone carries two pieces of information -- the resolution (Fixed) and information When.
All other resolutions should be no milestone?
How do you catch if someone makes a mistake (forgets to set milestone or sets milestone when it was not truly fixed?)
What about No Repro?

Anyway, this is independent higher level discussion, not relevant technically to this issue. If you are passionate about it, let's discuss it separately on meta issue. There are pros and cons for both approaches and we just went with the simplest one which is easier to audit and reason about. Maybe we can change our approach if there are compelling arguments ...

Shouldn't security related protocols/implementations be considered important enough to be taken up by the core team? And not only current adoption level but "potential for adoption" if something is given as part of .Net-Core be considered for inclusion into .net-core to make core product more useful/popular.

@shashikantshukla we consider all useful and widely used APIs important for the platform. For narrow use cases like this one we don't think it makes sense to add them to the platform as the value is low - see https://github.com/dotnet/runtime/issues/27395#issuecomment-528516656 ... it is more appropriate to support .NET ecosystem to be able to cover such cases. Not everything has to be included directly in the platform to make .NET more useful/popular.

There is nothing narrow about a single sign on via Kerberos. Not only is Kerberos widely used throughout the industry, it is ALSO the authentication method/repository used by Microsoft Windows.

Also, where we MAY be able to do the loading of the credential cache file ourself, and then pass it to Steve's APIs, we are not able to handle the true single signon via MSLSA that Steve does not support. And it doesn't make a lot of sense to require EVERY library that wants to do single sign on via Kerberos to have to do redo the same code to load the credentials, when it could instead be done via the library.

There is nothing narrow about a single sign on via Kerberos

This is the first time single sign on is mentioned on this issue. So far, we have been discussing the low-level APIs proposed at the top. Or did I misunderstand the topic?

The low-level APIs proposed in this issue may be valuable in some .NET library -- I am not arguing with that. However, they don't seem to be good fit for BCL from these reasons:

  1. There is limited number of customers who will use these low-level APIs directly and not via another library.
  2. BCL in general does not expose these kind of low-level APIs to my best knowledge. We are trying to expose higher-level concepts that are easy to use, then using low-level APIs under the hood to implement them.
    Based on previous replies (https://github.com/dotnet/runtime/issues/27395#issuecomment-627110663) I thought we have common understanding here. Is that not the case yet?

Also, where we MAY be able to do the loading of the credential cache file ourself, and then pass it to Steve's APIs, we are not able to handle the true single signon via MSLSA that Steve does not support. And it doesn't make a lot of sense to require EVERY library that wants to do single sign on via Kerberos to have to do redo the same code to load the credentials, when it could instead be done via the library.

It seems that these could be potentially good solutions:

  1. Can a contribution to Steve's library address the needs?
  2. Can extension built on top of Steve's library address the needs?
  3. Can entirely different (maybe brand new) library address the needs? (maybe it can start as fork of Steve's library?)
    Are any of these feasible?

This lack of kerberos support in NET core is preventing a Oracle project I am involved in from moving forward. It boggles the mind that this security feature would be dismissed as utilized by a small set of people. What does that say about program security in general? I am a DBA. What can I do to help get this implemented for Oracle Kerberos connections?

Yes, Karelz, Kerberos is definitely used widely throughout the industry as a single sign-on.

Also, I specified the low level libraries, because without high level Kerberos APIs from .NET, that is our only choice. ALSO the low level APIs give the user the ULTIMATE flexibility in terms of handling ALL THE DIFFERENT usage cases that all the different applications may require.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

aggieben picture aggieben  Â·  3Comments

Timovzl picture Timovzl  Â·  3Comments

noahfalk picture noahfalk  Â·  3Comments

bencz picture bencz  Â·  3Comments

chunseoklee picture chunseoklee  Â·  3Comments