Merge lp:~michael.nelson/django-openid-auth/801499-check-name-length into lp:~django-openid-auth/django-openid-auth/trunk

Proposed by Michael Nelson
Status: Merged
Approved by: Anthony Lenton
Approved revision: 85
Merged at revision: 82
Proposed branch: lp:~michael.nelson/django-openid-auth/801499-check-name-length
Merge into: lp:~django-openid-auth/django-openid-auth/trunk
Diff against target: 227 lines (+78/-54)
2 files modified
django_openid_auth/auth.py (+11/-9)
django_openid_auth/tests/test_auth.py (+67/-45)
To merge this branch: bzr merge lp:~michael.nelson/django-openid-auth/801499-check-name-length
Reviewer Review Type Date Requested Status
Anthony Lenton Approve
Review via email: mp+65785@code.launchpad.net

Description of the change

Overview
========
This branch fixes the following bugs:
 * bug 801499 - long first/last names are too long for the django.contrib.auth.models.User fields.
 * bug 632857 - leading/trailing spaces in fullname don't cause errors.

Together these two bugs were causing approx. 4 oopses each day for the Ubuntu software center server.

Details
=======
I also took the chance to refactor the tests for readability, adding a factory for creating successful (AX) responses.

To test: `make check`

To post a comment you must log in.
Revision history for this message
Anthony Lenton (elachuni) wrote :

Looks fine!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'django_openid_auth/auth.py'
2--- django_openid_auth/auth.py 2011-05-12 09:46:37 +0000
3+++ django_openid_auth/auth.py 2011-06-24 13:05:30 +0000
4@@ -44,7 +44,7 @@
5
6 class StrictUsernameViolation(Exception):
7 pass
8-
9+
10 class OpenIDBackend:
11 """A django.contrib.auth backend that authenticates the user based on
12 an OpenID response."""
13@@ -132,8 +132,10 @@
14 if fullname and not (first_name or last_name):
15 # Django wants to store first and last names separately,
16 # so we do our best to split the full name.
17- if ' ' in fullname:
18- first_name, last_name = fullname.rsplit(None, 1)
19+ fullname = fullname.strip()
20+ split_names = fullname.rsplit(None, 1)
21+ if len(split_names) == 2:
22+ first_name, last_name = split_names
23 else:
24 first_name = u''
25 last_name = fullname
26@@ -147,7 +149,7 @@
27 if getattr(settings, 'OPENID_STRICT_USERNAMES', False):
28 if nickname is None or nickname == '':
29 raise StrictUsernameViolation("No username")
30-
31+
32 # If we don't have a nickname, and we're not being strict, use a default
33 nickname = nickname or 'openiduser'
34
35@@ -157,7 +159,7 @@
36 except User.DoesNotExist:
37 # No conflict, we can use this nickname
38 return nickname
39-
40+
41 # Check if we already have nickname+i for this identity_url
42 try:
43 user_openid = UserOpenID.objects.get(
44@@ -178,7 +180,7 @@
45 except UserOpenID.DoesNotExist:
46 # No user associated with this identity_url
47 pass
48-
49+
50
51 if getattr(settings, 'OPENID_STRICT_USERNAMES', False):
52 if User.objects.filter(username__exact=nickname).count() > 0:
53@@ -197,7 +199,7 @@
54 break
55 i += 1
56 return username
57-
58+
59 def create_user_from_openid(self, openid_response):
60 details = self._extract_user_details(openid_response)
61 nickname = details['nickname'] or 'openiduser'
62@@ -234,10 +236,10 @@
63 def update_user_details(self, user, details, openid_response):
64 updated = False
65 if details['first_name']:
66- user.first_name = details['first_name']
67+ user.first_name = details['first_name'][:30]
68 updated = True
69 if details['last_name']:
70- user.last_name = details['last_name']
71+ user.last_name = details['last_name'][:30]
72 updated = True
73 if details['email']:
74 user.email = details['email']
75
76=== modified file 'django_openid_auth/tests/test_auth.py'
77--- django_openid_auth/tests/test_auth.py 2010-08-10 08:58:07 +0000
78+++ django_openid_auth/tests/test_auth.py 2011-06-24 13:05:30 +0000
79@@ -28,6 +28,7 @@
80
81 import unittest
82
83+from django.contrib.auth.models import User
84 from django.test import TestCase
85
86 from django_openid_auth.auth import OpenIDBackend
87@@ -60,74 +61,95 @@
88 "last_name": "User",
89 "email": "foo@example.com"})
90
91+ def make_response_ax(self, schema="http://axschema.org/",
92+ fullname="Some User", nickname="someuser", email="foo@example.com",
93+ first=None, last=None):
94+ endpoint = OpenIDServiceEndpoint()
95+ message = Message(OPENID2_NS)
96+ attributes = [
97+ ("nickname", schema + "namePerson/friendly", nickname),
98+ ("fullname", schema + "namePerson", fullname),
99+ ("email", schema + "contact/email", email),
100+ ]
101+ if first:
102+ attributes.append(
103+ ("first", "http://axschema.org/namePerson/first", first))
104+ if last:
105+ attributes.append(
106+ ("last", "http://axschema.org/namePerson/last", last))
107+
108+ message.setArg(AX_NS, "mode", "fetch_response")
109+ for (alias, uri, value) in attributes:
110+ message.setArg(AX_NS, "type.%s" % alias, uri)
111+ message.setArg(AX_NS, "value.%s" % alias, value)
112+ return SuccessResponse(
113+ endpoint, message, signed_fields=message.toPostArgs().keys())
114+
115 def test_extract_user_details_ax(self):
116- endpoint = OpenIDServiceEndpoint()
117- message = Message(OPENID2_NS)
118- attributes = [
119- ("nickname", "http://axschema.org/namePerson/friendly", "someuser"),
120- ("fullname", "http://axschema.org/namePerson", "Some User"),
121- ("email", "http://axschema.org/contact/email", "foo@example.com"),
122- ]
123- message.setArg(AX_NS, "mode", "fetch_response")
124- for (alias, uri, value) in attributes:
125- message.setArg(AX_NS, "type.%s" % alias, uri)
126- message.setArg(AX_NS, "value.%s" % alias, value)
127- response = SuccessResponse(
128- endpoint, message, signed_fields=message.toPostArgs().keys())
129+ response = self.make_response_ax(fullname="Some User",
130+ nickname="someuser", email="foo@example.com")
131
132 data = self.backend._extract_user_details(response)
133+
134 self.assertEqual(data, {"nickname": "someuser",
135 "first_name": "Some",
136 "last_name": "User",
137 "email": "foo@example.com"})
138
139 def test_extract_user_details_ax_split_name(self):
140- endpoint = OpenIDServiceEndpoint()
141- message = Message(OPENID2_NS)
142- attributes = [
143- ("nickname", "http://axschema.org/namePerson/friendly", "someuser"),
144- # Include this key too to show that the split data takes
145- # precedence.
146- ("fullname", "http://axschema.org/namePerson", "Bad Data"),
147- ("first", "http://axschema.org/namePerson/first", "Some"),
148- ("last", "http://axschema.org/namePerson/last", "User"),
149- ("email", "http://axschema.org/contact/email", "foo@example.com"),
150- ]
151- message.setArg(AX_NS, "mode", "fetch_response")
152- for (alias, uri, value) in attributes:
153- message.setArg(AX_NS, "type.%s" % alias, uri)
154- message.setArg(AX_NS, "value.%s" % alias, value)
155- response = SuccessResponse(
156- endpoint, message, signed_fields=message.toPostArgs().keys())
157+ # Include fullname too to show that the split data takes
158+ # precedence.
159+ response = self.make_response_ax(
160+ fullname="Bad Data", first="Some", last="User")
161
162 data = self.backend._extract_user_details(response)
163+
164 self.assertEqual(data, {"nickname": "someuser",
165 "first_name": "Some",
166 "last_name": "User",
167 "email": "foo@example.com"})
168
169 def test_extract_user_details_ax_broken_myopenid(self):
170- endpoint = OpenIDServiceEndpoint()
171- message = Message(OPENID2_NS)
172- attributes = [
173- ("nickname", "http://schema.openid.net/namePerson/friendly",
174- "someuser"),
175- ("fullname", "http://schema.openid.net/namePerson", "Some User"),
176- ("email", "http://schema.openid.net/contact/email",
177- "foo@example.com"),
178- ]
179- message.setArg(AX_NS, "mode", "fetch_response")
180- for (alias, uri, value) in attributes:
181- message.setArg(AX_NS, "type.%s" % alias, uri)
182- message.setArg(AX_NS, "value.%s" % alias, value)
183- response = SuccessResponse(
184- endpoint, message, signed_fields=message.toPostArgs().keys())
185+ response = self.make_response_ax(
186+ schema="http://schema.openid.net/", fullname="Some User",
187+ nickname="someuser", email="foo@example.com")
188
189 data = self.backend._extract_user_details(response)
190+
191 self.assertEqual(data, {"nickname": "someuser",
192 "first_name": "Some",
193 "last_name": "User",
194 "email": "foo@example.com"})
195
196+ def test_update_user_details_long_names(self):
197+ response = self.make_response_ax()
198+ user = User.objects.create_user('someuser', 'someuser@example.com',
199+ password=None)
200+ data = dict(first_name=u"Some56789012345678901234567890123",
201+ last_name=u"User56789012345678901234567890123",
202+ email=u"someotheruser@example.com")
203+
204+ self.backend.update_user_details(user, data, response)
205+
206+ self.assertEqual("Some56789012345678901234567890", user.first_name)
207+ self.assertEqual("User56789012345678901234567890", user.last_name)
208+
209+ def test_extract_user_details_name_with_trailing_space(self):
210+ response = self.make_response_ax(fullname="SomeUser ")
211+
212+ data = self.backend._extract_user_details(response)
213+
214+ self.assertEqual("", data['first_name'])
215+ self.assertEqual("SomeUser", data['last_name'])
216+
217+ def test_extract_user_details_name_with_thin_space(self):
218+ response = self.make_response_ax(fullname=u"Some\u2009User")
219+
220+ data = self.backend._extract_user_details(response)
221+
222+ self.assertEqual("Some", data['first_name'])
223+ self.assertEqual("User", data['last_name'])
224+
225+
226 def suite():
227 return unittest.TestLoader().loadTestsFromName(__name__)

Subscribers

People subscribed via source and target branches