Git Product home page Git Product logo

ldap4net's People

Contributors

balassamarton avatar douglaskreider avatar elodou01 avatar flamencist avatar gregbair avatar inel-it avatar jaredrsowers avatar jepperc avatar joperator avatar kemalelci avatar mend-bolt-for-github[bot] avatar mharrisn avatar mihailsidoroff avatar sam-mfb avatar vossjannik avatar vrachv avatar zubastic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ldap4net's Issues

ToLdapEntity messes with binary data

Describe the bug
ToLdapEntry method messes up with binary values in such a way that they are not reversible.

To Reproduce

  • Convert a DirectoryEntry to LdapEntry;
  • convert the LdapEntry back to DirectoryEntry;
  • compare the same attribute binary value.

Expected behavior
I would expect the two methods to retain the same data among conversions.

Environment:

  • OS'es: Windows and Linux (Docker containers)
  • Library version: 2.7.4
  • .NET Core 3.1
  • LDAP server: Active Directory

Additional context
This is quite an issue if you're using Search methods and you need to get binary attributes (e.g. objectSid or objectGuid). Also the SID conversion routines are internal so, if you're using SendRequest, you cannot make use of them for searching by objectSid.

I prepared a small NUnit test case for this: https://gist.github.com/axelgenus/622eca57b4e6218f0789136671a5cf72

Also, I ported from LDAP-wiki a very handy routine to get the objectSid SDDL string representation: https://gist.github.com/axelgenus/a9872a8bb57e3d3fa614dab3b9fa0b86

It would be nice if you could include both in LdapForNet.

How to mock SearchAsync method?

I am using dependency injection to allow the mocking of ILdapConnection interface.
How can I mock the SearchAsync method? I need to return "fake" values with fake attributes (fake name, fake sAMAccountName, etc).

_ldapConnectionMock.Setup(_ => _.SearchAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string[]>(),
    It.IsAny<Native.LdapSearchScope>(), It.IsAny<CancellationToken>()))
    .ReturnsAsync(new List<LdapEntry>()
{
    new LdapEntry
    {
        DirectoryAttributes = new SearchResultAttributeCollection() // Internal, not visible
        {
            new DirectoryAttribute() // ???
        }
    }
});

Thank you in advance.

Replace LdapDirectoryIdentifier from DirectoryServices

Is your feature request related to a problem? Please describe.
Hi!
I'm still working on an LDAP connection and trying to replace the DirectoryServices package by your LdapForNet package.
I need to find a replacement for LdapDirectoryIdentifier objects, but I can't find any, could you help me ?

Thank you a lot for your work, it is really great :)

Search doesnt work on Linux

Describe the bug
Search for objects dose not work on linux(ubuntu 18.04).

To Reproduce

add-type -AssemblyName /mnt/c/Users/kiranna/Source/LdapForNet.dll
$cn = [LdapForNet.LdapConnection]::new()
$cn.Connect("ldap://server.example.com:389",[LdapForNet.Native.Native+LdapVersion]::LDAP_VERSION3)
$base = "dc=example,dc=com"
$filter = "(&(objectcategory=person)(name=kiran*))"
$ldapcred = [LdapForNet.LdapCredential]::new()
$ldapcred.UserName = "admin"
$ldapcred.Password = "password"
$ldapcred.Realm = "example.com"
$cn.Bind([LdapForNet.Native.Native+LdapAuthType]::Digest,$ldapcred)
$cn.Search($base,$filter,"Name",[LdapForNet.Native.Native+LdapSearchScope]::LDAP_SCOPE_SUBTREE)

Expected behavior
The search function completes showing the returned objects.

Actual behavior
The search function seems to get stuck and never returns or times out.

Desktop (please complete the following information):

  • OS: Ubuntu 18.04
  • Library version :2.7.2
  • .NET\core\mono version - netstandard 2.0
  • LDAP server : Active Directory

Additional context
The search works perfectly fine on windows with the same ldap server its only on linux that its failing.
Also the search works with ad lds on linux so something seems to be going wrong specifically with AD.I have also tried changing the ad server but same result. Perhaps I am missing some parameter or setting something incorrectly on linux.
Would appreciate an example where it works with AD on linux.

LdapException

Is your feature request related to a problem? Please describe.
Now you couldn't handle invalid password with LdapException. Only parse message string and extract result code.

Describe the solution you'd like
Add result property to LdapException.

Is there a way to securely authenticate User1 using a Kerberos ticket from User2?

I am presently writing what amounts to a linux-based Active Directory proxy for authentication (I authenticate against AD then use AD group membership for API authorization).

