OpenID integration for django.contrib.auth

Merge lp:~mhall119/django-openid-auth/fixes-642132 into lp:django-openid-auth

Proposed by Michael Hall on 2011-03-21
Status: Merged
Approved by: James Henstridge on 2011-04-12
Approved revision: 84
Merged at revision: 81
Proposed branch: lp:~mhall119/django-openid-auth/fixes-642132
Merge into: lp:django-openid-auth
Diff against target: 433 lines (+283/-34) 3 files modified
To merge this branch: bzr merge lp:~mhall119/django-openid-auth/fixes-642132
Reviewer Review Type Date Requested Status
Michael Hall Approve on 2011-05-12
Anthony Lenton Needs Fixing on 2011-04-26
James Henstridge 2011-03-21 Approve on 2011-04-12
Review via email: mp+54193@code.launchpad.net

This proposal supersedes a proposal from 2010-10-13.

Description of the Change

Adds a new settings paramater: OPENID_FOLLOW_RENAMES

When set to True, and when OPENID_UPDATE_DETAILS_FROM_SREG is also True, the django User.username for the User with a matching identity_url will be updated with the nickname from the OpenID response.

Several checks are performed to make sure we don't conflict with an existing user with the same username.

To post a comment you must log in.
Michael Hall (mhall119) wrote : Posted in a previous version of this proposal

Can somebody please review this, it is needed for loco.ubuntu.com and summit.ubuntu.com

Anthony Lenton (elachuni) wrote : Posted in a previous version of this proposal

Hi Michael,

Thanks for your work on this. The code around lines 8-10 of the diff would need to be a bit more robust when updating the User's username, as there might be some other user in the system with the new username already.

I think the underlying problem is what we really want to do in this case (ie if 'joesmith' changes his openid username to 'joebobs', but you already have a 'joebobs' in your system). Skipping the username update in that case would work but it'll leave you with out-of-sync data. Refusing to sign the user in would be quite violent, and merging the two accounts would be definitely a bad idea. What would work in your use case?

Sites with a single OpenID provider would be less affected by this issue, but it could still bite you.

Otoh, I'm not sure why django-openid-auth doesn't currently update username together with fullname and email when OPENID_UPDATE_DETAILS_FROM_SREG is True, but using a second setting for this as your code does seems like a good way to make it work for everybody.

Michael Hall (mhall119) wrote : Posted in a previous version of this proposal

I think in the case of an existing username conflict, then we could go back to $username+1 increments until we find a unique one. Unfortunately it would do this incrementing process every time the user logged in, until their new LP username is available in Django, but I don't think that would be such a performance hit.

James Henstridge (jamesh) wrote : Posted in a previous version of this proposal

This should do the check to see if anyone else has the same user name, and should ideally use the same name checking code as create_user_from_openid() does (that way we only need to update the algorithm once if we want to change it).

I would suggest only changing the user name if the existing user name does not have the sreg nickname as a prefix. This should prevent us from trying to change the nickname on every login if there is a duplicate nickname.

With respect to the tests, how about factoring out the body of test_login_update_details() into a helper method, from the first client.post() call and returning the response object returned by client.get('/getuser/'). That helper could then be used to run both tests. I'd also like to see a test of when there is a conflict for the new nickname.

Lastly, a more basic question: do we want to have a setting for this behaviour? If it has minimal overhead and is something most people would want, is there any reason not to always do this?

review: Needs Fixing
Michael Hall (mhall119) wrote : Posted in a previous version of this proposal

There may be cases where renames aren't desirable, for example if the username is used to link tables, rather than a constant user id.

Ronnie (ronnie.vd.c) wrote : Posted in a previous version of this proposal

