I was developing a web part for a client which, given a URL copy/pasted from another source, had to resolve to the appropriate list or library item to display some information about it. While these URLs were obtained from another system, they were pretty well guaranteed to map to an item in SharePoint. Mapping the URLs is easy enough using either SPWeb.GetListItem (depending on the URL format), but it was also possible I'd be passed the URL of the web itself, which I would need to resolve to the welcome page library item. For example, given

http://intranet.vandelay/sites/foo

I would have to resolve to

http://intranet.vandelay/sites/foo/pages/default.aspx

Or whatever the home page was. Not a big deal right? Just use SPWeb.GetFile. Worked perfectly. Yay, blog post over!

Then it went to test.

A few users were reporting they'd sometimes get Access Denied errors, yet when they browsed to the URL they could see it fine. Getting some examples, they were all URLs of the SPWeb rather than a URL of an exact list/library item.

After a bit of digging around, I'd found out these users were in a particular SharePoint group, and this group had a custom permission level assigned. The only difference this custom permission level had, was that "Browse Directories" had been removed. Sure enough, lowering my account on my dev setup to this permission level replicated the problem, and I was able to determine that the call to UnauthorizedAccessException.

I could use SPSecurity.RunWithElevatedPrivileges to access that property, but it seems like an unnecessary hack. Besides, how does SharePoint redirect users to the welcome page when they browse to the web URL? I know SharePoints inner workings are magical, but surely this property is involved somewhere.

Time to fire up ILSpy (like I need an excuse to do that). The first thing I did was look at the implementation of SPWeb.RootFolder.WelcomePage:


// Microsoft.SharePoint.SPFolder
public string WelcomePage {
    get {
        // ok not exactly, but this is the nett result
        return (string)this.Properties["vti_welcomepage"];
    }
}

Not too exciting, but it did reveal why the error was happening: accessing SPFolder.Properties apparently requires Browse Directories permissions. Analysing its usage was a bit more interesting though. It's used in a bunch of places, but one caught my eye:

Microsoft.SharePoint.Utilities.SPMobileUtility.GetWelcomePageUrl(SPWeb web)

Opening this method I was hoping to be dazzled, instead…


// Microsoft.SharePoint.Utilities.SPMobileUtility
internal static string GetWelcomePageUrl(SPWeb web)
{
    if (web.DoesUserHavePermissions(SPBasePermissions.BrowseDirectories))
    {
        return web.RootFolder.WelcomePage;
    }
    string welcomePage = string.Empty;
    SPSecurity.RunWithElevatedPrivileges(delegate {
        using (SPSite sPSite = new SPSite(web.Site.ID))
        using (SPWeb sPWeb = sPSite.OpenWeb(web.ID))
        {
            welcomePage = sPWeb.RootFolder.WelcomePage;
        }
    });
    return welcomePage;
}
Face Palm

At least I was on the "right" track using SPSecurity.RunWithElevatedPrivileges