Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added basic OAuth2 backend for Microsoft Azure Active Direcotory (Ofice365). #630

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions docs/backends/azure_ad.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Microsoft Azure Active Directory / Office365
============================================

Azure Active Directory uses OAuth2 for its connect workflow.

- Register a new application at `Microsoft Azure Portal`_, set your site
domain as redirect domain,

- Fill ``Client Id`` and ``Client Secret`` values in the settings::

SOCIAL_AUTH_AZURE_AD_KEY = ''
SOCIAL_AUTH_AZURE_AD_SECRET = ''

- Also it's possible to define extra permissions with::

SOCIAL_AUTH_AZURE_AD_SCOPE = [...]

Default is empty, which is enough to retrieve the user's first name,
last name and email.

- Make sure to have a valid ``Redirect URL`` (``http://your-domain/complete/azure_ad``)
defined for the application in the portal.

.. _Microsoft Azure Portal: https://manage.windowsazure.com/
1 change: 1 addition & 0 deletions docs/backends/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Social backends
angel
aol
appsfuel
azure_ad
battlenet
beats
behance
Expand Down
67 changes: 67 additions & 0 deletions social/backends/azure_ad.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""
Azure Active Directory/Office365 authentication backend

The flow here is a little different from regular OAuth2 flow,
because the id_token returned by Microsoft already contains
basic information (user first name, last name, and username
which is an email address) and we only need to decode it,
so no further request for details from server is made.
"""
import jwt

from social.backends.oauth import BaseOAuth2


class AzureADAuth(BaseOAuth2):
name = 'azure_ad'
AUTHORIZATION_URL = 'https://login.microsoftonline.com/common/oauth2/authorize'
ACCESS_TOKEN_URL = 'https://login.microsoftonline.com/common/oauth2/token'
REDIRECT_STATE = False

# ID_KEY should name a unique ID for the user. Microsoft documentation for
# the data we use (id_token claims) says:
# oid -- Object identifier (ID) of the user object in Azure AD.
# sub -- Token subject identifier. This is a persistent and immutable identifier
# for the user that the token describes. Use this value in caching logic.
# We picked oid.
ID_KEY = 'oid'

def auth_complete_params(self, state=None):
# Specify a harmless resource
params = super(AzureADAuth, self).auth_complete_params(state)
# The resource name of your app is supposed to work here, but we found it didn't.
params['resource'] ='https://api.office.com/discovery/'
return params

def user_data(self, access_token, *args, **kwargs):
"""Loads user data"""
# As noted above, most backends issue an API request here, but we
# can get the basic data by just decoding the id_token we already have.
response = kwargs.get('response', {})
id_token = response.get('id_token')
if id_token:
try:
claims = jwt.decode(id_token, verify=False)
return claims
except jwt.DecodeError:
# Token was not really jwt claims
pass
except:
import traceback; traceback.print_exc()
raise
return {}

def get_user_details(self, response):
"""Return user details from AzureAD id_token claims"""
fullname, first_name, last_name = self.get_user_names(
first_name=response.get('given_name'),
last_name=response.get('family_name'),
fullname=response.get('name')
)
email = response['unique_name']
return {'username': email,
'email': email,
'fullname': fullname,
'first_name': first_name,
'last_name': last_name}