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
1=== modified file 'identityprovider/forms.py'
2--- identityprovider/forms.py 2011-05-11 18:35:14 +0000
3+++ identityprovider/forms.py 2011-05-12 13:21:07 +0000
4@@ -74,14 +74,6 @@
5 raise forms.ValidationError(_("Your account has been "
6 "deactivated"))
7
8- # check that the yubikey belongs to this acct
9- #TODO: DT Dynamic based on openid request
10- if hasattr(self, 'yubikey'):
11- try:
12- account.yubikey_set.get(pk=self.yubikey)
13- except YubiKey.DoesNotExist:
14- raise forms.ValidationError(_("This key is not valid for "
15- "this account"))
16 if user is not None and user.is_active:
17 return self.cleaned_data
18 else:
19
20=== added file 'identityprovider/templates/ubuntu/registration/two_step.html'
21--- identityprovider/templates/ubuntu/registration/two_step.html 1970-01-01 00:00:00 +0000
22+++ identityprovider/templates/ubuntu/registration/two_step.html 2011-05-12 13:21:07 +0000
23@@ -0,0 +1,122 @@
24+
25+{% extends "twocols.html" %}
26+
27+{% comment %}
28+Copyright 2010 Canonical Ltd. This software is licensed under the
29+GNU Affero General Public License version 3 (see the file LICENSE).
30+{% endcomment %}
31+
32+{% load i18n %}
33+
34+{% block extra_header %}
35+ <meta http-equiv="Expires" content="0" />
36+ <meta http-equiv="Cache-Control" content="no-cache" />
37+ <meta http-equiv="Pragma" content="no-cache" />
38+ <style type="text/css">
39+ form input[type='text'].yubifield {
40+ background: white
41+ url("/assets/identityprovider/yubiright_16x16.gif") no-repeat scroll 2px 2px;
42+ padding-left: 20px;
43+ }
44+ </style>
45+{% endblock %}
46+
47+{% block menu %}{% endblock %}
48+
49+{% block leftcol %}
50+<div id="auth">
51+ {% if rpconfig %}
52+ {% include "widgets/trusted_rp.html" %}
53+ {% else %}
54+ <h2 class="main">{% blocktrans %}Log in to Ubuntu Single Sign On{% endblocktrans %}</h2>
55+ {% endif %}
56+
57+ <div id="auth-text">
58+ {% if token and rpconfig %}
59+ <p>
60+ {% blocktrans with rpconfig.displayname as rpconfigname %}You are here because {{ rpconfigname }} uses the Ubuntu Single Sign On service.{% endblocktrans %}
61+
62+ </p>
63+ {% endif %}
64+ <p>
65+ {% blocktrans %}Please note that if you've registered with Launchpad you can use your existing Launchpad credentials to log in.{% endblocktrans %}
66+ </p>
67+ </div>
68+
69+ <form id="login-form" action="+login" method="post" name="loginform">
70+ <p class="input-row{% if form.email.errors or form.non_field_errors %} haserrors{% endif %}">
71+ <label class="formLabel">{% trans "Email address" %}</label><br />
72+ {{ form.email }}
73+ {% if form.email.errors %}
74+ <span class="error">{{ form.email.errors|join:"" }}</span>
75+ {% endif %}
76+ </p>
77+
78+ <p class="input-row{% if form.password.errors or form.non_field_errors %} haserrors{% endif %}">
79+ <label class="formLabel" for="id_password">{% trans "Password" %}</label><br />
80+ {{ form.password }}
81+ {% if form.password.errors %}
82+ <span class="error">
83+ {{ form.password.errors|join:"" }}
84+ </span>
85+ {% endif %}
86+ {% if form.non_field_errors %}
87+ <span class="error">{{ form.non_field_errors|join:"" }}</span>
88+ {% endif %}
89+ </p>
90+
91+ {% if form.otp %}
92+ <p class="input-row{% if form.email.errors or form.non_field_errors %} haserrors{% endif %}">
93+ <label class="formLabel yubikey">{% trans "One time password" %}</label><br />
94+ {{ form.otp }}
95+ <span class="formHelp">
96+ This form requires the use of a "one time password" device.
97+ You should have been assigned this device and been given
98+ instructions on how to use it.
99+ </span>
100+ {% if form.otp.errors %}
101+ <span class="error">{{ form.otp.errors|join:"" }}</span>
102+ {% endif %}
103+ </p>
104+ {% endif %}
105+
106+ <p style="clear: both">
107+{% if not readonly %}
108+ <a href="+forgot_password{% if form.email.data %}?email={{ form.email.data|urlencode }}{% endif %}" id="forgotpw-link">{% trans "Forgot your password?" %}</a>
109+{% endif %}
110+ </p>
111+
112+ <div class="actions">
113+ {% if next %}<input type="hidden" name="next" value="{{ next }}" />{% endif %}
114+ <button type="submit" class="btn" name="continue"><span><span>{% trans "Continue" %}</span></span></button>
115+ {% if token %}{% trans "or" %}
116+ <a href="+cancel">{% trans "cancel" %}</a>{% endif %}
117+ </div>
118+ <div style="clear: both">&nbsp;</div>
119+ </form>
120+ <script type="text/javascript">
121+ document.loginform.email.focus();
122+ </script>
123+</div>
124+
125+{% endblock %}
126+
127+{% block rightcol %}
128+ <h2 class="main">{% trans "Are you new?" %}</h2>
129+ <p>
130+ {% blocktrans %}This is a new service to provide a single, central login service for all Ubuntu-related sites.{% endblocktrans %}
131+ </p>
132+{%if not embedded %}
133+ <p class="findoutmore">
134+ <a href="/+description">{% trans "Find out more" %}</a>
135+ </p>
136+{% endif %}
137+ <p class="last">
138+ {{ brand.provides_access }}
139+ </p>
140+{% if not readonly %}
141+ <p>
142+ <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>
143+ </p>
144+{% endif %}
145+{% endblock %}
146
147=== modified file 'identityprovider/tests/test_views_ui.py'
148--- identityprovider/tests/test_views_ui.py 2011-01-19 20:57:48 +0000
149+++ identityprovider/tests/test_views_ui.py 2011-05-12 13:21:07 +0000
150@@ -19,6 +19,10 @@
151 from openid.message import IDENTIFIER_SELECT
152
153 from identityprovider import decorators, signed
154+from identityprovider.forms import (
155+ LoginForm,
156+ OTPLoginForm,
157+)
158 from identityprovider.models import AUTHTOKEN_LENGTH, authtoken as at
159 from identityprovider.models import EmailAddress, Person, OpenIDRPConfig
160 from identityprovider.models.const import EmailStatus
161@@ -722,6 +726,26 @@
162 r = self.client.get('/+suspended')
163 self.assertTemplateUsed(r, 'account/suspended.html')
164
165+ def test_login_when_account_requires_otp(self):
166+ account = Account.objects.get_by_email('mark@example.com')
167+ account.require_key = True
168+ account.save()
169+
170+ r = self.client.post('/+login', {'email': 'mark@example.com',
171+ 'password': 'test',
172+ 'next': '/+edit'})
173+ self.assertRedirects(r, '/+two_step_auth/')
174+
175+
176+ def test_login_when_account_does_not_require_otp(self):
177+ account = Account.objects.get_by_email('mark@example.com')
178+ account.save()
179+
180+ r = self.client.post('/+login', {'email': 'mark@example.com',
181+ 'password': 'test',
182+ 'next': '/+edit'})
183+ self.assertRedirects(r, '/+edit')
184+
185
186 class UIViewsLPModelTestCase(LPAccountTestCase):
187 def test_new_account_when_person_does_not_exist(self):
188
189=== modified file 'identityprovider/urls.py'
190--- identityprovider/urls.py 2011-05-10 14:32:26 +0000
191+++ identityprovider/urls.py 2011-05-12 13:21:07 +0000
192@@ -32,6 +32,7 @@
193 (r'^%(optional_token)s\+new_account$' % repls, 'new_account'),
194 (r'^%(optional_token)s\+forgot_password$' % repls, 'forgot_password'),
195 (r'^%(optional_token)s\+enter_token$' % repls, 'enter_token'),
196+ (r'^\+two_step_auth/$', 'two_step_auth'),
197 (r'^token/%(authtoken)s/$' % repls, 'claim_token'),
198
199 # Django's URL-reversing doesn't like to play with regex
200
201=== modified file 'identityprovider/views/account.py'
202--- identityprovider/views/account.py 2011-05-11 14:40:45 +0000
203+++ identityprovider/views/account.py 2011-05-12 13:21:07 +0000
204@@ -5,7 +5,6 @@
205
206 from django.conf import settings
207 from django.contrib.auth.decorators import login_required
208-from django.contrib.auth.models import User
209 from django.http import HttpResponseRedirect
210 from django.shortcuts import render_to_response, get_object_or_404
211 from django.template import RequestContext
212@@ -24,7 +23,7 @@
213 send_validation_email_request,
214 YubiKey,
215 )
216-from oauth_backend.models import Consumer, Token
217+from oauth_backend.models import Token
218 from identityprovider.models.const import EmailStatus
219 from identityprovider.views.utils import (redirection_url_for_token,
220 set_session_token_info)
221@@ -32,7 +31,6 @@
222
223
224 def index(request, token=None):
225- #TODO: DT Dynamic based on openid request
226 request.token = token
227 context = RequestContext(request)
228 if request.user.is_authenticated():
229@@ -41,7 +39,7 @@
230 if not request.session.test_cookie_worked():
231 request.session.set_test_cookie()
232 context = RequestContext(request, {
233- 'form': OTPLoginForm(), #LoginForm(),
234+ 'form': LoginForm(),
235 })
236 resp = render_to_response('registration/login.html', context)
237 resp[YADIS_HEADER_NAME] = '%s+xrds' % settings.SSO_ROOT_URL
238
239=== modified file 'identityprovider/views/ui.py'
240--- identityprovider/views/ui.py 2011-05-11 15:33:26 +0000
241+++ identityprovider/views/ui.py 2011-05-12 13:21:07 +0000
242@@ -82,6 +82,11 @@
243 username = form.cleaned_data['email']
244 password = form.cleaned_data['password']
245 user = auth.authenticate(username=username, password=password)
246+ # get the acct based on the user
247+ # check for key Required
248+ # if required redirect else go on
249+ if user.require_key:
250+ return HttpResponseRedirect('/+two_step_auth/')
251 auth.login(request, user)
252 next = request.POST.get('next')
253 limitlogin().reset_count(request)
254@@ -108,6 +113,10 @@
255 return render_to_response('registration/login.html', context)
256
257
258+def two_step_auth(request):
259+ context = RequestContext(request, {})
260+ return render_to_response('registration/two_step.html', context)
261+
262 def _is_safe_redirect_url(url):
263 """ Check whether 'url' resolves into a valid URL this application can
264 serve. """

Subscribers

People subscribed via source and target branches

to all changes: