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

LdapSessionOptions.VerifyServerCertificate is not supported in non-Windows and error message is not helpful. #60972

Open
macsux opened this issue Oct 28, 2021 · 47 comments
Labels
area-System.DirectoryServices bug help wanted [up-for-grabs] Good issue for external contributors
Milestone

Comments

@macsux
Copy link
Contributor

macsux commented Oct 28, 2021

Description

LdapConnection fails to bind on Linux when running .NET 6.0.0-rc.2.21480.5 version of System.DirectoryServices.Protocols package and throws

Unhandled exception. System.DirectoryServices.Protocols.LdapException: The feature is not supported. 
   at System.DirectoryServices.Protocols.LdapConnection.BindHelper(NetworkCredential newCredential, Boolean needSetCredential)
   at System.DirectoryServices.Protocols.LdapConnection.Bind()

The same code works when using switching to version 5.0.0 of System.DirectoryServices.Protocols or running under windows

Reproduction Steps

Run the following code under Linux

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="System.DirectoryServices.Protocols" Version="6.0.0-rc.2.21480.5" />
    </ItemGroup>
</Project>
using System.DirectoryServices.Protocols;
using System.Net;

var di = new LdapDirectoryIdentifier(server: "ad.almirex.com", 389);
var connection = new LdapConnection(di, new NetworkCredential("username","password","almirex.dc"));
connection.Bind();
Console.WriteLine("Hello, World!");

If the package version is switched to 5.0.0, the above code works.

Expected behavior

The code works

Actual behavior

The code throws

Regression?

This worked in .NET 5 version of the package.

Known Workarounds

None

Configuration

Tested with .NET 6.0.100-rc.2.21505.57 SDK on WSL2 Ubuntu

Other information

No response

@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.DirectoryServices untriaged New issue has not been triaged by the area owner labels Oct 28, 2021
@ghost
Copy link

ghost commented Oct 28, 2021

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

Issue Details

Description

LdapConnection fails to bind on Linux when running .NET 6.0.0-rc.2.21480.5 version of System.DirectoryServices.Protocols package and throws

Unhandled exception. System.DirectoryServices.Protocols.LdapException: The feature is not supported. 
   at System.DirectoryServices.Protocols.LdapConnection.BindHelper(NetworkCredential newCredential, Boolean needSetCredential)
   at System.DirectoryServices.Protocols.LdapConnection.Bind()

The same code works when using switching to version 5.0.0 of System.DirectoryServices.Protocols or running under windows

Reproduction Steps

Run the following code under Linux

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="System.DirectoryServices.Protocols" Version="6.0.0-rc.2.21480.5" />
    </ItemGroup>
</Project>
using System.DirectoryServices.Protocols;
using System.Net;

var di = new LdapDirectoryIdentifier(server: "ad.almirex.com", 389);
var connection = new LdapConnection(di, new NetworkCredential("username","password","ad.almirex.dc"));
connection.Bind();
Console.WriteLine("Hello, World!");

If the package version is switched to 5.0.0, the above code works.

Expected behavior

The code works

Actual behavior

The code throws

Regression?

This worked in .NET 5 version of the package.

Known Workarounds

None

Configuration

Tested with .NET 6.0.100-rc.2.21505.57 SDK on WSL2 Ubuntu

Other information

No response

Author: macsux
Assignees: -
Labels:

area-System.DirectoryServices, untriaged

Milestone: -

@macsux macsux changed the title LdapConnection is broken in .NET 6 on Linux LdapConnection fails to bind (connect to server) .NET 6 on Linux Oct 28, 2021
@macsux
Copy link
Contributor Author

macsux commented Oct 28, 2021

I think this is related to Ntlm somehow being broken on .NET 6. I switched it up like this:

using System.DirectoryServices.Protocols;
using System.Net;

var di = new LdapDirectoryIdentifier(server: "ad.almirex.com", 389);
var connection = new LdapConnection(di, new NetworkCredential("user","password", "almirex.dc"), AuthType.Ntlm);
connection.Bind();
Console.WriteLine("Hello, World!");

and getting

Unhandled exception. System.DirectoryServices.Protocols.LdapException: An unknown authentication error occurred.
   at System.DirectoryServices.Protocols.LdapConnection.BindHelper(NetworkCredential newCredential, Boolean needSetCredential)
   at System.DirectoryServices.Protocols.LdapConnection.Bind()

The same code works with 5.0.0 package, and v6 version of package works on Windows.

@joperezr
Copy link
Member

joperezr commented Nov 3, 2021

Thanks for logging the issue. Can you please try setting the connection auth type to Basic as well as setting the protocol version to 3.0?

var di = new LdapDirectoryIdentifier(server: "ad.almirex.com", 389);
var connection = new LdapConnection(di, new NetworkCredential("user", "password", "almirex.dc"));
connection.SessionOptions.ProtocolVersion = 3;
connection.AuthType = AuthType.Basic;
connection.Bind();
Console.WriteLine("Hello, World!");

@joperezr joperezr removed the untriaged New issue has not been triaged by the area owner label Nov 3, 2021
@joperezr joperezr added the bug label Nov 3, 2021
@joperezr joperezr added this to the Future milestone Nov 3, 2021
@ghost ghost added the needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration label Nov 3, 2021
@joperezr joperezr removed the needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration label Nov 3, 2021
@macsux
Copy link
Contributor Author

macsux commented Nov 5, 2021

Ok, that seems to have partially fixed the issue, I can connect to the LDAP endpoint on 389. It however fails to connect to LDAPS when running under linux, even though .NET 6 release notes says this is supposed to be supported. This is the code used:

using System.DirectoryServices.Protocols;
using System.Net;

var useSsl = true;
var port = useSsl ? 636 : 389;
var di = new LdapDirectoryIdentifier(server: "ad.almirex.com", port);
var connection = new LdapConnection(di, new NetworkCredential("username","password"), AuthType.Basic);
if (useSsl)
{
    connection.SessionOptions.SecureSocketLayer = true;
    connection.SessionOptions.VerifyServerCertificate = (ldapConnection, certificate) => true;
}
connection.Bind();
Console.WriteLine("Hello, World!");

@ghost ghost added the needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration label Nov 5, 2021
@joperezr
Copy link
Member

joperezr commented Nov 5, 2021

I believe ldaps is only supported when using protocol version 3. Can you try setting the protocol version to 3.0 in your connection before calling bind?

@macsux
Copy link
Contributor Author

macsux commented Nov 5, 2021

Didn't help. Looking closer it's actually choking on the setter for this line when run under Linux, but works fine on windows.

connection.SessionOptions.VerifyServerCertificate = (ldapConnection, certificate) => true;
Unhandled exception. System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable.
   at System.DirectoryServices.Protocols.ErrorChecking.CheckAndSetLdapError(Int32 error)
   at System.DirectoryServices.Protocols.LdapSessionOptions.set_VerifyServerCertificate(VerifyServerCertificateCallback value)
   at Program.<Main>$(String[] args) in /mnt/c/projects/ldapplay/Program.cs:line 12

@joperezr
Copy link
Member

joperezr commented Nov 8, 2021

I see, that is definitely a bug in Linux that we should fix, I'll update the title of the issue to say that this specific session option is the one that isn't working correctly. Out of curiosity, is there a specific reason you are defining that callback? I ask because the SSL handshake will automatically verify the server certificate already, and seems like yours isn't really changing anything. Can we get confirmation that if you remove that line the code works as expected?

@joperezr
Copy link
Member

joperezr commented Nov 8, 2021

Actually after looking this more closely, looks like the Option that this is internally trying to set is indeed not supported anywhere other than wldap32 (meaning this setting is not part of the LDAP spec) which explains why it doesn't work on Linux.

LDAP_OPT_SERVER_CERTIFICATE = 0x81, // Not Supported in Linux

Perhaps what this issue should track is just to have the right documentation on this API to mention that this is not supported in Linux, and we should be throwing a better exception with better details on it.

@joperezr joperezr changed the title LdapConnection fails to bind (connect to server) .NET 6 on Linux LdapSessionOptions.VerifyServerCertificate is not supported in non-Windows and error message is not helpful. Nov 8, 2021
@macsux
Copy link
Contributor Author

