Playing Windows authenticated SharePoint 2013 Videos from a Mac OS X device and Safari browser - Solution

The Problem:

You are Unable to play videos from an authenticated (Windows Authentication) SharePoint site on a MacBook (OS X) running the Safari browser. This was reproduced on SharePoint 2013 by editing a page and selecting Insert -> Video -> From Computer.

The video may say “Loading” or may just never start playing.

 

What Gives?

On a Windows PC using integrated AUTH (i.e. logged into the domain): All that is needed to make this work in Safari is to enable BLOB cache on the web application (ref: Disk-Based Caching for Binary Large Objects in SharePoint Server 2010 (ECM)). This is because BLOB cache adds support for byte-range requests, but more on that later.

On Mac OS X: When using NTLM authentication the first request to the server will be responded to with a 401 “WWW-Authenticate: <Methods>” response, indicating that the request needs to authenticate using one of the listed methods. When the Safari browser on Mac OSX receive the initial 401 response to the video request, Safari sends a "Connection: Close" in the next GET request for the video.

This same problem is seen if you take the video outside of SharePoint and just place it on a plain old .aspx or other page type that you create and put into a new IIS site. The authentication fails when trying to get the video, even though you are able to authenticate and get the page.

Below is an example using the .aspx page I created and placed in an IIS site with Windows Authentication enabled and an HTML5 video tag:

 

First, we request the page:

--------anonymous Get request for page-----------

GET /pages/page1.aspx HTTP/1.1

Host: WebServer.contoso.com

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.30.1 (KHTML, like Gecko) Version/6.0.5 Safari/536.30.1

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: en-us

Accept-Encoding: gzip, deflate

Connection: keep-alive

Connection: keep-alive

 

-----401 with allowed Auth types response from server---------

HTTP/1.1 401 Unauthorized

Content-Type: text/html

Server: Microsoft-IIS/8.0

WWW-Authenticate: Negotiate

WWW-Authenticate: NTLM

X-Powered-By: ASP.NET

Date: Fri, 04 Oct 2013 22:54:26 GMT

Content-Length: 1293

Proxy-Support: Session-Based-Authentication

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="https://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>

<title>401 - Unauthorized: Access is denied due to invalid credentials.</title>

<style type="text/css">

<!--

body{margin:0;font-size:.7em;font-family:Verdana, Arial, Helvetica, sans-serif;background:#EEEEEE;}

fieldset{padding:0 15px 10px 15px;}

h1{font-size:2.4em;margin:0;color:#FFF;}

h2{font-size:1.7em;margin:0;color:#CC0000;}

h3{font-size:1.2em;margin:10px 0 0 0;color:#000000;}

#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:"trebuchet MS", Verdana, sans-serif;color:#FFF;

background-color:#555555;}

#content{margin:0 0 0 2%;position:relative;}

.content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;}

-->

</style>

</head>

<body>

<div id="header"><h1>Server Error</h1></div>

<div id="content">

<div class="content-container"><fieldset>

  <h2>401 - Unauthorized: Access is denied due to invalid credentials.</h2>

  <h3>You do not have permission to view this directory or page using the credentials that you supplied.</h3>

</fieldset></div>

</div>

</body>

</html>

 

--------GET request with NTLM stub-------------

GET /pages/page1.aspx HTTP/1.1

Host: WebServer.contoso.com

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.30.1 (KHTML, like Gecko) Version/6.0.5 Safari/536.30.1

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: en-us

Accept-Encoding: gzip, deflate

Connection: keep-alive

Connection: keep-alive

Authorization: NTLM TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=

 

------NTLM challenge response from server--------------

HTTP/1.1 401 Unauthorized

Content-Type: text/html; charset=us-ascii

Server: Microsoft-HTTPAPI/2.0

WWW-Authenticate: NTLM TlRMTVNTUAACAAAAFAAUADgAAAAFgokCz7/tVAyW0JkAAAAAAAAAALYAtgBMAAAABgLwIwAAAA9UAEUAUwBUADMAMgA2ADcAMwA2AAIAFABUAEUAUwBUADMAMgA2ADcAMwA2AAEAFABNAEkASwBFAEQARQBNADIAMwA0AAQAHAB0AGUAcwB0ADMAMgA2ADcAMwA2AC4AbABhAGIAAwAyAE0ASQBLAEUARABFAE0AMgAzADQALgB0AGUAcwB0ADMAMgA2ADcAMwA2AC4AbABhAGIABQAcAHQAZQBzAHQAMwAyADYANwAzADYALgBsAGEAYgAHAAgAq7/9vlTBzgEAAAAA

Date: Fri, 04 Oct 2013 22:54:56 GMT

Content-Length: 341

Proxy-Support: Session-Based-Authentication

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""https://www.w3.org/TR/html4/strict.dtd">

<HTML><HEAD><TITLE>Not Authorized</TITLE>

<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>

<BODY><h2>Not Authorized</h2>

<hr><p>HTTP Error 401. The requested resource requires user authentication.</p>

</BODY></HTML>

 

----------fully authenticated NTLM GET request----------------

GET /pages/page1.aspx HTTP/1.1

Host: WebServer.contoso.com

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.30.1 (KHTML, like Gecko) Version/6.0.5 Safari/536.30.1

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: en-us

Accept-Encoding: gzip, deflate

Connection: keep-alive

Connection: keep-alive

Authorization: NTLM TlRMTVNTUAADAAAAGAAYAEAAAADmAOYAWAAAABQAFAA+AQAACgAKAFIBAAAUABQAXAEAAAAAAAAAAAAABYIIAIrY6OVFM5g5nl+qrMQcJpeDek9uIM5K6EqzQ4NNWJdkxhRg5j3wlhsBAQAAAAAAAKDoVb5Uwc4Bg3pPbiDOSugAAAAAAgAUAFQARQBTAFQAMwAyADYANwAzADYAAQAUAE0ASQBLAEUARABFAE0AMgAzADQABAAcAHQAZQBzAHQAMwAyADYANwAzADYALgBsAGEAYgADADIATQBJAEsARQBEAEUATQAyADMANAAuAHQAZQBzAHQAMwAyADYANwAzADYALgBsAGEAYgAFABwAdABlAHMAdAAzADIANgA3ADMANgAuAGwAYQBiAAcACACrv/2+VMHOAQAAAAAAAAAAVABFAFMAVAAzADIANgA3ADMANgB1AHMAZQByADEAcwBzAGMAaABpAGUAbQBtAGEAYwA=

 

---------200 OK and content response from server------------

HTTP/1.1 200 OK

Cache-Control: private

Content-Type: text/html; charset=utf-8

Content-Encoding: gzip

Vary: Accept-Encoding

Server: Microsoft-IIS/8.0

X-AspNet-Version: 4.0.30319

Persistent-Auth: true

X-Powered-By: ASP.NET

Date: Fri, 04 Oct 2013 22:54:56 GMT

Content-Length: 628

------------------------------------------------------------------

Now, we request the video

------------------------------------------------------------------

----------Anonymous GET request for video------(Notice the "Range: bytes=0-1 header)

GET /content/BirthdayParty.mp4 HTTP/1.1

Host: WebServer.contoso.com

User-Agent: AppleCoreMedia/1.0.0.11G63 (Macintosh; U; Intel Mac OS X 10_7_5; en_us)

Accept: */*

Range: bytes=0-1

Accept-Encoding: identity

Connection: keep-alive

Connection: keep-alive

 

-----------401 WWW-Authenticate: NTLM response from server-----------(Safari on MAC apparently requires this first response to be a byte range response)

HTTP/1.1 401 Unauthorized

Content-Type: text/html

Server: Microsoft-IIS/8.0

WWW-Authenticate: Negotiate

WWW-Authenticate: NTLM

X-Powered-By: ASP.NET

Date: Fri, 04 Oct 2013 22:54:56 GMT

Content-Length: 1293

Proxy-Support: Session-Based-Authentication

…<div class="content-container"><fieldset>

  <h2>401 - Unauthorized: Access is denied due to invalid credentials.</h2>

  <h3>You do not have permission to view this directory or page using the credentials that you supplied.</h3>…

 

----------Since no byte range response was sent, Safari sends a "Connection: Close"-------(Also notice that Safari has changed the user agent)

GET /content/BirthdayParty.mp4 HTTP/1.1

Host: WebServer.contoso.com

User-Agent: QuickTime/7.7.1 (qtver=7.7.1;cpu=IA32;os=Mac 10.7.5)

Accept: */*

Connection: close

Connection: close

 

--------401 response with auth types allowed from server--------------

HTTP/1.1 401 Unauthorized

Content-Type: text/html

Server: Microsoft-IIS/8.0

WWW-Authenticate: Negotiate

WWW-Authenticate: NTLM

X-Powered-By: ASP.NET

Date: Fri, 04 Oct 2013 22:54:56 GMT

Content-Length: 1293

Proxy-Support: Session-Based-Authentication

… <h2>401 - Unauthorized: Access is denied due to invalid credentials.</h2>

  <h3>You do not have permission to view this directory or page using the credentials that you supplied.</h3>…

------------------------------------------------------------------

This is what Safari is apparently looking for in terms of a response:

-------------------------------------------------------------------

HTTP/1.1 206 Partial Content

Cache-Control: public, max-age=86400

Content-Length: 2

Content-Type: video/mp4

Content-Range: bytes 0-1/383631

Last-Modified: Tue, 15 Oct 2013 23:30:53 GMT

Accept-Ranges: bytes

ETag: "{35DF5330-208E-4900-A467-F6327DFC241B},1pub"

Server: Microsoft-IIS/7.5

X-AspNet-Version: 4.0.30319

SPRequestGuid: 2c0a4d9c-2c89-b0f8-a067-c5db7abeabf7

request-id: 2c0a4d9c-2c89-b0f8-a067-c5db7abeabf7

X-FRAME-OPTIONS: SAMEORIGIN

X-Powered-By: ASP.NET

MicrosoftSharePointTeamServices: 16.0.0.2120

X-Content-Type-Options: nosniff

X-MS-InvokeApp: 1; RequireReadOnly

P3P: CP="ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo CNT COM INT NAV ONL PHY PRE PUR UNI"

Date: Tue, 15 Oct 2013 23:31:41 GMT

 

-------------------------------------------------------------------------------

 

There are several WORKING scenarios for playing videos from SharePoint in Safari on Mac OS X or Windows:

 

1. Safari for Windows – accessing SharePoint 2013 with NTLM (or basic, other) authentication: Requires BLOB cache be enabled on SharePoint web application.
Thanks to Kirk Liemohn for pointing out in his Blog, you need blobcache to be enabled on all WFE servers.

 

2. Safari for Mac – accessing SharePoint 2013 with ADFS claims authentication (or other SAML claim type auth): Requires BLOB cache be enabled on SharePoint web application.

 

3. Safari for Mac or PC accessing a page on an IIS site with HTML5 video tag, anonymous access allowed: works out of the box – IIS 7.5+ support byte-range natively.

 

4. Safari on Mac or PC accessing Office 365 : Works out of the box. BLOB cache is enabled, and federated claims authentication is used in this scenario so no 401 challenge response is returned.

 

5. Safari on Mac or PC accessing SharePoint 2013 with anonymous enabled on asset library: Works, because of an odd behavior in that a) Safari does not send an anonymous access token like IE does on first request, so we return a 401 (Remember that anonymous is still authenticated using the IUSR account, so the anonymous token is still needed) B) When Safari responds with another GET request with the “Connection: close” header, we send the video file anyway in response, resulting in the file being available and playable in the browser.

 

So, from the above scenarios, and there may be more not addressed here, the overriding themes are:

- BLOB cache should be enabled (SharePoint BLOB cache supports serving byte-range requests).

- Safari expects and requires a byte-range response from the server. If one is not received, it sends a “connection: close” header in the next request.

 

Knowing what Safari is looking for in the response, and considering NTLM protected files will always return a 401 challenge response to an initial GET request, there really isn’t a change that I can see on the SharePoint side that will fix this. The server must respond to unauthenticated requests with a 401, when NTLM windows authentication is used.

 

Further, Safari on Mac with Kerberos authentication – We run into a similar issue as we do with NTLM because it seems that Safari on Mac doesn't send the Kerberos token with the initial request. While a Windows client will send "Authentication: Negotiate YIIGPg<rest of base64 encoded Kerberos string>" with the first request each time, the Mac and Safari do not. I don't know if this is something that can be changed in OS X or Safari, to allow it to send the Kerberos ticket with the initial request, or if this is a limitation of Mac/Safari. If this were to be corrected, and the Mac is able to send the Kerberos ticket with the first request for the video file (should already be authenticated when accessing the page), then it would not be prompted with the 401 challenge, then the videos would work as expected.

 

What can I do?

First, turn on BLOB cache on your SharePoint server or make sure if you are running a pure IIS site (no SharePoint), that you are running IIS 7.5+. This will fix most Safari on Windows scenarios.

For Safari on MAC OS X, A couple of options are:

1. Use Forms based Authentication

2. Use Federated Authentication (such as ADFS)

3. Use a SSO (Single sign-on) server to broker authentication to the back end SharePoint servers

4. Allow anonymous access on the asset library

5. Request a change to Safari’s reaction to a 401 “NTLM challenge response” on initial video byte-range request, so that it doesn't send the "Connection: Close" if the 206 is not immediately returned.