2

The company I work for has a product that uses Active Directory to enable our product's security features using a library that includes DirectoryEntry and DirectorySearcher components.

If someone is a member of group FOO, they have standard access. If they are a member of FOO-ADMIN, they have Admin rights.

We have a potential client who does not use Active Directory. They have an Apache server running their LDAP, and they have provided this screenshot.

Customer Properties

Above, it looks like I would need to connect to a domain of xxx.xxx.5.101:389 (i.e. DirectoryEntry("LDAP://xxx.xxx.5.101:389")), but how does that "DN or user" field fit with the password?

Are Active Directory components able to do LDAP authentication on an Apache system, or would the code need completely different controls?

Here is some crude code that I have put together:

/// <summary>
/// Untested Method
/// </summary>
/// <param name="hostIp">String (EX: xxx.xxx.5.101)</param>
/// <param name="port">Int (EX: 389)</param>
/// <param name="user">String (EX: cn=danibla,ou=sysdata,ou=townhall,o=toh)</param>
/// <param name="password">String - provided password</param>
/// <param name="groupsLike">String (EX: find all groups like FOO)</param>
/// <returns>String[] array of matching membership groups</returns>
public static String[] GetMemberships(String hostIp, int port, String user, String password, String groupsLike)
{
    var results = new List<String>();
    var path = String.Format("LDAP://{0}:{1}", hostIp, port);
    using (var entry = new DirectoryEntry(path, user, password))
    {
        using (var search = new DirectorySearcher(entry, String.Format("(CN={0}*)", groupsLike)))
        {
            var expression = new Regex("CN=([^,]*),", RegexOptions.Compiled & RegexOptions.IgnoreCase);
            foreach (SearchResult item in search.FindAll())
            {
                var match = expression.Match(item.Path);
                var name = match.Groups[1].Value;
                if (name.StartsWith(groupsLike, StringComparison.OrdinalIgnoreCase))
                {
                    if (!results.Contains(name))
                    {
                        results.Add(name);
                    }
                }
            }
        }
    }
    return results.ToArray();
}

I am bothered by the "path like" parameters they pass in for the "DN or user" field, particularly when it shows them providing a password with it.

We do not have an Apache environment to test this on. Our company does not want me going to this client with a lot of unnecessary questions.

UPDATE:
Still need a way to do this. Starting a bounty. Maybe bringing some attention to this will get me a solution.

currentState

In the screenshot above, the value for username in the code was both cn-mikead,ou=sysdata,ou=townhall,o=toh and separately mikead, both with the same COM Exception at the call to FindAll().

Here is the code I have now.

public static String[] Groups(String domain, int port, String username, int authenticationValue, String startsWith)
{
    String name;
    var results = new List<String>();
    var ldapPath =
        String.IsNullOrEmpty(domain) ? null :
        (0 < port) ?
        String.Format("LDAP://DC={0}:{1}", domain, port) :
        String.Format("LDAP://DC={0}", domain);
    using (var entry = new DirectoryEntry(String.Format("WinNT://{0}/{1}", Environment.UserDomainName, username)))
    {
        name = String.Format("{0}", entry.Properties["fullName"].Value);
    }
    var filter = String.Format("(CN={0}", name);
    var expression = new Regex("CN=([^,]*),", RegexOptions.Compiled & RegexOptions.IgnoreCase);
    using (var entry = new DirectoryEntry(ldapPath))
    {
        entry.AuthenticationType = (AuthenticationTypes)authenticationValue;
        using (var search = new DirectorySearcher(entry) { Filter = filter })
        {
            search.PropertiesToLoad.Add("memberOf");
            try
            {
                foreach (SearchResult item in search.FindAll())
                {
                    foreach (var property in item.Properties["memberOf"])
                    {
                        var name = expression.Match(String.Format("{0}", property)).Groups[1].Value;
                        if (name.StartsWith(startsWith, StringComparison.OrdinalIgnoreCase))
                        {
                            if (!results.Contains(name))
                            {
                                results.Add(name);
                            }
                        }
                    }
                }
            }
            catch (Exception err)
            {
                LogError("Groups", err);
            }
        }
    }
    return results.ToArray();
}
  • LDAP is a protocol, so as long as the product you use use only standard operation of the protocol there should not be any problem to connect to Apache DS instead of AD. The problems will rise if you use custom control of AD which are not part of the LDAP protocol, but only you could know that ;) – Esteban Sep 28 '17 at 09:00

2 Answers2

2

Apache can run LDAP, my advice would be to make sure your client has LDAP configured properly on their server. This could be done in the httpd.conf on their server

