Commit 16d47b61 by ichuang

add auto_enroll and ssl_login_shortcut decorators

see AUTH_USE_MIT_CERTIFICATES and ENABLE_AUTO_COURSE_REGISTRATION features
parent bffd9ac3
......@@ -217,6 +217,56 @@ def ssl_dn_extract_info(dn):
return (user, email, fullname)
def ssl_get_cert_from_request(request):
"""
Extract user information from certificate, if it exists, returning (user, email, fullname).
Else return None.
"""
certkey = "SSL_CLIENT_S_DN" # specify the request.META field to use
cert = request.META.get(certkey, '')
if not cert:
cert = request.META.get('HTTP_' + certkey, '')
if not cert:
try:
# try the direct apache2 SSL key
cert = request._req.subprocess_env.get(certkey, '')
except Exception:
return ''
return cert
(user, email, fullname) = ssl_dn_extract_info(cert)
return (user, email, fullname)
def ssl_login_shortcut(fn):
"""
Python function decorator for login procedures, to allow direct login
based on existing ExternalAuth record and MIT ssl certificate.
"""
def wrapped(*args, **kwargs):
if not settings.MITX_FEATURES.get('AUTH_USE_MIT_CERTIFICATES',''):
return fn(*args, **kwargs)
request = args[0]
cert = ssl_get_cert_from_request(request)
if not cert: # no certificate information - show normal login window
return fn(*args, **kwargs)
(user, email, fullname) = ssl_dn_extract_info(cert)
def continue_login():
return fn(*args, **kwargs)
return external_login_or_signup(request,
external_id=email,
external_domain="ssl:MIT",
credentials=cert,
email=email,
fullname=fullname,
retfun=continue_login)
return wrapped
@csrf_exempt
def ssl_login(request):
"""
......
......@@ -38,6 +38,7 @@ from datetime import date
from collections import namedtuple
from courseware.courses import get_courses_by_university
from courseware.access import has_access
from courseware.courses import get_course_with_access
log = logging.getLogger("mitx.student")
Article = namedtuple('Article', 'title url author image deck publication publish_date')
......@@ -146,6 +147,38 @@ def dashboard(request):
return render_to_response('dashboard.html', context)
def auto_enroll(fn):
"""
Automatically enroll user in course (if has access)
This function may be used as a decorator.
"""
def wrapped(*args, **kwargs):
if not settings.MITX_FEATURES.get('ENABLE_AUTO_COURSE_REGISTRATION',''):
return fn(*args, **kwargs)
if 'course_id' not in kwargs:
log.debug('[auto_enroll] no course_id - kwargs=%s' % kwargs)
return fn(*args, **kwargs)
request = args[0]
course_id = kwargs['course_id']
user = request.user
try:
course = get_course_with_access(request.user, course_id, 'load')
except ItemNotFoundError:
log.warning("User {0} tried to enroll in non-existant course {1}"
.format(user.username, course_id))
registered = CourseEnrollment.objects.filter(user=user, course_id=course.id).exists()
if registered:
return fn(*args, **kwargs)
if has_access(user, course, 'enroll'):
enrollment, created = CourseEnrollment.objects.get_or_create(user=user, course_id=course.id)
log.debug('User %s enrolled in %s' % (user, course_id))
return fn(*args, **kwargs)
return wrapped
#return fn
def try_change_enrollment(request):
"""
This method calls change_enrollment if the necessary POST
......
......@@ -30,6 +30,8 @@ from multicourse import multicourse_settings
from django_comment_client.utils import get_discussion_title
from student.views import auto_enroll
from external_auth.views import ssl_login_shortcut
from student.models import UserTestGroup, CourseEnrollment
from util.cache import cache, cache_if_anonymous
from xmodule.course_module import CourseDescriptor
......@@ -158,6 +160,8 @@ def save_child_position(seq_module, child_name, instance_module):
instance_module.save()
@login_required
@auto_enroll
@ssl_login_shortcut
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
def index(request, course_id, chapter=None, section=None,
......
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