Access denied within SPSecurity.RunWithElevatedPrivileges


     Learned something really interesting (and a few lessons) in the last few days. We were doing an operation within a webpart which required higher level of access. Since this was to be executed irrespective of the access of the user logged in, we had the code enclosed within the SPSecurity.RunWithElevatedPrivileges. Surprisingly the code was failing and showing "Error : Access Denied". I remembered having seen this issue earlier on another project. That time we had a workaround which looked elegant and we didn't need to investigate the root cause. But now things were not as good and made me think this was going to be a bummer.  Luckily I was able to figure it out in time.  Let me explain this with the below code that throws access denied even though it is wrapped within the SPSecurity.RunWithElevatedPrivileges.

The code is part of a webpart that just displayed all the users in the owners group of the current site.  This code runs fine with users having Full control or Contribute access. But fails for users having only Read access. 

Label  labelUsers;  

protected override void CreateChildControls() {

 labelUsers = new Label();   

this.Controls.Add(labelUsers);  

SPSecurity.RunWithElevatedPrivileges(delegate() {

   SPSite site = SPContext.Current.Site;   

   SPWeb web = SPContext.Current.Web;  

   SPGroup group = web.Groups.GetByID(3);//get the owners group

   if (group != null) {

            StringBuilder users = new StringBuilder();  

             for (int cnt = 0; cnt < group.Users.Count; cnt++) {   

                   users.AppendFormat("{0},", group.Users[cnt]);

              }

                      labelUsers.Text = users.ToString();//display it on the label 

 

              }//End of "If" block 

        });//Close "SPSecurity.RunWithElevatedPrivileges" block

 }

  This code throws an exception for Read users at the line "for (int cnt = 0; cnt < group.Users.Count; cnt++)". This line fails when the Users collection withing the SPGroup it being accessed.

Looks like the SPSecurity class is not behaving correctly here but lt is working perfectly in the way it is supposed to.Though the entire code is enclosed within SPSecurity.RunWithElevatedPrivileges not all code is able to run with the elevated privileges. So the rule is --  The code will not run within elevated privilege if the object accessed was not created within the SPSecurity.RunWithElevatedPrivileges block. If we take a relook at the code we can see that the instances of SPSite (i.e. site object ) and SPWeb (i.e. web object) are retrieved through the current SPContext. The SPContext is created much before our elevated privilege code runs. Accessing the child objects of the SPWeb instance in form of "web.Groups.GetByID(3)" returns a SPGroup object which will also fail to run within the elevated privilege. And once we (with only read access) try to access the Users collection within the SPGroup object Sharepoint rings the bell indicating the information is classified. It throws you out of execution by rasing an exception.

 

    Now that we know the reason for the error, the problem doesn't look too tough and in reality the solution is simple. To run this code successully we need to create the SPSite and SPWeb instances within the SPSecurity.RunWithElevatedPrivileges. So we have the new code below (the changes are highlighted)

 Label labelUsers;

 protected override void CreateChildControls(){

    labelUsers =  new Label();

    this.Controls.Add(labelUsers);

    SPSecurity.RunWithElevatedPrivileges(delegate(){  

        SPSite site = SPContext.Current.Site;   

        SPWeb web = SPContext.Current.Web;  

         using (SPSite newSite = new SPSite(site.ID)) {  

            using (SPWeb newWeb = newSite.OpenWeb(web.ID)){ //Do not use the site object to create the SPWeb instance else the code will still fail     

                SPGroup group = newWeb.Groups.GetByID(3);  //get the owners group      

                if (group != null) {   

                    StringBuilder users = new StringBuilder();                    

                    for (int cnt = 0; cnt < group.Users.Count; cnt++) {  

                            users.AppendFormat("{0},", group.Users[cnt]);

                    }

                    labelUsers.Text = users.ToString();

//display it on the label

              }// End of "If" block

          }// End of using for SPWeb

       }// End of Using for SPSite

   });//End of SPSecurity.RunWithElevatedPrivileges 

}

 This code now works beautifully.

With some more space to write let me jot down the lessons learned  (little bits of wisdom we cannot afford to ignore 😉 )

Lesson 1 -  Just putting your code within SPSecurity.RunWithElevatedPrivileges does not guarantee your code to run successfully irrespective of the access of the user logged in. You may want to look at the code carefully when writing it and look back at it again once you have written thinking that it will work fine no matter what.

Lesson 2 - No matter how confident you are with your code, its always better in sharepoint to unit test your code with all three types of user access (i.e. Owner/Full control access, Members/Contribute access and Read/Visitor access). I have made it a point to write my unit tests with all the three types user access in consideration and hopefully will be able to avoid similar mistakes in future.

Lesson 3 - And the final one. As one of my friend says "the world is round". So things we ignore (or maybe just use some workarounds no matter how elegant) do come back to us :-). In software it always pays to get to the root of the problem even if there is a workaround to the problem.  

Comments (14)

  1. Nice post, you saved my day says:

    Nice post, well written,  you saved my day

  2. Hi Sohail,

    I also facing same kind of prolem with read only user but in my code i have override SiteMapNodeCollection GetChildNodes(SiteMapNode node) and if user has read only permisson this method is not called  by sharepoint , can you please provide some idea.

  3. Satz says:

    Very helpful post. Saved my time.

    Cheers!!

    keep rocking

  4. venkat says:

    good one… keep posting these type of tips…

  5. Venkadesh says:

    Very Useful. Nice Post… Keep Going !!!

  6. vishal says:

    nice blog thanks for details boot cause of problem and solution

  7. Subbiah says:

    Nice post with a clean explanation. Thank you!

  8. Tommy says:

    Brilliant!! Thank you.

  9. Mike Catignani says:

    This is a very interesting article and a real eye opener for many developers even seasoned developer like myself – many thanks for sharing this – http://www.solutionsdeveloped.co.uk

  10. Ankitkumar Malde says:

    Important piece of Information for SharePoint beginners…!!!!

  11. Andrew says:

    This just saved my sanity! Thank you 😀

  12. Mike I says:

    Thanks for this nugget of wisdom…..  Been beating my head on the desk for 2 days trying to figure out why a code block was not behaving as I expected.

  13. Manas Behera says:

    Conceptual post..Thanks for the same

Skip to main content