I would suggest checking the OpenId-Provider (url like: https://login.launchpad.net/) from the claimed id.

If the new username exists, but claimed_id does not match (but is from the same provider), The old username should be called OpenIdUserX,

OPENIDPROVIDER1 (Google)
    - {'nickname': 'Ben', 'claimed_id': 'http://login.google.com/ABCD', 'display_id': '...'}

OPENIDPROVIDER2 (Launchpad)
    - {'nickname': 'Ben', 'claimed_id': 'https://login.launchpad.net/+id/AAAA', 'display_id': '...'}
    - {'nickname': 'Cees', 'claimed_id': 'https://login.launchpad.net/+id/ABCD', 'display_id': '...'}
======
    - Ben deletes his account on launchpad
    - Cees changed name to Ben

OPENIDCONSUMER
    - Ben (http://login.google.com/ABCD) register => username 'Ben'
    - Ben (https://login.launchpad.net/+id/AAAA) registers => username 'Ben1'
    - Cees (https://login.launchpad.net/+id/ABCD) registers => username 'Cees'
=======
    - Ben (previous Cees | https://login.launchpad.net/+id/ABCD) logs in =>
        -- user 'Ben1' should be renamed to 'OpenIdUserX'
        -- user Cees should be renamed to 'Ben1'

small catch: What to do if Ben (https://login.launchpad.net/+id/AAAA) changes his name to 'Ben1' on the openid-provider?

Ronnie (ronnie.vd.c) wrote : Posted in a previous version of this proposal

A more general approach, which also solves the small catch:

The username should always be renamed if it has changed, one exception for this is when the same username exists for another openid-provider. If there is already an user with that username (same provider) then the old_user should be renamed to the name without number (if available) else to the name + first_available_number.

If the same username is kept by another openid-provider, the user should keep its old username (if exists), if a new user is created, it should be username1 (username2 etc which first is available)

Therefore in the example above:
  OPENIDPROVIDER
    User Ben(https://login.launchpad.net/+id/AAAA) change name to Ben1
    User Cees(https://login.launchpad.net/+id/ABCD) change name to Ben
  OPENIDCONSUMER
    Ben (previous Cees | https://login.launchpad.net/+id/ABCD) logs in =>
       user 'Ben1' (https://login.launchpad.net/+id/AAAA) should be renamed to 'Ben2'
       user 'Cees' should be renamed to 'Ben1'
    Ben2 (https://login.launchpad.net/+id/AAAA) logs in with username 'Ben1'
       user 'Ben1' (previous Cees | https://login.launchpad.net/+id/ABCD) should be renamed to 'Ben3'
       user 'Ben2' should be renamed to 'Ben1'

All next logins for Ben3 (Cees/Ben (https://login.launchpad.net/+id/ABCD)) should check if 'Ben' is available. If not, keep the old username

84. By Michael Hall on 2011-03-23

Add new option to README.txt and removed an unecessary check in _get_available_username()

Anthony Lenton (elachuni) wrote :

Discussed this with Michael via IRC, it looks good to me now.

JamesH, let us know if you have comments or complaints about this one in its current state, it'll be landing soon if not!

review: Approve
James Henstridge (jamesh) wrote :

Looks good.

review: Approve
85. By Michael Hall on 2011-04-19

Updates from trunk

Anthony Lenton (elachuni) wrote :

I now get 1 fail and 1 error after merging into trunk:

http://pastebin.ubuntu.com/599377/

review: Needs Fixing
86. By Michael Hall on 2011-05-12

Check for STRICT_USERNAMES before defaulting the nickname to openiduser

Michael Hall (mhall119) wrote :

Fixed the failing tests.

review: Resubmit
Michael Hall (mhall119) :
review: Approve
87. By Michael Hall on 2011-05-12

Make sure auto-mapping is turned off when testing teams->group

Preview Diff

1=== modified file 'README.txt'
2--- README.txt 2011-03-23 19:26:19 +0000
3+++ README.txt 2011-05-12 10:19:59 +0000
4@@ -126,6 +126,16 @@
5 The easiest way to resolve this is to use traditional authentication (OPENID_USE_AS_ADMIN_LOGIN = False) to sign in as your first user with a password and authorise your
6 openid user to be staff.
7
8+== Change Django usernames if the nickname changes on the provider ==
9+
10+If you want your Django username to change when a user updates the nickname on their provider, add the following setting:
11+
12+ OPENID_FOLLOW_RENAMES = True
13+
14+If the new nickname is available as a Django username, the user is renamed.
15+Otherwise the user will be renamed to nickname+i for an incrememnting value of i until no conflict occurs.
16+If the user has already been renamed to nickname+1 due to a conflict, and the nickname is still not available, the user will keep their existing username.
17+
18 == Require a valid nickname ==
19
20 If you must have a valid, unique nickname in order to create a user accont, add the following setting:
21
22=== modified file 'django_openid_auth/auth.py'
23--- django_openid_auth/auth.py 2011-03-18 20:01:05 +0000
24+++ django_openid_auth/auth.py 2011-05-12 10:19:59 +0000
25@@ -86,7 +86,7 @@
26
27 if getattr(settings, 'OPENID_UPDATE_DETAILS_FROM_SREG', False):
28 details = self._extract_user_details(openid_response)
29- self.update_user_details(user, details)
30+ self.update_user_details(user, details, openid_response)
31
32 teams_response = teams.TeamsResponse.fromSuccessResponse(
33 openid_response)
34@@ -103,7 +103,6 @@
35 email = sreg_response.get('email')
36 fullname = sreg_response.get('fullname')
37 nickname = sreg_response.get('nickname')
38-
39 # If any attributes are provided via Attribute Exchange, use
40 # them in preference.
41 fetch_response = ax.FetchResponse.fromSuccessResponse(openid_response)
42@@ -142,17 +141,49 @@
43 return dict(email=email, nickname=nickname,
44 first_name=first_name, last_name=last_name)
45
46- def create_user_from_openid(self, openid_response):
47- details = self._extract_user_details(openid_response)
48- nickname = details['nickname'] or 'openiduser'
49- email = details['email'] or ''
50-
51+ def _get_available_username(self, nickname, identity_url):
52+ # If we're being strict about usernames, throw an error if we didn't
53+ # get one back from the provider
54 if getattr(settings, 'OPENID_STRICT_USERNAMES', False):
55- if details['nickname'] is None or details['nickname'] == '':
56+ if nickname is None or nickname == '':
57 raise StrictUsernameViolation("No username")
58+
59+ # If we don't have a nickname, and we're not being strict, use a default
60+ nickname = nickname or 'openiduser'
61+
62+ # See if we already have this nickname assigned to a username
63+ try:
64+ user = User.objects.get(username__exact=nickname)
65+ except User.DoesNotExist:
66+ # No conflict, we can use this nickname
67+ return nickname
68+
69+ # Check if we already have nickname+i for this identity_url
70+ try:
71+ user_openid = UserOpenID.objects.get(
72+ claimed_id__exact=identity_url,
73+ user__username__startswith=nickname)
74+ # No exception means we have an existing user for this identity
75+ # that starts with this nickname, so it's possible we've had to
76+ # assign them to nickname+i already.
77+ oid_username = user_openid.user.username
78+ if len(oid_username) > len(nickname):
79+ try:
80+ # check that it ends with a number
81+ int(oid_username[len(nickname):])
82+ return oid_username
83+ except ValueError:
84+ # username starts with nickname, but isn't nickname+#
85+ pass
86+ except UserOpenID.DoesNotExist:
87+ # No user associated with this identity_url
88+ pass
89+
90+
91+ if getattr(settings, 'OPENID_STRICT_USERNAMES', False):
92 if User.objects.filter(username__exact=nickname).count() > 0:
93 raise StrictUsernameViolation("Duplicate username: %s" % nickname)
94-
95+
96 # Pick a username for the user based on their nickname,
97 # checking for conflicts.
98 i = 1
99@@ -161,15 +192,23 @@
100 if i > 1:
101 username += str(i)
102 try:
103- User.objects.get(username__exact=username)
104+ user = User.objects.get(username__exact=username)
105 except User.DoesNotExist:
106 break
107 i += 1
108+ return username
109+
110+ def create_user_from_openid(self, openid_response):
111+ details = self._extract_user_details(openid_response)
112+ nickname = details['nickname'] or 'openiduser'
113+ email = details['email'] or ''
114+
115+ username = self._get_available_username(details['nickname'], openid_response.identity_url)
116
117 user = User.objects.create_user(username, email, password=None)
118- self.update_user_details(user, details)
119-
120 self.associate_openid(user, openid_response)
121+ self.update_user_details(user, details, openid_response)
122+
123 return user
124
125 def associate_openid(self, user, openid_response):
126@@ -192,7 +231,7 @@
127
128 return user_openid
129
130- def update_user_details(self, user, details):
131+ def update_user_details(self, user, details, openid_response):
132 updated = False
133 if details['first_name']:
134 user.first_name = details['first_name']
135@@ -203,6 +242,9 @@
136 if details['email']:
137 user.email = details['email']
138 updated = True
139+ if getattr(settings, 'OPENID_FOLLOW_RENAMES', False):
140+ user.username = self._get_available_username(details['nickname'], openid_response.identity_url)
141+ updated = True
142
143 if updated:
144 user.save()
145
146=== modified file 'django_openid_auth/tests/test_views.py'
147--- django_openid_auth/tests/test_views.py 2011-03-18 20:01:05 +0000
148+++ django_openid_auth/tests/test_views.py 2011-05-12 10:19:59 +0000
149@@ -136,6 +136,7 @@
150 self.old_sso_server_url = getattr(settings, 'OPENID_SSO_SERVER_URL', None)
151 self.old_teams_map = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING', {})
152 self.old_use_as_admin_login = getattr(settings, 'OPENID_USE_AS_ADMIN_LOGIN', False)
153+ self.old_follow_renames = getattr(settings, 'OPENID_FOLLOW_RENAMES', False)
154
155 settings.OPENID_CREATE_USERS = False
156 settings.OPENID_STRICT_USERNAMES = False
157@@ -143,6 +144,7 @@
158 settings.OPENID_SSO_SERVER_URL = None
159 settings.OPENID_LAUNCHPAD_TEAMS_MAPPING = {}
160 settings.OPENID_USE_AS_ADMIN_LOGIN = False
161+ settings.OPENID_FOLLOW_RENAMES = False
162
163 def tearDown(self):
164 settings.LOGIN_REDIRECT_URL = self.old_login_redirect_url
165@@ -152,6 +154,7 @@
166 settings.OPENID_SSO_SERVER_URL = self.old_sso_server_url
167 settings.OPENID_LAUNCHPAD_TEAMS_MAPPING = self.old_teams_map
168 settings.OPENID_USE_AS_ADMIN_LOGIN = self.old_use_as_admin_login
169+ settings.OPENID_FOLLOW_RENAMES = self.old_follow_renames
170
171 setDefaultFetcher(None)
172 super(RelyingPartyTests, self).tearDown()
173@@ -289,6 +292,213 @@
174 self.assertEquals(user.last_name, 'User')
175 self.assertEquals(user.email, 'foo@example.com')
176
177+ def _do_user_login(self, openid_req, openid_resp):
178+ # Posting in an identity URL begins the authentication request:
179+ response = self.client.post('/openid/login/', openid_req)
180+ self.assertContains(response, 'OpenID transaction in progress')
181+
182+ # Complete the request, passing back some simple registration
183+ # data. The user is redirected to the next URL.
184+ openid_request = self.provider.parseFormPost(response.content)
185+ sreg_request = sreg.SRegRequest.fromOpenIDRequest(openid_request)
186+ openid_response = openid_request.answer(True)
187+ sreg_response = sreg.SRegResponse.extractResponse(
188+ sreg_request, openid_resp)
189+ openid_response.addExtension(sreg_response)
190+ response = self.complete(openid_response)
191+ self.assertRedirects(response, 'http://testserver/getuser/')
192+
193+ def test_login_without_nickname(self):
194+ settings.OPENID_CREATE_USERS = True
195+
196+ openid_req = {'openid_identifier': 'http://example.com/identity',
197+ 'next': '/getuser/'}
198+ openid_resp = {'nickname': '', 'fullname': 'Openid User',
199+ 'email': 'foo@example.com'}
200+ self._do_user_login(openid_req, openid_resp)
201+ response = self.client.get('/getuser/')
202+
203+ # username defaults to 'openiduser'
204+ self.assertEquals(response.content, 'openiduser')
205+
206+ # The user's full name and email have been updated.
207+ user = User.objects.get(username=response.content)
208+ self.assertEquals(user.first_name, 'Openid')
209+ self.assertEquals(user.last_name, 'User')
210+ self.assertEquals(user.email, 'foo@example.com')
211+
212+ def test_login_follow_rename(self):
213+ settings.OPENID_FOLLOW_RENAMES = True
214+ settings.OPENID_UPDATE_DETAILS_FROM_SREG = True
215+ user = User.objects.create_user('testuser', 'someone@example.com')
216+ useropenid = UserOpenID(
217+ user=user,
218+ claimed_id='http://example.com/identity',
219+ display_id='http://example.com/identity')
220+ useropenid.save()
221+
222+ openid_req = {'openid_identifier': 'http://example.com/identity',
223+ 'next': '/getuser/'}
224+ openid_resp = {'nickname': 'someuser', 'fullname': 'Some User',
225+ 'email': 'foo@example.com'}
226+ self._do_user_login(openid_req, openid_resp)
227+ response = self.client.get('/getuser/')
228+
229+ # If OPENID_FOLLOW_RENAMES, they are logged in as
230+ # someuser (the passed in nickname has changed the username)
231+ self.assertEquals(response.content, 'someuser')
232+
233+ # The user's full name and email have been updated.
234+ user = User.objects.get(username=response.content)
235+ self.assertEquals(user.first_name, 'Some')
236+ self.assertEquals(user.last_name, 'User')
237+ self.assertEquals(user.email, 'foo@example.com')
238+
239+ def test_login_follow_rename_conflict(self):
240+ settings.OPENID_FOLLOW_RENAMES = True
241+ settings.OPENID_UPDATE_DETAILS_FROM_SREG = True
242+ # Setup existing user who's name we're going to switch to
243+ user = User.objects.create_user('testuser', 'someone@example.com')
244+ UserOpenID.objects.get_or_create(
245+ user=user,
246+ claimed_id='http://example.com/existing_identity',
247+ display_id='http://example.com/existing_identity')
248+
249+ # Setup user who is going to try to change username to 'testuser'
250+ renamed_user = User.objects.create_user('renameuser', 'someone@example.com')
251+ UserOpenID.objects.get_or_create(
252+ user=renamed_user,
253+ claimed_id='http://example.com/identity',
254+ display_id='http://example.com/identity')
255+
256+ # identity url is for 'renameuser'
257+ openid_req = {'openid_identifier': 'http://example.com/identity',
258+ 'next': '/getuser/'}
259+ # but returned username is for 'testuser', which already exists for another identity
260+ openid_resp = {'nickname': 'testuser', 'fullname': 'Rename User',
261+ 'email': 'rename@example.com'}
262+ self._do_user_login(openid_req, openid_resp)
263+ response = self.client.get('/getuser/')
264+
265+ # If OPENID_FOLLOW_RENAMES, attempt to change username to 'testuser'
266+ # but since that username is already taken by someone else, we go through
267+ # the process of adding +i to it, and get testuser2.
268+ self.assertEquals(response.content, 'testuser2')
269+
270+ # The user's full name and email have been updated.
271+ user = User.objects.get(username=response.content)
272+ self.assertEquals(user.first_name, 'Rename')
273+ self.assertEquals(user.last_name, 'User')
274+ self.assertEquals(user.email, 'rename@example.com')
275+
276+ def test_login_follow_rename_false_onlyonce(self):
277+ settings.OPENID_FOLLOW_RENAMES = True
278+ settings.OPENID_UPDATE_DETAILS_FROM_SREG = True
279+ # Setup existing user who's name we're going to switch to
280+ user = User.objects.create_user('testuser', 'someone@example.com')
281+ UserOpenID.objects.get_or_create(
282+ user=user,
283+ claimed_id='http://example.com/existing_identity',
284+ display_id='http://example.com/existing_identity')
285+
286+ # Setup user who is going to try to change username to 'testuser'
287+ renamed_user = User.objects.create_user('testuser2000eight', 'someone@example.com')
288+ UserOpenID.objects.get_or_create(
289+ user=renamed_user,
290+ claimed_id='http://example.com/identity',
291+ display_id='http://example.com/identity')
292+
293+ # identity url is for 'testuser2000eight'
294+ openid_req = {'openid_identifier': 'http://example.com/identity',
295+ 'next': '/getuser/'}
296+ # but returned username is for 'testuser', which already exists for another identity
297+ openid_resp = {'nickname': 'testuser2', 'fullname': 'Rename User',
298+ 'email': 'rename@example.com'}
299+ self._do_user_login(openid_req, openid_resp)
300+ response = self.client.get('/getuser/')
301+
302+ # If OPENID_FOLLOW_RENAMES, attempt to change username to 'testuser'
303+ # but since that username is already taken by someone else, we go through
304+ # the process of adding +i to it. Even though it looks like the username
305+ # follows the nickname+i scheme, it has non-numbers in the suffix, so
306+ # it's not an auto-generated one. The regular process of renaming to
307+ # 'testuser' has a conflict, so we get +2 at the end.
308+ self.assertEquals(response.content, 'testuser2')
309+
310+ # The user's full name and email have been updated.
311+ user = User.objects.get(username=response.content)
312+ self.assertEquals(user.first_name, 'Rename')
313+ self.assertEquals(user.last_name, 'User')
314+ self.assertEquals(user.email, 'rename@example.com')
315+
316+ def test_login_follow_rename_conflict_onlyonce(self):
317+ settings.OPENID_FOLLOW_RENAMES = True
318+ settings.OPENID_UPDATE_DETAILS_FROM_SREG = True
319+ # Setup existing user who's name we're going to switch to
320+ user = User.objects.create_user('testuser', 'someone@example.com')
321+ UserOpenID.objects.get_or_create(
322+ user=user,
323+ claimed_id='http://example.com/existing_identity',
324+ display_id='http://example.com/existing_identity')
325+
326+ # Setup user who is going to try to change username to 'testuser'
327+ renamed_user = User.objects.create_user('testuser2000', 'someone@example.com')
328+ UserOpenID.objects.get_or_create(
329+ user=renamed_user,
330+ claimed_id='http://example.com/identity',
331+ display_id='http://example.com/identity')
332+
333+ # identity url is for 'testuser2000'
334+ openid_req = {'openid_identifier': 'http://example.com/identity',
335+ 'next': '/getuser/'}
336+ # but returned username is for 'testuser', which already exists for another identity
337+ openid_resp = {'nickname': 'testuser', 'fullname': 'Rename User',
338+ 'email': 'rename@example.com'}
339+ self._do_user_login(openid_req, openid_resp)
340+ response = self.client.get('/getuser/')
341+
342+ # If OPENID_FOLLOW_RENAMES, attempt to change username to 'testuser'
343+ # but since that username is already taken by someone else, we go through
344+ # the process of adding +i to it. Since the user for this identity url
345+ # already has a name matching that pattern, check if first.
346+ self.assertEquals(response.content, 'testuser2000')
347+
348+ # The user's full name and email have been updated.
349+ user = User.objects.get(username=response.content)
350+ self.assertEquals(user.first_name, 'Rename')
351+ self.assertEquals(user.last_name, 'User')
352+ self.assertEquals(user.email, 'rename@example.com')
353+
354+ def test_login_follow_rename_false_conflict(self):
355+ settings.OPENID_FOLLOW_RENAMES = True
356+ settings.OPENID_UPDATE_DETAILS_FROM_SREG = True
357+ # Setup existing user who's username matches the name+i pattern
358+ user = User.objects.create_user('testuser2', 'someone@example.com')
359+ UserOpenID.objects.get_or_create(
360+ user=user,
361+ claimed_id='http://example.com/identity',
362+ display_id='http://example.com/identity')
363+
364+ # identity url is for 'testuser2'
365+ openid_req = {'openid_identifier': 'http://example.com/identity',
366+ 'next': '/getuser/'}
367+ # but returned username is for 'testuser', which looks like we've done
368+ # a username+1 for them already, but 'testuser' isn't actually taken
369+ openid_resp = {'nickname': 'testuser', 'fullname': 'Same User',
370+ 'email': 'same@example.com'}
371+ self._do_user_login(openid_req, openid_resp)
372+ response = self.client.get('/getuser/')
373+
374+ # If OPENID_FOLLOW_RENAMES, username should be changed to 'testuser'
375+ # because it wasn't currently taken
376+ self.assertEquals(response.content, 'testuser')
377+
378+ # The user's full name and email have been updated.
379+ user = User.objects.get(username=response.content)
380+ self.assertEquals(user.first_name, 'Same')
381+ self.assertEquals(user.last_name, 'User')
382+ self.assertEquals(user.email, 'same@example.com')
383+
384 def test_strict_username_no_nickname(self):
385 settings.OPENID_CREATE_USERS = True
386 settings.OPENID_STRICT_USERNAMES = True
387@@ -354,31 +564,17 @@
388 display_id='http://example.com/identity')
389 useropenid.save()
390
391- # Posting in an identity URL begins the authentication request:
392- response = self.client.post('/openid/login/',
393- {'openid_identifier': 'http://example.com/identity',
394- 'next': '/getuser/'})
395- self.assertContains(response, 'OpenID transaction in progress')
396-
397- # Complete the request, passing back some simple registration
398- # data. The user is redirected to the next URL.
399- openid_request = self.provider.parseFormPost(response.content)
400- sreg_request = sreg.SRegRequest.fromOpenIDRequest(openid_request)
401- openid_response = openid_request.answer(True)
402- sreg_response = sreg.SRegResponse.extractResponse(
403- sreg_request, {'nickname': 'someuser', 'fullname': 'Some User',
404- 'email': 'foo@example.com'})
405- openid_response.addExtension(sreg_response)
406- response = self.complete(openid_response)
407- self.assertRedirects(response, 'http://testserver/getuser/')
408-
409- # And they are now logged in as testuser (the passed in
410- # nickname has not caused the username to change).
411+ openid_req = {'openid_identifier': 'http://example.com/identity',
412+ 'next': '/getuser/'}
413+ openid_resp = {'nickname': 'testuser', 'fullname': 'Some User',
414+ 'email': 'foo@example.com'}
415+ self._do_user_login(openid_req, openid_resp)
416 response = self.client.get('/getuser/')
417+
418 self.assertEquals(response.content, 'testuser')
419
420 # The user's full name and email have been updated.
421- user = User.objects.get(username='testuser')
422+ user = User.objects.get(username=response.content)
423 self.assertEquals(user.first_name, 'Some')
424 self.assertEquals(user.last_name, 'User')
425 self.assertEquals(user.email, 'foo@example.com')
426@@ -473,6 +669,7 @@
427 self.assertEquals(user.email, 'foo@example.com')
428
429 def test_login_teams(self):
430+ settings.OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO = False
431 settings.OPENID_LAUNCHPAD_TEAMS_MAPPING = {'teamname': 'groupname',
432 'otherteam': 'othergroup'}
433 user = User.objects.create_user('testuser', 'someone@example.com')

Subscribers

People subscribed via source and target branches