2

I'm using the below code to activate the "SharePoint Server Publishing Infrastructure" feature for a site collection. My code runs fine when I'm logged in as a site collection administrator. The purpose is a less privileged user can also activate this feature, through my custom app page with a custom button with the following code behind.

SPSecurity.RunWithElevatedPrivileges(delegate()
        {           
                SPSite CurrentSite = SPContext.Current.Site;               
                CurrentSite.AllowUnsafeUpdates = true;
                CurrentSite.Features.Add(new Guid("{f6924d36-2fa8-4f0b-b16d-06b7250180fa}"));
                CurrentSite.AllowUnsafeUpdates = false;                         
        });

        }

For a less privileged user the pressing teh button results in the access denied page. And below data in the error logs:

Feature Activation: Activating Feature 'PublishingPrerequisites' (ID: 'a392da98-270b-4e85-9769-04c0fde267aa') at URL

Feature Activation: Failed to ensure feature dependencies for feature 'PublishingSite' (id: 'f6924d36-2fa8-4f0b-b16d-06b7250180fa'), exception thrown: System.Threading.ThreadAbortException: Thread was being aborted.
at System.Threading.Thread.AbortInternal()
at System.Threading.Thread.Abort(Object stateInfo)
at System.Web.HttpResponse.End()
at Microsoft.SharePoint.Utilities.SPUtility.Redirect(String url, SPRedirectFlags flags, HttpContext context, String queryString)
at Microsoft.SharePoint.Utilities.SPUtility.RedirectToAccessDeniedPage(HttpContext context)
at Microsoft.SharePoint.Utilities.SPUtility.HandleAccessDenied(HttpContext context)
at Microsoft.SharePoint.Utilities.SPUtility.HandleAccessDenied(Exception ex)
at Microsoft.SharePoint.SPSecurableObject.CheckPermissions(SPBasePermissions permissionMask)
at Microsoft.SharePoint.SPSecurity.ValidateSecurityOnOperation(SPOperationCode code, SPSecurableObject obj)
at Microsoft.SharePoint.SPFeature.AddRowToFeaturesTable(SPFeaturePropertyCollection props, SPSite site, SPWeb web, Boolean fForce)
at Microsoft.SharePoint.SPFeature.Activate(SPSite siteParent, SPWeb webParent, SPFeaturePropertyCollection props, Boolean fForce)
at Microsoft.SharePoint.SPFeatureCollection.AddInternal(SPFeatureDefinition featdef, Version version, SPFeaturePropertyCollection properties, Boolean force, Boolean fMarkOnly)
at Microsoft.SharePoint.SPFeatureCollection.CheckSameScopeDependency(SPFeatureDefinition featdefDependant, SPFeatureDependency featdep, SPFeatureDefinition featdefDependency, Boolean fActivateHidden, Boolean fUpgrade, Boolean fForce, Boolean fMarkOnly)
at Microsoft.SharePoint.SPFeatureCollection.CheckFeatureDependency(SPFeatureDefinition featdefDependant, SPFeatureDependency featdep, Boolean fActivateHidden, Boolean fUpgrade, Boolean fForce, Boolean fMarkOnly, FailureReason& errType)
at Microsoft.SharePoint.SPFeatureCollection.CheckFeatureDependencies(SPFeatureDefinition featdef, Boolean fActivateHidden, Boolean fUpgrade, Boolean fForce, Boolean fThrowError, Boolean fMarkOnly, List`1& missingFeatures)
at Microsoft.SharePoint.SPFeatureCollection.CheckFeatureDependencies(SPFeatureDefinition featdef, Boolean fActivateHidden, Boolean fUpgrade, Boolean fForce, Boolean fMarkOnly)
at Microsoft.SharePoint.SPFeatureCollection.AddInternal(SPFeatureDefinition featdef, Version version, SPFeaturePropertyCollection properties, Boolean force, Boolean fMarkOnly)

Updated (Working!) Code:

 private void SubmitButton_Click(object sender, EventArgs e){

        SPSecurity.RunWithElevatedPrivileges(delegate()
        {
            using (SPSite CurrentSite = new SPSite(SPContext.Current.Site.ID))
            {
                Microsoft.SharePoint.Utilities.SPUtility.ValidateFormDigest();
                CurrentSite.Features.Add(new Guid("{f6924d36-2fa8-4f0b-b16d-06b7250180fa}"));
        });
    }
1
  • May I know how can I get the GUID of a feature ? CurrentSite.Features.Add(new Guid("{f6924d36-2fa8-4f0b-b16d-06b7250180fa}")); Wim Hill, how did you got the GUID of that feature ? Thanks in advance.
    – Zakir HC
    Feb 3, 2012 at 13:18

3 Answers 3

10

You should not use SPContext.Current.Site in the delegate method. Instead instantiate a new SPSite within the delegate. That's why you still get an access denied I would assume.

So, replace

SPSite CurrentSite = SPContext.Current.Site; 

With:

SPSite CurrentSite = new SPSite(SPContext.Current.Site.Id); 

And use a using statement around the CurrentSite like so:

using(SPSite CurrentSite = new SPSite(SPContext.Current.Site.Id))
{
       // your code
}
4
  • It didn't solve the issue but the error logging changed: The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again. (See Updated Code)
    – Wim Hill
    Jan 25, 2012 at 9:38
  • 2
    That is because you stripped the AllowUnsafeUpdates away. Re-add this or try to use the SPUtility.ValidateFormDigest() method instead. Jan 25, 2012 at 9:53
  • Removing the AllowUnsafeUpdates and adding Microsoft.SharePoint.Utilities.SPUtility.ValidateFormDigest(); did the trick! Thanks Bernd!
    – Wim Hill
    Jan 25, 2012 at 10:18
  • You are still referencing SPContext inside the delegate. Grab the SPSite.ID before and use it in the ctor. Jan 28, 2012 at 17:37
3

Be careful when using RunWithElevatedPrivileges, as it has alot of threading issues, and only works in specific cases where your current thread is impersonated (like in a web part, but not for example a feature receiver if its activated from PowerShell). Since your thread gets elevated to the application pool account, its permissions will vary on your security setup. This account might have permission to do stuff in the web application, but certainly should not have farm wide privileges!

I only use A more safe way to do elevation is to use yourSite.SystemAccount.UserToken and use it within

using (SPSite sites new SPSite(yourSite.ID, systemAccountToken))
{
    // do elevated stuff here
}

When that is said, there are PowerShell cmd-lets for what you are doing: open the SharePoint Management Console, and use commands like Get-SPFeature, Enable-SPFeature etc for this purpose.

More Features and Solution PowerShell cmdlets here
http://technet.microsoft.com/en-us/library/ee906539.aspx

More info here
http://solutionizing.net/2009/01/06/elegant-spsite-elevation/
and here https://stackoverflow.com/questions/1525953/sharepoint-2007-runwithelevatedprivileges-pitfalls-of-using-this

3

Whenever you use 'RunWithElevatedPrviliges', we have to take the current context outside the SPSecurity.RunWithElevatedPrivileges block and then create a new instance of SPSite and SPWeb inside the that block which will run under application pool identity

 SPSecurity.RunWithElevatedPrivileges(delegate() 
    {
       using(SPSite site = new SPSite(SPContext.Current.Site.Id)
       {

            //code

       }   
    } 
5
  • It didn't solve the issue but the error logging changed: The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again. (See Updated Code)
    – Wim Hill
    Jan 25, 2012 at 9:33
  • see my updated response. Jan 25, 2012 at 9:40
  • site.Update(); generates the following in VS: 'Microsoft.SharePoint.SPSite' does not contain a definition for 'Update' and no extension method 'Update'....
    – Wim Hill
    Jan 25, 2012 at 9:56
  • As far as I know, site.Update(); is not required when using site.AllowUnsafeUpdates = true; because this property is not persisted: refer to this question sharepoint.stackexchange.com/questions/12675/… Jan 25, 2012 at 10:12
  • Do not use AllowUnsafeUpdates in this scenario. ValidateFormDigest is the correct approach. Jan 28, 2012 at 17:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.