Running SharePoint Code with Elevated Privileges – A Real Example

By , August 31, 2009

In case you didn’t know, there is a construct built into SharePoint that allows developers to create code that runs as the System Account instead of the logged in user, essentially giving that user Administrator Level Permissions in a confined space. I will go over the code required to do this below, but essentially you have a block of code within your larger project that needs the logged in user to have certain permissions that they may not have, and this small block of code will then be run as the System Account, giving it the permissions needed for the task at hand.

Well, at first thought everyone I have explained this to has the same questions and concerns, “Why would you ever want to do that?” or “That is a huge security risk!”.
I could never come up with a very good example to explain it and my attempts to reassure customers that the security risk is very minimal as the user will only have permission to do exactly what the developer lets them sometimes was not well understood.

Well I finally had a project that required me to do this, so I figured I would share it to give a fairly simple real world example.

Project Objective: Create an extranet to serve as a customer support site where users can log Service Requests, manage their account, order new products, etc. via the web or by phone.

This is fairly simple and something I have done several times for different customers, but this project had one difference. Service / Support Requests could be made by phone, where all of my other projects were strictly web oriented. Does anyone see the problem this raises yet? Well I eventually incorporated the Cisco phone system into the site to generate Service Requests, but that is not what I am talking about. With any system like this, it is vital that customers only have access to their own Service Requests (as in they cant view other user’s requests).

Typically, when using a SharePoint list one can turn on the settings in the Advanced Settings section of a List (seen below) so that users can only view and edit their own List Items. This is very handy and works very well when users are always the creator of their own items, but in this case when someone calls in, someone else will be creating the service request for them… see the problem? Well, I thought about trying to change the Created By field to the user that called in, but decided it would be a neat place to use the elevated permissions approach.

Advanced List Settings

The Solution: So, this is the summary of what I did. I didn’t give any customers permissions to the Service Request List at all from within SharePoint. All access that customers had to that List was done through custom forms and web parts that made use of the elevated permission construct. This ended up being 3 forms and 3 web parts that used Elevated Permissions. Customers would use one form to create a Service Request, another to view it, another to edit it and then three web parts to display the contents of the list on various pages.

I added a custom text field to the list called Customer ID which would store each customer’s unique ID, detailing who each Service Request belonged to. The custom forms that users would use would populate this field upon creation by looking to see who the current user was, and looking up their ID in another List. Likewise when a member of the support staff was creating a service request received over the phone, they would fill in the Customer’s ID before creating it (The phone system was later used to automate this). This way, we are not relying on the Created Field to limit what each user is allowed to see.

Below I will go through the basics of how Elevated Permissions work and then show in more detail how I used it in my solution. Then in the next few days I hope to stick out a web part that incorporates it as well.

This is the basic code snippet you need to run with elevated permissions:

private void yourFunction()
{
      // Non-Elevated Permission Code Goes Here

      SPSecurity.RunWithElevatedPrivileges(delegate()
      {
            // Elevated Permission Code Goes Here
      });      

      // Non-Elevated Permission Code Goes Here
}

Pretty much everything you find online about this has code that is poorly explained, so hopefully I can do a decent job and make it easy. The code above is simple enough right? Well here is one place people routinely run into problems. If you are using an instance of SPWeb or SPSite before your Elevated Permission Code block, you won’t be able to use it. You need to get a new instance of the SPWeb or SPSite object to use once you enter the elevated block. Below is the code that I use to do this.

private void yourFunction()
{
      SPSite site = SPContext.Current.Site;
      SPWeb web = SPContext.Current.Web;

      SPSecurity.RunWithElevatedPrivileges(delegate()
      {
            using (SPSite ElevatedSite = new SPSite(site.ID))
            {
                  using (SPWeb ElevatedWeb = ElevatedSite.OpenWeb(web.ID))
                  {
                        // Code Using the SPWeb Object Goes Here
                  }
            }
       });
}

I am pretty sure that little tidbit cost me about a day the first time I tried to play with Elevated Permissions, so hopefully that will help some of you out. After that, it is really simple as you just put your code in the middle of it just like you would if you weren’t using the elevated permissions.

As further example, in my NewSR.aspx form that users go to when creating a new Service Request, I use a runWithElevatedPrivileges block in two functions. The first is a private function I call within the OnPreLoad() function called LoadData(). Inside this function I am populating drop down menus from data in a SharePoint list for the Priority of the service request and the products that are affected.

The second function with a runWithElevatedPrivileges block is my onSubmit() function that is called when a user clicks the submit button.

New SR Form

So it is actually pretty simple. The only other thing I am going to demonstrate is how I made the view and Edit Forms Secure. As you probably know, every List Item has an integer ID (.ID) and a unique guid ID (.UniqueID). Well, the custom forms I made for view and edit look in the querystring for a guid which it then uses to look up the Service Request. (If you can guess the guid of another service request, well you broke my security but it seems quite unlikely) There isn’t anything fancy about accessing the querystring to get the guid and look up the Service Request, but I thought it would be handy to store a link to the item within the item itself as an additional field. This makes it easy to email the user a link to view their service request among other things.

