dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.01k stars 4.67k forks source link

System.DirectoryServices.Protocols LdapConnection doesn't work with Ntlm and Kerberos on Linux #66945

Open pollymykh opened 2 years ago

pollymykh commented 2 years ago

Description

We have a simple LDAP connector in our app that currently works with System.DirectoryServices.Protocols 5.0.0 nuget package. To use SSL/TLS features I'm trying to upgrade in to package 6.0.0 and higher, but when I do that I find that it's not possible to connect using Ntlm or Kerberos AuthType anymore and those are what our clients mostly use.

Reproduction Steps

App is netcore3.1. The connection code looks like this

_ldapConnection = new LdapConnection(_ldapServer) { AuthType = authType }; _ldapConnection.SessionOptions.ProtocolVersion = 3; if (IsWindows()) { _ldapConnection.SessionOptions.ReferralChasing = ReferralChasingOptions.None; } if (useSsl) { _ldapConnection.SessionOptions.SecureSocketLayer = true; if (IsWindows()) { _ldapConnection.SessionOptions.VerifyServerCertificate = new VerifyServerCertificateCallback(VerifyServerCertificate); } } var credentials = new NetworkCredential(_ldapServerLogin, _ldapServerPassword, keyDistributionCenter ?? string.Empty); _ldapConnection.Bind(credentials);

The only thing I change is nuget package version from 5.0.0 to 6.0.0.

Expected behavior

Successful bind when AuthType is Ntlm or Kerberos and app runs on Windows or Linux

Actual behavior

Successful bind on Windows, but on Linux I get the following errors Ntlm: Error code AuthUnknown (86) (System.DirectoryServices.Protocols.LdapException: An unknown authentication error occurred.) Kerberos: Error code NotSupported (92) (System.DirectoryServices.Protocols.LdapException: The feature is not supported.)

Regression?

Works with System.DirectoryServices.Protocols 5.0.0 nuget package on both Windows and Linux

Known Workarounds

No response

Configuration

No response

Other information

No response

ghost commented 2 years ago

Tagging subscribers to this area: @dotnet/area-system-directoryservices, @jay98014 See info in area-owners.md if you want to be subscribed.

Issue Details
### Description We have a simple LDAP connector in our app that currently works with System.DirectoryServices.Protocols 5.0.0 nuget package. To use SSL/TLS features I'm trying to upgrade in to package 6.0.0 and higher, but when I do that I find that it's not possible to connect using Ntlm or Kerberos AuthType anymore and those are what our clients mostly use. ### Reproduction Steps App is netcore3.1. The connection code looks like this ` _ldapConnection = new LdapConnection(_ldapServer) { AuthType = authType }; _ldapConnection.SessionOptions.ProtocolVersion = 3; if (IsWindows()) { _ldapConnection.SessionOptions.ReferralChasing = ReferralChasingOptions.None; } if (useSsl) { _ldapConnection.SessionOptions.SecureSocketLayer = true; if (IsWindows()) { _ldapConnection.SessionOptions.VerifyServerCertificate = new VerifyServerCertificateCallback(VerifyServerCertificate); } } var credentials = new NetworkCredential(_ldapServerLogin, _ldapServerPassword, keyDistributionCenter ?? string.Empty); _ldapConnection.Bind(credentials);` The only thing I change is nuget package version from 5.0.0 to 6.0.0. ### Expected behavior Successful bind when AuthType is Ntlm or Kerberos and app runs on Windows or Linux ### Actual behavior Successful bind on Windows, but on Linux I get the following errors Ntlm: Error code AuthUnknown (86) Kerberos: Error code NotSupported (92) ### Regression? Works with System.DirectoryServices.Protocols 5.0.0 nuget package on both Windows and Linux ### Known Workarounds _No response_ ### Configuration _No response_ ### Other information _No response_
Author: pollymykh
Assignees: -
Labels: `area-System.DirectoryServices`, `untriaged`
Milestone: -
filipnavara commented 2 years ago

Did you test both of the .NET versions on the same machine against the same server? Is the gss-ntlmssp package installed on the machine?

pollymykh commented 2 years ago

@filipnavara yes, same machine to run app, same AD server, same credentials, same codebase except the indicated nuget package version. gss-ntlmssp isn't installed on the machine I run my app on, should it be?

filipnavara commented 2 years ago

I believe @iinuwa may have some insight about what is going on but I am not particularly familiar with LDAP.

The error message look like something returned by GSSAPI library (the one that is responsible for Kerberos, NTLM and Negotiate authentication). Specifically, the Linux GSSAPI implementation is provided with the krb5 package and the gss-ntlmssp optional package. The AuthUnknown error code is something that I would expect if krb5 was intalled and gss-ntlmssp was not installed.

However, I cannot find any explanation for the fact that it works with older version of the System.DirectoryServices.Protocols package. Majority of the fixes in that library after version 5.0.0 focused on unrelated bug fixes (TLS, referral chasing options). While it could be some unintentional side effect I cannot see any change that would be directly related.

filipnavara commented 2 years ago

The only change that touched the code, as far as I can see, is https://github.com/dotnet/runtime/pull/52904.

filipnavara commented 2 years ago

My suspicion is that the authentication type may have inadvertently been ignored in version 5.0.0 (on Linux) and it silently proceeded with Basic authentication. Would it be possible to run Wireshark traces for both package versions? (assuming that it may fail early for 6.0.0 and not produce anything useful)

joperezr commented 2 years ago

Hello @pollymykh thank you for logging the issue, and thanks @filipnavara for the initial triage. Seems like you are using credentials to login, and in such case, you aren't really doing Kerberos authentication. If you take a look at this comment on an issue that was logged right after 5.0 release, we discovered that in the 5.0.0 package setting AuthType to a value like Kerberos would basically be incorrectly discarded if you provided credentials, since we were silently falling back to Basic. I suspect this is why if you use 5.0.0 NuGet package it "works" (quoted since you aren't really doing Kerberos auth, we are silently falling back to basic auth instead.), but in 6.0.0 it doesn't. This is because after figuring out we had this problem, we now fail if you try to use Kerberos auth in 6.0 (and also in package 5.0.1 BTW) and provided credentials.

In Linux, we currently only support two types of authentication:

All of the rest of the Authentication types are currently not supported in Linux. We do plan to add support for them, but haven't planned that work for a milestone yet.

joperezr commented 2 years ago

My suspicion is that the authentication type may have inadvertently been ignored in version 5.0.0 (on Linux) and it silently proceeded with Basic authentication.

@filipnavara this is almost 100% sure what is going on. If you take a look at 5.0 branch, you can see under a feature flag what our code (incorrectly) used to do:

https://github.com/dotnet/runtime/blob/c7a22f1d9d7fa40464d888f2438f78af0b200ef2/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Linux.cs#L28-L38

We provided that feature flag only because this was a breaking change we made in 5.0.1 to fix this incorrect behavior we had in 5.0.0, so the feature flag allowed code to continue working in case they depended on the 5.0.0 behavior. If you see what we used to do, is basically that if credentials were used, then no matter which AuthType you had selected, we would always fallback to a simple bind (meaning AuthType.Basic)

filipnavara commented 2 years ago

and also in package 5.0.1 BTW

That explains why I missed the change. I always look at the tip of the servicing branches. 😅

pollymykh commented 2 years ago

