Remote Authentication in SharePoint Online

wnnmaw picture wnnmaw · Feb 3, 2016 · Viewed 11.6k times · Source

I am attempting to write a script with SharePoint package to access files on my company's SharePoint. The tutorial states

First, you need to create a SharePointSite object. We’ll assume you’re using basic auth; if you’re not, you’ll need to create an appropriate urllib2 Opener yourself.

However, after several attempts, I've concluded that basic auth is not sufficient. While researching how to try to make it work, I came upon this article which gives a good overview of the general scheme of authentication. What I'm struggling with is implementing this in Python.

I've managed to hijack the basic auth in the SharePoint module. To do this, I took the XML message in the linked article and used it to replace the XML generated by the SharePoint module. After making a few other changes, I now recieve a token as described in Step 2 of the linked article.

Now, in Step 3, I need to send that token to SharePoint with a POST. The below is a sample of what it should look like:

POST http://yourdomain.sharepoint.com/_forms/default.aspx?wa=wsignin1.0 HTTP/1.1
Host: yourdomain.sharepoint.com
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Content-Length: [calculate]

t=EwBgAk6hB....abbreviated

I currently use the following code to generate my POST. With the guidance from a few other questions, I've omitted the content-length header since that should be automatically calculated. I was unsure of where to put the token, so I just shoved it in data.

headers = {
    'Host': 'mydomain.sharepoint.com',
    'Connection': 'keep-alive',
    'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)'
}

data = {'t':'{}'.format(token[2:])}
data = urlencode(data) 

postURL = "https://mydomain.sharepoint.com/_forms/default.aspx?wa=wsignin1.0"   
req = Request(postURL, data, headers) 
response = urlopen(req)

However, this produces the following error message:

urllib2.HTTPError: HTTP Error 302: The HTTP server returned a redirect error that would lead to an infinite loop.
The last 30x error message was:
Found

How do I generate a POST which will correctly return the authentication cookies I need?

Answer

Vadim Gremyachev picture Vadim Gremyachev · Feb 8, 2016

According to Remote Authentication in SharePoint Online Using Claims-Based Authentication and SharePoint Online authentication articles :

The Federation Authentication (FedAuth) cookie is for each top level site in SharePoint Online such as the root site, the MySite, the Admin site, and the Public site. The root Federation Authentication (rtFA) cookie is used across all of SharePoint Online. When a user visits a new top level site or another company’s page, the rtFA cookie is used to authenticate them silently without a prompt.

To summarize, to acquire authentication cookies the request needs to be sent to the following endpoint:

url: https://tenant.sharepoint.com/_forms/default.aspx?wa=wsignin1.0  
method: POST
data: security token

Once the request is validated the response will contain authentication cookies (FedAuth and rtFa) in the HTTP header as explained in the article that you mentioned.

SharePoint Online REST client for Python

As a proof of concept the SharePoint Online REST client for Python has been released which shows how to:

  • perform remote authentication in SharePoint Online
  • perform basic CRUD operations against SharePoint resources such as Web, List or List Item using REST API

Implementation details:

  • AuthenticationContext.py class contains the SharePoint Online remote authentication flow implementation, in particular the acquireAuthenticationCookie function demonstrates how to handle authentication cookies
  • ClientRequest.py class shows how to consume SharePoint Online REST API

Examples

The example shows how to read Web client object properties:

from client.AuthenticationContext import AuthenticationContext
from client.ClientRequest import ClientRequest

url = "https://contoso.sharepoint.com/"
username = "[email protected]"
password = "password"


ctxAuth = AuthenticationContext(url)
if ctxAuth.acquireTokenForUser(username, password):
  request = ClientRequest(url,ctxAuth)
  requestUrl = "/_api/web/"   #Web resource endpoint
  data = request.executeQuery(requestUrl=requestUrl)

  webTitle = data['d']['Title']
  print "Web title: {0}".format(webTitle)

else:
  print ctxAuth.getLastErrorMessage()

More examples could be found under examples folder of GitHub repository