locked
Programmatically creating a site in sharepoint generates Access Denied RRS feed

  • Question

  • Hello,

     I've created a WCF WebService for Sharepoint 2010. The WebService is deployed at farm scope. One of the methods of the WebService creates a site in the Web Application's main site collection. The problem is that when the code reaches the siteCollection.Add() statement I get an access denied exception.

     This is the code:
     
    SPWebApplication webapp = SPContext.Current.Site.WebApplication;
    SPSiteCollection siteCollection = webapp.Sites;
    siteCollection.Add("mysite", "DOMAIN\\Administrator", "mail@yahoo.com");
    webapp.Update();

      The error I get is:

     Got Exception: 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.SPUtilityInternal.SendResponse(HttpContext context, Int32 code, String strBody)
       at Microsoft.SharePoint.Utilities.SPUtility.HandleAccessDenied(HttpContext context)
       at Microsoft.SharePoint.Utilities.SPUtility.HandleAccessDenied(Exception ex)
       at Microsoft.SharePoint.Library.SPRequest.ValidateFormDigest(String bstrUrl, String bstrListName)
       at Microsoft.SharePoint.SPWeb.ValidateFormDigest()
       at Microsoft.SharePoint.Administration.SPSiteCollection.Add(SPContentDatabase database, SPSiteSubscription siteSubscription, String siteUrl, String title, String description, UInt32 nLCID, String webTemplate, String ownerLogin, String ownerName, String ownerEmail, String secondaryContactLogin, String secondaryContactName, String secondaryContactEmail, String quotaTemplate, String sscRootWebUrl, Boolean useHostHeaderAsSiteName)
       at Microsoft.SharePoint.Administration.SPSiteCollection.Add(SPSiteSubscription siteSubscription, String siteUrl, String title, String description, UInt32 nLCID, String webTemplate, String ownerLogin, String ownerName, String ownerEmail, String secondaryContactLogin, String secondaryContactName, String secondaryContactEmail, Boolean useHostHeaderAsSiteName)
       at Microsoft.SharePoint.Administration.SPSiteCollection.Add(String siteUrl, String ownerLogin, String ownerEmail)
       at WCFWSTest001.Test001Service.CreateSite(String siteName)

    I've tried to determine the application pool that runs the service in order to see what credentials it is using but I have 20 application pools and I don't know which one is running the service. I've also tried to somehow get the current user programmatically from the webApplication object but I couldn't get it.

    Many thanks....
    Wednesday, February 29, 2012 4:45 PM

Answers