macsux commented Nov 9, 2021 via email

@macsux
Copy link
Contributor Author

macsux commented Nov 9, 2021

Also, I'm getting a CA1416 warning on connection.SessionOptions.SecureSocketLayer = options.UseSsl; telling me this API is windows only. Is this a left over that forgot to be removed after LDAPS supported was added for Linux?

@joperezr
Copy link
Member

joperezr commented Nov 9, 2021

Oh good catch, seems like when we added this feature we forgot to remove this attribute:

[System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")]

Would you be interested in submitting a PR fixing that? 😃

@joperezr
Copy link
Member

joperezr commented Nov 9, 2021

We are trying to ignore ssl cert validation at least in lower tier
environments, is this possible?

I'm not sure that is supported as the TLS handshaking happens at the openldap layer and we particularly want to make sure that this happens correctly, as any error during the handshaking process could result in openldap not encrypting the communication if we were to ignore the failure with the handshake.

@macsux
Copy link
Contributor Author

macsux commented Nov 10, 2021

I've submitted a PR to remove the leftover warning attribute.

I've found a workaround for this problem that works for me. By setting LDAPTLS_REQCERT=never environmental variable I can opt-out of SSL validation by OpenSSL as described by OpenSSL configuration. Interestingly trying to do this from within the process via Environment.SetEnvironmentVariable("LDAPTLS_REQCERT","never"); does not work.

The existing API VerifyServerCertificate offers a flexible callback that would allow users to provide a custom delegate on how cert validation should be performed. It seems that such callback feature is only available on Windows, as the only options that OpenSSL exposes are:

       TLS_REQCERT <level>
              Specifies what checks to perform on server certificates in a TLS
              session, if any. The <level> can be  specified  as  one  of  the
              following keywords:

              never  The   client   will  not  request  or  check  any  server
                     certificate.

              allow  The server certificate is requested. If no certificate is
                     provided,   the  session  proceeds  normally.  If  a  bad
                     certificate is provided,  it  will  be  ignored  and  the
                     session proceeds normally.

              try    The server certificate is requested. If no certificate is
                     provided,  the  session  proceeds  normally.  If  a   bad
                     certificate  is  provided,  the  session  is  immediately
                     terminated.

              demand | hard
                     These keywords are equivalent. The server certificate  is
                     requested.  If  no  certificate  is  provided,  or  a bad
                     certificate  is  provided,  the  session  is  immediately
                     terminated. This is the default setting.

While my workaround works for my use case, it's not very good long term because

  1. It has to be set outside of the process
  2. It affects ALL LDAP connections in the app.

I think it's worth discussing at this point whether a simplified SkipCertificateValidation or similarly named boolean property should be added to the LdapSessionOptions to give some degree of control over cert validation within code. While not as powerful as the callback offered by VerifyServerCertificate, 99% of the time developers are just trying to do a blanked bypass of cert validation without any custom logic.

I believe the only thing that would be required is to call ldap_set_option with LDAP_OPT_X_TLS_REQUIRE_CERT to one of LDAP_OPT_X_TLS_NEVER if the above property is true. More details here.

macsux added a commit to NMica/NMica.Security that referenced this issue Nov 10, 2021
@parrssee
Copy link

@akamud
We've found out that this issue was related to the wrong configurated LDAP server & missing certificates. Also, I found that specifying FQDN as server address in the LdapDirectoryIdentifier not working on the Linux platform, probably because of this.
Also, there's the VerifyServerCertificate callback in which you must validate your LDAP certificate, but this functionality not working on the Linux (because, on the Linux, we are basically only passing through the Bind to the underlying native library), and I'm not sure about Mac platform.

Here's the code sample of the class that I wrote to manage LDAP connections (I changed the code a bit so as not to violate the police company I work with):

string address = "some.ldap.server.com"; // You can specify port number here and then extract it from this string
int port = IsSsl ? 636 : 389;           
var directoryIdentifier = new LdapDirectoryIdentifier(address, port);
_ldapConnection = new LdapConnection(directoryIdentifier, credential, AuthType.Basic);
_ldapConnection.SessionOptions.ReferralChasing = _referralChasingOptions; // All
_ldapConnection.SessionOptions.ProtocolVersion = LDAP3ProtocolVersion; // 3
_ldapConnection.SessionOptions.SecureSocketLayer = IsSsl;
_ldapConnection.Timeout = Timeout;
_ldapConnection.AutoBind = AutoBind; 
// When using LDAPS in Linux we are basically only passing through the Bind to the underlying native library (openldap), which does perform a certificate validation.
// If the certificate fails to validate successfully, we will get an exception during call to Bind() which should have more info saying that the certificate was invalid or
// that the connection with the server couldn't be established.
// In case of Win NT systems we can use the built-in verification functionality provided in the X509Cerificate2 class
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
    _ldapConnection.SessionOptions.VerifyServerCertificate += 
        (ldapConnection, certificate) => new X509Certificate2(certificate).Verify();
}   

In the case of Mac, maybe you must verify the certificate yourself too (like on Win), so try to do some experiments with this sample.

@akamud
Copy link

akamud commented May 13, 2022

@akamud We've found out that this issue was related to the wrong configurated LDAP server & missing certificates. Also, I found that specifying FQDN as server address in the LdapDirectoryIdentifier not working on the Linux platform, probably because of this. Also, there's the VerifyServerCertificate callback in which you must validate your LDAP certificate, but this functionality not working on the Linux (because, on the Linux, we are basically only passing through the Bind to the underlying native library), and I'm not sure about Mac platform.

Here's the code sample of the class that I wrote to manage LDAP connections (I changed the code a bit so as not to violate the police company I work with):

string address = "some.ldap.server.com"; // You can specify port number here and then extract it from this string
int port = IsSsl ? 636 : 389;           
var directoryIdentifier = new LdapDirectoryIdentifier(address, port);
_ldapConnection = new LdapConnection(directoryIdentifier, credential, AuthType.Basic);
_ldapConnection.SessionOptions.ReferralChasing = _referralChasingOptions; // All
_ldapConnection.SessionOptions.ProtocolVersion = LDAP3ProtocolVersion; // 3
_ldapConnection.SessionOptions.SecureSocketLayer = IsSsl;
_ldapConnection.Timeout = Timeout;
_ldapConnection.AutoBind = AutoBind; 
// When using LDAPS in Linux we are basically only passing through the Bind to the underlying native library (openldap), which does perform a certificate validation.
// If the certificate fails to validate successfully, we will get an exception during call to Bind() which should have more info saying that the certificate was invalid or
// that the connection with the server couldn't be established.
// In case of Win NT systems we can use the built-in verification functionality provided in the X509Cerificate2 class
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
    _ldapConnection.SessionOptions.VerifyServerCertificate += 
        (ldapConnection, certificate) => new X509Certificate2(certificate).Verify();
}   

In the case of Mac, maybe you must verify the certificate yourself too (like on Win), so try to do some experiments with this sample.

Thanks for the reply, in fact we found something similar here. One of our servers wasn't correctly configured, when we tried the other one it worked. Now we configured the server correctly and everything is working fine.

Regarding the VerifyServerCertificate, it doesn't work on macOS either, so I used the same strategy of setting the LDAPTLS_REQ env for the openldap verification.

@joperezr any chance the error messages from theses cases can be more helpful? I used Apache Directory Server to try and connect to the server using SSL and it provided me better error messages, only then we started to investigate our server. The "server is unavailable" message from the .NET implementation is very generic.

@joperezr
Copy link
Member

Yes, we have several issues for trying to surface the error messages better, we can use this issue to track the work of making that better for .NET 7

@erosen03
Copy link

erosen03 commented Sep 3, 2022

@joperezr was LdapSessionOptions.VerifyServerCertificate ever implemented on Linux? I'm having the exact same issues as the other folks on this thread, and the only workaround was to issue export LDAPTLS_REQCERT=never in the parent process of pwsh (i.e. the bash shell that spawns PowerShell).

This is not a great workaround, because the export must be run prior to spawning the PowerShell process. It cannot be run from within a PowerShell script. This is very problematic when working with an AWS PowerShell Lambda Function.

@jborean93
Copy link
Contributor

You can set it in proc but you need to use PInvoke to call setenv in libc directly and not through the dotnet APIs. It’s not ideal but it at least doesn’t rely on the env var being set before the process starts.

@joperezr
Copy link
Member

@joperezr was LdapSessionOptions.VerifyServerCertificate ever implemented on Linux? I'm having the exact same issues as the other folks on this thread, and the only workaround was to issue export LDAPTLS_REQCERT=never in the parent process of pwsh (i.e. the bash shell that spawns PowerShell).

We haven't been able to prioritize this issue to add the support in Linux yet, but we would definitely be open into taking a contribution that addresses this in case anyone is interested in helping. Otherwise, we will keep it in the backlog and hopefully be able to get to it in 8.0, but that would greatly depend on the work going to the rest of the libraries and their priorities.

@joperezr joperezr added the help wanted [up-for-grabs] Good issue for external contributors label Oct 10, 2022
@GeertvanHorrik
Copy link
Contributor

Been struggling with this as well (LPAP via SSL on Linux). A few things that might be useful for others:

  1. It's important to set the environment variable before creating the connection. I did it after creating the connection (where I used to set the server certificate validation callback), but then the underlying library seems to have already read the state and won't do that again. So if you are using the workaround by setting the environment via the setenv, make sure to do it earlier if it's not working for you.

  2. As suggested here, I've tried doing this "per connection / instance" instead by using the handle with custom interop. It looks like it's a global (handle should be null (or IntPtr.Zero)) setting according to this post and cannot be set per instance.

The Novell.Directory.Ldap.NETStandard library that some have mentioned can do this per connection / instance, but it would require a rewrite of most of the LDAP / AD related code.

@michiproep
Copy link

This code is confirmed to work https://github.com/NMica/NMica.Security/blob/3868ceab4880058fbca4b66d651a169d04757d1d/src/NMica.AspNetCore.Authentication.Spnego/Ldap/LdapRolesClaimsTransformation.cs#L204

On Thu., Mar. 17, 2022, 1:40 p.m. parrssee, @.> wrote: It works but if you're looking to skip ssl validation you have to do it via env var rather then the callback event. See my earlier comments Quite the contrary, I don't need to skip this validation and because of this I don't know how to connect over 636 port — Reply to this email directly, view it on GitHub <#60972 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAINFWDKZ2X7GY7L4T3LU33VANU7RANCNFSM5G5DSI3A . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you were mentioned.Message ID: @.>

I cannot believe that this is working on Linux.
Line 214 "connection.SessionOptions.SecureSocketLayer = options.UseSsl;" is not support on Linux. It throws an exception.

All in all, this is quite a mess. My code is fully working on windows but I cannot connect using port 636 on linux. If I use 389, I can connect, but I have to use the full distinguished name as username and all my other methods in my class fail (e.g. searching users, etc).
Also, I'm missing a good example on how to setup a dockerfile which includes all dependencies which actually works.
Any help would be aprreciated.
btw, I'm using .net 7

@GeertvanHorrik
Copy link
Contributor

On linux (simplified version):

// call invoke on setting environment variable if you need to disable ssl verification

var identifier = new LdapDirectoryIdentifier("your-host", 636);
var networkCredential = new NetworkCredential(username, password, domain);

var connection = new LdapConnection(identifier, networkCredential, AuthType.Basic)
{
    AutoBind = false,
};

connection.SessionOptions.ProtocolVersion = 3;
connection.SessionOptions.SecureSocketLayer = true;

connection.Bind();

@michiproep
Copy link

For setting securesocketlayer I get a "not supported on this platform" exception

@GeertvanHorrik
Copy link
Contributor

Did you use the exact code provided (auto bind to false, etc)? It works fine here.

@michiproep
Copy link

I'll send a Screenshot tomorrow

@michiproep
Copy link

michiproep commented Mar 26, 2023

@GeertvanHorrik
grafik

This is the corresponding docker file:

FROM mcr.microsoft.com/dotnet/aspnet:7.0-alpine AS base
WORKDIR /app
RUN apk update
&& apk add --upgrade libldap
&& ln -s libldap.so.2 /usr/lib/libldap-2.4.so.2
ENV LDAPTLS_REQCERT=never
EXPOSE 80
EXPOSE 443

@GeertvanHorrik
Copy link
Contributor

Just to make sure:

Are you sure you are loading the correct runtime assemblies (Linux), not the reference ones from the nuget package?

The only difference I noticed in your example code is I am using net 6 jammy (Ubuntu) but that doesn't explain the difference in behavior.

@michiproep
Copy link

no. I'm not sure. how can I check? and which ones are the correct ones?

@michiproep
Copy link

Ok, this is a very confusing issue.
I did reference
System.DirectoryServices --version 7.0.1
which actually includes the System.DirectoryServices.Protocols namespace.
Now, I found that there is another package available:
System.DirectoryServices.Protocols --version 7.0.0

This one seems to work! Thanks for the hint.

But still confused about these two packages...

@wast
Copy link

wast commented Mar 30, 2023

This is working for me

// when using this constructor with servers, it doesn't work, it throws System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable
// var ldapDirectoryIdentifier = new LdapDirectoryIdentifier(_ldapSettings.Servers, _ldapSettings.Port, false, false); 

var ldapDirectoryIdentifier = new LdapDirectoryIdentifier(_ldapSettings.Servers.First(), _ldapSettings.Port);
using var ldapConnection = new LdapConnection(ldapDirectoryIdentifier);
var credentials = new NetworkCredential(_ldapSettings.ServiceUsername, _ldapSettings.ServicePassword);
ldapConnection.SessionOptions.ProtocolVersion = 3;
ldapConnection.AuthType = AuthType.Basic;
ldapConnection.SessionOptions.ReferralChasing = ReferralChasingOptions.None;
ldapConnection.SessionOptions.SecureSocketLayer = true;

Also I added issuing and root certificates to certificates store in Dockerfile.

@YuriiSaichuk
Copy link

YuriiSaichuk commented Apr 3, 2023

Hello everyone, I have the same problem as described in the title of the article.
At first I was getting the error

System.DirectoryServices.Protocols.LdapException: The feature is not supported.
at System.DirectoryServices.Protocols.LdapConnection.BindHelper(NetworkCredential new Credential, Boolean needSetCredential)

But after adding additional parameters to the connection, the error changed to

The LDAP server is unavailable.; Trace: at System.DirectoryServices.Protocols.LdapConnection.BindHelper(NetworkCredential newCredential, Boolean needSetCredential)

Here my code and config samples:

`
LdapDirectoryIdentifier identifier = new LdapDirectoryIdentifier(Domain);
NetworkCredential credential = new NetworkCredential(Login, Password);
string filter = $"(&(objectCategory=person)(SAMAccountName={samName}))";
string[] attributesToReturn = { "SAMAccountName", "givenname", "sn", "mail", "userPassword" };

        SearchRequest searchRequest = new SearchRequest(SomeGroup, filter, SearchScope.Subtree, attributesToReturn);

        try
        {
            using (LdapConnection connection = new LdapConnection(identifier, credential))
            {
                connection.SessionOptions.ProtocolVersion = 3;
                connection.AuthType = AuthType.Basic;
                connection.SessionOptions.ReferralChasing = ReferralChasingOptions.None;
                connection.SessionOptions.SecureSocketLayer = true;
                connection.Bind();

                SearchResponse searchResponse = connection.SendRequest(searchRequest) as SearchResponse;

                return searchResponse.Entries.Count > 0;
            }
        }

`

where
SomeGroup e.g. OU=Group,DC=example,DC=com
Login and Password - credentials for group
image

and docker config sample
image

I may have configured the docker incorrectly (did not install the ldap client) or something else.

The test version of the program works correctly on Windows Server 2016 under IIS inside the domain controller. The version with the docker works on a different subnet connected via a CISCO router. The ldap server is pinged from the docker image.

The domain parameter for the test version is example.com. For the docker version, I tried different things, including the ldap server IP
"System.DirectoryServices.Protocols" "7.0.0"
"System.DirectoryServices" "7.0.1"

@michiproep
Copy link

