Open macsux opened 2 years ago
Tagging subscribers to this area: @jay98014 See info in area-owners.md if you want to be subscribed.
Author: | macsux |
---|---|
Assignees: | - |
Labels: | `area-System.DirectoryServices`, `untriaged` |
Milestone: | - |
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.
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!");
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!");
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?
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
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?
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.
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.
We are trying to ignore ssl cert validation at least in lower tier environments, is this possible? The ability to ignore cert validation is a usual option in most TLS libraries.
On Mon., Nov. 8, 2021, 4:22 p.m. Jose Perez Rodriguez, < @.***> wrote:
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.
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.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/dotnet/runtime/issues/60972#issuecomment-963586802, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAINFWH7IEF2BQMLB6G5NALULA5SLANCNFSM5G5DSI3A . 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.
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?
Oh good catch, seems like when we added this feature we forgot to remove this attribute:
Would you be interested in submitting a PR fixing that? 😃
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.
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
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.
Thanks for submitting the PR. I'd be interested in debugging why setting it through Environment.SetEnvironmentVariable didn't work as I would have expected that to work.
Interestingly trying to do this from within the process via Environment.SetEnvironmentVariable("LDAPTLS_REQCERT","never"); does not work.
This is most likely because .NET sets environment vars for a process in a separate layer to the actual process environment block. I came across this issue before when trying to set KRB5_TRACE=/dev/stdout
(or any of the other GSSAPI env vars) to debug some stuff and the C layer was unable to see these env vars.
To set an env var at runtime for use by a called "PInvoke" function you need to essentially call setenv
in libc
like
using System;
using System.Runtime.InteropServices;
namespace Native
{
public class Libc
{
[DllImport("libc")]
public static extern void setenv(string name, string value);
[DllImport("libc")]
public static extern void unsetenv(string name);
}
}
You would then do Native.Libc.setenv("LDAPTLS_REQCERT", "never");
to set the env var.
@joperezr @macsux So, I still did not understand whether the SSL connection works on Linux or not. I have already searched all similar threads on this topic and could not find a normal solution. Here's code snippet that I took from @macsux to simply connect to my LDAP server over 636 port:
using System;
using System.DirectoryServices.Protocols;
using System.Net;
var di = new LdapDirectoryIdentifier(server: "<server>", 636);
using var connection = new LdapConnection(di, new NetworkCredential("LDAP\\user", "password"), AuthType.Basic);
connection.SessionOptions.ProtocolVersion = 3;
connection.SessionOptions.SecureSocketLayer = true;
Console.WriteLine("Hello, World!");
Am I missing something? I also tried to use
connection.SessionOptions.VerifyServerCertificate += (ldapConnection, certificate) => true;
but it doesn't help at all, and according to this thread this code doesn't work for Linux.
I'm always get this kind of errors:
Unhandled exception. System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable.
at System.DirectoryServices.Protocols.LdapConnection.BindHelper(NetworkCredential newCredential, Boolean needSetCredential)
at System.DirectoryServices.Protocols.LdapConnection.Bind()
at <Program>$.<Main>$(String[] args) in Program.cs:line 10
It worth to mention that if I connect through 389 port everything is OK. Does this library currently support SSL connection on Linux? I'm quite stuck and would be very grateful for help.
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
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
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 https://github.com/dotnet/runtime/issues/60972#issuecomment-1071136088, 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: @.***>
@macsux, Thank You. I'll try this out
@macsux I tried Your solution but got the same error as always:
Unhandled exception. System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable.
at System.DirectoryServices.Protocols.LdapConnection.BindHelper(NetworkCredential newCredential, Boolean needSetCredential)
at System.DirectoryServices.Protocols.LdapConnection.Bind()
at <Program>$.<Main>$(String[] args) in Program.cs:line 25
I use the same server address string as for Windows:
var di = new LdapDirectoryIdentifier(server: "10.6.1.162", 636, true, false);
Am I using wrong connection string? Maybe external connection to this IP address through 636 port is blocked, I'll try to contact my DevOps.
@macsux I tried Your solution but got the same error as always:
Unhandled exception. System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable. at System.DirectoryServices.Protocols.LdapConnection.BindHelper(NetworkCredential newCredential, Boolean needSetCredential) at System.DirectoryServices.Protocols.LdapConnection.Bind() at <Program>$.<Main>$(String[] args) in Program.cs:line 25
I use the same server address string as for Windows:
var di = new LdapDirectoryIdentifier(server: "10.6.1.162", 636, true, false);
Am I using wrong connection string? Maybe external connection to this IP address through 636 port is blocked, I'll try to contact my DevOps.
Have you managed to solve this? I'm trying the same thing on a Mac, and nothing on this thread worked, I am still getting a "The LDAP server is unavailable" message when I bind. I'm connecting pretty much exactly like mentioned here.
This is the code right now:
var ldapInfo = new LdapDirectoryIdentifier(config.Server, config.Port);
var ldapCred =
new NetworkCredential(ldapCred.User, ldapCred.Password, ldapCred.Domain);
_ldapConnection = new LdapConnection(ldapInfo, ldapCred)
{
AuthType = AuthType.Basic,
SessionOptions =
{
ReferralChasing = ReferralChasingOptions.None,
ProtocolVersion = 3,
#pragma warning disable CA1416
SecureSocketLayer = true
#pragma warning restore CA1416
}
};
@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 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.
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
@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.
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 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.
Been struggling with this as well (LPAP via SSL on Linux). A few things that might be useful for others:
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.
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.
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
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();
For setting securesocketlayer I get a "not supported on this platform" exception
Did you use the exact code provided (auto bind to false, etc)? It works fine here.
I'll send a Screenshot tomorrow
@GeertvanHorrik
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
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.
no. I'm not sure. how can I check? and which ones are the correct ones?
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...
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.
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
and docker config sample
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"
@YuriiSaichuk : The only thing which worked for me is completly removing System.DirectoryServices-Package and just keep the .protocols package.
@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?
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.
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.
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
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:
VerifyServerCertificate
Property. LDAPTLS_REQCERT=never
before starting the dotnet program in the docker container.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
Description
LdapConnection
fails to bind on Linux when running .NET6.0.0-rc.2.21480.5
version ofSystem.DirectoryServices.Protocols
package and throwsThe same code works when using switching to version 5.0.0 of
System.DirectoryServices.Protocols
or running under windowsReproduction Steps
Run the following code under Linux
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