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

System.DirectoryServices.Protocols.LdapConnection fails to find the new version of the LDAP library on Ubuntu 22.04 #69456

Closed
since22 opened this issue May 17, 2022 · 15 comments · Fixed by #88851
Assignees
Labels
area-System.DirectoryServices Cost:M Work that requires one engineer up to 2 weeks enhancement Product code improvement that does NOT require public API changes/additions
Milestone

Comments

@since22
Copy link

since22 commented May 17, 2022

Description

Ubuntu 20.04 has LDAP library libldap-2.4 https://packages.ubuntu.com/source/focal/openldap
Ubuntu 22.04 has LDAP library libldap-2.5.11 https://packages.ubuntu.com/source/jammy/openldap

When running .NET Core 6 code on Ubuntu 22.04, System.DirectoryServices.Protocols.LdapConnection cannot find the latest version of LDAP an fails.

Reproduction Steps

Install the LDAP libraries on Ubuntu 22.04:

ubuntu@w-ubuntu-2:~$ sudo apt-get install --no-install-recommends -y krb5-user ldap-utils libsasl2-modules-gssapi-mit wget
[sudo] password for ubuntu:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
ldap-utils is already the newest version (2.5.11+dfsg-1~exp1ubuntu3).
libsasl2-modules-gssapi-mit is already the newest version (2.1.27+dfsg2-3ubuntu1).
wget is already the newest version (1.21.2-2ubuntu1).
krb5-user is already the newest version (1.19.2-2).
The following package was automatically installed and is no longer required:
  libfreetype6
Use 'sudo apt autoremove' to remove it.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
ubuntu@w-ubuntu-2:~$

Steps to reproduce:
Run the following code from an ASP.NET Core 6 application on Ubuntu 22.04:

using System.DirectoryServices.Protocols;
var id = new LdapDirectoryIdentifier(servers[i], true, false);

Expected behavior

System.DirectoryServices.Protocols.LdapConnection finds the 2.5.11 version of LDAP library on Ubuntu 22.04 and connects to the LDAP server.

Actual behavior

System.TypeInitializationException
  HResult=0x80131534
  Message=The type initializer for 'Ldap' threw an exception.
  Source=System.DirectoryServices.Protocols
  StackTrace:
   at Interop.Ldap.ldap_initialize(IntPtr& ld, String uri)
   at System.DirectoryServices.Protocols.ConnectionHandle..ctor(String uri)
   at System.DirectoryServices.Protocols.LdapConnection.InternalInitConnectionHandle(String hostname)
   at System.DirectoryServices.Protocols.LdapConnection.Init()
   at System.DirectoryServices.Protocols.LdapConnection..ctor(LdapDirectoryIdentifier identifier, NetworkCredential credential, AuthType authType)
   at TheLdapService.Server.Services.LdapService.GetLdapConnection() in C:\Users\ubuntu\source\repos\TheLdapService\src\TheLdapService.Server\Services\LdapService.cs:line 58
   at TheLdapService.Server.Services.LdapService.Authenticate(String username, String password) in C:\Users\ubuntu\source\repos\TheLdapService\src\TheLdapService.Server\Services\LdapService.cs:line 199
   at TheLdapService.Server.Services.AuthorizationService.<>c__DisplayClass4_0.<Login>b__0() in C:\Users\ubuntu\source\repos\TheLdapService\src\TheLdapService.Server\Services\AuthorizationService.cs:line 39
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj)
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)

  This exception was originally thrown at this call stack:
    [External Code]

Inner Exception 1:
DllNotFoundException: Unable to load shared library 'libldap-2.4.so.2' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: liblibldap-2.4.so.2: cannot open shared object file: No such file or directory


Regression?

Same code worked under Ubuntu 20.04, which has libldap-2.4, the library System.DirectoryServices.Protocols.LdapConnection is looking for.

Known Workarounds

On Ubuntu 22.04, create a symbolic link from ldap-2.4 to ldap-2.5:

ubuntu@w-ubuntu-2:~$ sudo ln -s /usr/lib/x86_64-linux-gnu/libldap-2.5.so.0 /usr/lib/x86_64-linux-gnu/libldap-2.4.so.2

ubuntu@w-ubuntu-2:/usr/lib/x86_64-linux-gnu$ ll | grep ldap
lrwxrwxrwx  1 root root       42 May 17 15:29 libldap-2.4.so.2 -> /usr/lib/x86_64-linux-gnu/libldap-2.5.so.0
lrwxrwxrwx  1 root root       20 Feb 16 12:15 libldap-2.5.so.0 -> libldap-2.5.so.0.1.6
-rw-r--r--  1 root root   376576 Feb 16 12:15 libldap-2.5.so.0.1.6

Configuration

ubuntu@w-ubuntu-2:~$ dotnet --info
.NET SDK (reflecting any global.json):
 Version:   6.0.300
 Commit:    8473146e7d

Runtime Environment:
 OS Name:     ubuntu
 OS Version:  22.04
 OS Platform: Linux
 RID:         ubuntu.22.04-x64
 Base Path:   /usr/share/dotnet/sdk/6.0.300/

Host (useful for support):
  Version: 6.0.5
  Commit:  70ae3df4a6

.NET SDKs installed:
  6.0.300 [/usr/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.5 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 6.0.5 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

To install additional .NET runtimes or SDKs:
  https://aka.ms/dotnet-download

Other information

No response

@ghost ghost added the untriaged New issue has not been triaged by the area owner label May 17, 2022
@ghost
Copy link

ghost commented May 17, 2022

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

Ubuntu 20.04 has LDAP library libldap-2.4 https://packages.ubuntu.com/source/focal/openldap
Ubuntu 22.04 has LDAP library libldap-2.5.11 https://packages.ubuntu.com/source/jammy/openldap

When running .NET Core 6 code on Ubuntu 22.04, System.DirectoryServices.Protocols.LdapConnection cannot find the latest version of LDAP an fails.

Reproduction Steps

Install the LDAP libraries on Ubuntu 22.04:

ubuntu@w-ubuntu-2:~$ sudo apt-get install --no-install-recommends -y krb5-user ldap-utils libsasl2-modules-gssapi-mit wget
[sudo] password for ubuntu:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
ldap-utils is already the newest version (2.5.11+dfsg-1~exp1ubuntu3).
libsasl2-modules-gssapi-mit is already the newest version (2.1.27+dfsg2-3ubuntu1).
wget is already the newest version (1.21.2-2ubuntu1).
krb5-user is already the newest version (1.19.2-2).
The following package was automatically installed and is no longer required:
  libfreetype6
Use 'sudo apt autoremove' to remove it.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
ubuntu@w-ubuntu-2:~$

Steps to reproduce:
Run the following code from an ASP.NET Core 6 application on Ubuntu 22.04:

using System.DirectoryServices.Protocols;
var id = new LdapDirectoryIdentifier(servers[i], true, false);

Expected behavior

System.DirectoryServices.Protocols.LdapConnection finds the 2.5.11 version of LDAP library on Ubuntu 22.04 and connects to the LDAP server.

Actual behavior

System.TypeInitializationException
  HResult=0x80131534
  Message=The type initializer for 'Ldap' threw an exception.
  Source=System.DirectoryServices.Protocols
  StackTrace:
   at Interop.Ldap.ldap_initialize(IntPtr& ld, String uri)
   at System.DirectoryServices.Protocols.ConnectionHandle..ctor(String uri)
   at System.DirectoryServices.Protocols.LdapConnection.InternalInitConnectionHandle(String hostname)
   at System.DirectoryServices.Protocols.LdapConnection.Init()
   at System.DirectoryServices.Protocols.LdapConnection..ctor(LdapDirectoryIdentifier identifier, NetworkCredential credential, AuthType authType)
   at Itpid.Server.Services.LdapService.GetLdapConnection() in C:\Users\ubuntu\source\repos\itpid\src\Itpid.Server\Services\LdapService.cs:line 58
   at Itpid.Server.Services.LdapService.Authenticate(String username, String password) in C:\Users\ubuntu\source\repos\itpid\src\Itpid.Server\Services\LdapService.cs:line 199
   at Itpid.Server.Services.AuthorizationService.<>c__DisplayClass4_0.<Login>b__0() in C:\Users\ubuntu\source\repos\itpid\src\Itpid.Server\Services\AuthorizationService.cs:line 39
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj)
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)

  This exception was originally thrown at this call stack:
    [External Code]

Inner Exception 1:
DllNotFoundException: Unable to load shared library 'libldap-2.4.so.2' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: liblibldap-2.4.so.2: cannot open shared object file: No such file or directory

Regression?

Same code worked under Ubuntu 20.04, which has libldap-2.4, the library System.DirectoryServices.Protocols.LdapConnection is looking for.

Known Workarounds

On Ubuntu 22.04, create a symbolic link from ldap-2.4 to ldap-2.5:

ubuntu@w-ubuntu-2:~$ sudo ln -s /usr/lib/x86_64-linux-gnu/libldap-2.5.so.0 /usr/lib/x86_64-linux-gnu/libldap-2.4.so.2

ubuntu@w-ubuntu-2:/usr/lib/x86_64-linux-gnu$ ll | grep ldap
lrwxrwxrwx  1 root root       42 May 17 15:29 libldap-2.4.so.2 -> /usr/lib/x86_64-linux-gnu/libldap-2.5.so.0
lrwxrwxrwx  1 root root       20 Feb 16 12:15 libldap-2.5.so.0 -> libldap-2.5.so.0.1.6
-rw-r--r--  1 root root   376576 Feb 16 12:15 libldap-2.5.so.0.1.6

Configuration

ubuntu@w-ubuntu-2:~$ dotnet --info
.NET SDK (reflecting any global.json):
 Version:   6.0.300
 Commit:    8473146e7d

Runtime Environment:
 OS Name:     ubuntu
 OS Version:  22.04
 OS Platform: Linux
 RID:         ubuntu.22.04-x64
 Base Path:   /usr/share/dotnet/sdk/6.0.300/

Host (useful for support):
  Version: 6.0.5
  Commit:  70ae3df4a6

.NET SDKs installed:
  6.0.300 [/usr/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.5 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 6.0.5 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

To install additional .NET runtimes or SDKs:
  https://aka.ms/dotnet-download

Other information

No response

Author: since22
Assignees: -
Labels:

area-System.DirectoryServices, untriaged

Milestone: -

@danmoseley
Copy link
Member

We hard code this version

internal const string OpenLdap = "libldap-2.4.so.2";

If I'm looking at the right thing, 2.5 came out a year ago, and current is 2.6.
https://www.openldap.org/software/roadmap.html#current

@joperezr
Copy link
Member

Correct, we hard coded the version because back when we added the support the library hadn't been updated in over 14 years so we didn't expect exact versioning to be a problem, but it does seem like two new versions have been released since then. By taking a quick look at the changelog it doesn't seem like we should have any issues with also supporting 2.5 and 2.6, but we will need to test all of our scenarios in order to double check, and then we can adjust that line to be able to support those other versions as well.

@retifrav
Copy link

retifrav commented Jun 8, 2022

I got the same problem on Kubuntu 22.04, here's my environment just in case (seems to be the same as OP's):

.NET SDK (reflecting any global.json):
 Version:   6.0.300
 Commit:    8473146e7d

Runtime Environment:
 OS Name:     ubuntu
 OS Version:  22.04
 OS Platform: Linux
 RID:         ubuntu.22.04-x64
 Base Path:   /usr/share/dotnet/sdk/6.0.300/

Host (useful for support):
  Version: 6.0.5
  Commit:  70ae3df4a6

