Daniel's profileDaniel Larson's Develope...BlogListsGuestbookMore Tools Help

Blog


    June 13

    Elevated Privilege with SPSite

    Here is a code sample of a utility class for elevated privileges using the best practices outlined in my last post.  99% of the time you'll be able to get the system token using site.SystemAccount.UserToken. However, you may need to elevate privilege if the current user doesn't have permission to read that object from the SPSite. In this case, you'll need to elevate privilege just to get the user token-- but we don't want to perform any operations inside RunWithElevatedPrivilege, we only want to get a token out (which is basically a simple byte array). You could also cache the system token in the application if you needed to, although I'm not sure I'd endorse that.

    The following static class includes two methods that will reliably run in all security contexts, assuming the assembly has the right CAS permissions. The GetSystemToken method returns a token, while the GetElevatedSite returns an elevated SPSite context. Be sure you wrap these in a using statement to avoid any leaks, and you're safe to pass in the SPContext.Current.Site object to these methods.

    Also, these methods should be used in working with SharePoint's security, not just to bypass it. Just because you can doesn't mean that you should, so be sure to practice trustworthy computing practices in your code.  

    using System;
    using Microsoft.SharePoint;

    namespace LitwareSecurity
    {
        /// <summary>A class for working with elevated privilege</summary>
        public static class SpSecurityHelper
        {
            /// <summary>Returns an elevated site</summary>
            /// <param name="theSite">
            /// The site that you want an elevated instance of.
            /// You must dispose of this object unless it is part of SPContext.Current.
            /// </param>
            /// <returns>An elevated site context.</returns>
            /// <remarks>Be sure to dispose of objects created from this method.</remarks>
            public static SPSite GetElevatedSite(SPSite theSite)
            {
                var sysToken = GetSystemToken(theSite);
                return new SPSite(theSite.ID, sysToken);
            }

            /// <summary>Gets a UserToken for the system account.</summary>
            /// <param name="site"></param>
            /// <returns>A usertoken for the system account user./returns>
            /// <remarks>Use this token to impersonate the system account</remarks>
            public static SPUserToken GetSystemToken(SPSite site)
            {
                site.CatchAccessDeniedException = false;
                try {
                    return site.SystemAccount.UserToken;
                }
                catch (UnauthorizedAccessException) {
                    SPUserToken sysToken = null;

                    // Only use runwithelevated to grab the system user token.
                    SPSecurity.RunWithElevatedPrivileges(
                        delegate()
                        {
                            using (SPSite lolcatKiller = new SPSite(site.ID)) {
                                sysToken = lolcatKiller.SystemAccount.UserToken;
                            }
                        }
                    );
                    return sysToken;
                }
            }
        }
    }

    June 09

    Link: How we did Social Sites 2.0

    Today, we're shipping NewsGator Social Sites 2.0. Check out my guest post on the Microsoft SharePoint Blog:

    How We Did It: NewsGator Social Sites 2.0 - Enhanced Social Computing on the SharePoint Platform

    June 06

    Best Practices for Elevated Privilege in SharePoint

    Elevated Privilege can be used to bypass or work with security, and can be performed either through SPSecurity or through impersonation techniques involving the SPUserToken and the SPSite class. It's one of the most misunderstood aspects of the SharePoint API, but in general you should always prefer impersonation using the SPSite class and SPUserToken objects.

    While I've been ranting about SPSecurity over the last few days, it can be useful for running code under the context of the application pool for code that access network or file resources, or for MOSS code that does not support impersonation through the SPSite object. Without further introduction, here's my list of best practices for elevated privilege code in SharePoint that will help you create more reliable applications for the enterprise.

    • Avoid using SPSecurity.RunwithElevatedPrivilege to access the SharePoint object model. Instead, use the SPUserToken to impersonate with SPSite.
    • If you do use SPSecurity.RunwithElevatedPrivilege, dispose of all objects in the delegate. Do not pass SharePoint objects out of the RunwithElevatedPrivilege  method.
    • Only use SPSecurity.RunwithElevatedPrivilege to make network calls under the application pool identity. Don't use it for elevation of privilege of SharePoint objects.
    • Always use the SPSite constructor with an SPUserToken to create an elevated privilege security context in SharePoint. To impersonate the system, use the SystemAccount.UserToken property of the current SPSite context, such as:
      var site = new SPSite(SPContext.Current.Site.ID,  SPContext.Current.Site.SystemAccount.UserToken);
    • Avoid passing SharePoint objects between different security contexts (SPSite instances), with the exception of the SPUserToken used in the SPSite ctor. An SPUser object created from SPSite A cannot (reliably) be passed to SPSite B. This can be the source of obscure bugs in production that are difficult to reproduce in development. For example, an SPUser reference created from SPContext.Current.Site cannot reliably be used in an elevated site context, as the user reference may take on a different meaning in the alternate context.
    • Never use elevated privilege to bypass security-- always use it to work with security.
    • Restrict what assemblies can use elevated privilege by running in minimal trust, avoiding the GAC, and auditing any CAS policies deployed with vendor solutions.
    June 05

    SharePoint Security: The Evils of RunWithElevatedPrivilege (and our hero, SPUserToken)

    Since I've been ranting on this for a few days, I thought I'd wrap it up. When SPSecurity was first found, we thought it was the best thing in the API since since SPPeanutButter. We used it... we abused it... we loved it. Over the course of the last few months though, it betrayed us. We started to see all sorts of obscure bugs when working with the SharePoint object model within the delegate in RunWithElevatedPrivelege. One such issue was with My Sites. Somehow, we managed to abuse SPSecurity.RunWithElevatedPrivilege enough to disable MySite creation in the current ASP.NET application in completely unrelated code. Through simple calls sent through RunWithElevatedPrivilege we were able to corrupt the ASP.NET application instance so that MySites could not be created, with another misleading error message on the failed My Site creation page. QA loved this, of course.

    As the MSDN documentation says, SPSecurity.RunWithElevatedPrivelege "Executes the specified method with Full Control rights even if the user does not otherwise have Full Control." What it does is it uses the Win32 ImpersonateSelf API method to drop down to the thread's identity. There's a lot of hairy native code that's used to do this... just check out the method with Reflector. What we found was that all SP object model instances need to be created and disposed of inside of the delegate-- and even that can cause obscure bugs.

    I'm not recommending to never use SPSecurity-- but I will recommend to never use SPSecurity to access or manipulate the SharePoint object model. There's too much overhead, too much chances of introducing obscure bugs, and too much potential abuse. Only us SPSecurity.RunWithElevatedPrivelege to use the application pool's credentials for network calls. And for that, you may be better off simply using WindowsImpersonationContext and WindowsIdentity.Impersonate(IntPtr.Zero).

    For all other impersonation needs, use the SPUserToken to impersonate. Remember that the elevation of the object model happens through the SPSite constructor- no matter which elevation method you use, either through RunWithElevatedPrivilege or though simple impersonation using the user token. 

    To impersonate the SYSTEM and use elevated privilege, get the user token from the SYSTEM ACCOUNT. Fortunately, the SystemAccount SPUser is a property of any SPSite object. So instead of using SPSecurity.RunWithElevatedPrivelege, you can use the following code to perform elevated actions:

     

    SPUserToken sysToken = SPContext.Current.Site.SystemAccount.UserToken;
    using(var systemSite = new SPSite(SPContext.Current.Site.ID, sysToken))
    {
        using (var sysWeb = systemSite.OpenWeb(SPContext.Current.Web.ID))
        {
            // Perform elevated actions here
        }
    }

    June 03

    Please, just say no to RunWithElevatedPriveleges!

    You were warned. But you just HAD to use SPSecurity.RunWithElevatedPrivileges. See what you did???

    kitteez

    June 02

    RunWithElevatedPriveleges kills baby lolcats.

    It's official. SPSecurity.RunWithElevatedPrivileges is one of the most evil methods in the SharePoint API. Just say no, and use the SPUserTokens for impersonation. Please, it's for the lolcatz.

     

    spsecuritykillzlolcats