1
votes

Im going slightly crazy over this.. I have claims authentication working against a sharepoint online site in a Windows Store application. But the exact same code in a Windows Phone 8 App does not work. One difference is that System.Net.Http-namespace is only available as a Nuget package for Windows Phone.

The authentication process is to first send a HttpRequest to microsoft to retrieve a STS Saml token. Then send this token with a second HttpRequest to the sharepoint online site to get the authentication cookies (FedAuth / rtFA).

In Windows Store App STA Saml token:

 HttpRequestMessage {Method: POST, RequestUri: https://login.microsoftonline.com/extSTS.srf', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  Accept: application/soap+xml; charset=utf-8
  Content-Type: application/soap+xml; charset=utf-8
  Content-Length: 1335
}}  System.Net.Http.HttpRequestMessage

HttpResponse {StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  Pragma: no-cache
  X-XSS-Protection: 0
  PPServer: PPV: 30 H: CO1IDOALGN08 V: 0
  Connection: close
  Cache-Control: no-cache
  Date: Tue, 29 Oct 2013 07:52:18 GMT
  P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
  Server: Microsoft-IIS/7.5
  Content-Length: 3661
  Content-Type: application/soap+xml; charset=utf-8
  Expires: Tue, 29 Oct 2013 07:51:18 GMT
}}  System.Net.Http.HttpResponseMessage

HttpResponse.Content {byte[3661]}   byte[]

In Windows Store App SPOAuthToken:

HttpRequestMessage  {Method: POST, RequestUri: 'https://xxx.sharepoint.com/SitePages/Startsida.aspx', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  Accept: application/x-www-form-urlencoded
  Content-Type: application/x-www-form-urlencoded
  Content-Length: 893
}}  System.Net.Http.HttpRequestMessage


HttpResponse {StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  X-SharePointHealthScore: 0
  SPRequestGuid: 0556519c-19a2-20e0-a937-44fc861d2ddc
  request-id: 0556519c-19a2-20e0-a937-44fc861d2ddc
  X-FRAME-OPTIONS: SAMEORIGIN
  SPRequestDuration: 742
  SPIisLatency: 1
  MicrosoftSharePointTeamServices: 16.0.0.2120
  X-Content-Type-Options: nosniff
  X-MS-InvokeApp: 1; RequireReadOnly
  Cache-Control: max-age=0, private
  Date: Tue, 29 Oct 2013 07:52:57 GMT
  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"
  Set-Cookie: 8167acc39dff40bf855ec089c80b8fbc2ca28f1fc09f48f5ad16ab2bd0e6ee02i%3A0%23%2Ef%7Cmembership%7Crobert%40portalplus%2Ese=0; expires=Wed, 30-Oct-2013 07:52:57 GMT; path=/; HttpOnly
  Server: Microsoft-IIS/7.5
  X-AspNet-Version: 4.0.30319
  X-Powered-By: ASP.NET
  Content-Length: 107958
  Content-Type: text/html; charset=utf-8
  Expires: Mon, 14 Oct 2013 07:52:56 GMT
  Last-Modified: Tue, 29 Oct 2013 07:52:56 GMT
}}  System.Net.Http.HttpResponseMessage


HttpResponse.Content {byte[107958]} byte[]

In Windows Phone App STA Saml token:

HttpRequestMessage  {Method: POST, RequestUri: 'https://login.microsoftonline.com/extSTS.srf', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  Accept: application/soap+xml; charset=utf-8
  Content-Type: application/soap+xml; charset=utf-8
  Content-Length: 1335
}}  System.Net.Http.HttpRequestMessage

HttpResponse {StatusCode: 200, ReasonPhrase: 'OK', Version: 0.0, Content: System.Net.Http.StreamContent, Headers:
{
  Cache-Control: no-cache
  Pragma: no-cache
  Server: Microsoft-IIS/7.5
  P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
  X-XSS-Protection: 0
  PPServer: PPV: 30 H: CO1IDOLGN56 V: 0
  Date: Tue, 29 Oct 2013 07:50:25 GMT
  Connection: close
  Content-Length: 3661
  Content-Type: application/soap+xml; charset=utf-8
  Expires: Tue, 29 Oct 2013 07:49:26 GMT
}}  System.Net.Http.HttpResponseMessage

HttpResponse.Content  {byte[3661]}  byte[]

In Windows Phone App SPOAuthToken:

HttpRequestMessage  {Method: POST, RequestUri: 'https://xxx.sharepoint.com/SitePages/Startsida.aspx', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  Accept: application/x-www-form-urlencoded
  Content-Type: application/x-www-form-urlencoded
  Content-Length: 893
}}  System.Net.Http.HttpRequestMessage


HttpResponse {StatusCode: 200, ReasonPhrase: 'OK', Version: 0.0, Content: System.Net.Http.StreamContent, Headers:
{
  Cache-Control: max-age=0, private
  Server: Microsoft-IIS/7.5
  X-SharePointHealthScore: 0
  X-AspNet-Version: 4.0.30319
  SPRequestGuid: ef55519c-0917-20e0-6056-033a05a409d8
  request-id: ef55519c-0917-20e0-6056-033a05a409d8
  X-FRAME-OPTIONS: SAMEORIGIN
  SPRequestDuration: 1289
  SPIisLatency: 0
  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, 29 Oct 2013 07:51:25 GMT
  Content-Length: 107956
  Content-Type: text/html; charset=utf-8
  Expires: Mon, 14 Oct 2013 07:51:24 GMT
  Last-Modified: Tue, 29 Oct 2013 07:51:24 GMT
}}  System.Net.Http.HttpResponseMessage

HttpResponse.Content  {byte[107956]}    byte[]

The differences I see is

  • Response: Version 0.0 in WP instead of Version 1.1 in WS
  • No Set-Cookie in response for WP8 (the root error)
  • ResponseContent for SPO-cookies WS is 2 bytes larger than WP8

Is there something in WP8 that somehow invalidates the http request before they "leave the phone"? Any and all ideas are very much appreciated.

EDIT: I'm now fairly certain that WP8 OS is the culprit. I have moved the authentication code into a portable library so I can run the exact same code from both platforms. Still, only the store app works! And the weirdness continues: when run in debug mode on an actual phone instead of the emulator I DO get the cookies.

BUT, in the portable code executed in WP, the cookies get stored differently in the CookieContainer, so I have not yet been able to actually use the cookies to retrieve any data from Sharepoint... my head hurts.

Conclusion: Windows Phone OS does something strange with the data, probably on the receiving end since I actually get the raw cookie data from Microsoft/SP. It's when this finds its way into the portable code that it looks different than in Windows 8.

EDIT2: Upon further inspection I see that the cookiecontainer that is used to put the cookies in on the client side behaves differently.

After the cookies has been added to the container there is a private string "m_fqdnMyDomain" that is empty in WP8 but contains my domain when run from W8. The GetCookies(uri) returns nothing in WP8 (even though I just added them with Add(uri, cookie)) but correctly returns them in W8. All this happens in the same portable code run in both enviroments.

1

1 Answers

1
votes

Ok, I now have this working. The workaround is to set the cookies directly in the HttpWebRequest headers, bypassing using a CookieContainer:

context.SendingRequest2 += (s, e) =>
                    {
                        var message = e.RequestMessage as HttpWebRequestMessage;    
                        var cookieHeader = string.Format("rtFA={0}; FedAuth={1}", AuthCookies.RtFA, AuthCookies.FedAuth);                                
                        message.HttpWebRequest.Headers["Cookie"] = cookieHeader;      
                     };

Instead of

context.SendingRequest2 += (s, e) => (e.RequestMessage as HttpWebRequestMessage).HttpWebRequest.CookieContainer = myCookieContainer;

Note that the second option still works in Windows Store Application...