Home > Back-end >  C# LdapConnection SearchRequest not returning attributes
C# LdapConnection SearchRequest not returning attributes

Time:07-26

Background

I am trying to authenticate a user, and after that fetch it's attributes so I know what user groups have been assigned to it.

After many efforts I have finally managed to authenticate the user, and perform a searchrequest that actually returns an entry.

problem

The entry returned has no attributes in it, even though I requested some. When using Ad explorer I can verify thet there actually are attributes assigbned to it.

Check source below:

public IUserDto Authenticate(string username, string password)
{
    if (string.IsNullOrEmpty(username))
        return new UserDto() { Username = "Anonymous", Id = 1 };
    try
    {
        NetworkCredential usercredential = new() { UserName = username, Password = password };
        var conn = Connection;
        var filter = $"(&(objectClass = user)(uid ={username}))";
        string[] attributes = new string[] { "cn", "memberOf", "name" };
        conn.Bind(usercredential);

        SearchRequest searchrequest = new(null, filter, SearchScope.Base, attributes);

        var response = conn.SendRequest(searchrequest);
        if (response is SearchResponse searchResponse)
        {
            foreach (SearchResultEntry entry in searchResponse.Entries)
            {
                entry.ToString(); // gets executed
                foreach (string attributename in entry.Attributes.AttributeNames)
                {
                    attributename.ToString(); // is not executed
                }
            }
        }

        UserDto user = new()
        {
            Username = username,
        };
        return user;
    }
    catch (Exception e)
    {
        throw new ArgumentException($"{GetType().Name}.{nameof(Authenticate)} : {e.Message}", e);
    }
}

I am aware that using the DirectoryServices dll/assembly may provide an easier way around this, but this makes my program platform dependent (windows), which I am trying to avoid.

What have I tried

Changing the SearchScope to anything else than SearchScope.Base will generate an exception on the SendRequest call:

System.DirectoryServices.Protocols.DirectoryOperationException: 'The object does not exist. 0000208D: NameErr: DSID-031001E5, problem 2001 (NO_OBJECT), data 0, best match of:

Changing the distinguishedName parameter from the SearchRequest constructor to not-null will generate an similar exception.

The question

Obviously I have overlooked something... What could it be? TIA

CodePudding user response:

As usual, the solution turned out to be ever so simple, I just had to change

var filter = $"(&(objectClass = user)(sAMAccountName = {username}))";

into

 var filter = $"(&(objectClass=user)(sAMAccountName={username}))";

So... I really didnt expect the filter to be space sensitive. Removing the spaces from the filter clauses did the trick.

Also, I have changed the Scope to SearchScope.Subtree and change the Searchroot to (in my case) "DC=sng, DC=local"

These parameters are stored in my appsettings files, and the complete (working) source now looks like this:

public IUserDto Authenticate(string username, string password)
{
    if (string.IsNullOrEmpty(username))
        return new UserDto() { Username = "Anonymous", Id = 1 };
    try
    {
        NetworkCredential usercredential = new() { UserName = username, Password = password };
        var conn = Connection;
        conn.Bind(usercredential);

        string filter= string.Format(_config.SearchFilter, username);
        string[] attributes = new string[] { "cn", "memberOf", "name", "sAMAccountName","uid" };

        SearchRequest searchrequest = new(_config.SearchBase, filter, SearchScope.Subtree, attributes);

        var response = conn.SendRequest(searchrequest);
        if (response is SearchResponse searchResponse)
        {
            foreach (SearchResultEntry entry in searchResponse.Entries)
            {
                entry.ToString();
                foreach (string attributename in entry.Attributes.AttributeNames)
                {
                    attributename.ToString();
                }
            }
        }

        UserDto user = new()
        {
            Username = username,
        };
        return user;
    }
    catch (Exception e)
    {
        throw new ArgumentException($"{GetType().Name}.{nameof(Authenticate)} : {e.Message}", e);
    }
}

I hope someone else can take profit of the hours I spent fiddling and messing with this :)

  • Related