All replies

  • Using that approach you would have to add your application pool account to farm administrators and wrap your code inside a SPSecurity.RunWithElevatedPrivileges delegate.

    A much better approach would be to use SelfService :

    SPSite.SelfServiceCreateSite

    http://msdn.microsoft.com/en-us/library/ms458475.aspx


    Industrial inspection cameras | traffic cameras | open road tolling cameras | speed enforcement cameras

    Wednesday, February 29, 2012 6:27 PM
  • hi

    as in your case SPContext.Current is not null, Sharepoint tries to verify request using security validation digest provided by FormDigest Class. According to msdn:

    "To make posts from a Web application that modify the contents of the database, you must include the FormDigest control in the form making the post. The FormDigest control generates a security validation, or message digest, to help prevent the type of attack whereby a user is tricked into posting data to the server without knowing it. The security validation is specific to a user, site, and time period and expires after a configurable amount of time. When the user requests a page, the server returns the page with security validation inserted. When the user then submits the form, the server verifies that the security validation has not changed".

    In WCF service you don't have security digest. To avoid this check try to set HttpContext.Current to null temporary when you call siteCollection.Add() method:

    var ctx = HttpContext.Current;
    try
    {
        HttpContext.Current = null;
        siteCollection.Add(...);
    }
    finally
    {
        HttpContext.Current = ctx;
    }
    In this case code will be treated as running from outside the Sharepoint context (e.g. from timer job or console application) which requires more privileges from you, comparing with request which came from page which can be easily simulated.

    Blog - http://sadomovalex.blogspot.com
    CAML via C# - http://camlex.codeplex.com


    Wednesday, February 29, 2012 7:10 PM
  • Hello Anders,

    I've tried your approach. I've enabled Self-Service Site Creation from Central Administration for my web application: http://myip:34448/ - this is the url of the web application.

    After executing:

    using (SPSite oSiteCollection = new SPSite("http://myip:34448"))
     {
       SPSite oSiteCollectionSelfServ = oSiteCollection.SelfServiceCreateSite("http://myip:34448/siteName", "siteName", "siteNameDescription", HarvestCurrentLCID(), "STS", "DOMAIN\\Administrator","DOMAIN\\Administrator", "email@yahoo.com", "DOMAIN\\Administrator", "DOMAIN\\Administrator", "email@yahoo.com");
       oSiteCollectionSelfServ.Dispose();
     }
    
    ....
    public uint HarvestCurrentLCID()
     {
      return Microsoft.SharePoint.WebControls.SPControl.GetContextWeb(HttpContext.Current).Language;
     }

    I get the same error

    Got Exception: 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.SPUtilityInternal.SendResponse(HttpContext context, Int32 code, String strBody)
       at Microsoft.SharePoint.Utilities.SPUtility.HandleAccessDenied(HttpContext context)
       at Microsoft.SharePoint.Utilities.SPUtility.HandleAccessDenied(Exception ex)
       at Microsoft.SharePoint.Library.SPRequest.ValidateFormDigest(String bstrUrl, String bstrListName)
       at Microsoft.SharePoint.SPWeb.ValidateFormDigest()
       at Microsoft.SharePoint.Administration.SPSiteCollection.Add(SPContentDatabase database, SPSiteSubscription siteSubscription, String siteUrl, String title, String description, UInt32 nLCID, String webTemplate, String ownerLogin, String ownerName, String ownerEmail, String secondaryContactLogin, String secondaryContactName, String secondaryContactEmail, String quotaTemplate, String sscRootWebUrl, Boolean useHostHeaderAsSiteName)
       at Microsoft.SharePoint.SPSite.SelfServiceCreateSite(String siteUrl, String title, String description, UInt32 nLCID, String webTemplate, String ownerLogin, String ownerName, String ownerEmail, String contactLogin, String contactName, String contactEmail, String quotaTemplate, SPSiteSubscription siteSubscription)
       at Microsoft.SharePoint.SPSite.SelfServiceCreateSite(String siteUrl, String title, String description, UInt32 nLCID, String webTemplate, String ownerLogin, String ownerName, String ownerEmail, String contactLogin, String contactName, String contactEmail)
       at WCFWSTest001.Test001Service.CreateSite(String siteName)

    So using the SelfServiceCreateSite didn't help :(.


    Thursday, March 1, 2012 11:46 AM
  • Hello sadomovalex,

    I've tried your suggestion too. Here is the code:

    SPWebApplication webapp = SPContext.Current.Site.WebApplication;
    SPSiteCollection siteCollection = webapp.Sites;
    
    var ctx = HttpContext.Current;
    try
      {
        HttpContext.Current = null;
        for (int i = 0; i < siteCollection.Count; i++)  
         {
          LogMessage("Site " + i + " url: " + siteCollection[i].Url);
         }
        foreach (var name in siteCollection.Names)
        {
          LogMessage("Site Name: " + name);   
        }               
    
        siteCollection.Add(siteName, "DOMAIN\\Administrator", "mail@yahoo.com");
      }
      finally
      {
        HttpContext.Current = ctx;
      }
    
      webapp.Update();

    This generates the following error:

    3/1/2012 2:03:32 PM -- Site 0 url: http://myip:34448
    3/1/2012 2:03:32 PM -- Site 1 url: http://myip:34448/sites/Office_Viewing_Service_Cache
    3/1/2012 2:03:32 PM -- Site Name: 
    3/1/2012 2:03:32 PM -- Site Name: sites/Office_Viewing_Service_Cache
    3/1/2012 2:03:32 PM -- Got Exception: System.ArgumentException: Another site already exists at http://myip:34448. Delete this site before attempting to create a new site with the same URL, choose a new URL, or create a new inclusion at the path you originally specified.
       at Microsoft.SharePoint.Administration.SPConfigurationDatabase.CreateSite(SPWebApplication application, SPContentDatabase database, String originalPath, Guid id, Guid siteSubscriptionId, Boolean useHostHeaderAsSiteName)
       at Microsoft.SharePoint.Administration.SPConfigurationDatabase.CreateSite(SPWebApplication application, SPContentDatabase database, String path, Boolean useHostHeaderAsSiteName)
       at Microsoft.SharePoint.Administration.SPSiteCollection.Add(SPContentDatabase database, SPSiteSubscription siteSubscription, String siteUrl, String title, String description, UInt32 nLCID, String webTemplate, String ownerLogin, String ownerName, String ownerEmail, String secondaryContactLogin, String secondaryContactName, String secondaryContactEmail, String quotaTemplate, String sscRootWebUrl, Boolean useHostHeaderAsSiteName)
       at Microsoft.SharePoint.Administration.SPSiteCollection.Add(SPSiteSubscription siteSubscription, String siteUrl, String title, String description, UInt32 nLCID, String webTemplate, String ownerLogin, String ownerName, String ownerEmail, String secondaryContactLogin, String secondaryContactName, String secondaryContactEmail, Boolean useHostHeaderAsSiteName)
       at Microsoft.SharePoint.Administration.SPSiteCollection.Add(String siteUrl, String ownerLogin, String ownerEmail)
       at WCFWSTest001.Test001Service.CreateSite(String siteName)

    The existing sites are weird. From the web interface I've added only one site (called "first" - with url http://myip:34448/first) to my site collection. When I list the sites of the current web application's site collection I don't see my site. Instead i see a site for http://myip:34448 and one for http://myip:34448/sites/Office_Viewing_Service_Cache. The Site URL for the Visual Studio Solution is http://myip:34448/. I don't know why I can't see my site.

    Besides this I still can't add the site to my site collection.



    Thursday, March 1, 2012 12:21 PM
  • Cool hack, sadomovalex, I'll be sure to store it for future reference! But, the FormDigest control only applies when you're changing the contents of the SharePoint database in an HTTP Post, not the case here in the web service call.

    As for Eborix13 (geez, the names you guys make me type!): there's really no substitute for understanding the security context you're running under. Start with establishing the application pool identity, having 20 app pools is no excuse for not doing that:

    - Open IIS Manager.
    - Select the WCF service application node.
    - Select Basic Settings.

    This shows the name of the application pool. And what went wrong with establishing the current user programmatically (share the code?) you can do it with some code like this (on top of my head, but close to this):

    SPContext.Current.Site.OpenWeb().CurrentUser


    Kind regards,
    Margriet Bruggeman

    Lois & Clark IT Services
    web site: http://www.loisandclark.eu
    blog: http://www.sharepointdragons.com




    Thursday, March 1, 2012 12:26 PM
  • Hello Margriet,

    These are the application pools from my IIS Manager. I have no idea in which one my service runs.

    Thursday, March 1, 2012 3:00 PM
  • Sorry I missed the fact that you was creating the site collection from a WCF service. SelfServiceCreateSite is there to allow impersonated users to create new site collections with themself as site collection admins.

    The hack from sadomovalex actually fixed your issue. Now you just need the right URL :)


    Industrial inspection cameras | Speed enforcement | Line scan cameras | Machine vision cameras

    • Marked as answer by Qiao Wei Tuesday, April 3, 2012 1:50 AM
    Tuesday, March 13, 2012 9:00 PM