Merge lp:~canonical-isd-hackers/canonical-identity-provider/yubikey-acct-requires-key into lp:~canonical-isd-hackers/canonical-identity-provider/add-yubikey-support

Proposed by Danny Tamez
Status: Merged
Approved by: David Owen
Approved revision: no longer in the source branch.
Merged at revision: 162
Proposed branch: lp:~canonical-isd-hackers/canonical-identity-provider/yubikey-acct-requires-key
Merge into: lp:~canonical-isd-hackers/canonical-identity-provider/add-yubikey-support
Diff against target: 264 lines (+158/-12)
6 files modified
identityprovider/forms.py (+0/-8)
identityprovider/templates/ubuntu/registration/two_step.html (+122/-0)
identityprovider/tests/test_views_ui.py (+24/-0)
identityprovider/urls.py (+1/-0)
identityprovider/views/account.py (+2/-4)
identityprovider/views/ui.py (+9/-0)
To merge this branch: bzr merge lp:~canonical-isd-hackers/canonical-identity-provider/yubikey-acct-requires-key
Reviewer Review Type Date Requested Status
David Owen (community) Approve
Review via email: mp+60778@code.launchpad.net

Commit message

Initial step for redirect to two form auth page when the account requires it.

Description of the change

This branch is the initial step towards two step authentication if the account requires it. If the acct requires it then after filling out email and password they will be redirected to a second page. This second page is only stubbed out right now. Newz2000 will finish that page.

To post a comment you must log in.
Revision history for this message
David Owen (dsowen) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'identityprovider/forms.py'
--- identityprovider/forms.py 2011-05-11 18:35:14 +0000
+++ identityprovider/forms.py 2011-05-12 13:21:07 +0000
@@ -74,14 +74,6 @@
74 raise forms.ValidationError(_("Your account has been "74 raise forms.ValidationError(_("Your account has been "
75 "deactivated"))75 "deactivated"))
7676
77 # check that the yubikey belongs to this acct
78 #TODO: DT Dynamic based on openid request
79 if hasattr(self, 'yubikey'):
80 try:
81 account.yubikey_set.get(pk=self.yubikey)
82 except YubiKey.DoesNotExist:
83 raise forms.ValidationError(_("This key is not valid for "
84 "this account"))
85 if user is not None and user.is_active:77 if user is not None and user.is_active:
86 return self.cleaned_data78 return self.cleaned_data
87 else:79 else:
8880
=== added file 'identityprovider/templates/ubuntu/registration/two_step.html'
--- identityprovider/templates/ubuntu/registration/two_step.html 1970-01-01 00:00:00 +0000
+++ identityprovider/templates/ubuntu/registration/two_step.html 2011-05-12 13:21:07 +0000
@@ -0,0 +1,122 @@
1
2{% extends "twocols.html" %}
3
4{% comment %}
5Copyright 2010 Canonical Ltd. This software is licensed under the
6GNU Affero General Public License version 3 (see the file LICENSE).
7{% endcomment %}
8
9{% load i18n %}
10
11{% block extra_header %}
12 <meta http-equiv="Expires" content="0" />
13 <meta http-equiv="Cache-Control" content="no-cache" />
14 <meta http-equiv="Pragma" content="no-cache" />
15 <style type="text/css">
16 form input[type='text'].yubifield {
17 background: white
18 url("/assets/identityprovider/yubiright_16x16.gif") no-repeat scroll 2px 2px;
19 padding-left: 20px;
20 }
21 </style>
22{% endblock %}
23
24{% block menu %}{% endblock %}
25
26{% block leftcol %}
27<div id="auth">
28 {% if rpconfig %}
29 {% include "widgets/trusted_rp.html" %}
30 {% else %}
31 <h2 class="main">{% blocktrans %}Log in to Ubuntu Single Sign On{% endblocktrans %}</h2>
32 {% endif %}
33
34 <div id="auth-text">
35 {% if token and rpconfig %}
36 <p>
37 {% blocktrans with rpconfig.displayname as rpconfigname %}You are here because {{ rpconfigname }} uses the Ubuntu Single Sign On service.{% endblocktrans %}
38
39 </p>
40 {% endif %}
41 <p>
42 {% blocktrans %}Please note that if you've registered with Launchpad you can use your existing Launchpad credentials to log in.{% endblocktrans %}
43 </p>
44 </div>
45
46 <form id="login-form" action="+login" method="post" name="loginform">
47 <p class="input-row{% if form.email.errors or form.non_field_errors %} haserrors{% endif %}">
48 <label class="formLabel">{% trans "Email address" %}</label><br />
49 {{ form.email }}
50 {% if form.email.errors %}
51 <span class="error">{{ form.email.errors|join:"" }}</span>
52 {% endif %}
53 </p>
54
55 <p class="input-row{% if form.password.errors or form.non_field_errors %} haserrors{% endif %}">
56 <label class="formLabel" for="id_password">{% trans "Password" %}</label><br />
57 {{ form.password }}
58 {% if form.password.errors %}
59 <span class="error">
60 {{ form.password.errors|join:"" }}
61 </span>
62 {% endif %}
63 {% if form.non_field_errors %}
64 <span class="error">{{ form.non_field_errors|join:"" }}</span>
65 {% endif %}
66 </p>
67
68 {% if form.otp %}
69 <p class="input-row{% if form.email.errors or form.non_field_errors %} haserrors{% endif %}">
70 <label class="formLabel yubikey">{% trans "One time password" %}</label><br />
71 {{ form.otp }}
72 <span class="formHelp">
73 This form requires the use of a "one time password" device.
74 You should have been assigned this device and been given
75 instructions on how to use it.
76 </span>
77 {% if form.otp.errors %}
78 <span class="error">{{ form.otp.errors|join:"" }}</span>
79 {% endif %}
80 </p>
81 {% endif %}
82
83 <p style="clear: both">
84{% if not readonly %}
85 <a href="+forgot_password{% if form.email.data %}?email={{ form.email.data|urlencode }}{% endif %}" id="forgotpw-link">{% trans "Forgot your password?" %}</a>
86{% endif %}
87 </p>
88
89 <div class="actions">
90 {% if next %}<input type="hidden" name="next" value="{{ next }}" />{% endif %}
91 <button type="submit" class="btn" name="continue"><span><span>{% trans "Continue" %}</span></span></button>
92 {% if token %}{% trans "or" %}
93 <a href="+cancel">{% trans "cancel" %}</a>{% endif %}
94 </div>
95 <div style="clear: both">&nbsp;</div>
96 </form>
97 <script type="text/javascript">
98 document.loginform.email.focus();
99 </script>
100</div>
101
102{% endblock %}
103
104{% block rightcol %}
105 <h2 class="main">{% trans "Are you new?" %}</h2>
106 <p>
107 {% blocktrans %}This is a new service to provide a single, central login service for all Ubuntu-related sites.{% endblocktrans %}
108 </p>
109{%if not embedded %}
110 <p class="findoutmore">
111 <a href="/+description">{% trans "Find out more" %}</a>
112 </p>
113{% endif %}
114 <p class="last">
115 {{ brand.provides_access }}
116 </p>
117{% if not readonly %}
118 <p>
119 <a href="+new_account{% if form.email.data %}?email={{ form.email.data|urlencode }}{% endif %}" class="btn alt"><span><span>{% trans "New account" %}</span></span></a>
120 </p>
121{% endif %}
122{% endblock %}
0123
=== modified file 'identityprovider/tests/test_views_ui.py'
--- identityprovider/tests/test_views_ui.py 2011-01-19 20:57:48 +0000
+++ identityprovider/tests/test_views_ui.py 2011-05-12 13:21:07 +0000
@@ -19,6 +19,10 @@
19from openid.message import IDENTIFIER_SELECT19from openid.message import IDENTIFIER_SELECT
2020
21from identityprovider import decorators, signed21from identityprovider import decorators, signed
22from identityprovider.forms import (
23 LoginForm,
24 OTPLoginForm,
25)
22from identityprovider.models import AUTHTOKEN_LENGTH, authtoken as at26from identityprovider.models import AUTHTOKEN_LENGTH, authtoken as at
23from identityprovider.models import EmailAddress, Person, OpenIDRPConfig27from identityprovider.models import EmailAddress, Person, OpenIDRPConfig
24from identityprovider.models.const import EmailStatus28from identityprovider.models.const import EmailStatus
@@ -722,6 +726,26 @@
722 r = self.client.get('/+suspended')726 r = self.client.get('/+suspended')
723 self.assertTemplateUsed(r, 'account/suspended.html')727 self.assertTemplateUsed(r, 'account/suspended.html')
724728
729 def test_login_when_account_requires_otp(self):
730 account = Account.objects.get_by_email('mark@example.com')
731 account.require_key = True
732 account.save()
733
734 r = self.client.post('/+login', {'email': 'mark@example.com',
735 'password': 'test',
736 'next': '/+edit'})
737 self.assertRedirects(r, '/+two_step_auth/')
738
739
740 def test_login_when_account_does_not_require_otp(self):
741 account = Account.objects.get_by_email('mark@example.com')
742 account.save()
743
744 r = self.client.post('/+login', {'email': 'mark@example.com',
745 'password': 'test',
746 'next': '/+edit'})
747 self.assertRedirects(r, '/+edit')
748
725749
726class UIViewsLPModelTestCase(LPAccountTestCase):750class UIViewsLPModelTestCase(LPAccountTestCase):
727 def test_new_account_when_person_does_not_exist(self):751 def test_new_account_when_person_does_not_exist(self):
728752
=== modified file 'identityprovider/urls.py'
--- identityprovider/urls.py 2011-05-10 14:32:26 +0000
+++ identityprovider/urls.py 2011-05-12 13:21:07 +0000
@@ -32,6 +32,7 @@
32 (r'^%(optional_token)s\+new_account$' % repls, 'new_account'),32 (r'^%(optional_token)s\+new_account$' % repls, 'new_account'),
33 (r'^%(optional_token)s\+forgot_password$' % repls, 'forgot_password'),33 (r'^%(optional_token)s\+forgot_password$' % repls, 'forgot_password'),
34 (r'^%(optional_token)s\+enter_token$' % repls, 'enter_token'),34 (r'^%(optional_token)s\+enter_token$' % repls, 'enter_token'),
35 (r'^\+two_step_auth/$', 'two_step_auth'),
35 (r'^token/%(authtoken)s/$' % repls, 'claim_token'),36 (r'^token/%(authtoken)s/$' % repls, 'claim_token'),
3637
37 # Django's URL-reversing doesn't like to play with regex38 # Django's URL-reversing doesn't like to play with regex
3839
=== modified file 'identityprovider/views/account.py'
--- identityprovider/views/account.py 2011-05-11 14:40:45 +0000
+++ identityprovider/views/account.py 2011-05-12 13:21:07 +0000
@@ -5,7 +5,6 @@
55
6from django.conf import settings6from django.conf import settings
7from django.contrib.auth.decorators import login_required7from django.contrib.auth.decorators import login_required
8from django.contrib.auth.models import User
9from django.http import HttpResponseRedirect8from django.http import HttpResponseRedirect
10from django.shortcuts import render_to_response, get_object_or_4049from django.shortcuts import render_to_response, get_object_or_404
11from django.template import RequestContext10from django.template import RequestContext
@@ -24,7 +23,7 @@
24 send_validation_email_request,23 send_validation_email_request,
25 YubiKey,24 YubiKey,
26)25)
27from oauth_backend.models import Consumer, Token26from oauth_backend.models import Token
28from identityprovider.models.const import EmailStatus27from identityprovider.models.const import EmailStatus
29from identityprovider.views.utils import (redirection_url_for_token,28from identityprovider.views.utils import (redirection_url_for_token,
30 set_session_token_info)29 set_session_token_info)
@@ -32,7 +31,6 @@
3231
3332
34def index(request, token=None):33def index(request, token=None):
35 #TODO: DT Dynamic based on openid request
36 request.token = token34 request.token = token
37 context = RequestContext(request)35 context = RequestContext(request)
38 if request.user.is_authenticated():36 if request.user.is_authenticated():
@@ -41,7 +39,7 @@
41 if not request.session.test_cookie_worked():39 if not request.session.test_cookie_worked():
42 request.session.set_test_cookie()40 request.session.set_test_cookie()
43 context = RequestContext(request, {41 context = RequestContext(request, {
44 'form': OTPLoginForm(), #LoginForm(),42 'form': LoginForm(),
45 })43 })
46 resp = render_to_response('registration/login.html', context)44 resp = render_to_response('registration/login.html', context)
47 resp[YADIS_HEADER_NAME] = '%s+xrds' % settings.SSO_ROOT_URL45 resp[YADIS_HEADER_NAME] = '%s+xrds' % settings.SSO_ROOT_URL
4846
=== modified file 'identityprovider/views/ui.py'
--- identityprovider/views/ui.py 2011-05-11 15:33:26 +0000
+++ identityprovider/views/ui.py 2011-05-12 13:21:07 +0000
@@ -82,6 +82,11 @@
82 username = form.cleaned_data['email']82 username = form.cleaned_data['email']
83 password = form.cleaned_data['password']83 password = form.cleaned_data['password']
84 user = auth.authenticate(username=username, password=password)84 user = auth.authenticate(username=username, password=password)
85 # get the acct based on the user
86 # check for key Required
87 # if required redirect else go on
88 if user.require_key:
89 return HttpResponseRedirect('/+two_step_auth/')
85 auth.login(request, user)90 auth.login(request, user)
86 next = request.POST.get('next')91 next = request.POST.get('next')
87 limitlogin().reset_count(request)92 limitlogin().reset_count(request)
@@ -108,6 +113,10 @@
108 return render_to_response('registration/login.html', context)113 return render_to_response('registration/login.html', context)
109114
110115
116def two_step_auth(request):
117 context = RequestContext(request, {})
118 return render_to_response('registration/two_step.html', context)
119
111def _is_safe_redirect_url(url):120def _is_safe_redirect_url(url):
112 """ Check whether 'url' resolves into a valid URL this application can121 """ Check whether 'url' resolves into a valid URL this application can
113 serve. """122 serve. """

Subscribers

People subscribed via source and target branches

to all changes: