Add “OpenItems” permission to the default AnonymousPermMask64, enabling opening of Office Docs within an Anonymous Accessible SharePoint site.

Hello Everyone..!! It’s been a little while since I last posted. There have been several inquiries on this issue and it also appears to be a common query among search engines, peers, and friends in the SharePoint community. Since SharePoint 2010 is growing in popularity, I am going to put emphasis on this version of the product within this blog.

The issue at hand is when directly linking Office Documents within your site, even though anonymous access is enabled, you are still prompted for credentials and if you cancel, an error is received:

401 Unauthorized

Ideally, as an anonymous user, you should be able to open this document, without being prompted for credentials and without getting a “401 Unauthorized”

Initially this was a common problem when direct links were added to .xlsx files. Findings show when a Document library containing .xlsx and .xls files are directly linked to URL’s, the .xlsx fails and the .xls succeeds.

We are now seeing similar behavior in SharePoint 2010 where Office Web Apps have been installed on the SharePoint servers.

So… Why do we get this error in the first place…?

  • In SharePoint 2007 and 2010, “.xlsx” extensions are mapped to the “xlviewer.aspx” page, via a file called, “serverfilesExcelServer.xml”
  • This page actually requires an additional permission, “OpenItems”, in order for it to successfully render a “.xlsx” file.
  • In SharePoint 2010, when you install Office Web Apps, we add additional file handlers that now map other extensions, like .doc and .docx, to pages, like “wordviewer.aspx”.
  • These pages also require the “OpenItems” permission that anonymous users do NOT have.
  • By default, Anonymous Users do NOT have this “OpenItems” permission and this is what causes the failure to open or render the files

Note: There have been numerous postings on the web advising simply remove the mapping within the above mentioned XML file, but this will put you into an unsupported state, so it is recommended NOT to do this.

If you were to look at the ULS logs while trying to access a directly linked document, you will see something like this:

09/19/2011 16:20:59.87 w3wp.exe (0x3164) 0x3DF4 SharePoint Foundation General ewn8 Verbose OriginalPermissionMask check failed. asking for 0x00000021, have 0x1000031041 f22f656c-a188-4a4c-9b41-8deeb6b934bd

And this is what the Permission Mask(s) translates to:

OriginalPermissionMask check failed. asking for 0x00000021, have 0x1000031041

0x00000021 = ViewListItems, OpenItems

0x1000031041 = ViewListItems, ViewVersions, ViewFormPages, Open, ViewPages, UseClientIntegration

As we can see, we are asking for “OpenItems” and we do not have it…

KB2498047 was published to address the “.xlsx” extension, but it will also address additional Office Doc extensions. There are 3 possible work arounds, but I am going to focus on the solution provided that utilizes PowerShell to add the “OpenItems” permission to our SPBasePermissions for anonymous users. This PowerShell will assist in adding “OpenItems” to a single web….

So what if I have a Site Collection and this site collection contains 2000 + webs?

What if some of these webs inherit permissions from the parent web, but a lot of them actually contain unique permissions? (They are still anonymous access webs, they just contain a Unique Permission Scope)

Do I need to execute this PowerShell for each web in my Site Collection…?

If your Site Collection had 2000+ webs and they all inherited from the parent web, then you could execute the PowerShell at the root Site Collection, or Top-Level Site and be done. But since you may have 2000+ webs that have unique permission scopes, we would need to iterate through the entire Web Application and set this “OpenItems” permission on our AnonymousPermMask64.

We put together a PowerShell script that would do this for you as well as the script to undo that permission add:

NOTE: Giving anonymous "OpenItems" permission allows anonymous users to have view source rights to certain files that could potentially contain sensitive info.

NOTE*: That you should only do this if you understand & accept the security implications.

 

To Set “OpenItems” across an entire Web Application:

 

· Once the ps1 is saved, pass the URL as the $arg, Ex:

 

.\AnonPermMask64_OpenItems_Add.ps1https://www.somesite.com

 

· Code:

Add-PSSnapin Microsoft.SharePoint.PowerShell

 

[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

 

 

    $siteUrl = Get-SPWebApplication $args[0] | Get-SPSite -limit All;

 

    foreach($url in $siteUrl)

   

    {

        write-host $url.url;

        $site = New-Object Microsoft.SharePoint.SPSite($url.url);

       

        foreach($webs in $site.AllWebs)

        {

           

            $enumPerms = [Microsoft.SharePoint.SPBasePermissions];

 

           

            if ($webs.HasUniquePerm)

            {

           

            Write-Host 'Setting Attribute for '$webs.url;

           

            $webs.AnonymousPermMask64 = $webs.AnonymousPermMask64 -bor $enumPerms::OpenItems

            $webs.Update();

           

            Write-Host 'Attribute for '$webs.url' has been set';

           

            } else

           

            {

           

            Write-Host 'Setting Attribute for '$webs.url;

            Write-Host 'Site Inherits Permission from Parent'

           

            }

        }

       

        $site.Dispose();

     } 

       ##end of the for each loop

 

write-host 'Finished';

 

 

 

To Remove The “OpenItems” across the Web Application:

 

· Code:

 

Add-PSSnapin Microsoft.SharePoint.PowerShell

 

[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

 

 

    $siteUrl = Get-SPWebApplication $args[0] | Get-SPSite -limit All;

 

    foreach($url in $siteUrl)

   

    {

        write-host $url.url;

        $site = New-Object Microsoft.SharePoint.SPSite($url.url);

       

        foreach($webs in $site.AllWebs)

        {

           

            $enumPerms = [Microsoft.SharePoint.SPBasePermissions];

 

           

            if ($webs.HasUniquePerm)

            {

           

            Write-Host 'Setting Attribute for '$webs.url;

           

            $webs.AnonymousPermMask64 = "ViewListItems, ViewVersions, ViewFormPages, Open, ViewPages, UseClientIntegration"

            $webs.Update();

           

            Write-Host 'Attribute for '$webs.url' has been set';

           

            } else

           

            {

           

            Write-Host 'Setting Attribute for '$webs.url 'back to default BasePermissions';

            Write-Host 'Site Inherits Permission from Parent'

           

            }

       

        }

       

        $site.Dispose();

     } 

       ##end of the for each loop

write-host 'Finished';

I hope you found this helpful. There is some information not covered here in order to keep it concise. If you have any questions, please feel free to post and I will address them as soon as possible. Thanks!