.NET SDKs installed:
  6.0.300 [/usr/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.5 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 6.0.5 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

I have a .NET 6 project that uses System.DirectoryServices.Protocols version 6.0.1.

While suggested workaround with adding a symlink does work, one might prefer to actually download the version 2.4 from archive and install it:

$ sudo apt install libgssapi3-heimdal
$ sudo dpkg -i ~/Downloads/libldap-2.4-2_2.4.49+dfsg-2ubuntu1.9_amd64.deb

For me that also resolved the problem, so that might be an alternative workaround.

@joperezr joperezr added this to the Future milestone Jun 29, 2022
@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Jun 29, 2022
@joperezr joperezr modified the milestones: Future, 7.0.0 Jun 29, 2022
@joperezr
Copy link
Member

I took a look at this today. Unfortunately, seems like libldap doesn't provide a major version .so or a version-less .so that we can create our PInvokes against. There is a version-less one but only on the dev package libldap2-dev which doesn't come installed on the distros. Due to the fact that DllImports require the library name to be a string constant, in order to support multiple versions we would need to create Interop stubs for each version in order for this to work. Alternatively, we could manually use NativeLibrary and implement our own policy for picking the right versions, or providing a native shim. Depending on the solution we go with, this may not make it to 7.0 depending on the complexity. I'll post an update in the next few days, and will adjust the milestone if necessary.

@joperezr joperezr added the enhancement Product code improvement that does NOT require public API changes/additions label Jul 18, 2022
@joperezr
Copy link
Member

joperezr commented Aug 1, 2022

I chatted with @AaronRobinsonMSFT about this last week. There is a way for us to basically hook into an event that gets triggered whenever binding to the native assembly fails, and at that point we can try some other versions to see if we can find one supported which is installed, and that seemed like a good-enough solution for now. Unfortunately, we won't have enough bandwidth to get that done for 7.0 any longer, so I'm adjusting the milestone accordingly.

For folks hitting this in 7.0, They will be able to use the workarounds provided above (adding symlink or manually downloading the 2.4 version) in order to get unblocked. I tried both and they worked for me in Ubuntu 22.04.

@leandrofagundes
Copy link

I still have this problem. Can someone explain me where is my mistake?
My code works fine on my machine (windows, without docker) but fails on docker inside a ubuntu 22.04

`try
{
var directoryIdentifier = new LdapDirectoryIdentifier(_servidor, true, false);
var credentials = new System.Net.NetworkCredential(usuario, senha);
LdapConnection connection = new(directoryIdentifier, credentials, AuthType.Negotiate);

            string searchFilter = $"(&(objectClass=user)(samAccountName={usuario}))";

            var searchRequest = new SearchRequest(
                _dominio,
                searchFilter,
                SearchScope.Subtree,
                Array.Empty<string>());

            connection.SessionOptions.ProtocolVersion = 3;
            connection.SessionOptions.ReferralChasing = ReferralChasingOptions.None;
            connection.Bind();

            var response = (SearchResponse)connection.SendRequest(searchRequest);
            if (response is null)
                return false;

            for (int i = 0; i < response.Entries.Count; i++)
            {
                var entry = response.Entries[i];
                if (entry is null)
                    return false;

                var attributes = entry.Attributes;
                if (attributes is null || attributes.Count == 0)
                    return false;

                var sAMAccountNames = attributes["sAMAccountName"];
                if (sAMAccountNames is null || sAMAccountNames.Count == 0)
                    return false;

                var sAMAccountName = sAMAccountNames[0];
                if (sAMAccountNames is null)
                    return false;

                var memberOfs = attributes["memberOf"];
                if (memberOfs is null || memberOfs.Count == 0)
                    return false;

                const int prefixGroupTypePosition = 3;
                foreach (byte[] memberOf in memberOfs)
                {
                    var groupTree = Encoding.UTF8.GetString(memberOf);
                    var treeNodes = groupTree.Split(',');
                    if (treeNodes.Length == 0)
                        continue;

                    var treeNode = treeNodes[0];
                    var groupName = treeNode.Substring(prefixGroupTypePosition);
                }
            }

            return true;
        }
        catch (Exception ex)
        {
            throw new Exception($"{_dominio}@{_servidor}--{ex.Message}_____{ex.StackTrace}", ex);
        }`

@joperezr
Copy link
Member

joperezr commented Jan 4, 2023

This is expected. The reason why this happens has nothing to do with your code, but instead with the native library installed in ubuntu 22.04. There is no fix for this available yet, just a known workaround that was posted above. Copying it here for reference:

sudo ln -s /usr/lib/x86_64-linux-gnu/libldap-2.5.so.0 /usr/lib/x86_64-linux-gnu/libldap-2.4.so.2

After running that, you should be able to run your app (this is assuming you are running on a x64 machine)

@leandrofagundes
Copy link

leandrofagundes commented Jan 4, 2023

ln: failed to create symbolic link '/usr/lib/x86_64-linux-gnu/libldap-2.4.so.2': File exists

I already did. Should I reboot the machine or something like that?

Just for reference:

administrador@srv-docker-dev-01:/usr/lib/x86_64-linux-gnu$ ll | grep ldap
lrwxrwxrwx  1 root root       42 Jan  4 21:06 libldap-2.4.so.2 -> /usr/lib/x86_64-linux-gnu/libldap-2.5.so.0
lrwxrwxrwx  1 root root       20 Aug  5 14:51 libldap-2.5.so.0 -> libldap-2.5.so.0.1.8 
-rw-r--r--  1 root root   376512 Aug  5 14:51 libldap-2.5.so.0.1.8
-rw-r--r--  1 root root   105912 Jun 21  2021 libnss_ldap-2.33.so
lrwxrwxrwx  1 root root       38 Jun 21  2021 libnss_ldap.so -> /lib/x86_64-linux-gnu/libnss_ldap.so.2
lrwxrwxrwx  1 root root       19 Jun 21  2021 libnss_ldap.so.2 -> libnss_ldap-2.33.so

@jade-lucas
Copy link

Does this workaround work with alpine based images?

@jade-lucas
Copy link

After some quick testing. Looks like this workaround does work for .net 6 alpine based images. Might need to update the link if the libldap version changes. Here is my docker file

FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

#install LDAP dependencies for System.DirectoryServices 
RUN apk update \
    && apk add --upgrade libldap \
    && ln -s libldap.so.2 /usr/lib/libldap-2.4.so.2

Looks like this is what you want in you /usr/lib directory.

/ # ls /usr/lib -la

image

My C# for ref.

private LdapConnection GetConnection(string userName, string password, string domain)
        {
            try
            {
                var ldapConnection = new LdapConnection(
                    new LdapDirectoryIdentifier(ldapServer),
                    new NetworkCredential($"{domain}\\{userName}", password),
                    OperatingSystem.IsLinux() ? AuthType.Basic : AuthType.Negotiate);

                ldapConnection.SessionOptions.ProtocolVersion = 3;
                ldapConnection.SessionOptions.ReferralChasing = ReferralChasingOptions.None;

                ldapConnection.Bind();

                return ldapConnection;
            }
            catch (LdapException ex)
            {
                logger.LogError(ex, "Authenticate user LDAP error. {message}", ex.Message);
                return null;
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Authenticate user unknown error. {message}", ex.Message);
                return null;
            }
        }

rhessinger pushed a commit to Inedo/inedox-inedocore that referenced this issue Feb 3, 2023
…ctoryServices in linux: dotnet/runtime#69456

- Reverted back System.DirectoryServices.Protocols back to version 6.0.1
@marco-carvalho
Copy link

@jade-lucas workaround worked here in 7.0-alpine

@odin568
Copy link

odin568 commented Mar 27, 2023

works also for 7.0-jammy

@durranitech
Copy link

8.0-preview5 apline I had to add in the runtime identifier to be linux-musl-x64.

@petertownsend
Copy link

petertownsend commented Jun 15, 2023

An alternative work around that worked for me is to use AssemblyLoadContext as shown below:

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
        {
            AssemblyLoadContext.Default.ResolvingUnmanagedDll += (assembly, s) =>
            {
                if (!s.Equals("libldap-2.4.so.2"))
                {
                    return IntPtr.Zero;
                }
                try
                {
                    return NativeLibrary.Load("libldap-2.4.so.2");
                }
                catch (Exception)
                {
                    return NativeLibrary.Load("libldap-2.5.so.0");
                }
            };
        }

@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Jul 13, 2023
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Jul 17, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Aug 17, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.DirectoryServices Cost:M Work that requires one engineer up to 2 weeks enhancement Product code improvement that does NOT require public API changes/additions
Projects
None yet