With my current configuration, I use kinit <username> to get and store a (static) Kerberos ticket for an Active Directory user. BindKerebos uses this ticket to send LDAP requests to Active Directory, ignoring any supplied username and password.

Is there a way I can securely bind using a provided username and password combination?

(Edit: I guess I'm asking if you've implemented SASL yet.)

Connection pooling

Is your feature request related to a problem? Please describe.
Opening new ldap connections is very expensive. It is better to reuse them, but this requires passing connections around your codebase. This is not an ideal solution.

Describe the solution you'd like
Many data access libraries contain a connection pooling mechanism, like Microsoft.Data.SqlClient for C#, and ldaptive for Java. I'd like a connection pooling mechanism for ldap4net.

Describe alternatives you've considered
Passing connections around.

Can't reach ldap server localhost without http://

Describe the bug
Hi !
I would like to connect to my localhost:5389 server. The connection is okay but the binding will fail with a ServerDown error.

To Reproduce

var server = "localhost:5389"
using var connection = new LdapConnection();
connection.Connect(server);
connection.Bind(LdapAuthType.Negotiate, credential);

When I use server = "http://localhost:5389" the binding is successful.
Why can't I bind on the localhost without http or https ?

Desktop (please complete the following information):

  • OS: Windows 10
  • Library version : 2.7.1
  • .NET\core\mono version : 3.1
  • LDAP server : ActiveDirectory

ObjectDisposedException after calling cancelling a CancellationToken used in async request

Describe the bug
ObjectDisposedException occurs when cancelling the cancellation token used in async ldap request, after the request has already been completed.
Stack trace: https://pastebin.com/eWkb8dpB

To Reproduce

  • Call any async request, e.g. SearchAsync with a cancellation token
  • After the request has finished, call Cancel on the cancellation token.

Desktop (please complete the following information):

  • OS: Alpine 3.12 in docker
  • Library version: 2.7.6
  • .NET\core\mono version: dotnet core 3.1.7
  • LDAP server: Active Directory

Additional context
I believe the problem is in LdapConnection.ProcessResponse.
token.Register(() => Abandon(new AbandonRequest(messageId)));
The CancellationToken.Register method returns CancellationTokenRegistration, which should be disposed after the ldap request is completed.

In my case, i have a background HostedService, which gets a cancellation token from the framework.
I create a new linked cancellation token for each ldap operation, but the abandon registration isn't cleaned up, and is called long after original request - when the application stops, and the root cancellation token is cancelled.

URI scheme

image

Cannot connect via IP:Port?

Exception thrown: System.UirFormatException: 'Invalid URI: The URI Scheme is not valid.'

Examples:
234.34.34.344:389
LDAP://234.44.44.545:389

Encoding

Describe the bug
Hi ! I need to use a DirectoryAttribute and convert it into strings but when I do it I have wrong values.
For example, if I convert a DirectoryAttribute into a string and back into a DirectoryAttribute, it won't have the same values. I am using a GUID like beneath :

To Reproduce

attribute = entry.Attributes["name"];
attribute.GetValues<string>().ToList();
var bytes = Encoding.ASCII.GetBytes(Values[0]);
var guid = new Guid(bytes).ToString("N", CultureInfo.InvariantCulture);

where attribute is a DirectoryAttribute.

The bytes object is only 15 bytes long whereas I need 16 bytes to create a GUID. My attribute object is 16 bytes long so there is no reason for the bytes not to be 16 bytes long.

Allow Change password in Active Directory

In order to do a modify password in Active Directory (not admin reset) you need to create a single request with a Delete and then an Add of unicodePwd (https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/6e803168-f140-4d23-b2d3-c3a8ab5917d2).

But, since ModifyAttributeCollection inherits from KeyedCollection<string, DirectoryAttribute> it does not allow adding 2 attributes with the same name.

What is the purpose for this instead of having it inherit from something like List<DirectoryModificationAttribute>?

I would be willing to do a pull request, but this is a potential breaking change...


var oldPasswordAttribute = new DirectoryModificationAttribute
{
    Name = "unicodePwd",
    LdapModOperation = Native.LdapModOperation.LDAP_MOD_DELETE
};

oldPasswordAttribute.Add(Encoding.Unicode.GetBytes($"\"{oldPassword}\""));

var newPasswordAttribute = new DirectoryModificationAttribute
{
    Name = "unicodePwd",
    LdapModOperation = Native.LdapModOperation.LDAP_MOD_ADD
};

newPasswordAttribute.Add(Encoding.Unicode.GetBytes($"\"{newPassword}\""));

var response = await _ldapConnection.Value.SendRequestAsync(new ModifyRequest(userDistinguishedName, oldPasswordAttribute, newPasswordAttribute));

Problem with äöü

First of all. Thank you for your effort. Very easy to use library which works very well.

I have just a small problem when for example the username has an ä in his name. In this case i will get back "B�ck" when the expected value is "Bäck".

My Code:

 private async Task<IEnumerable<LdapEntry>> QueryAsync(string filter)
        {
            using var ldapConnection = new LdapConnection();
            ldapConnection.Connect(adOptions.LdapHost, ldapsPort, LdapForNet.Native.Native.LdapVersion.LDAP_VERSION3);
            await ldapConnection.BindAsync(mechanism: LdapForNet.Native.Native.LdapAuthMechanism.SIMPLE, userDn: adOptions.LdapQueryUserDn, password: adOptions.LdapQueryUserPassword);
            var entries = await ldapConnection.SearchAsync(adOptions.LdapBase, filter);
            return entries;
        }

I put a breakpoint on the return line and got the value "B�ck" with the following query in the watcher window.
entries.First().Attributes.Where(x => x.Key == "sn").First().Value.First()

Expected Value is "Bäck"

I have use Version 2.2.0 of your library which should according to your release notes contains support for unicode.

I can provide further details if needed.

Add option for Autobind

Is your feature request related to a problem? Please describe.
There seems to be missing an option to specify the Autobind value. This might be a result of my ignorance on the subject of LDAP. I am specifically referring to this property (also mentioned here).

Describe the solution you'd like
Support for Autobind or a workaround.

How to perform paged SearchRequest queries?

Hi does this library support paged directory queries?

I see SizeLimit on the SearchRequest object but only see values 0<x<1000 for SizeLimit = x actually having a result.

Any x greater than 1000, only 1000 objects are returned from the directory.

Include DirectoryResponse in Exception details for ThrowIfResponseError

Is your feature request related to a problem? Please describe.
When using a VLV control you need to specify a Sort control, Sort controls can have maximum entry counts to be "UnwillingToPerform". The Response message will return with a error code 12 (unavailable extention error) but the controls themselves will contain a sub error to determine what went wrong (VLV missing Sort, Sort Unwilling to perform etc)

Describe the solution you'd like
When this occurs we would like to be able to read the response controls when an exception is thrown via the LdapConnection ThrowIfResponseError method to handle this gracefully

Describe alternatives you've considered
N/A

Additional context
N/A

Conversion fails in SendRequest

Describe the bug
Hi ! I am having trouble using a SendRequest, I have the following exception:

Error running send request: 00000057: LdapErr: DSID-0C0910B5, comment: Error in attribute conversion operation, data 0, v47ba

To Reproduce
The error message is contained in my response :

var response = connection.SendRequest(request);
if (response.ResultCode != LdapForNet.Native.Native.ResultCode.Success)
{
      throw new Exception("Error running send request: " + response.ErrorMessage);
}

The request is an AddRequest and the connection is inherited from an LdapConnection. More specifically, it is a pooled Ldap connection (you can find few documentation on google about it).
I am using a Bind() method for my connection, and an Anonymous authType.

I really don't understand where a conversion is done and why it fails.

Desktop (please complete the following information):

  • OS: Windows 10
  • Library version : 2.5

LdapOptions

Is your feature request related to a problem? Please describe.
I would like to replace the options from DirectoryServices with LdapForNet options.

Here is my code :

connection.SessionOptions.Sealing = true;

connection.SessionOptions.Signing = true;

connection.SessionOptions.VerifyServerCertificate = new VerifyServerCertificateCallback((con, cer) => true); 

connection.SessionOptions.QueryClientCertificate = new QueryClientCertificateCallback((con, trustedCAs) => null); 

Describe the solution you'd like
How can I use LdapForNet to set those options ? And with which options ?
I already use connection.SetOption(LdapForNet.Native.Native.LdapOption.LDAP_OPT_SSL, 1); for example

Change Type of LdapEntry to byte[] or object

Is your feature request related to a problem? Please describe.
For some attributes you need byte[]: objectGUID, ObjectSid, nTSecurityDescriptor, systemFlags, uSNChanged etc + exchange attributes.

Describe the solution you'd like
Change ToLdapEntry method to:

        public LdapEntry ToLdapEntry()
        {
            return new LdapEntry
            {
                Dn = Dn,
                Attributes = Attributes.ToDictionary(_ => _.Name, _ => _.GetValues<byte[]>().ToList())
            };
        }