@joperezr thank you for clarification. It seems like we have little choice now but to use Basic explicitly (since we're actually already using it with 5.0.0 logic). Does this behavior (switching to Basic when using credentials) only apply to Linux?

joperezr commented 2 years ago

Yes it only applies to Linux. If your Linux box is already domain-joined to your LDAP server and have a valid kerberos ticket for it, then you should be able to use that as well if you don't want to use credentials. Otherwise, yes, the choice would be to use Basic auth and if your LDAP server supports it, then using setting SSL or TLS options to true before calling Bind in order to encrypt the communication before passing your credentials to authenticate.

jmhickman commented 10 months ago

@joperezr Is the request to support other AuthTypes being tracked anywhere? My use-case is such that the user is on a non-domain joined machine, but has their username and password. It's (rather) unlikely that they would know their full DN for the account, making using the AuthType.Basic kind of a no-go for me. From my testing on Windows, it seems like AuthType.Ntlm would allow the workflow I'm aiming for.

Unless there's a programmatic way to retrieve the user's DN before connecting to the directory...but that seems like a chicken and egg problem.

joperezr commented 10 months ago

I can't find an issue for it from a quick search, so we can either create one for that or we can just re-use this one to track this (which is doing it specifically for Ntlm and Kerberos.)

corsiva commented 9 months ago

hi @joperezr, What do you think about issue #82430?

BR,

joperezr commented 9 months ago

Hi @corsiva, unfortunately I'm no longer focusing on System.DirectoryServices.* libraries, but looks like my colleagues who now own this are already engaged in that issue with you 😃

nhart12 commented 8 months ago
using LdapConnection conn = new(new LdapDirectoryIdentifier(hostname, 636));
conn.AuthType = AuthType.Negotiate;
conn.SessionOptions.SecureSocketLayer = true;
conn.SessionOptions.ReferralChasing = ReferralChasingOptions.None;
conn.Bind();

Is there any updates on this or any tips to help troubleshoot? I'm trying to do an ldap search in an ubuntu container using kuberos. The above code is giving me the same "The feature is not supported" error when attempting the Bind.

joperezr commented 8 months ago

Hello, The main AuthType supported in Linux is AuthType.Basic which will also need you to pass in credentials. Are you trying to reuse a connection on a system that is already domain joined?

nhart12 commented 8 months ago

Yes, I have a container that is doing kuberos auth to sql server (running kinit in a sidecar).. I was hoping I'd be able to piggy back on that to do ldap searches also so I don't need to mount a keytab as well as pass in the credentials

nhart12 commented 8 months ago

@joperezr are you saying AuthType.Negotiate is no longer a supported use-case in linux?

joperezr commented 8 months ago

It is supported, but only in the scenario where you are domain joined. Note that having run kinit is likely not enough, as that doesn't mean your machine is truly domain-joined and instead you may just be authenticated. My suggestion would be for you to try to run the ldapsearch linux utilities without passing in your credentials, and seeing if you are able to do that. Main reason why I ask is because the PInvokes we make in Linux for a Sasl bind is very similar to the one that those command line utilities do, so I would expect those won't work either. We unfortunately don't have good error messages for these issues, so another advantage from running those commands is that turning on the verbose output may give you more information on what is wrong with your configuration.

nhart12 commented 8 months ago

makes sense, thank you!

iinuwa commented 8 months ago

FWIW, ldapsearch does work with kinit on non-domain joined Linux computers.

JayVDZ commented 6 months ago

I too need NTLM/Kerberos support as well under Linux. Oddly, I did have it working, but seemingly without changing anything, it's stopped working. Clearly I'm going mad.

Scenario:

Dockerfile has some packages added:

RUN apt-get update \
    && apt-get install -y libldap-2.4-2

For a week or so this worked, but now just get the following exception:

System.DirectoryServices.Protocols.LdapException
  HResult=0x80131500
  Message=An unknown authentication error occurred.
  Source=System.DirectoryServices.Protocols
  StackTrace:
   at System.DirectoryServices.Protocols.LdapConnection.BindHelper(NetworkCredential newCredential, Boolean needSetCredential)

I'm using a Windows credential instead of an application partition one as I need to read the schema partition. I don't think you can do that using an application partition credential (so DN format). I have tried.

Any help from MS/others appreciated.

johnm123 commented 5 months ago

Hi,

I've hoping to use the DirectoryServices.Protocols (8.0.0) package on a Linux host to integrate with an LDAP server using Kerberos authentication. In earlier post by @joperezr, it appears that Basic and Negotiate are supported. Does this mean, by extension, that Kerberos is supported? Apologies as this appears to have been discussed, but the original discussion is regarding earlier versions and am wondering what the official line is now.

I've also been developing locally using this package on a MacOS machine. Basic authenication works fine but as soon as I use either a Negotiate or Kerberos AuthType to connect I get "LdapException: The feature is not supported.". Should the story for MacOS be the same as for Linux? I've noticed another post (in a slightly different context) suggesting this error message may be misleading.

Any clarification would be much appreciated.

jmhickman commented 1 month ago

Hoping for some movement on this. I'd like to make my tooling multi-platform by using S.DS.P, but I need to use the NTLM auth workflow. 🙏