.Net core Ldap Login / Member of groups check

Date: 2019-04-10
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using Domain.Enums;
using Domain.Models;
using Domain.Ports;
using Domain.Ports.Secondary;
using Novell.Directory.Ldap;

namespace LDAPAdapter
{
    public class LDAPAdapter : ILDAPAdapter
    {
        public Task<bool> Login(LoginCredentials credentials)
        {
            var sb = new StringBuilder();
            var useSsl = true;
            var config = DomainPorts.ConfigurationStore.GetConfig(ConfigurationType.AppConfig);
            string ldapserver = config["ApiSettings:LDAPServer"];
            using (LdapConnection ldapconnection = new LdapConnection())
            {
                ldapconnection.Connect(ldapserver, 389);
                ldapconnection.Bind(credentials.Username, credentials.Password);
                if (useSsl)
                {
                    ldapConnection.UserDefinedServerCertValidationDelegate += (o, certificate, chain, errors) => true;
                    ldapConnection.SecureSocketLayer = true;
                }
                ldapconnection.Bind("ldap_readonly", "password");

                try
                {

                    var searchConstraints = new LdapSearchConstraints
                    {
                        ReferralFollowing = true,
                        TimeLimit = 10000
                    };
                    var userName = credentials.Username.Split('\\')[1];
                    var searchResults = ldapconnection.Search("DC=company,DC=lan", LdapConnection.SCOPE_SUB,
                        "(sAMAccountName=" + EscapeLdapSearchFilterParam(userName) + ")",
                        null,
                        false,
                        searchConstraints);

                    var entriesDN = new List<string>();
                    while (searchResults.hasMore())
                    {
                        var entry = searchResults.next();
                        entriesDN.Add(entry.DN);
                    }

                    foreach (var ldapEntryDn in entriesDN)
                    {
                        var ldapEntry = ldapconnection.Read(ldapEntryDn);
                        sb.AppendLine(ldapEntry.DN);
                        foreach (var attributeObj in ldapEntry.getAttributeSet())
                        {
                            var attribute = (LdapAttribute) attributeObj;
                            if (attribute.Name.Equals("memberOf", StringComparison.OrdinalIgnoreCase))
                            {
                                foreach(var val in attribute.StringValueArray) {
                                    sb.AppendLine($"{attribute.Name}: {val}");
                                }
                            }                            
                            //sb.AppendLine($"{attribute.Name}: {attribute.StringValue}");
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                finally
                {
                    Console.WriteLine(sb.ToString());
                }

            }
            return (Task.FromResult(true));
        }

        public static string EscapeLdapSearchFilterParam(string searchFilter) {
            var escape = new StringBuilder();
            foreach (var current in searchFilter)
            {
                switch (current) {
                    case '\\': escape.Append(@"\5c"); break;
                    case '*': escape.Append(@"\2a"); break;
                    case '(': escape.Append(@"\28"); break;
                    case ')': escape.Append(@"\29"); break;
                    case '\u0000': escape.Append(@"\00"); break;
                    case '/': escape.Append(@"\2f"); break;
                    default: escape.Append(current); break;
                }
            }
            return escape.ToString();
        }

        private static string GetSearchBase(string schemaDn)
        {
            return string.Join(',', ParseDnString(schemaDn)
                .Where(x => x.Key.Equals("DC", StringComparison.OrdinalIgnoreCase))
                .Select(x => $"{x.Key}={x.Value}"));
        }

        private static string GetServerDomain(string schemaDn)
        {
            var invalidNames = new[] { "lan", "com" };
            var dn = ParseDnString(schemaDn)
                .Where(x => x.Key.Equals("DC", StringComparison.OrdinalIgnoreCase))
                .FirstOrDefault(x => x.Value.Length >= 3 && !invalidNames.Contains(x.Value.ToLower()));
            return dn.Value;
        }

        private static IEnumerable<KeyValuePair<string, string>> ParseDnString(string schemaDn)
        {
            var re = new Regex("([^,]*?)=([^,]+)");
            var dcs = re.Matches(schemaDn)
                .Select(x => new KeyValuePair<string, string>(x.Groups[1].Value, x.Groups[2].Value));
            return dcs;
        }


        bool FindUserInGroup(LdapConnection ldapConnection, string userDn, string groupDn, int ldapTimeout)
        {
            var foundUser = false;
            var names = new List<string>();

            var searchConstraints = new LdapSearchConstraints
            {
                ReferralFollowing = true,
                TimeLimit = ldapTimeout
            };
            var searchResults = ldapConnection.Search(groupDn, LdapConnection.SCOPE_SUB,
                                                      null, //"(sAMAccountName=" + EscapeLdapSearchFilterParam(userName) + ")",
                                                      null,
                                                      false,
                                                      searchConstraints);

            var entriesDn = new List<string>();
            while (searchResults.hasMore())
            {
                var entry = searchResults.next();
                entriesDn.Add(entry.DN);
            }
            IEnumerator objClass = null;
            foreach (var ldapEntryDn in entriesDn)
            {
                var isMember = false;
                string memberName = null;
                var isGroup = false;
                var ldapEntry = ldapConnection.Read(ldapEntryDn);
                foreach (var attributeObj in ldapEntry.getAttributeSet())
                {
                    var attribute = (LdapAttribute)attributeObj;

                    if (!names.Contains(attribute.Name))
                        names.Add(attribute.Name);

                    if (attribute.Name.Equals("objectClass", StringComparison.OrdinalIgnoreCase))
                        objClass = attribute.StringValues;

                    if (attribute.Name.Equals("member", StringComparison.OrdinalIgnoreCase))
                    {
                        isMember = true;
                        foreach (string val in attribute.StringValueArray)
                        {
                            /* Naam bewaren, het kan een groep zijn */
                            memberName = val;
                            if (val == userDn)
                            {
                                foundUser = true;
                                break;
                            }
                        }
                    }

                    if (foundUser)
                        break;
                }

                if (foundUser)
                    break;


                while (objClass != null && objClass.MoveNext())
                {
                    string objectName = (string)objClass.Current;

                    if (objectName.ToUpper().Equals("group".ToUpper()) ||
                        objectName.ToUpper().Equals("groupOfNames".ToUpper()) ||
                        objectName.ToUpper().Equals("groupOfUniqueNames".ToUpper()) ||
                        objectName.ToUpper().Equals("dynamicGroup".ToUpper()) ||
                        objectName.ToUpper().Equals("dynamicGroupAux".ToUpper()))
                        isGroup = true;
                }

                if (isGroup && isMember)
                {
                    /* recursie! */
                    foundUser = FindUserInGroup(ldapConnection, userDn, memberName, ldapTimeout);
                }
            }
            return (foundUser);
        }

        public Dictionary<string, string> GetAllUsersInGroup(string groupName)
        {
            var result = new Dictionary<string, string>();
            var domain = LdapHelper.GetProp($"{LdapSettingsSection}:Server", string.Empty);

            using (var principalContext = new PrincipalContext(ContextType.Domain, domain))
            using (var group = GroupPrincipal.FindByIdentity(principalContext, groupName))
            {
                if (group == null)
                    return result;

                foreach (UserPrincipal user in group.GetMembers(true))
                {
                    //user variable has the details about the user 
                    result.Add(user.EmployeeId, user.DisplayName);
                }
            }

            return result;
        }

        UserRole GetRole(LdapConnection ldapConnection, string userDn, int ldapTimeout)
        {
            var config = DomainPorts.ConfigurationStore.GetConfig(ConfigurationType.AppConfig);

            var groups = new List<GroupRole>();

            if (config.ContainsKey("ActiveDirectoryGroups:Administrator") && config["ActiveDirectoryGroups:Administrator"] != null)
                groups.Add(new GroupRole(config["ActiveDirectoryGroups:Administrator"], UserRole.Administrator));

            if (config.ContainsKey("ActiveDirectoryGroups:Installer") && config["ActiveDirectoryGroups:Installer"] != null)
                groups.Add(new GroupRole(config["ActiveDirectoryGroups:Installer"], UserRole.Installer));

            if (config.ContainsKey("ActiveDirectoryGroups:Logistician") && config["ActiveDirectoryGroups:Logistician"] != null)
                groups.Add(new GroupRole(config["ActiveDirectoryGroups:Logistician"], UserRole.Logistician));

            foreach (var groupRole in groups)
            {
                if (FindUserInGroup(ldapConnection, userDn, groupRole.Group, ldapTimeout))
                {
                    return groupRole.Role;
                }
            }

            // if user not found in any group
            return UserRole.Unknown;
        }
    }
}

20730cookie-check.Net core Ldap Login / Member of groups check