Updated Active Directory Helper Class

I’ve made some updates to my Active Directory Helper class, which now includes some impersonation, which means its time for some new code.

Active Directory Helper Class:

using System;
using System.Data;
using System.DirectoryServices;
using System.Configuration;

namespace MyLifeInAMinute.Base.Utiltities
{
    public class ActiveDirectoryHelper
    {
        /// <summary>
        /// returns a string (i.e. LDAP://example.dc.local
        /// </summary>
        private string LDAPConnection
        {
            get { return System.Configuration.ConfigurationManager.AppSettings["LDAPConnection"].ToString(); }
        }

        /// <summary>
        /// returns a string contain the username for the LDAP connection (preferably admin level so we
        /// can reset passwords)
        /// </summary>
        private string LDAPAdminPassword
        {
            get { return System.Configuration.ConfigurationManager.AppSettings["LDAPAdminPass"].ToString(); }
        }

        /// <summary>
        /// returns a string containing the password for the LDAP connection
        /// </summary>
        private string LDAPAdminUserName
        {
            get { return System.Configuration.ConfigurationManager.AppSettings["LDAPAdmin"].ToString(); }
        }

        private DirectoryEntry GetDirectoryObject()
        {
            DirectoryEntry oDE;
            oDE = new DirectoryEntry(this.LDAPConnection, this.LDAPAdminUserName, this.LDAPAdminPassword, AuthenticationTypes.Secure | AuthenticationTypes.ServerBind);
            return oDE;
        }

        public SearchResultCollection GetAllUsers()
        {
            DirectoryEntry de = GetDirectoryObject();
            DirectorySearcher deSearch = new DirectorySearcher();
            deSearch.SearchRoot = de;

            deSearch.Filter = "(&(objectClass=user))";
            deSearch.SearchScope = SearchScope.Subtree;
            SearchResultCollection results = deSearch.FindAll();

            return results;
        }

        public DirectoryEntry GetUser(string propertyName, string propertyValue)
        {
            DirectoryEntry de = GetDirectoryObject();
            DirectorySearcher deSearch = new DirectorySearcher();
            deSearch.SearchRoot = de;

            deSearch.Filter = "(&(objectClass=user)(" + propertyName + "=" + propertyValue + "))";
            deSearch.SearchScope = SearchScope.Subtree;
            SearchResult results = deSearch.FindOne();

            if (!(results == null))
            {
                de = new DirectoryEntry(results.Path, this.LDAPAdminUserName, this.LDAPAdminPassword, AuthenticationTypes.Secure | AuthenticationTypes.ServerBind);
                return de;
            }
            else
            {
                return null;
            }
        }

        public void SetProperty(DirectoryEntry de, string PropertyName, string PropertyValue)
        {
            if (PropertyValue != null)
            {
                if (de.Properties.Contains(PropertyName))
                {
                    de.Properties[PropertyName][0] = PropertyValue;
                }
                else
                {
                    de.Properties[PropertyName].Add(PropertyValue);
                }
            }
        }

        public void ChangePassword(string userPath, string userName, string userCurrentPwd, string userNewPwd)
        {
            DirectoryEntry oDE;
            oDE = new DirectoryEntry(userPath, userName, userCurrentPwd, AuthenticationTypes.Secure | AuthenticationTypes.ServerBind);

            try
            {
                // Change the password.
                oDE.Invoke("ChangePassword", new object[] { userCurrentPwd, userNewPwd });
                oDE.CommitChanges();
                oDE.Close();
            }
            catch (Exception excep)
            {
                throw new Exception("Error changing password. Reason: " + excep.Message + ". Detail: " + excep.InnerException);
            }
        }

        public void SetPassword(string userPath, string userPassword)
        {
            Utiltities.IdentityImpersonatorHelper impHelper = Utiltities.IdentityImpersonatorHelper.ImpersonateAdmin();
            DirectoryEntry usr = new DirectoryEntry(userPath, this.LDAPAdminUserName, this.LDAPAdminPassword, AuthenticationTypes.Secure | AuthenticationTypes.ServerBind);
            try
            {
                object[] password = new object[] { userPassword };
                object ret = usr.Invoke("SetPassword", password);
                usr.CommitChanges();
            }
            catch (Exception excep)
            {
                throw new Exception("Error changing password. Reason: " + excep.Message + ". Detail: " + excep.InnerException);
            }
            finally
            {
                usr.Close();
            }
            impHelper.UndoImpersonation();
        }

        public string ToADDateString(DateTime date)
        {
            string year = date.Year.ToString();
            int month = date.Month;
            int day = date.Day;
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append(year);
            if (month < 10)
            {
                sb.Append("0");
            }
            sb.Append(month.ToString());
            if (day < 10)
            {
                sb.Append("0");
            }
            sb.Append(day.ToString());
            sb.Append("000000.0Z");
            return sb.ToString();
        }
    }
}

Impersonation Helper Class:

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace MyLifeInAMinute.Base.Utiltities
{
    /// <summary>
    /// This class manages the creation of an impersonation to the Application
    ///  Pool's context for a defined scope.
    ///
    /// It just wraps the .Net class for impersonation, thus allowing easier
    ///  use.
    ///
    /// This class is made for use with the C# 'using' keyword, as in the
    ///  example below:
    /// <code>
    ///             using(Identity impersonate = Identity.ImpersonateAdmin())
    ///             {
    ///                     // ... Do whatever job you want as the AppPool
    ///             }
    ///             // Back to the original, you don't have to worry about reverting,
    ///             // this is automatically done with the IDisposable interface
    /// </code>
    /// </summary>
    public sealed class IdentityImpersonatorHelper : IDisposable
    {
        /// <summary>
        /// Windows identity used for the Application Pool
        /// </summary>
        private static WindowsIdentity _appPoolIdentity;
        private static WindowsIdentity _administratorIdentity;

        private static WindowsIdentity AdministratorIdentity
        {
            get
            {
                // Lock current type to ensure thread safety on
                //  identity creation.
                lock (typeof(IdentityImpersonatorHelper))
                {
                    if (_administratorIdentity == null)
                    {
                        // Create a new handle from this one
                        IntPtr token = IntPtr.Zero;

                        bool result = LogonUser(System.Configuration.ConfigurationManager.AppSettings["LDAPAdmin"].ToString(),
                            System.Configuration.ConfigurationManager.AppSettings["Domain"].ToString(),
                            System.Configuration.ConfigurationManager.AppSettings["LDAPAdminPass"].ToString(),
                            3,
                            0,
                            out token);

                        // Throw an exception if we have an empty token
                        if (token == IntPtr.Zero)
                        {
                            throw new ApplicationException("Unable to fetch administrator identity token !");
                        }

                        // Create a duplicate of the user's token in order to use it for impersonation
                        if (!DuplicateToken(token, 2, ref token))
                        {
                            throw new Win32Exception(Marshal.GetLastWin32Error(), "Unable to duplicate administrator identity token !");
                        }

                        // Throw an exception if we were unable to duplicate the token
                        if (token == IntPtr.Zero)
                        {
                            throw new ApplicationException("Unable to duplicate administrator identity token !");
                        }

                        // Store app pool's identity
                        _administratorIdentity = new WindowsIdentity(token);

                        // Free the windows unmanaged resource
                        CloseHandle(token);
                    }
                    return _administratorIdentity;
                }
            }
        }

        /// <summary>
        /// Gets the windows identity used for the Application Pool
        /// </summary>
        private static WindowsIdentity AppPoolIdentity
        {
            get
            {
                // Lock current type to ensure thread safety on
                //  identity creation.
                lock (typeof(IdentityImpersonatorHelper))
                {
                    if (_appPoolIdentity == null)
                    {
                        // Create a new handle from this one
                        IntPtr token = WindowsIdentity.GetCurrent().Token;

                        // Throw an exception if we have an empty token
                        if (token == IntPtr.Zero)
                        {
                            throw new ApplicationException("Unable to fetch AppPool's identity token !");
                        }

                        // Create a duplicate of the user's token in order to use it for impersonation
                        if (!DuplicateToken(token, 2, ref token))
                        {
                            throw new Win32Exception(Marshal.GetLastWin32Error(), "Unable to duplicate AppPool's identity token !");
                        }

                        // Throw an exception if we were unable to duplicate the token
                        if (token == IntPtr.Zero)
                        {
                            throw new ApplicationException("Unable to duplicate AppPool's identity token !");
                        }

                        // Store app pool's identity
                        _appPoolIdentity = new WindowsIdentity(token);

                        // Free the windows unmanaged resource
                        CloseHandle(token);
                    }
                    return _appPoolIdentity;
                }
            }
        }

        /// <summary>
        /// This function returns the current user's login name.
        /// </summary>
        public static string CurrentUserName
        {
            get { return WindowsIdentity.GetCurrent().Name; }
        }

        /// <summary>
        /// Stores the currently available Windows Impersonation context.
        /// </summary>
        private WindowsImpersonationContext _context;

        /// <summary>
        /// Stores the app pool's identity context.
        /// </summary>
        private WindowsImpersonationContext _selfContext;

        private enum Impersonator
        {
            ApplicationPool,
            Administrator
        }

        /// <summary>
        /// Private constructor, static function accessed class.
        /// </summary>
        private IdentityImpersonatorHelper(Impersonator who)
        {
            // Try catch structure to ensure we don't change context in case
            //  we had an error duplicating the token.
            try
            {
                _selfContext = WindowsIdentity.Impersonate(IntPtr.Zero); // REVERT to identity!
                switch (who)
                {
                    case Impersonator.Administrator:
                        _context = AdministratorIdentity.Impersonate();
                        break;
                    case Impersonator.ApplicationPool:
                        _context = AppPoolIdentity.Impersonate();
                        break;
                }
            }
            catch
            {
                // Close the context
                UndoImpersonation();

                // Rethrow the exception
                throw;
            }
        }

        public static IdentityImpersonatorHelper ImpersonateAppPool()
        {
            return new IdentityImpersonatorHelper(Impersonator.ApplicationPool);
        }

        /// <summary>
        /// This method creates a new impersonation context.
        /// </summary>
        public static IdentityImpersonatorHelper ImpersonateAdmin()
        {
            return new IdentityImpersonatorHelper(Impersonator.Administrator);
        }

        /// <summary>
        /// This method closes the current impersonation context in order revert the user
        /// to his real principal.
        /// </summary>
        public void UndoImpersonation()
        {
            if (_context != null)
            {
                _context.Undo();
                _context = null;
            }
            if (_selfContext != null)
            {
                _selfContext.Undo();
                _selfContext = null;
            }
        }

        /// <summary>
        /// Duplicates a token in order to have it working for impersonation.
        /// </summary>
        /// <param name="hToken_">Initial token to be duplicated</param>
        /// <param name="impersonationLevel_">Level of impersonation needed</param>
        /// <param name="hNewToken_">Reference to the new token created</param>
        /// <returns>True if the call succeeded, false otherwise.</returns>
        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool DuplicateToken(IntPtr hToken_, int impersonationLevel_, ref IntPtr hNewToken_);

        /// <summary>
        /// Closes an unmanaged handle in order to free allocated resources.
        /// </summary>
        /// <returns>True if the call succeeded, false otherwise.</returns>
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern bool CloseHandle(IntPtr handle);

        [DllImport("advapi32.dll")]
        public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
            int dwLogonType, int dwLogonProvider, out IntPtr phToken); 

        #region IDisposable Members

        /// <summary>
        /// This method disposes the current object, it frees all resources used by this class.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            // Ensure I'm garbage collected.
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// This method disposes the current object, it frees all resources used by this class.
        /// </summary>
        /// <param name="disposing_">Do actual disposing or not.</param>
        private void Dispose(bool disposing_)
        {
            if (disposing_)
            {
                this.UndoImpersonation();
            }
        }
        #endregion
    }
}
Bookmark and Share
Leave a comment

0 Comments.

Leave a Reply


[ Ctrl + Enter ]

Performance Optimization WordPress Plugins by W3 EDGE