And add to LdapEntry methods:

            => this.Attributes.Contains(attribute) ? this.Attributes[attribute] : null;

        public string GetString(string attributeName) => this.GetAttribute(attributeName)?.GetValue<string>();

        public IEnumerable<byte[]> GetBytes(string attributeName) => this.GetAttribute(attributeName)?.GetValues<byte[]>();

And some helper methods:

    public static class DirectoryAttributeExtension
    {
        public static T GetValue<T>(this DirectoryAttribute attribute)
            where T : class, IEnumerable
        {
            var items = attribute.GetValues<T>();
            var item = items.FirstOrDefault();
            return item == default(T) ? default(T) : item;
        }
    }

    public static class DictionaryExtensions
    {
        public static T Get<T>(this IDictionary<string, object> storage, string key)
        {
            if (storage == null)
            {
                throw new ArgumentNullException(nameof(storage));
            }
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            if (!storage.TryGetValue(key, out object value))
            {
                throw new KeyNotFoundException(
                    $"Method Get<{typeof(T).FullName}>(\"{key}\") can't resolve key in dictionary of type \"{storage}\".");
            }

            try
            {
                return (T)value;
            }
            catch (Exception ex)
            {
                throw new InvalidCastException(
                    $"Method Get<{typeof(T).FullName}>(\"{key}\") can't cast value \"{value?.ToString() ?? "<NULL>"}\"" +
                    $" of type \"{value?.GetType().FullName}\" to a resulting type \"{typeof(T).FullName}\".",
                    ex);
            }
        }
}

Example Search controls

Describe the bug
I am trying to use the LdapConnection and PageResultRequestControl that you use in your example which is supposed to support ldap v3 search controls, but the class PageResultRequestControl doesn't exist. Neither does the Controls attribute.

To Reproduce

var searchRequest = new SearchRequest(baseDN, filter, scope, attributes)
                    {
                        AttributesOnly = false,
                        TimeLimit = TimeSpan.Zero,
                        Controls =
                        {
                            new PageResultRequestControl(sizeLimit)
                            {
                                IsCritical = true,
                            },
                        },
                    }

Expected behavior
Controls and PageResultRequestControl are supposed to exist without the DirectoryServices package.

Desktop :

  • OS: Windows 10 Family
  • Library version : 05/22/2020 version cloned
  • .NET\core\mono version :
  • LDAP server : OpenLdap

SendRequest does not throw any response exception

Is your feature request related to a problem? Please describe.
When creating a new SendRequest, no ThrowIfResponseError is used so some errors may not be seen.

Describe the solution you'd like
The ThrowIfResponseError could be used directly within the SendRequest and not in the methods using the SendRequest (e.g. public void Add(LdapEntry entry) => ThrowIfResponseError(SendRequest(new AddRequest(entry))); )

Describe alternatives you've considered
The SendRequest could become like this :

		public DirectoryResponse SendRequest(DirectoryRequest directoryRequest)
		{
			ThrowIfNotBound();
			var requestHandler = SendRequest(directoryRequest, out var messageId);
			var directoryResponse = ProcessResponse(directoryRequest, requestHandler, messageId, CancellationToken.None);
                        ThrowIfResponseError(directoryResponse);
                        return directoryResponse;
		}

And then the other methods would be like this :

public void Add(LdapEntry entry) => SendRequest(new AddRequest(entry));

Cannot Connect

Hi sir. I'm using Vs2019 on windows.
When i try to connect open ldap server i'm getting this error.

What am i doing wrong ?

{"Unable to load DLL 'ldap-2.4.so.2' or one of its dependencies: The specified module could not be found. (Exception from HRESULT: 0x8007007E)"}

Here is my code.

 using (var connection = new LdapConnection())
                {
                    connection.Connect(Config.LdapHost, Config.LdapPort);
                    connection.Bind(LdapAuthMechanism.SIMPLE, Config.LdapUserDn, Config.LdapPassword);
                    var entries = connection.Search(Config.RootDn, "(&(objectclass=top)(cn=admin))");

                    return true;
                }

Inconsistent use of SafeHandle on win vs. mac/linux

Describe the bug
In TrustAllCertificates(), the operation is delegated to the native classes.

In linux and mac, a new LdapHandle is created and passed to ldap_set_option, meaning that this must be called before Connect(), or else the option won't apply to the current connection, only subsequent ones.

However, on Windows, this doesn't work, as the call to ldap_get_option is called with the passed-in handle, meaning it must be called after Connect(), as the handle is null until Connect is called.

I would create a PR for this, but I'm not sure which is the intended/correct behavior, but I suspect the Windows behavior is intended.

To Reproduce

using var connection = new LdapConnection();

connection.TrustAllCertificates(); // breaks on windows

connection.Connect();

connection.TrustAllCertificates(); // calling this here does not apply it to the current connection on mac/linux, only later ones

Expected behavior
Consistent behavior across platforms

Desktop (please complete the following information):

  • OS: All
  • Library version 2.7.11
  • .NET\core\mono version 3.1
  • LDAP server: OpenLdap

Additional context
Exception thrown on Windows:

System.ArgumentNullException: SafeHandle cannot be null. (Parameter 'pHandle')
   at System.StubHelpers.StubHelpers.SafeHandleAddRef(SafeHandle pHandle, Boolean& success)
   at LdapForNet.Native.NativeMethodsWindows.ldap_get_option(SafeHandle ld, Int32 option, Int32& value)
   at LdapForNet.Native.LdapNativeWindows.ldap_get_option(SafeHandle ld, Int32 option, Int32& value)
   at LdapForNet.Native.LdapNativeWindows.TrustAllCertificates(SafeHandle ld)
   at LdapForNet.LdapConnection.TrustAllCertificates()

Powershell Module publish to PSGallery?

Is your feature request related to a problem? Please describe.
The powershell module portion should be published to the Powershell Gallery. I can assist with getting this set up with a PR to the Azure Pipelines file if required.

Can I use this library in Xamarin forms mobile application?

After creating the object of LdapForNet.LdapConnection, I am getting the System.DllNotFoundException error when I try to use connect method in Xamarin.Forms (iOS).

Below is the code sample

var connection = new LdapForNet.LdapConnection();
connection.Connect(Host, int.Parse(Port));
connection.Bind(LdapAuthMechanism.SIMPLE, Email, password);

Error log:

{System.DllNotFoundException: libldap assembly: type: member:(null)
at (wrapper managed-to-native) LdapForNet.Native.NativeMethodsOsx.ldap_initialize(intptr&,string)
at LdapForNet.Native.LdapNativeOsx.Init (System.IntPtr& ld, System.String hostname, System.Int32 port) [0x00012] in <54341b85b3ad47748ae5f4d0c2393a96>:0
at LdapForNet.LdapConnection.Connect (System.String hostname, System.Int32 port, LdapForNet.Native.Native+LdapVersion version) [0x00046] in <54341b85b3ad47748ae5f4d0c2393a96>:0
at LDAPDemo.Models.LoginViewModel.OnSubmit () [0x0001b] in }

SearchResponse : missing attributes

Describe the bug
Hi !
I am working on an LdapConnection and a SearchRequest.
The problem is that even if I have the attribute "parentdn" in my list of attributes, the entries will never have an attribute called "parentdn".

To Reproduce

Here is a sample of my code :

 var searchRequest = new SearchRequest(baseDN, filter, scope, attributes)
{
      AttributesOnly = false,
      TimeLimit = TimeSpan.Zero,
      Controls =
       {
           new PageResultRequestControl()
            {
                 IsCritical = true,
            },
       },
};

var searchResponse = await connection.SendRequestAsync(searchRequest);

The attributes given in the SearchRequest are 13 and contain a "parentdn" attribute.
The results in my searchResponse only have 7 or 8 attributes and no "parentdn".

Expected behavior
I expected to have at least the "parentdn" attribute since I have the "Dn" and other attributes.

Desktop:

  • OS: Windows 10
  • Library version 2.5
  • LDAP server : LDAP

Additional context
I am using the SUBTREE scope

nTSecurityDescriptor parsing

Is your feature request related to a problem? Please describe.
Sometimes you need to parse nTSecurityDescriptor attribute. So it would be very usefull to handle it via library. This is not common ldap functional.

Describe the solution you'd like
https://stackoverflow.com/questions/16521790/how-can-i-access-the-ntsecuritydescriptor-with-a-normal-ldap-client
https://github.com/ldaptools/ldaptools/blob/master/src/LdapTools/Security/SecurityDescriptor.php
Here examples of parsing this context.

ILdapConnection does not contain async methods

Describe the bug
Although LdapConnection contains async versions of add, delete, and modify, the ILdapConnection interface does not.

To Reproduce

ILdapConnection conn = new LdapConnection();

// connect and bind
await conn.AddAsync(params)

Does not compile.

Expected behavior
These methods to exist on the interface

Desktop (please complete the following information):

  • OS: [e.g. iOS] MacOS Catalina
  • Library version [e.g. 2.3]: 2.4.0
  • .NET\core\mono version [e.g. 4.6, 3.1] core 3.1
  • LDAP server [e.g. Active Directory, OpenLdap] OpenLdap

