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();
}
}
});
- You code will need a the proper level of code access security (CAS) permissions in order to run the RunWithElevatedPrivileges method.
- 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.
- 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.
- 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();
- 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.
- 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.
- 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:
- You need to know the username and password of the account you want to impersonate.
- Accessing the Win32 API can generate non-intuitive error messages and be tough to debug.
- 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");
}
- 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.
- 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.
You're missing SPSite impersonation, a much better way to elevate within SharePoint.
Cheers ~
Keith
Keith, thanks for the comment. You’re right, supplying a user token to the SPSite constructor is a good option for user impersonation in SharePoint. The only reason I did not include it in this article is because that method does not actually alter the identity of the executing thread. This can lead to inconsistent behavior when accessing SharePoint and non-SharePoint resources. Nevertheless, I should have included that as an option and just listed the caveats. Thanks!
Eugene,
private WindowsImpersonationContext ctx = null;
ctx = WindowsIdentity.Impersonate(System.IntPtr.Zero);
This does NOT
"impersonate the Local System account"
It reverts the impersonation and thus runs as the application pool identity.
/Jonas
Jonas, thanks for correcting me. I confirmed with Todd that I had misquoted him. I've corrected this post.
Eugene,
Sorry to be such a picky reader but you can NOT impersonate the SYSTEM account or for that matter Network service UNLESS you run as SYSTEM…
Imagine the security implications if you could… The SYSTEM account has unrestricted access to the local machine so that is a VERY powerful account which you DON'T want people to be able to run as… You can schedule NT jobs and configure NT services to run as SYSTEM IF you are an administrator.
The whole reason for Network
There are ways to impersonate users without having to know their passwords using protocol transition. But still if you want to access resources using this approach you have to have a gateway service running as SYSTEM
http://msdn.microsoft.com/en-us/magazine/cc163500.aspx
Thanks
/Jonas
Nice post!
Are there any caveats when the authentication type between to web applications is different? e.g. One web application has some exotic custom authentication and role provider and the other one is windows or FBA.
Hope to here from you!
Kristof, great question. The main caveat when trying to access content in a web application from code running a different web application is generally one of authorization rather than authentication. Usually SharePoint application pool identities only have access to content in their own web applications.
Based on my experience, the authentication and impersonation works pretty much the same way, regardless of the underlying authentication provider. The operating system thread that is running your code will always have some identity context. We use this principal in our SharePoint products specifically to provide support for FBA and Windows Live ID users.
If you have a specific scenario in mind, I'd love to hear it. It would probably be a very interesting conversation.
The most detailed article about Impersonation in Sharepoint.
Thanks,
Raghav