@YuriiSaichuk : The only thing which worked for me is completly removing System.DirectoryServices-Package and just keep the .protocols package.

@jhughesjha
Copy link

@joperezr
We are using the LdapConnection with LDAPS on Linux and need a way to validate the server certificate is the expected one per call. I know the VerifyServerCertificate is not supported due to the ldap option that it tries to set. Is there another way to validate the server certificate? Or do you recommend moving to another package for this use case?

@joperezr
Copy link
Member

joperezr commented May 4, 2023

IIRC, in Linux the certificate is always validated automatically, the problem is that this is done by openldap layer which LdapConnection PInvokes into, but as you noted there is no hook (that I'm aware of) into OpenLdap validation process in order to run custom code for additional validation. My best guess is that if that is what is desired here (running custom validation apart from the general validation of the server certificate) you'd need to look into open ldap's documentation and see if there is something you can configure there.

@CenturySparkle
Copy link

CenturySparkle commented Aug 8, 2023

This is working for me

// when using this constructor with servers, it doesn't work, it throws System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable
// var ldapDirectoryIdentifier = new LdapDirectoryIdentifier(_ldapSettings.Servers, _ldapSettings.Port, false, false); 

var ldapDirectoryIdentifier = new LdapDirectoryIdentifier(_ldapSettings.Servers.First(), _ldapSettings.Port);
using var ldapConnection = new LdapConnection(ldapDirectoryIdentifier);
var credentials = new NetworkCredential(_ldapSettings.ServiceUsername, _ldapSettings.ServicePassword);
ldapConnection.SessionOptions.ProtocolVersion = 3;
ldapConnection.AuthType = AuthType.Basic;
ldapConnection.SessionOptions.ReferralChasing = ReferralChasingOptions.None;
ldapConnection.SessionOptions.SecureSocketLayer = true;

OMG! This saved my bacon. This is working for me under .Net 7 running under the Ubuntu 22.04 container. (I do have the certificates installed as well.) It was setting the connection SessionOptions that got it working for me.

@Deepak260726
Copy link

LdapDirectoryIdentifier identifier = new LdapDirectoryIdentifier("ldap.example.com", 389);
NetworkCredential networkCredential = new NetworkCredential(username, userLoginparameter.Password);

LdapConnection ldapConnection = new LdapConnection(identifier, networkCredential);

if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
ldapConnection.SessionOptions.VerifyServerCertificate = (ldapConnection, certificate) => true;
}
else if (!Environment.GetEnvironmentVariables().Contains("LDAPTLS_REQCERT"))
{
_logger.LogWarning("LDAPS certificate validation is disabled in config, but LDAPTLS_REQCERT environmental variable is not set. On non-Windows environments certificate validation must be disabled by setting environmental variable LDAPTLS_REQCERT to 'never'");
}

ldapConnection.Bind(networkCredential);

i have tried all your opinion still getting the errors in Linux server but not in windows

@DanielHabenicht
Copy link

This error was driving me crazy. Although it manifested slightly differently. I got the following error, which I think is slightly worse as it directs you into a completely different direction:

System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable.
at System.DirectoryServices.Protocols.ErrorChecking.CheckAndSetLdapError(Int32 error)
at System.DirectoryServices.Protocols.LdapSessionOptions.set_VerifyServerCertificate(VerifyServerCertificateCallback value)

On net8.0 (8.0.101) with the configuration VerifyServerCertificate = (ldapConnection, certificate) => true (for illustration in development) on Docker mcr.microsoft.com/dotnet/aspnet:8.0 with installed libldap-2.4-2_2.4.49.

Workaround for me:

  1. Removing the VerifyServerCertificate Property.
  2. Adding LDAPTLS_REQCERT=never before starting the dotnet program in the docker container.

@madetara
Copy link

madetara commented Mar 5, 2024

To anyone stumbling upon this: the issue with SSL/TLS on Linux still persists even when you explicitly disable certificate verification (which I advise you to not do)

I would suggest simply switching to Novell LDAP client: it works on Linux and has better API

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.DirectoryServices bug help wanted [up-for-grabs] Good issue for external contributors
Projects
No open projects
Development

No branches or pull requests