Commit 9f6edd1e by William Desloge Committed by Bertrand Marron

Add IONISx auth platform

parent ccb2e42b
...@@ -291,6 +291,12 @@ SESSION_INACTIVITY_TIMEOUT_IN_SECONDS = AUTH_TOKENS.get("SESSION_INACTIVITY_TIME ...@@ -291,6 +291,12 @@ SESSION_INACTIVITY_TIMEOUT_IN_SECONDS = AUTH_TOKENS.get("SESSION_INACTIVITY_TIME
##### X-Frame-Options response header settings ##### ##### X-Frame-Options response header settings #####
X_FRAME_OPTIONS = ENV_TOKENS.get('X_FRAME_OPTIONS', X_FRAME_OPTIONS) X_FRAME_OPTIONS = ENV_TOKENS.get('X_FRAME_OPTIONS', X_FRAME_OPTIONS)
##### Third-party auth options ################################################
THIRD_PARTY_AUTH = AUTH_TOKENS.get('THIRD_PARTY_AUTH', THIRD_PARTY_AUTH)
IONISX_AUTH = AUTH_TOKENS.get('IONISX_AUTH')
if FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
MIDDLEWARE_CLASSES += ('third_party_auth.middleware.PortalSynchronizerMiddleware',)
##### ADVANCED_SECURITY_CONFIG ##### ##### ADVANCED_SECURITY_CONFIG #####
ADVANCED_SECURITY_CONFIG = ENV_TOKENS.get('ADVANCED_SECURITY_CONFIG', {}) ADVANCED_SECURITY_CONFIG = ENV_TOKENS.get('ADVANCED_SECURITY_CONFIG', {})
......
...@@ -96,6 +96,10 @@ FEATURES = { ...@@ -96,6 +96,10 @@ FEATURES = {
# Turn on/off Microsites feature # Turn on/off Microsites feature
'USE_MICROSITES': False, 'USE_MICROSITES': False,
# Turn on third-party auth. Disabled for now because full implementations are not yet available. Remember to syncdb
# if you enable this; we don't create tables by default.
'ENABLE_THIRD_PARTY_AUTH': False,
# Allow creating courses with non-ascii characters in the course id # Allow creating courses with non-ascii characters in the course id
'ALLOW_UNICODE_COURSE_ID': False, 'ALLOW_UNICODE_COURSE_ID': False,
...@@ -668,6 +672,10 @@ for app_name in OPTIONAL_APPS: ...@@ -668,6 +672,10 @@ for app_name in OPTIONAL_APPS:
continue continue
INSTALLED_APPS += (app_name,) INSTALLED_APPS += (app_name,)
# Stub for third_party_auth options.
# See common/djangoapps/third_party_auth/settings.py for configuration details.
THIRD_PARTY_AUTH = {}
### ADVANCED_SECURITY_CONFIG ### ADVANCED_SECURITY_CONFIG
# Empty by default # Empty by default
ADVANCED_SECURITY_CONFIG = {} ADVANCED_SECURITY_CONFIG = {}
......
...@@ -25,6 +25,9 @@ def run(): ...@@ -25,6 +25,9 @@ def run():
add_mimetypes() add_mimetypes()
if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH', False):
enable_third_party_auth()
def add_mimetypes(): def add_mimetypes():
""" """
...@@ -38,3 +41,14 @@ def add_mimetypes(): ...@@ -38,3 +41,14 @@ def add_mimetypes():
mimetypes.add_type('application/x-font-opentype', '.otf') mimetypes.add_type('application/x-font-opentype', '.otf')
mimetypes.add_type('application/x-font-ttf', '.ttf') mimetypes.add_type('application/x-font-ttf', '.ttf')
mimetypes.add_type('application/font-woff', '.woff') mimetypes.add_type('application/font-woff', '.woff')
def enable_third_party_auth():
"""
Enable the use of third_party_auth, which allows users to sign in to edX
using other identity providers. For configuration details, see
common/djangoapps/third_party_auth/settings.py.
"""
from third_party_auth import settings as auth_settings
auth_settings.apply_settings(settings.THIRD_PARTY_AUTH, settings)
...@@ -49,6 +49,9 @@ urlpatterns += patterns( ...@@ -49,6 +49,9 @@ urlpatterns += patterns(
url(r'^create_account$', 'student.views.create_account', name='create_account'), url(r'^create_account$', 'student.views.create_account', name='create_account'),
url(r'^activate/(?P<key>[^/]*)$', 'student.views.activate_account', name='activate'), url(r'^activate/(?P<key>[^/]*)$', 'student.views.activate_account', name='activate'),
url(r'^signin$', 'student.views.signin_user', name="login"),
url(r'^signup$', 'student.views.signin_user', name='signup'),
# ajax view that actually does the work # ajax view that actually does the work
url(r'^login_post$', 'student.views.login_user', name='login_post'), url(r'^login_post$', 'student.views.login_user', name='login_post'),
...@@ -62,8 +65,6 @@ urlpatterns += patterns( ...@@ -62,8 +65,6 @@ urlpatterns += patterns(
url(r'^$', 'howitworks', name='homepage'), url(r'^$', 'howitworks', name='homepage'),
url(r'^howitworks$', 'howitworks'), url(r'^howitworks$', 'howitworks'),
url(r'^signup$', 'signup', name='signup'),
url(r'^signin$', 'login_page', name='login'),
url(r'^request_course_creator$', 'request_course_creator'), url(r'^request_course_creator$', 'request_course_creator'),
url(r'^course_team/{}/(?P<email>.+)?$'.format(settings.COURSE_KEY_PATTERN), 'course_team_handler'), url(r'^course_team/{}/(?P<email>.+)?$'.format(settings.COURSE_KEY_PATTERN), 'course_team_handler'),
...@@ -133,6 +134,12 @@ if settings.FEATURES.get('AUTOMATIC_AUTH_FOR_TESTING'): ...@@ -133,6 +134,12 @@ if settings.FEATURES.get('AUTOMATIC_AUTH_FOR_TESTING'):
url(r'^auto_auth$', 'student.views.auto_auth'), url(r'^auto_auth$', 'student.views.auto_auth'),
) )
# Third-party auth.
if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
urlpatterns += (
url(r'', include('third_party_auth.urls')),
)
if settings.DEBUG: if settings.DEBUG:
try: try:
from .urls_dev import urlpatterns as dev_urlpatterns from .urls_dev import urlpatterns as dev_urlpatterns
......
...@@ -9,6 +9,7 @@ import time ...@@ -9,6 +9,7 @@ import time
import json import json
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
...@@ -26,7 +27,7 @@ from django.http import (HttpResponse, HttpResponseBadRequest, HttpResponseForbi ...@@ -26,7 +27,7 @@ from django.http import (HttpResponse, HttpResponseBadRequest, HttpResponseForbi
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils.translation import ungettext from django.utils.translation import ungettext
from django_future.csrf import ensure_csrf_cookie from django_future.csrf import ensure_csrf_cookie
from django.utils.http import cookie_date, base36_to_int from django.utils.http import cookie_date, base36_to_int, urlquote
from django.utils.translation import ugettext as _, get_language from django.utils.translation import ugettext as _, get_language
from django.views.decorators.cache import never_cache from django.views.decorators.cache import never_cache
from django.views.decorators.http import require_POST, require_GET from django.views.decorators.http import require_POST, require_GET
...@@ -90,6 +91,7 @@ from util.password_policy_validators import ( ...@@ -90,6 +91,7 @@ from util.password_policy_validators import (
) )
from third_party_auth import pipeline, provider from third_party_auth import pipeline, provider
from social.apps.django_app.default import models
from xmodule.error_module import ErrorDescriptor from xmodule.error_module import ErrorDescriptor
from shoppingcart.models import CourseRegistrationCode from shoppingcart.models import CourseRegistrationCode
...@@ -335,59 +337,62 @@ def signin_user(request): ...@@ -335,59 +337,62 @@ def signin_user(request):
""" """
This view will display the non-modal login form This view will display the non-modal login form
""" """
if (settings.FEATURES['AUTH_USE_CERTIFICATES'] and if not settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
external_auth.views.ssl_get_cert_from_request(request)): if (settings.FEATURES['AUTH_USE_CERTIFICATES'] and
# SSL login doesn't require a view, so redirect external_auth.views.ssl_get_cert_from_request(request)):
# branding and allow that to process the login if it # SSL login doesn't require a view, so redirect
# is enabled and the header is in the request. # branding and allow that to process the login if it
return external_auth.views.redirect_with_get('root', request.GET) # is enabled and the header is in the request.
if settings.FEATURES.get('AUTH_USE_CAS'): return external_auth.views.redirect_with_get('root', request.GET)
# If CAS is enabled, redirect auth handling to there if settings.FEATURES.get('AUTH_USE_CAS'):
return redirect(reverse('cas-login')) # If CAS is enabled, redirect auth handling to there
if request.user.is_authenticated(): return redirect(reverse('cas-login'))
return redirect(reverse('dashboard')) if request.user.is_authenticated():
return redirect(reverse('dashboard'))
context = {
'course_id': request.GET.get('course_id'),
'enrollment_action': request.GET.get('enrollment_action'),
# Bool injected into JS to submit form if we're inside a running third-
# party auth pipeline; distinct from the actual instance of the running
# pipeline, if any.
'pipeline_running': 'true' if pipeline.running(request) else 'false',
'platform_name': microsite.get_value(
'platform_name',
settings.PLATFORM_NAME
),
}
return render_to_response('login.html', context) context = {
'course_id': request.GET.get('course_id'),
'enrollment_action': request.GET.get('enrollment_action'),
# Bool injected into JS to submit form if we're inside a running third-
# party auth pipeline; distinct from the actual instance of the running
# pipeline, if any.
'pipeline_running': 'true' if pipeline.running(request) else 'false',
'platform_name': microsite.get_value(
'platform_name',
settings.PLATFORM_NAME
),
}
return render_to_response('login.html', context)
else:
return redirect("/auth/login/portal-oauth2/?auth_entry=login")
@ensure_csrf_cookie @ensure_csrf_cookie
def register_user(request, extra_context=None): 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 request.user.is_authenticated(): if not settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
return redirect(reverse('dashboard')) if request.user.is_authenticated():
if settings.FEATURES.get('AUTH_USE_CERTIFICATES_IMMEDIATE_SIGNUP'): return redirect(reverse('dashboard'))
# Redirect to branding to process their certificate if SSL is enabled if settings.FEATURES.get('AUTH_USE_CERTIFICATES_IMMEDIATE_SIGNUP'):
# and registration is disabled. # Redirect to branding to process their certificate if SSL is enabled
return external_auth.views.redirect_with_get('root', request.GET) # and registration is disabled.
return external_auth.views.redirect_with_get('root', request.GET)
context = { context = {
'course_id': request.GET.get('course_id'), 'course_id': request.GET.get('course_id'),
'email': '', 'email': '',
'enrollment_action': request.GET.get('enrollment_action'), 'enrollment_action': request.GET.get('enrollment_action'),
'name': '', 'name': '',
'running_pipeline': None, 'running_pipeline': None,
'platform_name': microsite.get_value( 'platform_name': microsite.get_value(
'platform_name', 'platform_name',
settings.PLATFORM_NAME settings.PLATFORM_NAME
), ),
'selected_provider': '', 'selected_provider': '',
'username': '', 'username': '',
} }
# We save this so, later on, we can determine what course motivated a user's signup # We save this so, later on, we can determine what course motivated a user's signup
# if they actually complete the registration process # if they actually complete the registration process
...@@ -396,8 +401,8 @@ def register_user(request, extra_context=None): ...@@ -396,8 +401,8 @@ def register_user(request, extra_context=None):
if extra_context is not None: if extra_context is not None:
context.update(extra_context) context.update(extra_context)
if context.get("extauth_domain", '').startswith(external_auth.views.SHIBBOLETH_DOMAIN_PREFIX): if context.get("extauth_domain", '').startswith(external_auth.views.SHIBBOLETH_DOMAIN_PREFIX):
return render_to_response('register-shib.html', context) return render_to_response('register-shib.html', context)
# If third-party auth is enabled, prepopulate the form with data from the # If third-party auth is enabled, prepopulate the form with data from the
# selected provider. # selected provider.
...@@ -409,7 +414,13 @@ def register_user(request, extra_context=None): ...@@ -409,7 +414,13 @@ def register_user(request, extra_context=None):
overrides['selected_provider'] = current_provider.NAME overrides['selected_provider'] = current_provider.NAME
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("/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):
...@@ -826,6 +837,12 @@ def _get_course_enrollment_domain(course_id): ...@@ -826,6 +837,12 @@ def _get_course_enrollment_domain(course_id):
@never_cache @never_cache
@ensure_csrf_cookie @ensure_csrf_cookie
def auth_with_no_login(request):
return redirect("/auth/login/portal-oauth2/?auth_entry=login&next={0}".format(request.REQUEST.get('next', '')))
@never_cache
@ensure_csrf_cookie
def accounts_login(request): def accounts_login(request):
""" """
This view is mainly used as the redirect from the @login_required decorator. I don't believe that This view is mainly used as the redirect from the @login_required decorator. I don't believe that
...@@ -1075,6 +1092,17 @@ def login_user(request, error=""): # pylint: disable-msg=too-many-statements,un ...@@ -1075,6 +1092,17 @@ 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):
try:
user = models.DjangoStorage.user.objects.get(uid=user_mail)
response = request('POST', settings.IONISX_AUTH['SYNC_LOGOUT_URL'],
params={ 'access_token': user.extra_data['access_token'] })
except ConnectionError as err:
log.warning(err)
except Exception as err:
log.warning(err)
@ensure_csrf_cookie @ensure_csrf_cookie
def logout_user(request): def logout_user(request):
""" """
...@@ -1084,6 +1112,11 @@ def logout_user(request): ...@@ -1084,6 +1112,11 @@ def logout_user(request):
""" """
# We do not log here, because we have a handler registered # We do not log here, because we have a handler registered
# to perform logging on successful logouts. # to perform logging on successful logouts.
if isinstance(request.user, AnonymousUser):
user_mail = None
else:
user_mail = request.user.email
logout(request) logout(request)
if settings.FEATURES.get('AUTH_USE_CAS'): if settings.FEATURES.get('AUTH_USE_CAS'):
target = reverse('cas-logout') target = reverse('cas-logout')
...@@ -1094,6 +1127,8 @@ def logout_user(request): ...@@ -1094,6 +1127,8 @@ def logout_user(request):
settings.EDXMKTG_COOKIE_NAME, settings.EDXMKTG_COOKIE_NAME,
path='/', domain=settings.SESSION_COOKIE_DOMAIN, path='/', domain=settings.SESSION_COOKIE_DOMAIN,
) )
if user_mail:
logout_portal(user_mail)
return response return response
......
"""Middleware classes for third_party_auth.""" """Middleware classes for third_party_auth."""
import logging
import requests
from django.conf import settings
from django.contrib.auth import logout
from django.shortcuts import redirect
from django.contrib.auth.models import AnonymousUser
from student.models import UserProfile
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
log = logging.getLogger('third_party_auth.middleware')
class ExceptionMiddleware(SocialAuthExceptionMiddleware): class ExceptionMiddleware(SocialAuthExceptionMiddleware):
"""Custom middleware that handles conditional redirection.""" """Custom middleware that handles conditional redirection."""
...@@ -16,3 +27,37 @@ class ExceptionMiddleware(SocialAuthExceptionMiddleware): ...@@ -16,3 +27,37 @@ class ExceptionMiddleware(SocialAuthExceptionMiddleware):
auth_entry = request.session.get(pipeline.AUTH_ENTRY_KEY) auth_entry = request.session.get(pipeline.AUTH_ENTRY_KEY)
# Fall back to django settings's SOCIAL_AUTH_LOGIN_ERROR_URL. # Fall back to django settings's SOCIAL_AUTH_LOGIN_ERROR_URL.
return '/' + auth_entry if auth_entry else super(ExceptionMiddleware, self).get_redirect_uri(request, exception) return '/' + auth_entry if auth_entry else super(ExceptionMiddleware, self).get_redirect_uri(request, exception)
class PortalSynchronizerMiddleware(object):
"""Custom middleware to synchronize user status of LMS with Portal provider."""
def process_request(self, request):
if not isinstance(request.user, AnonymousUser):
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.email = response['emails'][0]['email']
user.username = response['username']
user.save()
profile = UserProfile.objects.get(user=request.user)
profile.name = response['name']
profile.save()
except requests.ConnectionError as err:
log.warning(err)
except Exception as err:
log.warning(err)
...@@ -60,6 +60,7 @@ See http://psa.matiasaguirre.net/docs/pipeline.html for more docs. ...@@ -60,6 +60,7 @@ See http://psa.matiasaguirre.net/docs/pipeline.html for more docs.
import random import random
import string # pylint: disable-msg=deprecated-module import string # pylint: disable-msg=deprecated-module
import analytics import analytics
import logging
from eventtracking import tracker from eventtracking import tracker
from django.contrib.auth.models import User from django.contrib.auth.models import User
...@@ -68,9 +69,14 @@ from django.shortcuts import redirect ...@@ -68,9 +69,14 @@ from django.shortcuts import redirect
from social.apps.django_app.default import models from social.apps.django_app.default import models
from social.exceptions import AuthException from social.exceptions import AuthException
from social.pipeline import partial from social.pipeline import partial
from django.db import IntegrityError, transaction
from student.models import (
Registration, UserProfile, create_comments_service_user
)
from . import provider from . import provider
log = logging.getLogger(__file__)
AUTH_ENTRY_KEY = 'auth_entry' AUTH_ENTRY_KEY = 'auth_entry'
AUTH_ENTRY_DASHBOARD = 'dashboard' AUTH_ENTRY_DASHBOARD = 'dashboard'
...@@ -338,6 +344,25 @@ def parse_query_params(strategy, response, *args, **kwargs): ...@@ -338,6 +344,25 @@ def parse_query_params(strategy, response, *args, **kwargs):
} }
def create_user_from_oauth(strategy, details, response, uid, is_dashboard=None, is_login=None, is_register=None, user=None, *args, **kwargs):
if 'is_new' in kwargs and kwargs['is_new'] is True:
user = User.objects.get(username=details['username'])
registration = Registration()
registration.register(user)
profile = UserProfile(user=user)
profile.name = details['fullname']
try:
profile.save()
except Exception:
log.exception("UserProfile creation failed for user {id}.".format(id=user.id))
raise
registration.activate()
registration.save()
create_comments_service_user(user)
@partial.partial @partial.partial
def redirect_to_supplementary_form(strategy, details, response, uid, is_dashboard=None, is_login=None, is_register=None, user=None, *args, **kwargs): def redirect_to_supplementary_form(strategy, details, response, uid, is_dashboard=None, is_login=None, is_register=None, user=None, *args, **kwargs):
"""Dispatches user to views outside the pipeline if necessary.""" """Dispatches user to views outside the pipeline if necessary."""
...@@ -367,6 +392,7 @@ def redirect_to_supplementary_form(strategy, details, response, uid, is_dashboar ...@@ -367,6 +392,7 @@ def redirect_to_supplementary_form(strategy, details, response, uid, is_dashboar
if is_register and user_unset: if is_register and user_unset:
return redirect('/register', name='register_user') return redirect('/register', name='register_user')
@partial.partial @partial.partial
def login_analytics(*args, **kwargs): def login_analytics(*args, **kwargs):
event_name = None event_name = None
......
from requests import HTTPError
from django.conf import settings
from social.backends.oauth import BaseOAuth2
from social.exceptions import AuthCanceled
class PortalOAuth2(BaseOAuth2):
"""Portal OAuth2 authentication backend"""
name = 'portal-oauth2'
auth_settings = settings.IONISX_AUTH
AUTHORIZATION_URL = auth_settings['AUTHORIZATION_URL']
ACCESS_TOKEN_URL = auth_settings['ACCESS_TOKEN_URL']
ACCESS_TOKEN_METHOD = 'POST'
REDIRECT_STATE = False
USER_DATA_URL = auth_settings['USER_DATA_URL']
def get_user_id(self, details, response):
"""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):
"""Return user details from Portal account"""
return {'username': response.get('username', ''),
'email': response.get('emails', '')[0]['email'],
'fullname': response.get('name')}
def user_data(self, access_token, *args, **kwargs):
"""Loads user data from service"""
params = self.setting('PROFILE_EXTRA_PARAMS', {})
params['access_token'] = access_token
return self.get_json(self.USER_DATA_URL, params=params)
def process_error(self, data):
super(PortalOAuth2, self).process_error(data)
if data.get('error_code'):
raise AuthCanceled(self, data.get('error_message') or
data.get('error_code'))
...@@ -5,6 +5,7 @@ invoke the Django armature. ...@@ -5,6 +5,7 @@ invoke the Django armature.
""" """
from social.backends import google, linkedin, facebook from social.backends import google, linkedin, facebook
from . import portal
_DEFAULT_ICON_CLASS = 'icon-signin' _DEFAULT_ICON_CLASS = 'icon-signin'
...@@ -170,6 +171,26 @@ class FacebookOauth2(BaseProvider): ...@@ -170,6 +171,26 @@ class FacebookOauth2(BaseProvider):
return provider_details.get('fullname') return provider_details.get('fullname')
class PortalOauth2(BaseProvider):
"""Provider for Portal's Oauth2 auth system."""
BACKEND_CLASS = portal.PortalOAuth2
ICON_CLASS = 'icon-ionisx'
NAME = 'Portal'
SETTINGS = {
'SOCIAL_AUTH_PORTAL_OAUTH2_KEY': None,
'SOCIAL_AUTH_PORTAL_OAUTH2_SECRET': None,
}
@classmethod
def get_email(cls, provider_details):
return provider_details.get('email')
@classmethod
def get_name(cls, provider_details):
return provider_details.get('fullname')
class Registry(object): class Registry(object):
"""Singleton registry of third-party auth providers. """Singleton registry of third-party auth providers.
......
...@@ -50,7 +50,7 @@ _FIELDS_STORED_IN_SESSION = ['auth_entry'] ...@@ -50,7 +50,7 @@ _FIELDS_STORED_IN_SESSION = ['auth_entry']
_MIDDLEWARE_CLASSES = ( _MIDDLEWARE_CLASSES = (
'third_party_auth.middleware.ExceptionMiddleware', 'third_party_auth.middleware.ExceptionMiddleware',
) )
_SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/dashboard' _SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/'
def _merge_auth_info(django_settings, auth_info): def _merge_auth_info(django_settings, auth_info):
...@@ -104,12 +104,12 @@ def _set_global_settings(django_settings): ...@@ -104,12 +104,12 @@ def _set_global_settings(django_settings):
'social.pipeline.social_auth.auth_allowed', 'social.pipeline.social_auth.auth_allowed',
'social.pipeline.social_auth.social_user', 'social.pipeline.social_auth.social_user',
'social.pipeline.user.get_username', 'social.pipeline.user.get_username',
'third_party_auth.pipeline.redirect_to_supplementary_form',
'social.pipeline.user.create_user', 'social.pipeline.user.create_user',
'social.pipeline.social_auth.associate_user', 'social.pipeline.social_auth.associate_user',
'social.pipeline.social_auth.load_extra_data', 'social.pipeline.social_auth.load_extra_data',
'social.pipeline.user.user_details', 'social.pipeline.user.user_details',
'third_party_auth.pipeline.login_analytics', 'third_party_auth.pipeline.login_analytics',
'third_party_auth.pipeline.create_user_from_oauth',
) )
# We let the user specify their email address during signup. # We let the user specify their email address during signup.
......
...@@ -446,6 +446,10 @@ X_FRAME_OPTIONS = ENV_TOKENS.get('X_FRAME_OPTIONS', X_FRAME_OPTIONS) ...@@ -446,6 +446,10 @@ X_FRAME_OPTIONS = ENV_TOKENS.get('X_FRAME_OPTIONS', X_FRAME_OPTIONS)
##### Third-party auth options ################################################ ##### Third-party auth options ################################################
THIRD_PARTY_AUTH = AUTH_TOKENS.get('THIRD_PARTY_AUTH', THIRD_PARTY_AUTH) THIRD_PARTY_AUTH = AUTH_TOKENS.get('THIRD_PARTY_AUTH', THIRD_PARTY_AUTH)
IONISX_AUTH = AUTH_TOKENS.get('IONISX_AUTH')
if FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
MIDDLEWARE_CLASSES += ('third_party_auth.middleware.PortalSynchronizerMiddleware',)
##### OAUTH2 Provider ############## ##### OAUTH2 Provider ##############
if FEATURES.get('ENABLE_OAUTH2_PROVIDER'): if FEATURES.get('ENABLE_OAUTH2_PROVIDER'):
......
...@@ -199,96 +199,6 @@ ...@@ -199,96 +199,6 @@
</section> </section>
% endif % endif
<section class="profile-sidebar">
<header class="profile">
<h1 class="user-name">${ user.username }</h1>
</header>
<section class="user-info">
<ul>
<li class="info--username">
<span class="title">${_("Full Name")} (<a href="#apply_name_change" rel="leanModal" class="edit-name">${_("edit")}</a>)</span> <span class="data">${ user.profile.name | h }</span>
</li>
<li class="info--email">
<span class="title">${_("Email")}
% if external_auth_map is None or 'shib' not in external_auth_map.external_domain:
(<a href="#change_email" rel="leanModal" class="edit-email">${_("edit")}</a>)
% endif
</span> <span class="data">${ user.email | h }</span>
</li>
%if len(language_options) > 1:
<%include file='dashboard/_dashboard_info_language.html' />
%endif
% if microsite.get_value('ENABLE_THIRD_PARTY_AUTH', settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH')):
<li class="controls--account">
<span class="title">
## Translators: this section lists all the third-party authentication providers (for example, Google and LinkedIn) the user can link with or unlink from their edX account.
${_("Connected Accounts")}
</span>
<span class="data">
<span class="third-party-auth">
% for state in provider_user_states:
<div class="auth-provider">
<div class="status">
% if state.has_account:
<i class="icon icon-link"></i> <span class="copy">${_("Linked")}</span>
% else:
<i class="icon icon-unlink"></i><span class="copy">${_("Not Linked")}</span>
% endif
</div>
<span class="provider">${state.provider.NAME}</span>
<span class="control">
% if state.has_account:
<form
action="${pipeline.get_disconnect_url(state.provider.NAME)}"
method="post"
name="${state.get_unlink_form_name()}">
<input type="hidden" name="csrfmiddlewaretoken" value="${csrf_token}">
<a href="#" onclick="document.${state.get_unlink_form_name()}.submit()">
## Translators: clicking on this removes the link between a user's edX account and their account with an external authentication provider (like Google or LinkedIn).
${_("Unlink")}
</a>
% else:
<a href="${pipeline.get_login_url(state.provider.NAME, pipeline.AUTH_ENTRY_DASHBOARD)}">
## Translators: clicking on this creates a link between a user's edX account and their account with an external authentication provider (like Google or LinkedIn).
${_("Link")}
</a>
% endif
</form>
</span>
</div>
% endfor
</span>
</li>
% endif
% if external_auth_map is None or 'shib' not in external_auth_map.external_domain:
<li class="controls--account">
<span class="title"><a href="#password_reset_complete" rel="leanModal" id="pwd_reset_button">${_("Reset Password")}</a></span>
<form id="password_reset_form" method="post" data-remote="true" action="${reverse('password_reset')}">
<input id="id_email" type="hidden" name="email" maxlength="75" value="${user.email}" />
<!-- <input type="submit" id="pwd_reset_button" value="${_("Reset Password")}" /> -->
</form>
</li>
% endif
<%include file='dashboard/_dashboard_status_verification.html' />
<%include file='dashboard/_dashboard_reverification_sidebar.html' />
</ul>
</section>
</section>
<section class="my-courses" id="my-courses"> <section class="my-courses" id="my-courses">
<header> <header>
<h2>${_("Current Courses")}</h2> <h2>${_("Current Courses")}</h2>
......
...@@ -31,7 +31,7 @@ urlpatterns = ('', # nopep8 ...@@ -31,7 +31,7 @@ urlpatterns = ('', # nopep8
url(r'^segmentio/event$', 'track.views.segmentio.track_segmentio_event'), url(r'^segmentio/event$', 'track.views.segmentio.track_segmentio_event'),
url(r'^t/(?P<template>[^/]*)$', 'static_template_view.views.index'), # TODO: Is this used anymore? What is STATIC_GRAB? url(r'^t/(?P<template>[^/]*)$', 'static_template_view.views.index'), # TODO: Is this used anymore? What is STATIC_GRAB?
url(r'^accounts/login$', 'student.views.accounts_login', name="accounts_login"), url(r'^accounts/login$', 'student.views.auth_with_no_login', name="auto_login"),
url(r'^accounts/manage_user_standing', 'student.views.manage_user_standing', url(r'^accounts/manage_user_standing', 'student.views.manage_user_standing',
name='manage_user_standing'), name='manage_user_standing'),
url(r'^accounts/disable_account_ajax$', 'student.views.disable_account_ajax', url(r'^accounts/disable_account_ajax$', 'student.views.disable_account_ajax',
......
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