1

I want to programatically interact with files in Office 365 E3 Sharepoint Site.

I am using Azure AD and ADAL Python library to authenticate access to Sharepoint Site file.

import adal
import urllib
import requests
import urllib2

## set variables
username = 'curtis@tenant.onmicrosoft.com'
password = 'OFoarry8Oe$'
authorization_url = 'https://login.windows.net/tenant.onmicrosoft.com' # Authority
redirect_uri = 'https://login.microsoftonline.com/login.srf'
client_id = 'dcbf844f-d2c3-42d1-8a7d-0f838f57899a' # Client id

## use ADAL to create token response
token_response = adal.acquire_token_with_username_password(
        authorization_url,
        username,
        password
    )
## endpoints discovery
## https://api.office.com/discovery/v2.0/me/allServices

## create refresh token and save it to use later 
refresh_token = token_response['refreshToken']
refresh_token_file = open('refresh_token.txt', 'w')
refresh_token_file.write(refresh_token)
refresh_token_file.close()

## get saved refresh token and use it to get new token response
refresh_token = open('refresh_token.txt', 'r').read()
token_response = adal.acquire_token_with_refresh_token(authorization_url, str(refresh_token))

## get access_token from token response
access_token = token_response.get('accessToken')
headers = {'Authorization':'BEARER ' + str(access_token)}

The authentication is successful as I can do

print access_token

which returns a token string.

I am struggling with the syntax to use to download and upload files from a Sharepoint folder. This is what I have so far:

## download file
file_url = 'https://tenant.sharepoint.com/_api/v1.0/files/root:/myfoldername/myfilename.csv:/content'
r = requests.get(file_url, headers=headers)
print r.text

So far I have not been able to successfully refer to the file. I am getting an error:

{"error":"invalid_client","error_description":"Invalid audience Uri 'https:\/\/management.core.windows.net\/'."}

This appears to indicate that I am referring to wrong Site. or perhaps referring to folder incorrectly

This is a url that I get from the Sharepoint site for the file I want to download (from its properties in Sharepoint):

https://tenant.sharepoint.com/Shared%20Documents/myfoldername/myfilename.csv

Does the url of the file from the Sharepoint site help to define what the file_url syntax should be? If not how else can I determine what the file_url should be?

Community
  • 1
  • 1
curtisp
  • 2,227
  • 3
  • 30
  • 62

2 Answers2

1

Based on the code, you were authenticate with Azure AD however call the SharePoint REST API. The SharePoint REST is the different authenticate flow. You can refer it from here.

In your scenario, we can use Microsoft Graph API to download the content from SharePoint site in Office 365. Here is an example that download the content of file on the your default site:

GET: https://graph.microsoft.com/v1.0/me/drive/root:/test.txt:/content

authorization: bearer {token}

More detail about Microsoft Graph API, please refer to links below:

https://graph.microsoft.io/en-us/docs/api-reference/v1.0/api/item_downloadcontent

https://graph.microsoft.io/en-us/docs/authorization/app_authorization

Fei Xue
  • 14,369
  • 1
  • 19
  • 27
  • Ok that is the issue. Was making assumption that if user was authenticated (my user is account admin) then all permissions would be granted. But not the case. I might switch to Graph API, it seems better documented. – curtisp May 26 '16 at 15:51
1

Fei Xue set me on right path. My code was requesting a resource that ADAL didn't expect.

Turns out adal.acquire_token_with_username_password in __init__.py has default values (see bottom of code in class _DefaultValues) for client_id and resource.

ADAL's default resource is https://management.core.windows.net/ which is what it was expecting my file_url resource to have. The invalid audiencewas https://tenant.sharepoint.com.

So I changed ADAL's default values:

`client_id` = my Azure AD app's client_id 
`resource` = `https://tenant.sharepoint.com/`  

ADAL's acquire_token_with_username_password (see below) has client_id and resource set to None. I didn't try but guess these could be edited to remove the =None and set in my code instead of class _DefaultValues.

def acquire_token_with_username_password(
    authority,
    username,
    password,
    client_id=None,
    resource=None,
    validate_authority=True
):

And also made minor (but required) change to my file_url (url to filename) to :

file_url = 'https://pokrant.sharepoint.com/_api/v2.0/drive/root:/analytics/output_analytics.csv:/content'

Now when I run code I get the csv file contents printed out in console.

curtisp
  • 2,227
  • 3
  • 30
  • 62