Skip to content

Commit

Permalink
Wrote units tests for .client and got tox and setup.py test working
Browse files Browse the repository at this point in the history
  • Loading branch information
AngellusMortis committed Nov 19, 2017
1 parent c751069 commit d18558a
Show file tree
Hide file tree
Showing 17 changed files with 431 additions and 61 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Before you submit a pull request, check that it meets these guidelines:
2. If the pull request adds functionality, the docs should be updated. Put
your new functionality into a function with a docstring, and add the
feature to the list in README.rst.
3. The pull request should work for Python 2.7, 3.5, and 3.6. Check
3. The pull request should work for Python 3.4, 3.5, and 3.6. Check
https://travis-ci.org/AngellusMortis/django_microsoft_auth/pull_requests
and make sure that the tests pass for all supported Python versions.

Expand Down
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ include CONTRIBUTING.rst
include HISTORY.rst
include LICENSE
include README.rst
include requirements.in
include test-requirements.in

recursive-include tests *
recursive-exclude * __pycache__
Expand Down
4 changes: 0 additions & 4 deletions microsoft_auth/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@
# override admin site template
admin.site.login_template = 'microsoft/admin_login.html'

# comment this out before making any new migrations
# move custom User model from microsoft_auth back to default auth in admin site
# User._meta.app_label = 'auth'

# djangoql support
extra_base = []
if apps.is_installed('djangoql'):
Expand Down
49 changes: 31 additions & 18 deletions microsoft_auth/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
from django.urls import reverse
from requests_oauthlib import OAuth2Session

from .conf import config


class MicrosoftClient(OAuth2Session):
""" Simple Microsoft OAuth2 Client to authenticate them
Expand All @@ -27,31 +25,39 @@ class MicrosoftClient(OAuth2Session):
token_url = \
'https://login.microsoftonline.com/common/oauth2/v2.0/token'

xbox_token_url = 'https://user.auth.xboxlive.com/user/authenticate'
profile_url = 'https://xsts.auth.xboxlive.com/xsts/authorize'

xbox_token = {}

config = None

# required OAuth scopes
SCOPE_XBL = ['XboxLive.signin', 'XboxLive.offline_access']
SCOPE_MICROSOFT = ['User.Read']

def __init__(self, state=None, *args, **kwargs):
from .conf import config
self.config = config

domain = Site.objects.get_current().domain
path = reverse('microsoft:auth-callback')
scope = ' '.join(self.SCOPE_MICROSOFT)

if config.MICROSOFT_AUTH_LOGIN_TYPE == 'xbl':
if self.config.MICROSOFT_AUTH_LOGIN_TYPE == 'xbl':
scope = ' '.join(self.SCOPE_XBL)

super().__init__(
config.MICROSOFT_AUTH_CLIENT_ID,
self.config.MICROSOFT_AUTH_CLIENT_ID,
scope=scope,
state=state,
redirect_uri=f'https://{domain}{path}',
redirect_uri='https://{0}{1}'.format(domain, path),
*args, **kwargs)

def authorization_url(self):
""" Generates Microsoft/Xbox or a Office 365 Authorization URL """
auth_url = self.ma_authorization
if config.MICROSOFT_AUTH_LOGIN_TYPE == 'o365':
if self.config.MICROSOFT_AUTH_LOGIN_TYPE == 'o365':
auth_url = self.o365_authorization

return super() \
Expand All @@ -60,9 +66,10 @@ def authorization_url(self):
def fetch_token(self, **kwargs):
""" Fetchs OAuth2 Token with given kwargs"""
return super() \
.fetch_token(self.token_url,
client_secret=config.MICROSOFT_AUTH_CLIENT_SECRET,
**kwargs)
.fetch_token(
self.token_url,
client_secret=self.config.MICROSOFT_AUTH_CLIENT_SECRET,
**kwargs)

def fetch_xbox_token(self):
""" Fetches Xbox Live Auth token.
Expand All @@ -84,19 +91,22 @@ def fetch_xbox_token(self):
# Content-type MUST be json for Xbox Live
headers = {
'Content-type': 'application/json',
'Accept': 'application/json'
'Accept': 'application/json',
}
params = {
'RelyingParty': 'http://auth.xboxlive.com',
'TokenType': 'JWT',
'Properties': {
'AuthMethod': 'RPS',
'SiteName': 'user.auth.xboxlive.com',
'RpsTicket': 'd={}'.format(self.token['access_token'])}}
'RpsTicket': 'd={}'.format(self.token['access_token']),
},
}
response = requests.post(
'https://user.auth.xboxlive.com/user/authenticate',
self.xbox_token_url,
data=json.dumps(params),
headers=headers)
headers=headers
)

