dotnet / runtime

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

Why System.DirectoryServices.Protocols not working on linux? #64900

Closed daniilzaonegin closed 2 years ago

daniilzaonegin commented 2 years ago

Description

I'm trying to perform a search request using System.DirectoryServices.Protocols. Here is my code (it works successfully on windows, but fails on linux docker container):

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

string userAccountName = "<login_to_search>";
string domainName = "<domain_name>";

var endpoint = new LdapDirectoryIdentifier("<fqdn ldap server>", true, false);

// Create a new Ldap connection.
using var ldap = new LdapConnection(endpoint,
    new NetworkCredential("<user_name>", "<password_plain_text>"))
{
    AuthType = AuthType.Basic
};

ldap.SessionOptions.ProtocolVersion = 3;
ldap.Timeout = TimeSpan.FromMinutes(1);
ldap.Bind();

var filter = $"(&(objectClass=user)(sAMAccountName={userAccountName}))";
var distinguishedName = domainName.Split('.').Select(name => $"dc={name}").Aggregate((a, b) => $"{a},{b}");

var request = new SearchRequest(
    distinguishedName,
    filter,
    SearchScope.Subtree,
    null);
var response = ldap.SendRequest(request, TimeSpan.FromMinutes(1)); // <- I get the error here

Console.WriteLine($"Response Result Code:{response?.ResultCode}. Response Error message:{response?.ErrorMessage}.");
if (response is SearchResponse searchResponse)
{
    foreach (SearchResultEntry searchResultEntry in searchResponse.Entries)
    {
        Console.WriteLine(searchResultEntry.DistinguishedName);
    }
}

csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.14.0" />
    <PackageReference Include="System.DirectoryServices.Protocols" Version="6.0.0" />
  </ItemGroup>

</Project>

Exception (happens in a docker container on linux):

System.DirectoryServices.Protocols.DirectoryOperationException: An operation error occurred. 000004DC: LdapErr: DSID-0C090A5C, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v4563
   at System.DirectoryServices.Protocols.LdapConnection.ConstructResponseAsync(Int32 messageId, LdapOperation operation, ResultAll resultType, TimeSpan requestTimeOut, Boolean exceptionOnTimeOut, Boolean sync)
   at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request, TimeSpan requestTimeout)
   at Program.<Main>$(String[] args) in C:\Users\ruazed1\source\repos\TestLdap\TestLdap\Program.cs:line 33

Reproduction Steps

Run the code above in description

Expected behavior

Code works on linux container

Actual behavior

Receive an exception

Regression?

No response

Known Workarounds

No response

Configuration

On my windows machine

❯ dotnet --info
.NET SDK (reflecting any global.json):
 Version:   6.0.101
 Commit:    ef49f6213a

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.19043
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\6.0.101\

Host (useful for support):
  Version: 6.0.1
  Commit:  3a25a7f1cc

.NET SDKs installed:
  3.1.414 [C:\Program Files\dotnet\sdk]
  5.0.202 [C:\Program Files\dotnet\sdk]
  5.0.404 [C:\Program Files\dotnet\sdk]
  6.0.100 [C:\Program Files\dotnet\sdk]
  6.0.101 [C:\Program Files\dotnet\sdk]

In a container

root@ff1928d98ed3:/app# dotnet --info

Host (useful for support):
  Version: 6.0.0
  Commit:  4822e3c3aa

