Commit 18546521 by ichuang

add openid authentication

parent 7f2f4759
...@@ -61,6 +61,15 @@ def index(request): ...@@ -61,6 +61,15 @@ def index(request):
if settings.COURSEWARE_ENABLED and request.user.is_authenticated(): if settings.COURSEWARE_ENABLED and request.user.is_authenticated():
return redirect(reverse('dashboard')) return redirect(reverse('dashboard'))
return main_index()
def main_index(extra_context = {}):
'''
Render the edX main page.
extra_context is used to allow immediate display of certain modal windows, eg signup,
as used by external_auth.
'''
feed_data = cache.get("students_index_rss_feed_data") feed_data = cache.get("students_index_rss_feed_data")
if feed_data == None: if feed_data == None:
if hasattr(settings, 'RSS_URL'): if hasattr(settings, 'RSS_URL'):
...@@ -81,8 +90,9 @@ def index(request): ...@@ -81,8 +90,9 @@ def index(request):
for course in courses: for course in courses:
universities[course.org].append(course) universities[course.org].append(course)
return render_to_response('index.html', {'universities': universities, 'entries': entries}) context = {'universities': universities, 'entries': entries}
context.update(extra_context)
return render_to_response('index.html', context)
def course_from_id(id): def course_from_id(id):
course_loc = CourseDescriptor.id_to_location(id) course_loc = CourseDescriptor.id_to_location(id)
...@@ -257,11 +267,26 @@ def change_setting(request): ...@@ -257,11 +267,26 @@ def change_setting(request):
@ensure_csrf_cookie @ensure_csrf_cookie
def create_account(request, post_override=None): def create_account(request, post_override=None):
''' JSON call to enroll in the course. ''' '''
JSON call to create new edX account.
Used by form in signup_modal.html, which is included into navigation.html
'''
js = {'success': False} js = {'success': False}
post_vars = post_override if post_override else request.POST post_vars = post_override if post_override else request.POST
# if doing signup for an external authorization, then get email, password, name from the eamap
# don't use the ones from the form, since the user could have hacked those
doExternalAuth = 'ExternalAuthMap' in request.session
if doExternalAuth:
eamap = request.session['ExternalAuthMap']
email = eamap.external_email
name = eamap.external_name
password = eamap.internal_password
post_vars = dict(post_vars.items())
post_vars.update(dict(email=email, name=name, password=password, username=post_vars['username']))
log.debug('extauth test: post_vars = %s' % post_vars)
# Confirm we have a properly formed request # Confirm we have a properly formed request
for a in ['username', 'email', 'password', 'name']: for a in ['username', 'email', 'password', 'name']:
if a not in post_vars: if a not in post_vars:
...@@ -356,8 +381,9 @@ def create_account(request, post_override=None): ...@@ -356,8 +381,9 @@ def create_account(request, post_override=None):
'key': r.activation_key, 'key': r.activation_key,
} }
# composes activation email
subject = render_to_string('emails/activation_email_subject.txt', d) subject = render_to_string('emails/activation_email_subject.txt', d)
# Email subject *must not* contain newlines # Email subject *must not* contain newlines
subject = ''.join(subject.splitlines()) subject = ''.join(subject.splitlines())
message = render_to_string('emails/activation_email.txt', d) message = render_to_string('emails/activation_email.txt', d)
...@@ -382,6 +408,17 @@ def create_account(request, post_override=None): ...@@ -382,6 +408,17 @@ def create_account(request, post_override=None):
try_change_enrollment(request) try_change_enrollment(request)
if doExternalAuth:
eamap.user = login_user
eamap.dtsignup = datetime.datetime.now()
eamap.save()
log.debug('Updated ExternalAuthMap for %s to be %s' % (post_vars['username'],eamap))
if settings.MITX_FEATURES.get('BYPASS_ACTIVATION_EMAIL_FOR_EXTAUTH'):
log.debug('bypassing activation email')
login_user.is_active = True
login_user.save()
js = {'success': True} js = {'success': True}
return HttpResponse(json.dumps(js), mimetype="application/json") return HttpResponse(json.dumps(js), mimetype="application/json")
......
...@@ -55,6 +55,18 @@ CACHES = { ...@@ -55,6 +55,18 @@ CACHES = {
# Dummy secret key for dev # Dummy secret key for dev
SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd' SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
################################ OpenID Auth #################################
MITX_FEATURES['AUTH_USE_OPENID'] = True
MITX_FEATURES['BYPASS_ACTIVATION_EMAIL_FOR_EXTAUTH'] = True
INSTALLED_APPS += ('external_auth',)
INSTALLED_APPS += ('django_openid_auth',)
OPENID_CREATE_USERS = False
OPENID_UPDATE_DETAILS_FROM_SREG = True
OPENID_SSO_SERVER_URL = 'https://www.google.com/accounts/o8/id' # TODO: accept more endpoints
OPENID_USE_AS_ADMIN_LOGIN = False
################################ DEBUG TOOLBAR ################################# ################################ DEBUG TOOLBAR #################################
INSTALLED_APPS += ('debug_toolbar',) INSTALLED_APPS += ('debug_toolbar',)
MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware',) MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware',)
......
...@@ -7,142 +7,110 @@ sessions. Assumes structure: ...@@ -7,142 +7,110 @@ sessions. Assumes structure:
/mitx # The location of this repo /mitx # The location of this repo
/log # Where we're going to write log files /log # Where we're going to write log files
""" """
import socket
if 'eecs1' in socket.gethostname():
MITX_ROOT_URL = '/mitx2'
from .common import * from .common import *
from .logsettings import get_logger_config from .logsettings import get_logger_config
from .dev import *
if 'eecs1' in socket.gethostname():
# MITX_ROOT_URL = '/mitx2'
MITX_ROOT_URL = 'https://eecs1.mit.edu/mitx2'
#-----------------------------------------------------------------------------
# edx4edx content server
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
MITX_FEATURES['REROUTE_ACTIVATION_EMAIL'] = 'ichuang@mit.edu'
EDX4EDX_ROOT = ENV_ROOT / "data/edx4edx"
#EMAIL_BACKEND = 'django_ses.SESBackend'
#-----------------------------------------------------------------------------
# ichuang
DEBUG = True DEBUG = True
ENABLE_MULTICOURSE = True # set to False to disable multicourse display (see lib.util.views.mitxhome) TEMPLATE_DEBUG = True
QUICKEDIT = False
MITX_FEATURES['DISABLE_START_DATES'] = True
MAKO_TEMPLATES['course'] = [DATA_DIR, EDX4EDX_ROOT ]
WIKI_ENABLED = True
#MITX_FEATURES['USE_DJANGO_PIPELINE'] = False
MITX_FEATURES['DISPLAY_HISTOGRAMS_TO_STAFF'] = False LOGGING = get_logger_config(ENV_ROOT / "log",
MITX_FEATURES['DISPLAY_EDIT_LINK'] = True logging_env="dev",
MITX_FEATURES['DEBUG_LEVEL'] = 10 # 0 = lowest level, least verbose, 255 = max level, most verbose tracking_filename="tracking.log",
debug=True)
COURSE_SETTINGS = {'6.002x_Fall_2012': {'number' : '6.002x',
'title' : 'Circuits and Electronics', DATABASES = {
'xmlpath': '/6002x-fall-2012/', 'default': {
'active' : True, 'ENGINE': 'django.db.backends.sqlite3',
'default_chapter' : 'Week_1', 'NAME': ENV_ROOT / "db" / "mitx.db",
'default_section' : 'Administrivia_and_Circuit_Elements', }
'location': 'i4x://edx/6002xs12/course/6.002x_Fall_2012', }
},
'8.02_Spring_2013': {'number' : '8.02x', CACHES = {
'title' : 'Electricity & Magnetism', # This is the cache used for most things. Askbot will not work without a
'xmlpath': '/802x/', # functioning cache -- it relies on caching to load its settings in places.
'github_url': 'https://github.com/MITx/8.02x', # In staging/prod envs, the sessions also live here.
'active' : True, 'default': {
'default_chapter' : 'Introduction', 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'default_section' : 'Introduction_%28Lewin_2002%29', 'LOCATION': 'mitx_loc_mem_cache',
}, 'KEY_FUNCTION': 'util.memcache.safe_key',
'6.189_Spring_2013': {'number' : '6.189x', },
'title' : 'IAP Python Programming',
'xmlpath': '/6.189x/', # The general cache is what you get if you use our util.cache. It's used for
'github_url': 'https://github.com/MITx/6.189x', # things like caching the course.xml file for different A/B test groups.
'active' : True, # We set it to be a DummyCache to force reloading of course.xml in dev.
'default_chapter' : 'Week_1', # In staging environments, we would grab VERSION from data uploaded by the
'default_section' : 'Variables_and_Binding', # push process.
}, 'general': {
'8.01_Fall_2012': {'number' : '8.01x', 'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
'title' : 'Mechanics', 'KEY_PREFIX': 'general',
'xmlpath': '/8.01x/', 'VERSION': 4,
'github_url': 'https://github.com/MITx/8.01x', 'KEY_FUNCTION': 'util.memcache.safe_key',
'active': True, }
'default_chapter' : 'Mechanics_Online_Spring_2012', }
'default_section' : 'Introduction_to_the_course',
'location': 'i4x://edx/6002xs12/course/8.01_Fall_2012', # Dummy secret key for dev
}, SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
'edx4edx': {'number' : 'edX.01',
'title' : 'edx4edx: edX Author Course', ################################ OpenID Auth #################################
'xmlpath': '/edx4edx/', MITX_FEATURES['AUTH_USE_OPENID'] = True
'github_url': 'https://github.com/MITx/edx4edx',
'active' : True, INSTALLED_APPS += ('external_auth',)
'default_chapter' : 'Introduction', INSTALLED_APPS += ('django_openid_auth',)
'default_section' : 'edx4edx_Course', #INSTALLED_APPS += ('ssl_auth',)
'location': 'i4x://edx/6002xs12/course/edx4edx',
}, #MIDDLEWARE_CLASSES += (
'7.03x_Fall_2012': {'number' : '7.03x', # #'ssl_auth.ssl_auth.NginxProxyHeaderMiddleware', # ssl authentication behind nginx proxy
'title' : 'Genetics', # )
'xmlpath': '/7.03x/',
'github_url': 'https://github.com/MITx/7.03x', #AUTHENTICATION_BACKENDS = (
'active' : True, # 'django_openid_auth.auth.OpenIDBackend',
'default_chapter' : 'Week_2', # 'django.contrib.auth.backends.ModelBackend',
'default_section' : 'ps1_question_1', # )
},
'3.091x_Fall_2012': {'number' : '3.091x', OPENID_CREATE_USERS = False
'title' : 'Introduction to Solid State Chemistry', OPENID_UPDATE_DETAILS_FROM_SREG = True
'xmlpath': '/3.091x/', OPENID_SSO_SERVER_URL = 'https://www.google.com/accounts/o8/id'
'github_url': 'https://github.com/MITx/3.091x', OPENID_USE_AS_ADMIN_LOGIN = False
'active' : True, #import external_auth.views as edXauth
'default_chapter' : 'Week_1', #OPENID_RENDER_FAILURE = edXauth.edXauth_openid
'default_section' : 'Problem_Set_1',
}, ################################ DEBUG TOOLBAR #################################
'18.06x_Linear_Algebra': {'number' : '18.06x', INSTALLED_APPS += ('debug_toolbar',)
'title' : 'Linear Algebra', MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware',)
'xmlpath': '/18.06x/', INTERNAL_IPS = ('127.0.0.1',)
'github_url': 'https://github.com/MITx/18.06x',
'default_chapter' : 'Unit_1', DEBUG_TOOLBAR_PANELS = (
'default_section' : 'Midterm_1', 'debug_toolbar.panels.version.VersionDebugPanel',
'active' : True, 'debug_toolbar.panels.timer.TimerDebugPanel',
}, 'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel',
'6.00x_Fall_2012': {'number' : '6.00x', 'debug_toolbar.panels.headers.HeaderDebugPanel',
'title' : 'Introduction to Computer Science and Programming', 'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',
'xmlpath': '/6.00x/', 'debug_toolbar.panels.sql.SQLDebugPanel',
'github_url': 'https://github.com/MITx/6.00x', 'debug_toolbar.panels.signals.SignalDebugPanel',
'active' : True, 'debug_toolbar.panels.logger.LoggingPanel',
'default_chapter' : 'Week_0',
'default_section' : 'Problem_Set_0', # Enabling the profiler has a weird bug as of django-debug-toolbar==0.9.4 and
'location': 'i4x://edx/6002xs12/course/6.00x_Fall_2012', # Django=1.3.1/1.4 where requests to views get duplicated (your method gets
}, # hit twice). So you can uncomment when you need to diagnose performance
'7.00x_Fall_2012': {'number' : '7.00x', # problems, but you shouldn't leave it on.
'title' : 'Introduction to Biology', # 'debug_toolbar.panels.profiling.ProfilingDebugPanel',
'xmlpath': '/7.00x/', )
'github_url': 'https://github.com/MITx/7.00x',
'active' : True, ############################ FILE UPLOADS (ASKBOT) #############################
'default_chapter' : 'Unit 1', DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
'default_section' : 'Introduction', MEDIA_ROOT = ENV_ROOT / "uploads"
}, MEDIA_URL = "/static/uploads/"
} STATICFILES_DIRS.append(("uploads", MEDIA_ROOT))
FILE_UPLOAD_TEMP_DIR = ENV_ROOT / "uploads"
#----------------------------------------------------------------------------- FILE_UPLOAD_HANDLERS = (
'django.core.files.uploadhandler.MemoryFileUploadHandler',
MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + ( 'django.core.files.uploadhandler.TemporaryFileUploadHandler',
'ssl_auth.ssl_auth.NginxProxyHeaderMiddleware', # ssl authentication behind nginx proxy )
)
########################### PIPELINE #################################
AUTHENTICATION_BACKENDS = (
'ssl_auth.ssl_auth.SSLLoginBackend', PIPELINE_SASS_ARGUMENTS = '-r {proj_dir}/static/sass/bourbon/lib/bourbon.rb'.format(proj_dir=PROJECT_ROOT)
'django.contrib.auth.backends.ModelBackend',
)
INSTALLED_APPS = INSTALLED_APPS + (
'ssl_auth',
)
LOGIN_REDIRECT_URL = MITX_ROOT_URL + '/'
LOGIN_URL = MITX_ROOT_URL + '/'
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>OpenID failed</title>
</head>
<body>
<h1>OpenID failed</h1>
<p>${message}</p>
</body>
</html>
...@@ -144,3 +144,12 @@ ...@@ -144,3 +144,12 @@
<iframe width="640" height="360" src="http://www.youtube.com/embed/C2OQ51tu7W4?showinfo=0" frameborder="0" allowfullscreen></iframe> <iframe width="640" height="360" src="http://www.youtube.com/embed/C2OQ51tu7W4?showinfo=0" frameborder="0" allowfullscreen></iframe>
</div> </div>
</section> </section>
% if show_signup_immediately is not UNDEFINED:
<script type="text/javascript">
function dosignup(){
document.getElementById('signup').click();
}
$(window).load(dosignup);
</script>
% endif
...@@ -27,6 +27,9 @@ ...@@ -27,6 +27,9 @@
<span>Not enrolled? <a href="#signup-modal" class="close-login" rel="leanModal">Sign up.</a></span> <span>Not enrolled? <a href="#signup-modal" class="close-login" rel="leanModal">Sign up.</a></span>
<a href="#forgot-password-modal" rel="leanModal" class="pwd-reset">Forgot password?</a> <a href="#forgot-password-modal" rel="leanModal" class="pwd-reset">Forgot password?</a>
</p> </p>
<p>
<a href="${MITX_ROOT_URL}/openid/login">login via openid</a>
</p>
</section> </section>
<div class="close-modal"> <div class="close-modal">
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
<div id="register_error" name="register_error"></div> <div id="register_error" name="register_error"></div>
<div class="input-group"> <div class="input-group">
% if has_extauth_info is UNDEFINED:
<label data-field="email">E-mail*</label> <label data-field="email">E-mail*</label>
<input name="email" type="email" placeholder="E-mail*"> <input name="email" type="email" placeholder="E-mail*">
<label data-field="password">Password*</label> <label data-field="password">Password*</label>
...@@ -27,6 +28,18 @@ ...@@ -27,6 +28,18 @@
<input name="username" type="text" placeholder="Public Username*"> <input name="username" type="text" placeholder="Public Username*">
<label data-field="name">Full Name</label> <label data-field="name">Full Name</label>
<input name="name" type="text" placeholder="Full Name*"> <input name="name" type="text" placeholder="Full Name*">
% else:
<p><i>Welcome</i> ${extauth_email}</p><br/>
<label data-field="email">E-mail*</label>
<input name="email" type="hidden" value="${extauth_email}" placeholder="E-mail*">
<p><i>Enter a public username:</i></p>
<label data-field="username">Public Username*</label>
<input name="username" type="text" value="${extauth_username}" placeholder="Public Username*">
<label data-field="password">Password*</label>
<input name="password" type="hidden" value="DoExtAuth" placeholder="Password*">
<label data-field="name">Full Name</label>
<input name="name" type="hidden" value="${extauth_name}" placeholder="Full Name*">
% endif
</div> </div>
<div class="input-group"> <div class="input-group">
...@@ -93,11 +106,13 @@ ...@@ -93,11 +106,13 @@
</div> </div>
</form> </form>
% if has_extauth_info is UNDEFINED:
<section class="login-extra"> <section class="login-extra">
<p> <p>
<span>Already have an account? <a href="#login-modal" class="close-signup" rel="leanModal">Login.</a></span> <span>Already have an account? <a href="#login-modal" class="close-signup" rel="leanModal">Login.</a></span>
</p> </p>
</section> </section>
% endif
</div> </div>
......
...@@ -160,12 +160,22 @@ if settings.DEBUG: ...@@ -160,12 +160,22 @@ if settings.DEBUG:
## Jasmine ## Jasmine
urlpatterns=urlpatterns + (url(r'^_jasmine/', include('django_jasmine.urls')),) urlpatterns=urlpatterns + (url(r'^_jasmine/', include('django_jasmine.urls')),)
if settings.MITX_FEATURES.get('AUTH_USE_OPENID'):
urlpatterns += (
url(r'^openid/login/$', 'django_openid_auth.views.login_begin', name='openid-login'),
url(r'^openid/complete/$', 'external_auth.views.edXauth_openid_login_complete', name='openid-complete'),
url(r'^openid/logo.gif$', 'django_openid_auth.views.logo', name='openid-logo'),
)
urlpatterns += (
url(r'^extauth/$', 'external_auth.views.edXauth_signup', name='extauth-signup'),
)
# urlpatterns += (url(r'^openid/', include('django_openid_auth.urls')),)
urlpatterns = patterns(*urlpatterns) urlpatterns = patterns(*urlpatterns)
if settings.DEBUG: if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
#Custom error pages #Custom error pages
handler404 = 'static_template_view.views.render_404' handler404 = 'static_template_view.views.render_404'
handler500 = 'static_template_view.views.render_500' handler500 = 'static_template_view.views.render_500'
......
...@@ -8,6 +8,7 @@ lxml ...@@ -8,6 +8,7 @@ lxml
boto boto
mako mako
python-memcached python-memcached
python-openid
path.py path.py
django_debug_toolbar django_debug_toolbar
-e git://github.com/MITx/django-pipeline.git#egg=django-pipeline -e git://github.com/MITx/django-pipeline.git#egg=django-pipeline
...@@ -37,6 +38,7 @@ django-jasmine ...@@ -37,6 +38,7 @@ django-jasmine
django-keyedcache django-keyedcache
django-mako django-mako
django-masquerade django-masquerade
django-openid-auth
django-robots django-robots
django-ses django-ses
django-storages django-storages
......
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