Bind on Linux (Docker container) throws LdapException

Describe the bug
Binding doesn't work on Linux

To Reproduce
using (var cn = new LdapConnection()) { cn.Connect("xxx.zzz.ccc.com", 389); cn.Bind(LdapAuthType.Digest, new LdapCredential { UserName = "xxxxxxxxx", AuthorizationId = "dc=xx,dc=xxx,dc=xxxx", Password = "xxxx2009" }); var user = cn.WhoAmI().Result; }

Expected behavior
It should return user id after running WhoAmI

Desktop (please complete the following information):

  • OS: Windows 10
  • Library version [e.g. 2.3]
  • .NET\core\mono version 3.1
  • LDAP server ??

Additional context
Code runs fine when ran in IISExpress, but not in Docker linux container

Missing Platform Detection for FreeBSD

Describe the bug
We plan to use this library on FreeBSD, but the platform detection mechanism is not implemented for FreeBSD.
Since .NET 5.0 Preview 8 and .NET Core 3.1 3.0 the OSPlatform enum contains this new value:

public static System.Runtime.InteropServices.OSPlatform FreeBSD { get; }
https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.osplatform.freebsd?view=netcore-3.1

Current behavior
A PlatformNotSupportedException is thrown.

Expected behavior
The platform should be identified correctly.

Potential problem
The current target framework of this library is netstandard2.0;netstandard2.1. Since the FreeBSD enum value is not supported by any .Net Standard version, netcoreapp3.0 should probably be added as a target.

Code snippets

            if (RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD))
            {
                return new UnixEncoder();
            }
            if (RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD))
            {
                return new LdapNativeLinux();
            }

Reset password for other user.

Hello, is there way to reset other user password using your library. I need implement changing user password in Windows Active Directory with .net core application hosted on Linux server. If this is possible please write some example for it. Thank you in advance.

thumbnailPhoto to Image

Is there a sample on how i have to convert an image (thumbnailPhoto Attribute) back to an image?

Would be nice if you could provide a sample or push me into the right direction.

Sample C# code?

Hello, I'm looking to see if you have sample C# code to operate your async operations available somewhere?

Replace DirectoryOperationException from DirectoryServices

Is your feature request related to a problem? Please describe.
I am currently working on a program using DirectoryServices.Protocols, and I am trying to replace everything related to this package with the LdapForNet solution.
How can I replace DirectoryOperationExceptions ? Is it implemented yet ?

Describe the solution you'd like
For example
try{ _something_ } catch(DirectoryOperationException);

I don't think that using LdapExceptions will be correct here.

Set custom timeout

Is your feature request related to a problem? Please describe.
Now timeout for connection is 10 minutes and you couldn't change it.

Describe the solution you'd like
Add param to Bind method.

SID.ToByteArray does not have the number of subauthorities in byte[1]

Describe the bug
SID.ToByteArray() always returns a byte array where byte[1] is zero, when it should be the number of subauthorities in the SID

To Reproduce

  1. Create an instance of the SID class.
  2. Call the ToByteArrayMethod()
  3. Check the returned byte array, and you'll see that the second byte in the array is always zero

Expected behavior
The second byte should be the number of subauthorities in the SID

Desktop (please complete the following information):

  • OS: Windows 10
  • Library version [e.g. 2.3]: 2.7.9
  • .NET\core\mono version [e.g. 4.6, 3.1] .NET Core 3.1
  • LDAP server [e.g. Active Directory, OpenLdap] Active Directory

Additional context
The issue is that the line of code in the method that is trying to set this value is taking the 4th byte of the bytes returned from GetBytes:

        buff.Write(NumberFacility.GetBytes(this.subAuthorities.Count)[3]);

It should be taking the first byte - it should look like this:

        buff.Write(NumberFacility.GetBytes(this.subAuthorities.Count)[0]);

Suggestion: Native.LdapAuthType.Anonamous for Bind

With the default LDAP classes, you could go

ldapConnection.AuthType = AuthType.Anonymous;

Your current version equivalent is

LdapCredential anonymousCredential = new LdapCredential();
ldapConnection.Bind(Native.LdapAuthType.Simple, anonymousCredential);

I suggest a

ldapConnection.Bind(Native.LdapAuthType.Anonymous);

version to simplify migration.

Better use of exceptions

Is your feature request related to a problem? Please describe.
Use of LdapException for every problem is not the best way to expose an error (we need to compare the ResultCode).

Describe the solution you'd like
An exception for every result code (ex. LdapInvalidCredentialsException, LdapUnavailableException, etc).

