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
}
}
0 Comments.