So I created a text field called Link and populated it as shown below.

private void yourFunction()
{
      SPSite site = SPContext.Current.Site;
      SPWeb web = SPContext.Current.Web;

      SPSecurity.RunWithElevatedPrivileges(delegate()
      {
            using (SPSite ElevatedSite = new SPSite(site.ID))
            {
                  using (SPWeb ElevatedWeb = ElevatedSite.OpenWeb(web.ID))
                  {
                        srList = ElevatedWeb.Lists["Service Requests"];
                        SPListItem newItem = srList.Items.Add();
                       
                        // Do stuff to create the list item
 
                        ElevatedWeb.AllowUnsafeUpdates = true;
                        newItem.Update();
                        Guid temp = newItem.UniqueId;
                        newItem["Link"] = "<DIV><a href=\"https://YourSite.com/_layouts/custom/ViewSR.aspx?ID=" + temp.ToString("d") + "\">View SR</a></DIV>";
                        newItem.Update();
                        ElevatedWeb.AllowUnsafeUpdates = false;
                  }
            }
       });
}

The tricky part here is having to call item.update() twice. You have to call it twice because the first time you call it is when the list item is actually created. Before then, it does not have a Unique ID to reference. So once it is created, you can grab the Unique ID, and populate the Link field with a HTML formatted URL that references the item and can be easily inserted into a HTML based email or a page that has a content editor web part CEWP with the JavaScript in it found here. You then call update the second time to save your link field.

Support Screen with Link

The use of the link field and the JavaScript found above allows me to render links in a web part as shown above.

Well, hopefully this will be useful to someone – I think it would have saved me a day or so once upon a time when I first tried to do this.

8 Responses to “Running SharePoint Code with Elevated Privileges – A Real Example”

  1. Scott H says:

    That is useful information Steve. I think I have an HR recruitment process that could use something like this, as we want some of our users to be able to initiate a workflow to begin recruitments on certain list items (positions), without being able to edit those items through the standard SharePoint list interface. I’m still working on getting caught up on your “Getting Started” tutorial, but hopefully down the line I can use this. Thanks!

  2. Steve Pye says:

    Hi Steve,

    I have another application where elevated user rights would be very advantageous. Please feel free to contact me, maybe we could jointly build it and demonstrate it.

    Thanks,

    Steve Pye

  3. Yonix says:

    Nice … used the elevated code block to connect to a database using windows Auth.

  4. Daniel Scott says:

    Hi Steve, thanks for confirming my suspiscions about needing a new SPWeb, SPList etc object created in the context of the elevated permissions – it explains neatly why my elevated code isn’t getting elevated permissions.

    For what it’s worth, I can think of plenty of good justifications for having code run elevated. Infact the code I’m working on right now is event receiver code which checks that no too items in the list have the same “document code” (which is a human-friendly unique alphanumeric identifier). Of course, it needs to be able to prevent duplicate numbers even if the logged in user doesn’t have access to all the documents in the list (some of them will contain sensitive information and will have restricted permissions).

    In another example in this same system, the process which generates new “document codes” records information about the last generated number in another list. We don’t want ordinary users to be able to mess with this list, so again this code needs to run elevated.

    Hope that helps when you’re next arguing the whys and wherefores

    Daniel

  5. Daniel Scott says:

    Oh, and while I think of it, like Yonix, I too have used the elevated scheme in sharepoint to connect to an external SQL Server database and fetch information (using Windows Authentication), regardless of the logged in user’s credentials.

    The interesting conundrum much of the time is that because the RunWithElevatedPrivileges method uses a delegate with no parameters, it’s not possible to (easily) pass arguments to your “elevated” code.

    My solution to this has generally been to create helper “command” classes that take a bunch of arguments in their constructor and then have a parameterless Execute() method (which contains a call to SPSecurity.RunWithElevatedPrivileges that invokes a private parameterless method). The class can then return something via a read-only property (or properties).

    Thus you end up with some calling code like:

    ElevatedQuery qry = new ElevatedQuery(listID, “MyField”, valueToFind);
    qry.Execute(); // builds and executes caml query object in elevated code

    foreach (int id in qry.ResultItemIDs) {

    }

    Daniel

  6. Antonio Gutierrez says:

    Hi:

    This is a very interesting article. I just have one question: I’m showing files from a documentset library as html links on a grid, but how can I allow those links to be open by users with no permissions to the list? I mean, how to execute the link itself with elevated privileges?

    Thanks in advance

  7. Sunil says:

    Hi,

    I have one issue, Workflow is not starting due to user is elevated to System account and SharePoint 2010 don’t kick off workflow for system account.

    How to reslove this issue.

  8. Joe Smoe says:

    I am trying to update the web.config in my feature activation. It worked on my box but does not work on my dev box. I do not see any errors. I added the code to run with elevated
    privileges. Any ideas why my web.config is not updated?

    Thanks

Leave a Reply