SharePoint: How to get SystemAccount token
As you probably know RunWithElevatedPrivileges allows to run code under the Application Pool identity, which has site collection administrator privileges on all site collections hosted by that application pool. In my opinion RunWithElevatedPrivileges provides too many rights for code, which usually operates in the bounds of only one certain site collection. That is why instead of using RunWithElevatedPrivileges I prefer dealing with an elevated SPSite-object created with SPUserToken of SystemAccount of the target site collection. SystemAccount or SHAREPOINT\system is an alias for the site collection administrators and it has full control over all content in the site collection. We can get it using property SystemAccount.UserToken of SPSite-object. However sometimes the current user doesn’t have permissions to access that property, in this case we will have to use RunWithElevatedPrivileges I’ve criticized above :). The method retrieving the token of SystemAccount can look like the following:
protected static SPUserToken GetSystemToken(SPSite spSite) { SPUserToken res = null; bool oldCatchAccessDeniedException = spSite.CatchAccessDeniedException; try { spSite.CatchAccessDeniedException = false; res = spSite.SystemAccount.UserToken; } catch (UnauthorizedAccessException) { SPSecurity.RunWithElevatedPrivileges(delegate() { using (SPSite elevatedSPSite = new SPSite(spSite.ID)) res = elevatedSPSite.SystemAccount.UserToken; // (***) }); } finally { spSite.CatchAccessDeniedException = oldCatchAccessDeniedException; } return res; }
Here spSite.CatchAccessDeniedException=false allows us to catch and handle UnauthorizedAccessException by ourself, and if the exception happens, we elevates privileges to read the user token by means of RunWithElevatedPrivileges. As we know the most of SharePoint objects somehow refers to SPSite and SPWeb objects, in context of which these SP-objects were created. From this viewpoint the GetSystemToken can look potentially buggy in the line marked with (***), because method returns SPUserToken while its parent elevatedSPSite is being disposed. To justify this code we should take a look at SPUserToken class kindly provided by .Net Reflector:
public sealed class SPUserToken { // Fields private byte[] m_token; // Methods public SPUserToken(byte[] token); public bool CompareUser(SPUserToken userTokenCheck); // Properties public byte[] BinaryToken { get; } }
As you can see SPUserToken is just an array of bytes, it doesn’t contain any references to any parental SharePoint objects, therefore we can return it from the method freely. Once SPUserToken is received, it can be cached for a while and reused.
If you don’t have any original SPSite-object (for example, you have a simple console application) you should create it, e.g.
protected static SPUserToken GetSystemToken(string siteUrl) { SPUserToken res = null; using (SPSite spSite = new SPSite(siteUrl)) res = GetSystemToken(spSite); return res; }
Thanks!