Commit f7cabf7f by Bertrand Marron

Fix IONISx social provider

parent e3397cf9
...@@ -7,9 +7,9 @@ import re ...@@ -7,9 +7,9 @@ import re
import uuid import uuid
import time import time
import json import json
import requests
from collections import defaultdict from collections import defaultdict
from pytz import UTC from pytz import UTC
from requests import request, ConnectionError
from django.conf import settings from django.conf import settings
from django.contrib.auth import logout, authenticate, login from django.contrib.auth import logout, authenticate, login
...@@ -372,9 +372,13 @@ def register_user(request, extra_context=None): ...@@ -372,9 +372,13 @@ def register_user(request, extra_context=None):
""" """
This view will display the non-modal registration form This view will display the non-modal registration form
""" """
if not settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
if request.user.is_authenticated(): if request.user.is_authenticated():
return redirect(reverse('dashboard')) return redirect(reverse('dashboard'))
if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
# Redirect to IONISx, we don't want the registration form.
return external_auth.views.redirect_with_get('/auth/login/portal-oauth2', request.GET, do_reverse=False)
if settings.FEATURES.get('AUTH_USE_CERTIFICATES_IMMEDIATE_SIGNUP'): if settings.FEATURES.get('AUTH_USE_CERTIFICATES_IMMEDIATE_SIGNUP'):
# Redirect to branding to process their certificate if SSL is enabled # Redirect to branding to process their certificate if SSL is enabled
# and registration is disabled. # and registration is disabled.
...@@ -415,14 +419,6 @@ def register_user(request, extra_context=None): ...@@ -415,14 +419,6 @@ def register_user(request, extra_context=None):
context.update(overrides) context.update(overrides)
return render_to_response('register.html', context) return render_to_response('register.html', context)
else:
if request.user.is_authenticated():
if 'course_id' in request.GET:
return redirect("/courses/{0}/about".format(request.GET.get('course_id')))
else:
return redirect('/')
else:
return redirect("/auth/login/portal-oauth2/?auth_entry=login&next={0}".format(urlquote(request.get_full_path())))
def complete_course_mode_info(course_id, enrollment): def complete_course_mode_info(course_id, enrollment):
...@@ -1094,14 +1090,16 @@ def login_user(request, error=""): # pylint: disable-msg=too-many-statements,un ...@@ -1094,14 +1090,16 @@ def login_user(request, error=""): # pylint: disable-msg=too-many-statements,un
}) # TODO: this should be status code 400 # pylint: disable=fixme }) # TODO: this should be status code 400 # pylint: disable=fixme
def logout_portal(user_mail): def logout_portal(request):
if request.user.is_authenticated():
user = request.user
social_data = models.DjangoStorage.user.get_social_auth_for_user(user)[0]
try: try:
user = models.DjangoStorage.user.objects.get(uid=user_mail) requests.post(
response = request('POST', settings.IONISX_AUTH['SYNC_LOGOUT_URL'], settings.IONISX_AUTH.get('SYNC_LOGOUT_URL'),
params={ 'access_token': user.extra_data['access_token'] }) headers={'Authorization': 'Bearer {0}'.format(social_data.extra_data['access_token'])}
except ConnectionError as err: )
log.warning(err) except requests.ConnectionError as err:
except Exception as err:
log.warning(err) log.warning(err)
...@@ -1119,9 +1117,8 @@ def logout_user(request): ...@@ -1119,9 +1117,8 @@ def logout_user(request):
else: else:
user_mail = request.user.email user_mail = request.user.email
logout_portal(request)
logout(request) logout(request)
if user_mail:
logout_portal(user_mail)
if settings.FEATURES.get('AUTH_USE_CAS'): if settings.FEATURES.get('AUTH_USE_CAS'):
target = reverse('cas-logout') target = reverse('cas-logout')
else: else:
......
...@@ -13,8 +13,9 @@ from social.apps.django_app.default import models ...@@ -13,8 +13,9 @@ from social.apps.django_app.default import models
from social.apps.django_app.middleware import SocialAuthExceptionMiddleware from social.apps.django_app.middleware import SocialAuthExceptionMiddleware
from . import pipeline from . import pipeline
from . import portal
log = logging.getLogger('third_party_auth.middleware') log = logging.getLogger(__file__)
class ExceptionMiddleware(SocialAuthExceptionMiddleware): class ExceptionMiddleware(SocialAuthExceptionMiddleware):
"""Custom middleware that handles conditional redirection.""" """Custom middleware that handles conditional redirection."""
...@@ -32,32 +33,36 @@ class PortalSynchronizerMiddleware(object): ...@@ -32,32 +33,36 @@ class PortalSynchronizerMiddleware(object):
"""Custom middleware to synchronize user status of LMS with Portal provider.""" """Custom middleware to synchronize user status of LMS with Portal provider."""
def process_request(self, request): def process_request(self, request):
if not isinstance(request.user, AnonymousUser): if request.user.is_authenticated():
try:
email = request.user.email
user = models.DjangoStorage.user.objects.get(uid=email)
response = requests.request('POST', settings.IONISX_AUTH['SYNC_USER_URL'],
params={ 'access_token': user.extra_data['access_token'] })
response = response.json()
if response is None:
logout(request)
response = redirect(request.get_full_path())
response.delete_cookie(
settings.EDXMKTG_COOKIE_NAME,
path='/', domain=settings.SESSION_COOKIE_DOMAIN,
)
return response
if response['updated'] is True:
log.warning('need update !')
user = request.user user = request.user
user.email = response['emails'][0]['email'] social_auth = models.DjangoStorage.user.get_social_auth_for_user(user)
user.username = response['username']
user.save()
profile = UserProfile.objects.get(user=request.user) if len(social_auth) == 1:
profile.name = response['name'] social_data = social_auth[0]
profile.save()
try:
r = requests.get(
settings.IONISX_AUTH.get('USER_DATA_URL'),
headers={'Authorization': 'Bearer {0}'.format(social_data.extra_data['access_token'])}
)
except requests.ConnectionError as err: except requests.ConnectionError as err:
log.warning(err) log.warning(err)
except Exception as err: return
log.warning(err)
user_data = r.json()
if user_data:
_id = user_data['_id']
email = portal.get_primary_email(user_data['emails'])
username = user_data['username']
name = user_data['name']
if (user.email != email or user.username != user_data['username']):
log.info('User {} needs to be updated'.format(_id))
user.email = email
user.username = username
user.save()
if user.profile.name != user_data['name']:
log.info('User profile for {} needs to be updated'.format(_id))
user.profile.name = name
user.profile.save()
...@@ -5,35 +5,40 @@ from django.conf import settings ...@@ -5,35 +5,40 @@ from django.conf import settings
from social.backends.oauth import BaseOAuth2 from social.backends.oauth import BaseOAuth2
from social.exceptions import AuthCanceled from social.exceptions import AuthCanceled
def get_primary_email(emails):
for email in emails:
if email['primary'] is True:
return email['email']
return None
class PortalOAuth2(BaseOAuth2): class PortalOAuth2(BaseOAuth2):
"""Portal OAuth2 authentication backend""" """Portal OAuth2 authentication backend"""
name = 'portal-oauth2'
auth_settings = settings.IONISX_AUTH auth_settings = settings.IONISX_AUTH
AUTHORIZATION_URL = auth_settings['AUTHORIZATION_URL']
ACCESS_TOKEN_URL = auth_settings['ACCESS_TOKEN_URL'] name = 'portal-oauth2'
ID_KEY = '_id'
AUTHORIZATION_URL = auth_settings.get('AUTHORIZATION_URL')
ACCESS_TOKEN_URL = auth_settings.get('ACCESS_TOKEN_URL')
ACCESS_TOKEN_METHOD = 'POST' ACCESS_TOKEN_METHOD = 'POST'
REDIRECT_STATE = False REDIRECT_STATE = False
USER_DATA_URL = auth_settings['USER_DATA_URL']
def get_user_id(self, details, response): USER_DATA_URL = auth_settings.get('USER_DATA_URL')
"""Use portal email as unique id"""
if self.setting('USE_UNIQUE_USER_ID', False):
return response['id']
else:
return details['email']
def get_user_details(self, response): def get_user_details(self, response):
"""Return user details from Portal account""" """Return user details from IONISx account"""
return {'username': response.get('username', ''), return {
'email': response.get('emails', '')[0]['email'], 'username': response['username'],
'fullname': response.get('name')} 'email': get_primary_email(response['emails']),
'fullname': response['name']
}
def user_data(self, access_token, *args, **kwargs): def user_data(self, access_token, *args, **kwargs):
"""Loads user data from service""" """Loads user data from service"""
params = self.setting('PROFILE_EXTRA_PARAMS', {}) return self.get_json(
params['access_token'] = access_token self.USER_DATA_URL,
return self.get_json(self.USER_DATA_URL, params=params) headers={'Authorization': 'Bearer {0}'.format(access_token)}
)
def process_error(self, data): def process_error(self, data):
super(PortalOAuth2, self).process_error(data) super(PortalOAuth2, self).process_error(data)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment