SharePoint 2007 Anonymous MS Office Document Download Login Prompts
I ran into what I guess is a years old headbanger of a situation with a public-facing anonymous access-enabled SP 2007 site which allows document downloads. This one has probably caused many late nights and was probably a real friction point in SharePoint being considered for normal public website usage.
When certain Office Documents are downloaded (in this case, .DOT and .DOTX Word Document Templates, users:
– Click the download link and the file transfer initiates
– Are inappropriately given 2-3 login prompts, which when cancelled through, finally allow access to the downloaded document template
This behaviour does not occur when the user clicks “Save As”, only when the direct download link is clicked. I tried uploading new documents made from scratch and the same behaviour occured, so it didn’t seem to have anything to do with the content of the documents/templates downloaded.
Anonymous access appeared to be correctly configured and all IIS settings were ok. Nothing out of the ordinary seemed to appear when monitoring the download process with Fiddler. I tried turning off Client Integration since that seems to be the realm of the failure however it did not resolve the issue. More to that point, turning off Client Integration would remove that expected functionality for authenticated users with authoring rights. SP Permissions on the documents appear consistent with other documents that don’t exhibit this issue.
An excellent summary of this issue (which is essentially a “by-design” Microsoft trait) of this well-known problem is described here. That post also features one method of overcoming the issue.
Multiple Logon while open office Document from SharePoint
http://blogs.technet.com/b/steve_chen/archive/2010/06/25/multiple-logon-while-open-office-document-from-sharepoint.aspx
Office: Authentication prompts when opening Microsoft Office documents
http://support.microsoft.com/kb/2019105
NOTE: This issue has apparently been fixed for SharePoint 2010. These fixes only apply to SharePoint 2007.
See the end of this post for the final solution that worked for my situation the best. Methods 1-6 work to varying degrees and situations but none by themselves fulfilled the simple requirement of allowing anonymous users with IE to not get login prompts, without taking functionality away from someone else.
1. Editing the web.config to remove the “OPTION,PROPFIND” values from the for SharePoint.
Ref: http://support.microsoft.com/kb/2019105
If the web application is not intended to be used for WebDAV, the Web Service Extension that provides the WebDAV functionality can be set to Prohibited on a default server that is running IIS. (This might be WebDAV or FrontPage Server Extensions.) If the site provides WebDAV functionality through another extension, the provider of that extension should be involved. For example, to do this with Windows SharePoint Services (WSS), the site should be configured to disable Client Integration, or the OPTIONS and PROPFIND verb should be inhibited. (On IIS 6, remove the verbs from the registration line in the web.config file. On IIS 7.0, use the HTTP Verbs tab of the Request Filtering feature to deny the verbs.) Be aware that this approach will open the content in read-only mode because this approach disables direct-edit functionality.
Risks: Will disable client integration so if authenticated authors/users are expecting to open Office docs with integration Potentially disables site admin options in SharePoint Designer. Causes application recompile as we are committing change to web.config.
Rewards: Eliminates 1 out of the 2 login prompt windows that pop up. –IF- you are using IIS7 there is the potential that denying PROPFIND and OPTION in IIS > Site > Request Filtering would also be required. I don’t know of a deny method for IIS6 except using 3rd party tools such as LinkDeny.
2. Editing Core DOCICON.XML
Basically, hacking the code for the open/edit documents links that appear in list views, in the hive. Open the file:
C:Program FilesCommon FilesMicrosoft Sharedweb server extensions12TEMPLATEXML
Change the default settings for Office Document format files from:
<Mapping Key="dot" Value="icdot.gif" EditText="Microsoft Office Word" OpenControl="SharePoint.OpenDocuments"/> <Mapping Key="dotm" Value="icdotx.gif" EditText="Microsoft Office Word" OpenControl="SharePoint.OpenDocuments"/> <Mapping Key="dotx" Value="icdotx.gif" EditText="Microsoft Office Word" OpenControl="SharePoint.OpenDocuments"/>
to:
<Mapping Key="dot" Value="icdot.gif" EditText="Microsoft Office Word" /> <Mapping Key="dotm" Value="icdotx.gif" EditText="Microsoft Office Word" /> <Mapping Key="dotx" Value="icdotx.gif" EditText="Microsoft Office Word" />
Note: some of the “less advanced” formats such as Rich Text Format come out-of-the-box without the extra EditText=”Microsoft Office Word” OpenControl=”SharePoint.OpenDocuments” tags:
<Mapping Key="rtf" Value="icrtf.gif"/>
Risks: Disables Open in Office functionality for authenticated author/users
Rewards: Will disable the open with Office Client Integration on Office documents – users will just get a Save prompt.
3. Edit Publication Detail page by modifying Download Hyperlink to use Javascript download link
You can either modify existing custom page layouts (or create a new one) to include a user control which provides the actual download link for documents in a list grid or on a detail page. In my case I edited an existing user control embedded in the downloads masterpage:
Old link:
<a href=" <%= Utility.GetListItemServerRelativeUrl(PublicationItem) %> ">Download</a>
New Link:
<a href="javascript:STSNavigate('http://www.mysite.com/_layouts/download.aspx?SourceUrl=<%= Utility.GetListItemServerRelativeUrl(PublicationItem) %>' );">Download</a>
Risks: Disables Open/Edit in Office functionality for authenticated author/users
Rewards: Removes one of the two login prompts. Tried in combination with the technique of removing OPTIONS,PROPFIND from web.config
4. Custom Download Handler to Intercept Office documents being downloaded with specific format
Created an .ASPX page as per (the idea in the comments) http://www.theblackknightsings.com/CommentView,guid,1c85a4a8-879e-4974-b7c8-e48e6811eedd.aspx that forces the download to go through in binary for specific document formats, in this case .DOT/.DOTX. The same method as trick #3 is used (modifying the download link in the control that actually provides the download link). This time instead of using the JS method it points to the custom .ASPX page .
Here is an example of such as custom user control, which is specifically wired to intercept the .DOT and .DOTX mime types:
<%@ Control Language="C#" %> <%@ Import Namespace="Microsoft.SharePoint" %> <asp:Label ID="error" runat="server" /> <script runat="server"> public partial class Office_Client_Integration_Override : System.Web.UI.UserControl { protected void Page_Load(object sender, EventArgs e) { try { if (!String.IsNullOrEmpty(Request.QueryString["open"]) && (Request.UserAgent != "Microsoft Office Protocol Discovery") && (Request.UserAgent != "Microsoft Data Access Internet Publishing Provider Protocol Discovery") && (Request.UserAgent != "Microsoft Office Existence Discovery") && (Request.UserAgent != "MSFrontPage/14.0")) { string fullPath = Request.QueryString["open"].ToLower(); int start = fullPath.IndexOf("/PublicationDocuments/"); string webPath = fullPath.Substring(0, start); if (webPath == "") webPath = "/"; SPSecurity.RunWithElevatedPrivileges(delegate() { using (SPSite site = new SPSite("http://www.sharepoint.com")) { using (SPWeb web = site.OpenWeb(webPath)) { string strContentType = ""; SPFile tempFile = web.GetFile(fullPath); //Get the extension of File. string[] fext = tempFile.Name.Split('.'); byte[] obj = (byte[])tempFile.OpenBinary(); // Get the extension of File to determine the file type string casestring = ""; if (fext.Length > 1) { casestring = fext[fext.Length - 1]; } //set the content type of file according to extension switch (casestring) { case ".dotx": strContentType = "application/vnd.openxmlformats"; break; case ".dot": strContentType = "application/msword"; break; default: strContentType = "application/msword"; break; } Response.ClearContent(); Response.ClearHeaders(); Response.AppendHeader("Content-Disposition", "attachment; filename= " + tempFile.Name); Response.ContentType = strContentType; //Check that the client is connected and has not closed the connection after the request if (Response.IsClientConnected) Response.BinaryWrite(obj); Response.Flush(); Response.Close(); } } }); } else Error.Text = "<p>No file was specified.</p>"; } catch { Error.Text = "<p>There was an error downloading that file.</p>"; } } } </script>
Risks: Uses SPRunWithElevatedPrivileges to access the doc which could circumvent security if there was ever a need to have secure .DOT/.DOTX/ in the same site (unlikely)
Rewards: None, gives a straight 401 unauthorized.
5. Modifying Core.js in SharePoint hive to hotwire document opening behaviours
As per the post at , the following .JS modification will selectively (based on what file extensions you leave in there) override the core opening behaviour.
Find this line in the core.js file at:
C:Program FilesCommon FilesMicrosoft Sharedweb server extensions12templatelayouts1033 folder. [/sourceode] function DispDocItemEx(ele, fTransformServiceOn, fShouldTransformExtension, fTransformHandleUrl, strProgId) {
Add the following directly after that opening {:
/************************************************************* Suppress Document Authentication Prompt Mod for WSS 3.0 by Kevin Cornwell 2/28/2007 Open document without SharePoint hook to edit, thus suppressing the authentication prompt. *************************************************************/ var _ele; if (_ele = ele.toString()){ if (_ele_ext = _ele.substring(_ele.lastIndexOf('.')+1).toLowerCase()){ /* list of office docs - add or remove Office file extensions as desired */ var arr_office_ext = new Array('doc','xls','dot','dotx','bmp','gif','jpeg', 'jpg','csv','docm','docx','docmhtml', 'docxml','dothtml','gcsx','ico','mdb', 'mde','mdn','png','pot','pothtml','potm', 'potx','pps','ppt','pptm','pptx','pub', 'xlb','xlc','xls','xlsm','xlt','xltm', 'xltx','xlw','xlxml'); var _i; var b_office_doc = false; /* check for ext in array */ for (_i=0; _i < arr_office_ext.length; _i++) { if (arr_office_ext[_i] === _ele_ext){ //alert(_ele); b_office_doc = true; break; } } /* send only if office ext */ if (b_office_doc){ /* Open the doc via download.aspx (supress sp editing) */ STSNavigate(ctx.HttpRoot + '/_layouts/download.aspx?SourceUrl=' + _ele); /* Kill the “regular” sp handling of the doc (edit mode) onClick(true) and simply download the doc. */ return false; } } } /* End mod ***************************************************/
Risks: You are modifying core SharePoint hive file which can be a maintenance/upgrade issue. Core.JS file will not be updated on end users browser until they refresh their caches or the JS expires naturally – they won’t see the new behaviour until that JS is refreshed.
Rewards: Overrides the open behaviour without requiring Office Integration in general to be turned off. Allows selected file extensions to be downloaded without the Office client producing the dummy login prompts.
6. Re-applying Anonymous permissions to Web App, Document Library
Risks: none
Rewards: There’s been reports that this would correct any issues with document prompts, however I didn’t see this result in my test cases.
The Winning Combination
The following is what worked consistently best and with minimal interference with standard Office Client Integration functionality for logged in users. Note that I only illustrate how to insert a download link in a detail page, if you want to wire this up to a document list view it will require adapting it yourself. 🙂
1. Create/modify a document detail page in SharePoint Designer. Add a User Control which references your desired document fields (title, description, image etc.) and add the following as the download link:
Note: the following assumes you have a working knowledge of how to use the SharePoint API to grab your server variables. The bolded text in the following link are the part you will have to sort out depending on where you will be applying this download link:
<a href="javascript:STSNavigate('http://<strong><servername>:<port></strong>/_layouts/download.aspx?SourceUrl=<strong>/doc lib name/documentname.doc</strong>');">download a copy</a>
2. Open the file:
C:Program FilesCommon FilesMicrosoft Sharedweb server extensions12templatelayoutsdownload.aspx
I dont have to tell you to make a backup first.
3. Make some modifications, so your file will end like this (note that I have added the vital runat=”server” which is required):
<%@ Assembly Name="Microsoft.SharePoint.ApplicationPages" %> <%@ Page Language="C#" Inherits="Microsoft.SharePoint.ApplicationPages.Download" %> <script runat="server">// <![CDATA[ protected override bool AllowAnonymousAccess { get{ return true; } } // ]]></script>
3. That’s it! Needless to say, if you have the Publishing Cache feature turned on you may need refresh your cache in order for the changes to kick in on the download detail page you’ve made. Otherwise, no messy sticky client-side Javascript and a very light core modification. It’s up to you if you want to beef up the restrictions in the AllowAnonymousAccess override – you could potentially combine some of the file extension restriction methods referenced in Method 4 to lock it down.
(Credit to http://www.uv.mx/personal/gvera/sharepoint-login-prompt-when-accessing-files-in-a-document-library/ for the final clue needed to put this together)