Skip to content

Instantly share code, notes, and snippets.

@alexdresko
Created July 15, 2010 18:08
Show Gist options
  • Select an option

  • Save alexdresko/477296 to your computer and use it in GitHub Desktop.

Select an option

Save alexdresko/477296 to your computer and use it in GitHub Desktop.
SharePointSiteAndWebHelper
namespace CSI.ESS.ServiceModel.Contracts
{
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Principal;
/// <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(CSI.Shared.SharePoint.Identity impersonate = CSI.Shared.SharePoint.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 Identity : IDisposable
{
#region Constants and Fields
/// <summary>
/// Windows identity used for the Application Pool
/// </summary>
private static WindowsIdentity _appPoolIdentity;
/// <summary>
/// Stores the currently available Windows Impersonation context.
/// </summary>
private WindowsImpersonationContext _context;
/// <summary>
/// Stores the app pool's identity context.
/// </summary>
private WindowsImpersonationContext _selfContext;
#endregion
#region Constructors and Destructors
/// <summary>
/// Private constructor, static function accessed class.
/// </summary>
private Identity()
{
// Try catch structure to ensure we don't change context in case
// we had an error duplicating the token.
try
{
this._selfContext = WindowsIdentity.Impersonate(IntPtr.Zero); // REVERT to AppPool identity!
this._context = AppPoolIdentity.Impersonate();
}
catch
{
// Close the context
this.UndoImpersonation();
// Rethrow the exception
throw;
}
}
#endregion
#region Properties
/// <summary>
/// This function returns the current user's login name.
/// </summary>
public static string CurrentUserName
{
get
{
// ReSharper disable PossibleNullReferenceException
return WindowsIdentity.GetCurrent().Name;
// ReSharper restore PossibleNullReferenceException
}
}
/// <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(Identity))
{
if (_appPoolIdentity == null)
{
// Create a new handle from this one
// ReSharper disable PossibleNullReferenceException
var token = WindowsIdentity.GetCurrent().Token;
// ReSharper restore PossibleNullReferenceException
// 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;
}
}
}
#endregion
#region Public Methods
/// <summary>
/// This method creates a new impersonation context.
/// </summary>
public static Identity ImpersonateAdmin()
{
return new Identity();
}
/// <summary>
/// This method closes the current impersonation context in order revert the user
/// to his real principal.
/// </summary>
public void UndoImpersonation()
{
if (this._context != null)
{
this._context.Undo();
this._context = null;
}
if (this._selfContext != null)
{
this._selfContext.Undo();
this._selfContext = null;
}
}
#endregion
#region Implemented Interfaces
#region IDisposable
/// <summary>
/// This method disposes the current object, it frees all resources used by this class.
/// </summary>
public void Dispose()
{
this.Dispose(true);
// Ensure I'm garbage collected.
GC.SuppressFinalize(this);
}
#endregion
#endregion
#region Methods
/// <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);
/// <summary>
/// Duplicates a token in order to have it working for impersonation.
/// </summary>
/// <param name = "tokenHandle">Initial token to be duplicated</param>
/// <param name = "impersonationLevel_">Level of impersonation needed</param>
/// <param name = "newTokenHandle">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 tokenHandle, int impersonationLevel_, ref IntPtr newTokenHandle);
/// <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
}
}
namespace CSI.ESS.Common
{
using System;
using System.Web;
using CSI.ESS.ServiceModel.Contracts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
public class SharePointSiteAndWebHelper
{
public static void UseSiteAndWebWithImpersonation(bool allowUnsafeUpdates, Action<SPSite, SPWeb> action)
{
using (Identity.ImpersonateAdmin())
{
UseSiteAndWebWithDefaultSecurity(allowUnsafeUpdates, action);
}
}
public static void UseSiteAndWebWithElevatedPermissions(bool allowUnsafeUpdates, Action<SPSite, SPWeb> action)
{
UseSiteAndWebWithDefaultSecurity(allowUnsafeUpdates, (site, web) =>
{
var webGuid = web.ID;
var siteGuid = web.Site.ID;
SPSecurity.RunWithElevatedPrivileges(
() =>
{
// get the site in this context
var site2 = new SPSite(siteGuid) { AllowUnsafeUpdates = allowUnsafeUpdates };
using (var web2 = site2.OpenWeb(webGuid))
{
if (web2 != null)
{
web2.AllowUnsafeUpdates = allowUnsafeUpdates;
action(site2, web2);
}
}
});
});
}
public static void UseSiteAndWebWithDefaultSecurity(bool allowUnsafeUpdates, Action<SPSite, SPWeb> action)
{
var httpContext = HttpContext.Current;
if (httpContext != null)
{
var site = SPControl.GetContextSite(httpContext);
if (site != null)
{
site.AllowUnsafeUpdates = allowUnsafeUpdates;
using (var web = site.OpenWeb())
{
if (web != null)
{
web.AllowUnsafeUpdates = allowUnsafeUpdates;
action(site, web);
}
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment