Skip to content
Snippets Groups Projects
Commit ce0b6407 authored by John Cox's avatar John Cox
Browse files

Add third-party auth implementation and tests

parent 83853098
No related merge requests found
<%! from django.utils.translation import ugettext as _ %>
<%! from django.template import RequestContext %>
<%! from third_party_auth import pipeline %>
<%!
from django.core.urlresolvers import reverse
......@@ -194,6 +195,13 @@
</section>
%endif
% if duplicate_provider:
<section class="dashboard-banner third-party-auth">
## Translators: this message is displayed when a user tries to link their account with a third-party authentication provider (for example, Google or LinkedIn) with a given edX account, but their third-party account is already associated with another edX account. provider_name is the name of the third-party authentication provider, and platform_name is the name of the edX deployment.
${_('The selected {provider_name} account is already linked to another {platform_name} account. Please {link_start}log out{link_end}, then log in with your {provider_name} account.').format(link_end='</a>', link_start='<a href="%s">' % logout_url, provider_name='<strong>%s</strong>' % duplicate_provider.NAME, platform_name=platform_name)}
</section>
% endif
<section class="profile-sidebar">
<header class="profile">
<h1 class="user-name">${ user.username }</h1>
......@@ -215,6 +223,53 @@
<%include file='dashboard/_dashboard_info_language.html' />
%endif
% if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
<li class="controls--account">
<span class="title">
<div class="icon icon-gears"></div>
## 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.
${_("Account Links")}
</span>
<span class="data">
<span class="third-party-auth">
% for state in provider_user_states:
<div>
% if state.has_account:
<span class="icon icon-link pull-left"></span>
% else:
<span class="icon icon-unlink pull-left"></span>
% endif
<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}">
</form>
<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
</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"><div class="icon"></div><a href="#password_reset_complete" rel="leanModal" id="pwd_reset_button">${_("Reset Password")}</a></span>
......
......@@ -4,6 +4,7 @@
<%! from django.core.urlresolvers import reverse %>
<%! from django.utils.translation import ugettext as _ %>
<%! from third_party_auth import provider, pipeline %>
<%block name="pagetitle">${_("Log into your {platform_name} Account").format(platform_name=platform_name)}</%block>
......@@ -93,6 +94,22 @@
text("${_(u'Processing your account information…')}");
}
}
function thirdPartySignin(event, url) {
event.preventDefault();
window.location.href = url;
}
(function post_form_if_pipeline_running(pipeline_running) {
// If the pipeline is running, the user has already authenticated via a
// third-party provider. We want to invoke /login_ajax to loop in the
// code that does logging and sets cookies on the request. It is most
// consistent to do that by using the same mechanism that is used when
// the use does first-party sign-in: POSTing the sign-in form.
if (pipeline_running) {
$('#login-form').submit();
}
})(${pipeline_running})
</script>
</%block>
......@@ -164,6 +181,28 @@
<button name="submit" type="submit" id="submit" class="action action-primary action-update"></button>
</div>
</form>
% if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
<hr />
<p class="instructions">
## Developers: this is a sentence fragment, which is usually frowned upon. The design of the pags uses this fragment to provide an "else" clause underneath a number of choices. It's OK to leave it.
## Translators: this is the last choice of a number of choices of how to log in to the site.
${_('or, if you have connected one of these providers, log in below.')}
</p>
<div class="form-actions form-third-party-auth">
% for enabled in provider.Registry.enabled():
## Translators: provider_name is the name of an external, third-party user authentication provider (like Google or LinkedIn).
<button type="submit" class="button button-primary" onclick="thirdPartySignin(event, '${pipeline.get_login_url(enabled.NAME, pipeline.AUTH_ENTRY_LOGIN)}');"><span class="icon ${enabled.ICON_CLASS}"></span>${_('Sign in with {provider_name}').format(provider_name=enabled.NAME)}</button>
% endfor
</div>
% endif
</section>
<aside role="complementary">
......
......@@ -12,6 +12,7 @@
<%! from django.utils.translation import ugettext as _ %>
<%! from student.models import UserProfile %>
<%! from datetime import date %>
<%! from third_party_auth import pipeline, provider %>
<%! import calendar %>
<%block name="pagetitle">${_("Register for {platform_name}").format(platform_name=platform_name)}</%block>
......@@ -67,6 +68,11 @@
});
})(this);
function thirdPartySignin(event, url) {
event.preventDefault();
window.location.href = url;
}
function toggleSubmitButton(enable) {
var $submitButton = $('form .form-actions #submit');
......@@ -110,11 +116,46 @@
<ul class="message-copy"> </ul>
</div>
% if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
% if not running_pipeline:
<p class="instructions">
${_("Register to start learning today!")}
</p>
<div class="form-actions form-third-party-auth">
% for enabled in provider.Registry.enabled():
## Translators: provider_name is the name of an external, third-party user authentication service (like Google or LinkedIn).
<button type="submit" class="button button-primary" onclick="thirdPartySignin(event, '${pipeline.get_login_url(enabled.NAME, pipeline.AUTH_ENTRY_REGISTER)}');"><span class="icon ${enabled.ICON_CLASS}"></span>${_('Sign in with {provider_name}').format(provider_name=enabled.NAME)}</button>
% endfor
</div>
<p class="instructions">
${_('or create your own {platform_name} account by completing all <strong>required*</strong> fields below.').format(platform_name=platform_name)}
</p>
% else:
<p class="instructions">
## Translators: selected_provider is the name of an external, third-party user authentication service (like Google or LinkedIn).
${_("You've successfully signed in with {selected_provider}.").format(selected_provider='<strong>%s</strong>' % selected_provider)}<br />
${_("Finish your account registration below to start learning.")}
</p>
% endif
% else:
<p class="instructions">
${_("Please complete the following fields to register for an account. ")}<br />
${_('Required fields are noted by <strong class="indicator">bold text and an asterisk (*)</strong>.')}
</p>
% endif
<div class="group group-form group-form-requiredinformation">
<h2 class="sr">${_('Required Information')}</h2>
......@@ -123,20 +164,33 @@
<ol class="list-input">
<li class="field required text" id="field-email">
<label for="email">${_('E-mail')}</label>
<input class="" id="email" type="email" name="email" value="" placeholder="${_('example: username@domain.com')}" required aria-required="true" />
<input class="" id="email" type="email" name="email" value="${email}" placeholder="${_('example: username@domain.com')}" required aria-required="true" />
</li>
% if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH') and running_pipeline:
<li class="is-disabled field optional password" id="field-password" hidden>
<label for="password">${_('Password')}</label>
<input id="password" type="password" name="password" value="" disabled required aria-required="true" />
</li>
% else:
<li class="field required password" id="field-password">
<label for="password">${_('Password')}</label>
<input id="password" type="password" name="password" value="" required aria-required="true" />
</li>
% endif
<li class="field required text" id="field-username">
<label for="username">${_('Public Username')}</label>
<input id="username" type="text" name="username" value="" placeholder="${_('example: JaneDoe')}" required aria-required="true" aria-describedby="username-tip"/>
<input id="username" type="text" name="username" value="${username}" placeholder="${_('example: JaneDoe')}" required aria-required="true" aria-describedby="username-tip"/>
<span class="tip tip-input" id="username-tip">${_('Will be shown in any discussions or forums you participate in')} <strong>(${_('cannot be changed later')})</strong></span>
</li>
<li class="field required text" id="field-name">
<label for="name">${_('Full Name')}</label>
<input id="name" type="text" name="name" value="" placeholder="${_('example: Jane Doe')}" required aria-required="true" aria-describedby="name-tip" />
<input id="name" type="text" name="name" value="${name}" placeholder="${_('example: Jane Doe')}" required aria-required="true" aria-describedby="name-tip" />
<span class="tip tip-input" id="name-tip">${_("Needed for any certificates you may earn")}</span>
</li>
</ol>
......
......@@ -60,7 +60,7 @@ pyparsing==2.0.1
python-memcached==1.48
python-openid==2.2.5
python-dateutil==2.1
python-social-auth==0.1.21
python-social-auth==0.1.23
pytz==2012h
pysrt==0.4.7
PyYAML==3.10
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment