Intro

At CodeRed, we are primarily Python/Django developers. I don't frequently get the opportunity to work with Microsoft services/products. However, we do use Office 365 services quite a bit. From the security aspect, Office 365 is an amazing cloud-based system as it can govern identity management and secure file sharing through AzureAD and SharePoint. I say "secure" file sharing because Office 365 has a strong commitment to cloud and SDLC security, compliance, and data privacy. As a result, we have been integrating our Python-based tools with Office 365 to help us manage user identities and file transfers.

To test some concepts out, I built a quick file upload tool that connects to Microsoft's OneDrive API from a Django project.

Breaking Down Microsoft Jargon

Having no previous knowledge of how Microsoft's APIs were organized, I was extremely confused on which API to use. During the research phase, I kept seeing a handful of different APIs. There's the Graph API, the Office365 API, the SharePoint 2013 API, and the OneDrive API. And while they all have SharePoint capabilities, their documentation wasn't always the clearest in communicating that.

Graph API

Currently, in the middle of 2016, Microsoft has been developing and pushing for the Graph API. It is meant to be a unifying API that connects all of their other service API's so that you won't need to obtain separate access tokens for each service you use and you can access everything through a single endpoint. That sounded great, but it is currently still in development and does not easily offer file uploads above 4 MB.

API Madness

Additionally, Microsoft has a tendency to brand "OneDrive", "OneDrive for Business", and "SharePoint" all as "OneDrive" in their API's. This led to a problem initially as developers who are unfamiliar with Microsoft's branding may not realize that you can use OneDrive APIs to access SharePoint. This problem is compounded by the fact that there is a separate SharePoint API.

OneDrive API

Through much trial and error, I have found the OneDrive API (https://dev.onedrive.com/) to offer the most flexibility and ease.

All of the API's mentioned above use the same method for authentication, Azure Active Directory. Just like working with other API's you will need to register your app with Azure AD to get your credentials. If you are unfamiliar with how to go about doing that, the OneDrive API has documentation that shows you the steps required. Look at the section title "Register your app for OneDrive for Business" https://dev.onedrive.com/app-registration.htm.

Keep note of your app's Client ID and your key.  Make sure you are requesting the correct permissions outlined at the bottom of the page.

Setting up Python Social Auth in Django

For our use case, we want people to be able to log into our Django Web App using their Office365 account.  Our goto pip package for OAuth is python-social-auth.  Luckily they already have support for AzureAD, so authenticating becomes easy.

You can install it by calling

pip install python-social-auth

 
To setup python-social-auth properly, we will need to modify our settings.py file.

In your django settings file, modify INSTALLED_APPS.  This will add python-social-auth to our project.

INSTALLED_APPS = (
    ...,
    'social.apps.django_app.default',
    ...,


In your django settings file, modify AUTHENTICATION_BACKENDS.  This will allow us to authenticate users via AzureAD.

AUTHENTICATION_BACKENDS = (
    ...,
    'oauth.backends.AzureADOAuth2',
    ...,


In your django settings file, you will want to add a couple of variables.  These are for connecting to our AzureAD app.

SOCIAL_AUTH_AZUREAD_OAUTH2_KEY = 'Your AzureAD Client ID'

SOCIAL_AUTH_AZUREAD_OAUTH2_SECRET = 'Your AzureAD Secret'

SOCIAL_AUTH_AZUREAD_OAUTH2_RESOURCE = 'https://{YourSharepointTenant}.sharepoint.com'

SOCIAL_AUTH_AZUREAD_OAUTH2_SCOPE = ['Files.ReadWrite',]


Note:  If you set SOCIAL_AUTH_AZUREAD_OAUTH2_RESOURCE = 'https://{YourSharepointTenant}-my.sharepoint.com', all of your api calls will instead be performed on your OneDrive for Business Drive versus the SharePoint site.

You will also want to add the OAuth URL's to your urls.py file:

import social.apps.django_app.urls as social_urls

urlpatterns = patterns ('',

    ...,

    url(r'^social/', include(social_urls, namespace='social')),

    ...,

)


To login through AzureAD, your login link in your template will look like this:

    # Getting the authenticated user credentials from python-social-auth

    # This call assumes the user you are trying to access is the logged in user.

    social = request.user.social_auth.get(provider='azuread-oauth2')

access_token = social.extra_data['access_token']


# build our header for the api call

headers = {

        'Authorization' : 'Bearer {0}'.format(access_token),

    }


    # build the url for the api call

    # Look at https://dev.onedrive.com/items/upload_put.htm for reference

    url = settings.SOCIAL_AUTH_AZUREAD_OAUTH2_RESOURCE + '/_api/v2.0/drive/root:/' + file_to_upload.name + ':/content'


    # Make the api call

    response = requests.put(url, data=open(file_to_upload, 'rb'), headers=headers)

    return response


Assuming everything has worked, your response code should be 200 and your file should be in your root directory of your Sharepoint documents!