if response.status_code == 200:
self.xbox_token = response.json()
Expand Down Expand Up @@ -133,18 +143,21 @@ def get_xbox_profile(self):
# Content-type MUST be json for Xbox Live
headers = {
'Content-type': 'application/json',
'Accept': 'application/json'
'Accept': 'application/json',
}
params = {
'RelyingParty': 'http://xboxlive.com',
'TokenType': 'JWT',
'Properties': {
'UserTokens': [self.xbox_token['Token']],
'SandboxId': 'RETAIL'}}
'SandboxId': 'RETAIL'
},
}
response = requests.post(
'https://xsts.auth.xboxlive.com/xsts/authorize',
self.profile_url,
data=json.dumps(params),
headers=headers)
headers=headers
)

if response.status_code == 200:
return response.json()['DisplayClaims']['xui'][0]
Expand All @@ -154,7 +167,7 @@ def valid_scopes(self, scopes):
""" Validates response scopes based on MICROSOFT_AUTH_LOGIN_TYPE """
scopes = set(scopes)
required_scopes = None
if config.MICROSOFT_AUTH_LOGIN_TYPE == 'xbl':
if self.config.MICROSOFT_AUTH_LOGIN_TYPE == 'xbl':
required_scopes = set(self.SCOPE_XBL)
else:
required_scopes = set(self.SCOPE_MICROSOFT)
Expand Down
2 changes: 1 addition & 1 deletion microsoft_auth/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def post(self, request):

domain = Site.objects.get_current().domain
context = {
'base_url': f'https://{domain}/',
'base_url': 'https://{0}/'.format(domain),
'message': {}}

# validates state using Django CSRF system
Expand Down
3 changes: 3 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[pytest]
DJANGO_SETTINGS_MODULE = tests.settings

3 changes: 3 additions & 0 deletions requirements.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Django>=1.11,<2.0
requests
requests-oauthlib
15 changes: 15 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile --output-file requirements.txt requirements.in
#
certifi==2017.11.5 # via requests
chardet==3.0.4 # via requests
django==1.11.7
idna==2.6 # via requests
oauthlib==2.0.6 # via requests-oauthlib
pytz==2017.3 # via django
requests-oauthlib==0.8.0
requests==2.18.4
urllib3==1.22 # via requests
11 changes: 0 additions & 11 deletions requirements_dev.txt

This file was deleted.

29 changes: 13 additions & 16 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,26 @@

"""The setup script."""

from setuptools import setup, find_packages
from os import path

with open('README.rst') as readme_file:
from setuptools import find_packages, setup

BASE_DIR = path.abspath(path.dirname(__file__))

with open(path.join(BASE_DIR, 'README.rst')) as readme_file:
readme = readme_file.read()

with open('HISTORY.rst') as history_file:
with open(path.join(BASE_DIR, 'HISTORY.rst')) as history_file:
history = history_file.read()

requirements = [
'django>=1.11,<2.0',
'requests==2.18.4',
'requests-oauthlib==0.8.0',
]
with open(path.join(BASE_DIR, 'requirements.in')) as f:
requirements = f.read().split('\n')

with open(path.join(BASE_DIR, 'test-requirements.in')) as f:
test_requirements = f.read().split('\n')

setup_requirements = [
'pytest-runner',
# TODO(AngellusMortis): put setup requirements (distutils extensions, etc.) here
]

test_requirements = [
'pytest',
# TODO: put package test requirements here
]

setup(
Expand All @@ -46,9 +44,8 @@
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Natural Language :: English',
"Programming Language :: Python :: 2",
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
],
Expand Down
7 changes: 7 additions & 0 deletions test-requirements.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
coverage
flake8
pip-tools
pytest
pytest-cov
pytest-django
tox
31 changes: 31 additions & 0 deletions test-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile --output-file test-requirements.txt requirements.in test-requirements.in
#
certifi==2017.11.5 # via requests
chardet==3.0.4 # via requests
click==6.7 # via pip-tools
coverage==4.4.2
django==1.11.7
first==2.0.1 # via pip-tools
flake8==3.5.0
idna==2.6 # via requests
mccabe==0.6.1 # via flake8
oauthlib==2.0.6 # via requests-oauthlib
pip-tools==1.10.1
pluggy==0.5.2 # via tox
py==1.5.2 # via pytest, tox
pycodestyle==2.3.1 # via flake8
pyflakes==1.6.0 # via flake8
pytest-cov==2.5.1
pytest-django==3.1.2
pytest==3.2.5
pytz==2017.3 # via django
requests-oauthlib==0.8.0
requests==2.18.4
six==1.11.0 # via pip-tools, tox
tox==2.9.1
urllib3==1.22 # via requests
virtualenv==15.1.0 # via tox
30 changes: 30 additions & 0 deletions tests/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

SECRET_KEY = 'fake-key'
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',

'microsoft_auth',
'tests',
]

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}

SITE_ID = 1

ROOT_URLCONF = 'tests.urls'

LANGUAGE_CODE = 'en-us'
Loading

0 comments on commit d18558a

Please sign in to comment.