One of my colleagues recently asked me to look into connecting to a SharePoint site running on Office 365 from a Windows Phone 7 application. Now this is something that the phone has native support for but in this case he wanted to be able to build an application that had added functionality and then called into the SharePoint web service APIs to extract data from SharePoint.
Attempt number 1
At first I thought this would be really easy, add a reference to the web service, call the Logon API and then we’re away. Unfortunately that isn’t the case.
I found this blog article by Paul Stubbs which was a good starting point.
When I implemented this against Office 365 it all seemed good until I actually tried to logon, I kept getting a logon failure and couldn’t figure out why. Eventually I twigged, Office 365 uses federated identity. As a result the SharePoint logon APIs don’t recognise your credentials, it knows nothing about them.
Attempt number 2
I then traced out the flow of an actual logon and found that Office 365 uses login.microsoftonline.com to authenticate against. At least this is the case on my Office 365 site, if you federate with a different provider then you’ll have to adapt this solution appropriately.
Now the flow here is a fairly standard WS-Trust flow, you hit the SharePoint site, that redirects a couple of times internally and then goes off to microsoftonline.com passing it a bit of security information. This asks you for your username and password in a web page and then redirects you back to Office 365 with some more security information.
SharePoint then writes out a cookie with a security token in, as long as web service API requests pass this cookie they’ll work.
So this is simple, I pop up a web browser, hit SharePoint go through the logon flow, grab the cookie once it comes back to SharePoint and we’re good to go.
Except we’re not, the cookie gets written with HttpOnly which means that you cannot programatically get the cookie.
Enter the hack
So what I do is roughly this:
- Check if not logged on
- Pop up a web browser control
- Navigate to the SharePoint site home page which will redirect to the STS
- User enters credentials
- I hook up navigation events from the browser control and when I spot a navigate to the page with the POST data from the STS…
- Capture the security information from the form from the browser control
- Programatically POST the form back to SharePoint using a new CookieContainer and HttpWebRequest
- SharePoint completes the WS-Trust flow and issues the SP security cookie which goes into the new CookieContainer
- Attach the new CookieContainer to all web service API calls and it’s sorted
Now as mentioned this is a little brittle as if the STS changes how it works a bit then it’ll break but most of the time that’s unlikely, especially if you are running you own STS to federate your corporate logons, you’ll control it’s appearance.
I’ve included some sample code that does this, usual caveats apply. The DefaultSettings class has the SharePoint site address and SSL settings in there, change this to point at your site.
I’ve wrapped the CookieContainer in a SharepointServerContext class to isolate the using code from this. This class also contains other information about the connection the server such as it’s address etc. All of the web service API calls are executed by my own ISharepointCommand classes, these commands all take a SharepointServerContext so they know which server to talk to and can get to the CookieContainer for authentication.
Most of the logon flow code is in the code behind for the LogonView since it needs access to the browser control.
There are bugs in the code, things are not complete, this is a work in progress but it does demonstrate the flow mentioned above. Currently if you authenticate and tick remember me it’ll break the next time you run since the flow will be different, it doesn’t cache cookies yet as that’s something else I need to work out so this is not a perfect approach. But hopefully it’ll help as a starting point for people looking at this.
You can download the sample project from here SharePointConnector. Good luck.
Original Post by Robert Garfoot on Jan 21st, 2012