try
{
    // Connection
}
catch (LdapUnavailableException exception)
{
    // Do something
}

Describe alternatives you've considered
Currently the code is like this.

try
{
    // Connection
}
catch (LdapException exception) when (exception.ResultCode == Native.ResultCode.Unavailable)
{
    // Do something
}

Unable to create mock of list of LdapEntry values due to internal constructor for SearchResultAttributeCollection

Description of the Problem
I am creating unit tests that need to mock (using the Moq library) various parts of LdapForNet. I have an interface (ILapService) and implementation (LdapService) between my application and LdapForNet. In order to unit LdapService, I need to be able to mock what LdapForNet returns. To be specific, I want to set up my unit test such that a call to SearchAsync returns a list of LdapEntry objects that I have created in advance of the call.

I can easily create multiple LdapEntry instances and put them in a list, but I'm having trouble setting up their DirectoryAttribute values, because I cannot create a new SearchResultAttributeCollection instance to assign to the DirectoryAttributes property of the LdapEntry instance, because the constructor for SearchResultAttributeCollection uses the internal access modifier. Also, the LdapEntry class has no constructors defined, so the default generated by the compiler will leave the DirectoryAttributes property set to null.

Because of this, my unit test code throws a NullReferenceException when I'm trying to add DirectoryAttribute objects to the DirectoryAttributes property using it's Add method,

To Reproduce
Here is the relevant code

        private void SetupUserSearchOneUser(string dn)
        {
            // Next line creates a new LdapEntry instance, no constructor is defined, so
            // compiler generated default leaves the DirectoryAttributes property as null
            var entry = new LdapEntry();
            // Can't do this next line because the constructor has internal access modifier
            //entry.DirectoryAttributes = new SearchResultAttributeCollection();

            entry.Dn = dn;
            AddNewDirectoryAttribute(entry, "distinguishedName", dn);
            AddNewDirectoryAttribute(entry, "accountExpires", "0x7FFFFFFFFFFFFFFF");
            AddNewDirectoryAttribute(entry, "pwdLastSet", "0x0");
            AddNewDirectoryAttribute(entry, "userAccountControl", "512");
            // purposely leaving off logonHours


            var list = new List<LdapEntry> { entry };

            this.mockLdapConnection.Setup(m => m.SearchAsync(It.IsAny<string>(),
                                                             It.IsAny<string>(),
                                                             It.IsAny<string[]>(),
                                                             Native.LdapSearchScope.LDAP_SCOPE_SUB,
                                                             new CancellationToken())).ReturnsAsync(list);
        }

        private void AddNewDirectoryAttribute(LdapEntry e, string name, string value)
        {
            var dirAttr = new DirectoryAttribute();
            dirAttr.Name = name;
            dirAttr.Add(value);
            // This next line throws the NullReferenceException because e.DirectoryAttributes is null.
            e.DirectoryAttributes.Add(dirAttr);
        }

Expected behavior
I expect to be able to manually construct LdapEntry objects with DirectoryAttribute instances in the DirectoryAttributes property for use in unit testing. I see two possible ways to address this:

  1. Change the access modifier of the SearchResultAttributeCollection constructor to public.

OR

  1. Add a constructor to the LdapEntry class that initializes the DirectoryAttributes property using the existing SearchResultAttributeCollection constructor, leaving the access modifier as is.

I'd be more than happy to clone the repo, make either of these changes (I lean towards #2 being the better option), and then create a pull request.

Desktop (please complete the following information):

  • OS: Windows, but will also be running on Linux
  • Library version [e.g. 2.3] 2.7.6
  • .NET\core\mono version [e.g. 4.6, 3.1] .NET Core 3.1
  • LDAP server [e.g. Active Directory, OpenLdap] Active Directory

Additional context
This code is part of an IdentityServer4 based service that provides authentication & authorization services within our enterprise, and is part of a project to host this service in a Linux Kubernetes cluster. Development occurs under Windows, but some testing and production use will be hosted in the Linux Kubernetes cluster.

Attributes with empty or null values cause an exception

Describe the bug
Attributes with empty or null values cause an exception

To Reproduce

filter = "(&(cn=JohnDoe)(objectCategory=Person)(objectClass=user))"
var entries = cn.Search(Base, Filter,string[]{"cn","manager"} scope: ToSearchScope(Scope));
foreach (var entry in entries)
{
    var res = new PSObject();
    foreach (string attrName in string[]{"cn","manager"})
    {
        res.Properties.Add(new PSNoteProperty(attrName, entry.Attributes[attrName][0]));
    }
    WriteObject(res);
}

