SharePoint Impersonation

Completely copied from this site. Useful stuff and I’m glad he posted the code with all of the comments.:

http://www.sharepoint-tips.com/2007/03/sample-event-handler-to-set-permi…

using System;
using System.Globalization;
using System.ComponentModel;
using System.IO;
using System.Data;
using System.Text;
using System.Xml;
using System.Collections;
using System.Configuration;
using System.Diagnostics;
using System.Web;
using System.Security;
using System.Security.Policy;
using System.Security.Principal;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using Microsoft.SharePoint;
namespace SharePointTips.SharePoint.Samples.EventHandlers
{
///
/// This is the event receiver that traps the item added event of the sharepoint list it is attached to.
///
class ListItemSecuritySetter:SPItemEventReceiver
{
#region constants
///
/// defines the permission set for editors.
///
const SPBasePermissions c_EditorPermissions = SPBasePermissions.EditListItems | SPBasePermissions.ViewListItems;
///
/// defines the permission set for readers
///
const SPBasePermissions c_ReaderPermissions = SPBasePermissions.ViewListItems;
///
/// The name of the role that will be created for the author
///
const string c_AuthorRoleName = “Item Author and Editor”;
///
/// The name of the role that will be created for the reader
///
const string c_ReaderRoleName = “Item Reader”;
///
/// Debug mode writes almost every action to the file log. In production switch this to false. Recommend changing that to read from a configuration file
///
const bool DEBUG_MODE = true;
///
/// The page where the log file will be created. Recommend changing that to read from a configuration file
///
const string c_logFileFolder = @”c:\temp”;
#endregion

#region class properties
///
/// Returns the name of the log file to be used (file name only – not path)
/// The string returned will contain {0} and {1} that should be replaced with list name and site name.
///
private string LogFileName
{
get
{
return “ListItemSecuritySetter-{0}-{1}-” + DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + “.htm”;
}
}

#endregion

#region local variables

HTMLFileLogging log;

#endregion

#region event handler event trapping
///
/// The sharepoint event for ItemAdded
///
///
public override void ItemAdded(SPItemEventProperties properties)
{
//run the default event handlers on the item
base.ItemAdded(properties);

//create the log handler object
log = new HTMLFileLogging(c_logFileFolder, string.Format(LogFileName,properties.ListTitle,properties.OpenWeb().Title) , true, false);
this.WriteToLog(“ItemAdded was triggered”,true);
//if in debug mode, write all the properties in the item to the log
if(DEBUG_MODE)
WriteItemPropertiesToLog(properties.ListItem);

this.WriteToLog(“Setting permissions”, true);
try
{
//impersonate an administrator who can change permissions on list items in the list
ImpersonationUtility imp = ImpersonationUtility.ImpersonateAdmin();
//open the spweb object to get the token for the user
using (SPWeb webOrigUser = properties.OpenWeb())
{
//get the token for the impersonation user (this will get the user that the ImpersonationUtility is using)
SPUserToken token = webOrigUser.AllUsers[WindowsIdentity.GetCurrent().Name].UserToken;
//reopen the spweb object with the new token – full impersonation!
using (SPSite site = new SPSite(properties.SiteId, token))
{
using (SPWeb web = site.OpenWeb(properties.RelativeWebUrl))
{

//call the function that changes the permissions on the list item.
//Do not use properties.ListItem since that will break impersonation!
SetAuthorAsOnlyEditor(web.Lists[properties.ListId].GetItemById(properties.ListItemId));
}
}
}

}
catch (Exception ex)
{
this.WriteToLog(“Setting permissions encountered an error: ” + ex.Message + Environment.NewLine + ex.ToString(), true);
}
}

#endregion

#region custom functions
///
/// Loops over the item properties and prints them to the log file. should only be called in debug mode!
///
/// the list item that is currently handled
private void WriteItemPropertiesToLog(SPListItem item)
{
this.WriteToLog(“Item Properties:”,false);
foreach(SPField field in item.Fields)
{
try
{
this.WriteToLog(field.Title + ” : ” + item[field.InternalName].ToString(), false);
}
catch { }
}
}
///
/// Function sets the permission on the list item so that the author has edit permission on the item,
/// and all other people with access to the document library can only read.
/// Relies on the values in the constants c_EditorPermissions and c_ReaderPermissions.
///
/// the list item that is currently handled
private void SetAuthorAsOnlyEditor(SPListItem item)
{

using (SPWeb currentWeb = item.Web)
{
this.WriteToLog(“Getting author from item”, true);
//get the author from the item. ‘Author’ is a built-in property, so it should be in all lists.
string authorValue = item[“Author”].ToString();
SPFieldUserValue authorUserValue = new SPFieldUserValue(currentWeb, authorValue);
SPUser authorUser = authorUserValue.User;
this.WriteToLog(“Got author name:'” + authorUser.Name + “‘, email: ‘” + authorUser.Email + “‘”, true);

this.WriteToLog(“Breaking role inheritance for the item”, true);
//break the security of the item from the list, but keep the permissions
item.BreakRoleInheritance(true);
//change the permissions of everyone with access to this item so they are readers only (c_ReaderPermissions)
ChangeItemExistingRoles(item);

this.WriteToLog(“Creating role ‘” + c_AuthorRoleName + “‘ in the site if needed”, true);
//create a security definition in the web for an author-editor
SPRoleDefinition def = CreateRoleInSite(currentWeb,c_AuthorRoleName,c_EditorPermissions);
this.WriteToLog(“Assigning role to the user”, true);
//Set the author user with the permissions defined
SPRoleAssignment authorRole = new SPRoleAssignment(authorUser.LoginName, authorUser.Email, authorUser.Name, authorUser.Notes);
this.WriteToLog(“Binding the role assignment of the user to the definition”, true);
authorRole.RoleDefinitionBindings.Add(def);
this.WriteToLog(“Adding the role to the item”, true);
item.RoleAssignments.Add(authorRole);
this.WriteToLog(“Updating the item”, true);
item.Update();
this.WriteToLog(“Success!”, true);
}
}
///
/// This function will make everyone with access to the item a reader.
/// Loops over all the roles that exist in the item, removes the bindings and adds the reader permission definition to them
///
/// the list item currently handled
private void ChangeItemExistingRoles(SPListItem item)
{
//get, and if necessary create, the reader role
SPRoleDefinition readerDef = CreateRoleInSite(item.Web, c_ReaderRoleName, c_ReaderPermissions);

foreach (SPRoleAssignment roleAssignment in item.RoleAssignments)
{
//delete the existing permissions
roleAssignment.RoleDefinitionBindings.RemoveAll();
//add the reader permission
roleAssignment.RoleDefinitionBindings.Add(readerDef);
roleAssignment.Update();
item.Update();

}
}
///
/// Gets and if necessary creates the role in the site.
///
/// The site where the role should be created
/// The name of the role to create
/// The permission set to give the role. Example: SPBasePermissions.EditListItems | SPBasePermissions.ViewListItems
///
private SPRoleDefinition CreateRoleInSite(SPWeb web,string roleName,SPBasePermissions permissions)
{
this.WriteToLog(“Checking if role ‘”+roleName+”‘ exists in the web”, true);
//check that the role exists
if (RoleExists(web, roleName))
{
this.WriteToLog(“Role exists in the web”, true);
//role exists – return it
return web.RoleDefinitions[roleName];
}
else
{
//role does not exist in the site- create it and return.
this.WriteToLog(“Role does not exist in the web. creating a new role”, true);
//Create the role definition in the web by the name specified in c_AuthorRoleName
SPRoleDefinition def = new SPRoleDefinition();
def.BasePermissions = permissions;
def.Name = roleName;
this.WriteToLog(“Adding the role to the FirstUniqueRoleDefinitionWeb”, true);
web.FirstUniqueRoleDefinitionWeb.RoleDefinitions.Add(def);
this.WriteToLog(“Updating the web”, true);
web.FirstUniqueRoleDefinitionWeb.Update();
web.FirstUniqueRoleDefinitionWeb.Dispose();
this.WriteToLog(“Reopening the current web object”, true);
web = web.Site.OpenWeb();
this.WriteToLog(“Verifying role is in current web”, true);
if (RoleExists(web, roleName))
return web.RoleDefinitions[roleName];
else
{
throw new Exception(“Role does not exist?”);
}

}
}
///
/// This function checks the spweb objec to see if a specific role exists (by name)
///
/// the spweb object for the site to contain the role.
/// the name of the role searched for
///
private bool RoleExists(SPWeb web, string roleName)
{
this.WriteToLog(“Loading the RoleDefinitions xml string:”, true);
this.WriteToLog(web.RoleDefinitions.Xml, true);
//read the xml of the roledefinitions
XmlDocument doc = new XmlDocument();
doc.LoadXml(web.RoleDefinitions.Xml);
this.WriteToLog(“Searching for the role in the xml”, true);
//search for the role with the name in the xml
XmlNode node = doc.SelectSingleNode(“//Role[@Name='”+roleName+”‘]”);
//if the search returned null, the role does not exist
if (node == null)
return false;
else
return true;
}
///
/// writes a message to the log file
///
/// The message to write
/// If true, the message will only get written when the code runs in debug mode.
private void WriteToLog(string message,bool debugOnly)
{
if (DEBUG_MODE || !debugOnly)
log.WriteToLogFile(message);
}
#endregion
}
///
/// Handles simple file logging. Recommend switching to trace log.
///
class HTMLFileLogging
{
#region class properties
private string logFolderPath = @”c:\logs”;
public string LogFolderPath
{
get
{
return logFolderPath;
}
set
{
if (Directory.Exists(value))
{
logFolderPath = value;
if (logFolderPath.EndsWith(“\\”))
{
logFolderPath = logFolderPath.Remove(logFolderPath.Length);
}
}
else
{
throw new DirectoryNotFoundException();
}
}
}
private string logFileName = “”;
public string LogFileName
{
get
{
return logFileName;
}
set
{
logFileName = value;
}
}
public string LogFilePath
{
get
{
return this.LogFolderPath + “\\” + this.LogFileName;
}
}

#endregion

#region CTOR
///
/// Create a HTMLFileLogging object
///
/// The path of the folder that will hold the log file (no file name)
/// The name of the file to create
/// When this is set to true and the folder does not exist, the code will create the folder.
/// When this is set to true and the file exists, the code will delete the file and create a new one
public HTMLFileLogging(string folderPath, string fileName, bool createPath, bool deleteFile)
{

this.LogFileName = fileName;

if (createPath && !Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
this.LogFolderPath = folderPath;
if (File.Exists(this.LogFilePath) && deleteFile)
{
File.Delete(this.LogFilePath);
}

}

#endregion

#region custom code
///
/// Writes a string to the log file.
///
/// a string to write. supports html tags.
public void WriteToLogFile(string message)
{
try
{
StreamWriter sw = new StreamWriter(this.LogFilePath,true);
sw.WriteLine(“”);
sw.WriteLine(“” + DateTime.Now.ToShortDateString()+ ” ” + DateTime.Now.ToLongTimeString() + ” ” + message + “”);
sw.WriteLine(“”);
sw.Flush();
sw.Close();
}
catch (Exception ex)
{
}
}

#endregion

}
///
/// Thanks to impersonation example of Victor Vogelpoel [Macaw]
/// http://dotnetjunkies.com/WebLog/victorv/archive/category/2032.aspx
///
public sealed class ImpersonationUtility
{
private static string ADMINDOMAINACCOUNT = @”domain\user”;//CHANGE THIS!
private static string ADMINDOMAIN = “domain”;//CHANGE THIS!
private static string ADMINACCOUNT = “user”;//CHANGE THIS!
private static string ADMINPASSWORD = “password”;//CHANGE THIS!
private WindowsImpersonationContext _wiContext;
public IntPtr token;
///
/// Private ctor.
///
private ImpersonationUtility()
{ }
///
/// Start impersonating the administrator.
///
/// an ImpersonationUtility instance.
public static ImpersonationUtility ImpersonateAdmin()
{
ImpersonationUtility imp = new ImpersonationUtility();
imp._ImpersonateAdmin();
return imp;
}
///
/// Undo the impersonation.
///
public void Undo()
{
if (this._wiContext != null)
{
this._wiContext.Undo();
this._wiContext = null;
}
}
private void _ImpersonateAdmin()
{
token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
try
{
// Only start admin impersonation if we’re not the admin…
if (String.Compare(ADMINDOMAINACCOUNT, WindowsIdentity.GetCurrent().Name, true, CultureInfo.InvariantCulture) != 0)
{
// Temporarily stop the impersonation started by Web.Config.
// WindowsIdentity.Impersonate() will store the current identity (the
// account of the requestor) and return to the account of the ApplicationPool
// which is “DOMAIN\SPAdmin”.
this._wiContext = WindowsIdentity.Impersonate(IntPtr.Zero);
// But somehow the reverted account “DOMAIN\SPAdmin” still does
// not have enough privileges to access SharePoint objects, so
// we’re logging in DOMAIN\SPAdmin again…
if (NativeMethods.LogonUserA(ADMINACCOUNT, ADMINDOMAIN, ADMINPASSWORD, NativeMethods.LOGON32_LOGON_INTERACTIVE,
NativeMethods.LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if (NativeMethods.DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
WindowsIdentity wi = new WindowsIdentity(tokenDuplicate);
// NOTE: Impersonate may fail if account that tries to impersonate does
// not hold the “Impersonate after Authentication” privilege
// See local security policy – user rights assignment.
// Note that the ImpersonationContext from the Impersonate() call
// is ignored. Upon the Undo() call, the original account
// will be reinstated.
wi.Impersonate();
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error(),
“Impersonation: Error duplicating token after logon for user \”DOMAIN\\SPAdmin\””);
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error(),
“Impersonation: Error logging on user \”DOMAIN\\SPAdmin\””);
}
}
}
finally
{
if (token != IntPtr.Zero)
NativeMethods.CloseHandle(token);
if (tokenDuplicate != IntPtr.Zero)
NativeMethods.CloseHandle(tokenDuplicate);
}
}
}
///
/// Thanks to impersonation example of Victor Vogelpoel [Macaw]
/// http://dotnetjunkies.com/WebLog/victorv/archive/category/2032.aspx
///
internal sealed class NativeMethods
{
private NativeMethods() { }

[DllImport(“kernel32.dll”, CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);

public const int LOGON32_PROVIDER_DEFAULT = 0;
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_LOGON_NETWORK = 3;

[DllImport(“advapi32.dll”)]
public static extern int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);

[DllImport(“advapi32.dll”, CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);

[DllImport(“advapi32.dll”, CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();
}
}

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s