.NET SDKs installed:
  No SDKs were found.

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

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

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 I'm trying to perform a search request using `System.DirectoryServices.Protocols`. Here is my code (it works successfully on windows, but fails on linux docker container): ```c# using System; using System.DirectoryServices.Protocols; using System.Linq; using System.Net; string userAccountName = ""; string domainName = ""; var endpoint = new LdapDirectoryIdentifier("", true, false); // Create a new Ldap connection. using var ldap = new LdapConnection(endpoint, new NetworkCredential("", "")) { AuthType = AuthType.Basic }; ldap.SessionOptions.ProtocolVersion = 3; ldap.Timeout = TimeSpan.FromMinutes(1); ldap.Bind(); var filter = $"(&(objectClass=user)(sAMAccountName={userAccountName}))"; var distinguishedName = domainName.Split('.').Select(name => $"dc={name}").Aggregate((a, b) => $"{a},{b}"); // Create a search request to locate the Configuration Naming Context for the forest. var request = new SearchRequest( distinguishedName, filter, SearchScope.Subtree, null); var response = ldap.SendRequest(request, TimeSpan.FromMinutes(1)); // <- I get the error here Console.WriteLine($"Response Result Code:{response?.ResultCode}. Response Error message:{response?.ErrorMessage}."); if (response is SearchResponse searchResponse) { foreach (SearchResultEntry searchResultEntry in searchResponse.Entries) { Console.WriteLine(searchResultEntry.DistinguishedName); } } ``` csproj ``` Exe net6.0 Linux ``` Exception (happens in a docker container on linux): ``` System.DirectoryServices.Protocols.DirectoryOperationException: An operation error occurred. 000004DC: LdapErr: DSID-0C090A5C, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v4563 at System.DirectoryServices.Protocols.LdapConnection.ConstructResponseAsync(Int32 messageId, LdapOperation operation, ResultAll resultType, TimeSpan requestTimeOut, Boolean exceptionOnTimeOut, Boolean sync) at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request, TimeSpan requestTimeout) ``` at Program.
$(String[] args) in C:\Users\ruazed1\source\repos\TestLdap\TestLdap\Program.cs:line 33 ### Reproduction Steps Run the code above in description ### Expected behavior Code works on linux container ### Actual behavior Receive an exception ### Regression? _No response_ ### Known Workarounds _No response_ ### Configuration On my windows machine ``` ❯ dotnet --info .NET SDK (reflecting any global.json): Version: 6.0.101 Commit: ef49f6213a Runtime Environment: OS Name: Windows OS Version: 10.0.19043 OS Platform: Windows RID: win10-x64 Base Path: C:\Program Files\dotnet\sdk\6.0.101\ Host (useful for support): Version: 6.0.1 Commit: 3a25a7f1cc .NET SDKs installed: 3.1.414 [C:\Program Files\dotnet\sdk] 5.0.202 [C:\Program Files\dotnet\sdk] 5.0.404 [C:\Program Files\dotnet\sdk] 6.0.100 [C:\Program Files\dotnet\sdk] 6.0.101 [C:\Program Files\dotnet\sdk] ``` In a container ``` root@ff1928d98ed3:/app# dotnet --info Host (useful for support): Version: 6.0.0 Commit: 4822e3c3aa .NET SDKs installed: No SDKs were found. .NET runtimes installed: Microsoft.NETCore.App 6.0.0 [/usr/share/dotnet/shared/Microsoft.NETCore.App] To install additional .NET runtimes or SDKs: https://aka.ms/dotnet-download ``` ### Other information _No response_
Author: daniilzaonegin
Assignees: -
Labels: `area-System.DirectoryServices`, `untriaged`
Milestone: -
daniilzaonegin commented 2 years ago

I've managed to solve it!

It works when you set an option ldap.SessionOptions.ReferralChasing = ReferralChasingOptions.None;

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

string userAccountName = "<login_to_search>";
string domainName = "<domain_name>";

var endpoint = new LdapDirectoryIdentifier("<fqdn ldap server>", true, false);

// Create a new Ldap connection.
using var ldap = new LdapConnection(endpoint,
    new NetworkCredential("<user_name>", "<password_plain_text>"))
{
    AuthType = AuthType.Basic
};

ldap.SessionOptions.ProtocolVersion = 3;
ldap.SessionOptions.ReferralChasing = ReferralChasingOptions.None; // <-- this solves the problem!
ldap.Timeout = TimeSpan.FromMinutes(1);
ldap.Bind();
joperezr commented 2 years ago

I see, I'm glad you were able to find the workaround. I believe we have seen this before and the issue seems to stem from the fact that you are searching on the root of the ldap directory.