Expected behavior
The user JohnDoe has a null value for the manager attribute so the entry should list something like this:

cn             manager
--              --
JohnDoe

Actual Behavior

cn             
--              
JohnDoe

Desktop (please complete the following information):

  • OS: Windows 10
  • Library version : 2.7.1
  • .NET standard 2.0
  • LDAP server Active Directory

Additional context
It seems that when the search returns an attribute with an empty or null that attribute is not added to the dictionary or is removed.

The reason this is a problem is because when we use a filter like so:
filter = "(&(cn=John*)(objectCategory=Person)(objectClass=user))"

It process lets say 5 users and as soon as it comes across the user with empty manager attribute it throws an error:
The given key was not present in the dictionary.

i could additionally check and catch this exception within the foreach loop but when processing a large number of results this will add a lot of overhead and time.

Package does not have a strong name

Describe the bug
I am unable to reference the LdapForNet package in an application that is strongly signed.
CSC : error CS8002: Referenced assembly 'LdapForNet, Version=2.7.10.0, Culture=neutral, PublicKeyToken=null' does not have a strong name.

To Reproduce
Reference this package in a project that uses strong name signing. You cannot reference unsigned assembly from a signed assembly.

Expected behavior
The package should be strongly signed.

Desktop (please complete the following information):

  • OS: Windows, Linux, and FreeBSD
  • Library version 2.7.10
  • .NET Core 3.1

Additional information
I am currently using the following package as a workaround:
<PackageReference Include="Brutal.Dev.StrongNameSigner" Version="2.7.1" />

Referral Chasing mode

Is your feature request related to a problem? Please describe.
At enterprise level infrastructure contains multiple domains. You connect to domain via kerberos and couldn't search at another trusted domain. This is fixed at Windows default library with ReferralChasingOptions option. Class LdapSessionOptions.

Settings:
LdapOption.LDAP_OPT_REFERRALS
LdapOption.LDAP_OPT_REFERRAL_HOP_LIMIT

Also usefull fuction:
LdapOption.LDAP_OPT_AUTO_RECONNECT

Describe the solution you'd like
Add referral chasing function to code.
Example:
https://www.php.net/manual/en/function.ldap-set-rebind-proc.php
https://linux.die.net/man/5/slapd-meta

https://klikr.org/4bbb0c55d527603667041ed0ce0a.png
This is current net framework referral connection example.

ldap_get_option

Is your feature request related to a problem? Please describe.
Now I couldn't get some options of connection directly via ldap_get_option.

Describe the solution you'd like
Make method ldap_get_option in connection class. Or maybe make LdapNative field in connection class protected, so anybody could inherit base class and use additional api of LdapNative functions.

Case sensitive TryGetValue

Hi !
I recently used the TryGetValue and I found out that it is case sensitive.
I believe that it would be great to implement a TryGetValue case insensitive or to be able to chose between sensitive or insensitive
For example :
entry.Attributes.TryGetValue("whencreated", out var whencreatedResult)
won't return me anything if my attribute is named "whenCreated".

I believe that you can do it for all KeyedCollection this way for example :

        internal ModifyAttributeCollection()
              :base(comparer)
        {
        }

Bind to Ldaps not working under Linux environment

Hello, i have some problem with connecting to Active Directory using ldaps (port 636) under linux environment(ubuntu).
I call Connect, after that i call Bind (via kerberos), and nothing happens, no errors, no cpu usage, no any other answers from Bind method.
All works fine using ldap port (389) without encription.
AD server configured for using ldaps.
Certificates verification ignored on client (LDAPTLS_REQCERT=never )
Same problem when i use ldapsearch, but if i set option maxssf (-O maxssf=200) all works fine.
I suggest if i set maxssf in LdapForNet before bind i would bind successfully, but SetOption not works without Bind (There is call method ThrowIfNotBound() before settting options as i see), i got error "LdapForNet.LdapException: Not bound. Please invoke Bind method before"

I try to setup SASL_SECPROPS maxssf= in /etc/ldap/ldap.conf and it had not affected LDapForNet behavior.
My question is how can i specify option LDAP_OPT_X_SASL_SSF_MAX via this LdapForNet library?

PInvokeStackImbalance exception thrown by using with .NET Framework

I'm trying to use this lib in .NET Standard 2.0 dll. It seems to work with a dotnetcore projects, but brakes if i use it in .NetFramework

PInvokeStackImbalance' : 'A call to PInvoke function 'LdapForNet!LdapForNet.Native.NativeMethodsWindows::ldap_init' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.