Tom
  • 389
  • 2
  • 15
  • This was supposed to be a comment my bad – Tom Oct 05 '17 at 20:08
  • The guy sending me the screenshots is the IT guy for the other company, and they are able to connect to their LDAP. We need a way for our program to authenticate using their LDAP. If we cannot, we do not make the sale. Shown above are all of the parameters he uses to connect on his tool called eDir (I don't know what that is). –  Oct 05 '17 at 20:30
  • Well if they are using LDAP for their authentication they will have a LDAP server configuration which you will need the username, password, servername and LDAP driver. If you are using apache as I say you will have to use the httpd.conf to connect to their LDAP server configuration – Tom Oct 05 '17 at 20:33
  • Have you tried to ping their IP and port it is contained on? – Tom Oct 05 '17 at 20:35
  • I'm hoping he has tried that. I asked my manager that question earlier, and he said that guy isn't that dumb. My small test program is being run on a PC. Are you saying above that it will need the LDAP username, password, servername and driver to establish a connection before I try authenticating a person on that LDAP system? If so, what LDAP driver am I going to need? –  Oct 05 '17 at 20:38
  • 1
    Well my advice would be to create an apache environment, if you just do a Google search on how to set up Apache24 on Windows, assuming you're using Windows and run through That, then run your program on there with their LDAP configuration inside the httpd.conf you should be able to test it properly – Tom Oct 05 '17 at 20:41
  • Due to you using C# I am unsure on what driver you require if I was you I would just do some research into the driver, I program in PHP but I authenticate everything with AD using LDAP – Tom Oct 05 '17 at 20:42
2

I wish I had more time to give you a more complete answer. But let me see if this helps at all. Group membership works differently in eDirectory and there is no memberOf attribute. You also may find that you have to go lower level than the DirectoryEntry, DirectorySearcher, etc... (as these are tailored for AD). The System.DirectoryServices.Protocols will give you lower level access.

Alternately, Novell also has c# libraries that you could consider using: https://www.novell.com/developer/ndk/ldap_libraries_for_c_sharp.html

  1. I suggest you first bind to the database as a user with the rights you need to search or anonymously (if anonymous can search) , and search for the (&(cn=USERNAME)(objectclass=Person)) to find the dn you need to bind as.
  2. Now bind as the user dn you found with the supplied credentials and get the groupMembership attribute.
  3. Examine the groupMembership attribute to determine your privileges.

If you can't get the groupMembership attribute to work, alternately, you can search the directory for the group: ((cn=GROUPNAME)(objectclass=groupOfNames)) Then you can look through the groupOfNames:member attributes to find your username.

I'd start by trying to get just binding/authenticating up and then add the group stuff. There's an example of binding here: https://www.codeproject.com/Articles/5969/Authentication-against-Active-Directory-and-Edirec

Or an alternate method here if you have certificate issues: https://www.codeproject.com/Articles/19097/eDirectory-Authentication-using-LdapConnection-and

Here are some useful references:

https://www.mediawiki.org/wiki/Extension:LDAP_Authentication/Examples#Configuration_for_non-AD_domains

https://docs.oracle.com/cd/E36500_01/E36503/html/ldap-filters-attrs-users.html#ldap-filters-attrs-users-openldap

https://www.ibm.com/support/knowledgecenter/en/SSEQTP_8.5.5/com.ibm.websphere.wlp.doc/ae/rwlp_config_edirectoryLdapFilterProperties.html

Connecting to LDAP from C# using DirectoryServices

https://forums.novell.com/showthread.php/491292-Is-user-member-of-group-in-C

https://www.novell.com/documentation/developer/ldapcsharp/?page=/documentation/developer/ldapcsharp/cnet/data/bovtz77.html

http://mikemstech.blogspot.com/2013/03/searching-non-microsoft-ldap.html

https://www.sqlservercentral.com/Forums/Topic811694-391-1.aspx

scotru
  • 2,563
  • 20
  • 37
  • 1
    [System.DirectoryServices.Protocols](https://msdn.microsoft.com/en-us/library/system.directoryservices.protocols.aspx) lead me to an article [Introduction to System.DirectoryServices.Protocols](https://msdn.microsoft.com/en-us/library/bb332056.aspx). I am reading that now. It may be what I need! –  Oct 17 '17 at 14:45
  • 1
    This has not completely solved my problems, but I'm also not all the way through the list of links you have added here. Thanks. –  Oct 19 '17 at 18:36
  • Thanks very much for the generous bounty. Let me know if you hit a specific problem and I can try to research more. I've implemented AD LDAP integration in C# and I've implemented non-AD LDAP implementation in Ruby. But I've not done non-AD in c# so sadly I don't have code to share. – scotru Oct 20 '17 at 05:33