When creating web parts, event receivers, timer jobs and other SharePoint code, I often find that I need to temporarily grant the code more permissions than the current user has. I’ve found that many developers either don’t know what options they have for user impersonation through code or are confused as to the subtle differences between the various options.

Impersonate the application pool identity

WSS V3 introduced the RunWithElevatedPrivileges method of the SPSecurity class. The RunWithElevatedPrivileges method impersonates the identity of the IIS application pool serving the current SharePoint request. The RunWithElevatedPrivileges method accepts a delegate method with no parameters. The RunWithElevatedPrivileges method impersonates the identity of the IIS application pool serving the current SharePoint request just prior to executing the user-specified delegate method. Once the delegate method has completed execution, the RunWithElevatedPrivileges method reverts the identity back to current user identity. Best of all: you don’t even need to know the username or password of the application pool identity. Here is some sample code that deletes a tasks list while impersonating the application pool identity:

Guid siteid = SPContext.Current.Site.ID;
Guid webid = SPContext.Current.Web.ID;

SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(siteid))
{
using (SPWeb web = site.OpenWeb(webid))
{
SPList taskList = web.Lists["Tasks"];
taskList.Delete();
}
}
});

There are a few gotchas of which you should be aware when using the RunWithElevatedPrivileges method:

  1. You code will need a the proper level of code access security (CAS) permissions in order to run the RunWithElevatedPrivileges method.
  2. While impersonating the IIS application pool identity will give your code the highest level of permission within the current SharePoint web application, your code will have minimal permissions within other SharePoint web applications. This usually makes the RunWithElevatedPrivileges method a poor choice if you need to access a different SharePoint web application from the one in which the code is currently executing.
  3. According to SharePoint deployment best practices, IIS application pool identities should have minimal permissions on the SharePoint web servers. This means that your code may have minimal access to the underlying web server while executing within the RunWithElevatedPrivileges delegate method. You may not be able to do things like write to the Windows Event logs, work with temporary files, access the registry, or any other web server resource that requires a high privilege level.
  4. This method was implemented in WSS V3, so it will be unavailable in WSS V2 or SharePoint Portal Server 2003.

 

Impersonate the application pool identity, take 2


Update: Thanks to Jonas for correcting me and apologies to Todd for misquoting him.


Todd Bleaker, SharePoint MVP, clued me in to this technique. Normally the .Net Framework System.Security.Principal.WindowsIdentity.Impersonate method accepts an integer value corresponding to a Win32 logon token. However, there is a neat trick you can use with the method: if you pass in a zero pointer (System.IntPtr.Zero), the method will allow your code to run as the identity of the IIS application pool serving the current SharePoint request. As with the RunWithElevatedPrivileges method, you do not need a username or password to do the impersonation. However, unlike the RunWithElevatedPrivileges method, you can use this technique with WSS V2 and SharePoint Portal Server 2003. Here is the same code as in the previous example, but altered to use this impersonation method:

private WindowsImpersonationContext ctx = null;
ctx = WindowsIdentity.Impersonate(System.IntPtr.Zero);

using (SPSite site = new SPSite(siteid))
{
using (SPWeb web = site.OpenWeb(webid))
{
SPList taskList = web.Lists["Tasks"];
taskList.Delete();
}
}

if (ctx != null)
ctx.Undo();

This impersonation method has the same caveats as the RunWithElevatedPrivileges method technique, except that this will work with WSS V2 and SharePoint Portal Server 2003:

  1. You code will need a the proper level of code access security (CAS) permissions in order to run the impersonation, WSS_Medium, according to Todd Bleaker’s article.
  2. While impersonating the IIS application pool identity will give your code the highest level of permission within the current SharePoint web application, your code will have minimal permissions within other SharePoint web applications. This usually makes impersonating the application pool identity a poor choice if you need to access a different SharePoint web application from the one in which the code is currently executing.
  3. According to SharePoint deployment best practices, IIS application pool identities should have minimal permissions on the SharePoint web servers. This means that your code may have minimal access to the underlying web server while executing within the RunWithElevatedPrivileges delegate method. You may not be able to do things like write to the Windows Event logs, work with temporary files, access the registry, or any other web server resource that requires a high privilege level.

 

Impersonate a named user account

While you can use the System.Security.Principal.WindowsIdentity.Impersonate method to impersonate the Local System account, the real purpose of the method is to allow you to impersonate named user accounts, such as mydomainjsmith. The .Net Framework has a nice model for handling the impersonation context once you have a logon token but is somewhat vague on the mechanics of actually getting logon tokens. My RunAs in C# article with source code details how to get these elusive logon tokens and execute your code in the generated impersonation context. The article wraps the LogonUser Win32 API. The main benefit to this approach is that you can execute code as any user you want, as long as you know the user’s username and password. This includes doing highly privileged operations within SharePoint, SharePoint farm servers, or any other server on the network. Here is a code sample that executes a file move using user-supplied credentials:

BlackBlade.Utilities.SecurityUtilities.RunAs(delegate()
{
File.Move(“local_file”, “network_file_location”);
},
“a_username”,
“some_password”);

What are the catches:

  1. You need to know the username and password of the account you want to impersonate.
  2. Accessing the Win32 API can generate non-intuitive error messages and be tough to debug.
  3. Finding a secure place to store the username and password of the account your impersonating can be tough. I recommend looking at the MOSS 2007 SSO infrastructure.

 

Impersonate the Local System Account

Normally the LogonUser Win32 function used to get logon tokens for .Net impersonation requires a domain, username, and password to get a logon token. However, there is a neat trick you can use with the method: if you pass in “NT AUTHORITY” for the domain and “Local System” as the username, the method will allow your code to run as the Local System account. You do not need a password. The Development Hole blog has a great article with code detailing how to impersonate Built-In service accounts. The Local System account can do pretty much anything on any SharePoint server in the farm. As with the other impersonation methods, you will need to manually revert the impersonation context. Here is some code that uses the Impersonate method to write an entry to the local SharePoint server’s Application event log:


using (Impersonation imp = new Impersonation(BuiltinUser.NetworkService))
{
this.EventLog.WriteEntry("This line would throw an exception for most SharePoint users or even most application pool identities");
}

If this method allows you to impersonate the Local System account and act as a local SharePoint server administrator at will, why would you not always want to use this impersonation method? Here are a couple of reasons:

  1. This method always impersonates the web server’s Local System account, regardless of in which SharePoint web application the code is running. This can make it very difficult to track which web application is accessing the web server’s resources.
  2. In most cases, the Local System account will not have rights to any network resources, including SharePoint content or administrative tasks. While you’ll be able to do anything you want on the local web server, you will not be able to engage in any SharePoint-related activities.

 

Technorati Tags: WSS,SharePoint,MOSS 2007,C#