Merge lp:~mhall119/django-openid-auth/fixes-642132 into lp:~django-openid-auth/django-openid-auth/trunk
- fixes-642132
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | James Henstridge | ||||
Approved revision: | 84 | ||||
Merged at revision: | 81 | ||||
Proposed branch: | lp:~mhall119/django-openid-auth/fixes-642132 | ||||
Merge into: | lp:~django-openid-auth/django-openid-auth/trunk | ||||
Diff against target: |
433 lines (+283/-34) 3 files modified
README.txt (+10/-0) django_openid_auth/auth.py (+55/-13) django_openid_auth/tests/test_views.py (+218/-21) |
||||
To merge this branch: | bzr merge lp:~mhall119/django-openid-auth/fixes-642132 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Hall | Approve | ||
Anthony Lenton | Needs Fixing | ||
James Henstridge | Approve | ||
Review via email: mp+54193@code.launchpad.net |
This proposal supersedes a proposal from 2010-10-13.
Commit message
Description of the change
Adds a new settings paramater: OPENID_
When set to True, and when OPENID_
Several checks are performed to make sure we don't conflict with an existing user with the same username.
Michael Hall (mhall119) wrote : Posted in a previous version of this proposal | # |
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_
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_
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_
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?
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:/
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://
OPENIDPROVIDER2 (Launchpad)
- {'nickname': 'Ben', 'claimed_id': 'https:/
- {'nickname': 'Cees', 'claimed_id': 'https:/
======
- Ben deletes his account on launchpad
- Cees changed name to Ben
OPENIDCONSUMER
- Ben (http://
- Ben (https:/
- Cees (https:/
=======
- Ben (previous Cees | https:/
-- user 'Ben1' should be renamed to 'OpenIdUserX'
-- user Cees should be renamed to 'Ben1'
small catch: What to do if Ben (https:/
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
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:/
User Cees(https:/
OPENIDCONSUMER
Ben (previous Cees | https:/
user 'Ben1' (https:/
user 'Cees' should be renamed to 'Ben1'
Ben2 (https:/
user 'Ben1' (previous Cees | https:/
user 'Ben2' should be renamed to 'Ben1'
All next logins for Ben3 (Cees/Ben (https:/
- 84. By Michael Hall
-
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!
- 85. By Michael Hall
-
Updates from trunk
Anthony Lenton (elachuni) wrote : | # |
I now get 1 fail and 1 error after merging into trunk:
- 86. By Michael Hall
-
Check for STRICT_USERNAMES before defaulting the nickname to openiduser
Michael Hall (mhall119) wrote : | # |
Fixed the failing tests.
Michael Hall (mhall119) : | # |
- 87. By Michael Hall
-
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 | 126 | 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 | 126 | 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 | 127 | openid user to be staff. | 127 | openid user to be staff. |
7 | 128 | 128 | ||
8 | 129 | == Change Django usernames if the nickname changes on the provider == | ||
9 | 130 | |||
10 | 131 | If you want your Django username to change when a user updates the nickname on their provider, add the following setting: | ||
11 | 132 | |||
12 | 133 | OPENID_FOLLOW_RENAMES = True | ||
13 | 134 | |||
14 | 135 | If the new nickname is available as a Django username, the user is renamed. | ||
15 | 136 | Otherwise the user will be renamed to nickname+i for an incrememnting value of i until no conflict occurs. | ||
16 | 137 | 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 | 138 | |||
18 | 129 | == Require a valid nickname == | 139 | == Require a valid nickname == |
19 | 130 | 140 | ||
20 | 131 | If you must have a valid, unique nickname in order to create a user accont, add the following setting: | 141 | If you must have a valid, unique nickname in order to create a user accont, add the following setting: |
21 | 132 | 142 | ||
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 | 86 | 86 | ||
27 | 87 | if getattr(settings, 'OPENID_UPDATE_DETAILS_FROM_SREG', False): | 87 | if getattr(settings, 'OPENID_UPDATE_DETAILS_FROM_SREG', False): |
28 | 88 | details = self._extract_user_details(openid_response) | 88 | details = self._extract_user_details(openid_response) |
30 | 89 | self.update_user_details(user, details) | 89 | self.update_user_details(user, details, openid_response) |
31 | 90 | 90 | ||
32 | 91 | teams_response = teams.TeamsResponse.fromSuccessResponse( | 91 | teams_response = teams.TeamsResponse.fromSuccessResponse( |
33 | 92 | openid_response) | 92 | openid_response) |
34 | @@ -103,7 +103,6 @@ | |||
35 | 103 | email = sreg_response.get('email') | 103 | email = sreg_response.get('email') |
36 | 104 | fullname = sreg_response.get('fullname') | 104 | fullname = sreg_response.get('fullname') |
37 | 105 | nickname = sreg_response.get('nickname') | 105 | nickname = sreg_response.get('nickname') |
38 | 106 | |||
39 | 107 | # If any attributes are provided via Attribute Exchange, use | 106 | # If any attributes are provided via Attribute Exchange, use |
40 | 108 | # them in preference. | 107 | # them in preference. |
41 | 109 | fetch_response = ax.FetchResponse.fromSuccessResponse(openid_response) | 108 | fetch_response = ax.FetchResponse.fromSuccessResponse(openid_response) |
42 | @@ -142,17 +141,49 @@ | |||
43 | 142 | return dict(email=email, nickname=nickname, | 141 | return dict(email=email, nickname=nickname, |
44 | 143 | first_name=first_name, last_name=last_name) | 142 | first_name=first_name, last_name=last_name) |
45 | 144 | 143 | ||
51 | 145 | def create_user_from_openid(self, openid_response): | 144 | def _get_available_username(self, nickname, identity_url): |
52 | 146 | details = self._extract_user_details(openid_response) | 145 | # If we're being strict about usernames, throw an error if we didn't |
53 | 147 | nickname = details['nickname'] or 'openiduser' | 146 | # get one back from the provider |
49 | 148 | email = details['email'] or '' | ||
50 | 149 | |||
54 | 150 | if getattr(settings, 'OPENID_STRICT_USERNAMES', False): | 147 | if getattr(settings, 'OPENID_STRICT_USERNAMES', False): |
56 | 151 | if details['nickname'] is None or details['nickname'] == '': | 148 | if nickname is None or nickname == '': |
57 | 152 | raise StrictUsernameViolation("No username") | 149 | raise StrictUsernameViolation("No username") |
58 | 150 | |||
59 | 151 | # If we don't have a nickname, and we're not being strict, use a default | ||
60 | 152 | nickname = nickname or 'openiduser' | ||
61 | 153 | |||
62 | 154 | # See if we already have this nickname assigned to a username | ||
63 | 155 | try: | ||
64 | 156 | user = User.objects.get(username__exact=nickname) | ||
65 | 157 | except User.DoesNotExist: | ||
66 | 158 | # No conflict, we can use this nickname | ||
67 | 159 | return nickname | ||
68 | 160 | |||
69 | 161 | # Check if we already have nickname+i for this identity_url | ||
70 | 162 | try: | ||
71 | 163 | user_openid = UserOpenID.objects.get( | ||
72 | 164 | claimed_id__exact=identity_url, | ||
73 | 165 | user__username__startswith=nickname) | ||
74 | 166 | # No exception means we have an existing user for this identity | ||
75 | 167 | # that starts with this nickname, so it's possible we've had to | ||
76 | 168 | # assign them to nickname+i already. | ||
77 | 169 | oid_username = user_openid.user.username | ||
78 | 170 | if len(oid_username) > len(nickname): | ||
79 | 171 | try: | ||
80 | 172 | # check that it ends with a number | ||
81 | 173 | int(oid_username[len(nickname):]) | ||
82 | 174 | return oid_username | ||
83 | 175 | except ValueError: | ||
84 | 176 | # username starts with nickname, but isn't nickname+# | ||
85 | 177 | pass | ||
86 | 178 | except UserOpenID.DoesNotExist: | ||
87 | 179 | # No user associated with this identity_url | ||
88 | 180 | pass | ||
89 | 181 | |||
90 | 182 | |||
91 | 183 | if getattr(settings, 'OPENID_STRICT_USERNAMES', False): | ||
92 | 153 | if User.objects.filter(username__exact=nickname).count() > 0: | 184 | if User.objects.filter(username__exact=nickname).count() > 0: |
93 | 154 | raise StrictUsernameViolation("Duplicate username: %s" % nickname) | 185 | raise StrictUsernameViolation("Duplicate username: %s" % nickname) |
95 | 155 | 186 | ||
96 | 156 | # Pick a username for the user based on their nickname, | 187 | # Pick a username for the user based on their nickname, |
97 | 157 | # checking for conflicts. | 188 | # checking for conflicts. |
98 | 158 | i = 1 | 189 | i = 1 |
99 | @@ -161,15 +192,23 @@ | |||
100 | 161 | if i > 1: | 192 | if i > 1: |
101 | 162 | username += str(i) | 193 | username += str(i) |
102 | 163 | try: | 194 | try: |
104 | 164 | User.objects.get(username__exact=username) | 195 | user = User.objects.get(username__exact=username) |
105 | 165 | except User.DoesNotExist: | 196 | except User.DoesNotExist: |
106 | 166 | break | 197 | break |
107 | 167 | i += 1 | 198 | i += 1 |
108 | 199 | return username | ||
109 | 200 | |||
110 | 201 | def create_user_from_openid(self, openid_response): | ||
111 | 202 | details = self._extract_user_details(openid_response) | ||
112 | 203 | nickname = details['nickname'] or 'openiduser' | ||
113 | 204 | email = details['email'] or '' | ||
114 | 205 | |||
115 | 206 | username = self._get_available_username(details['nickname'], openid_response.identity_url) | ||
116 | 168 | 207 | ||
117 | 169 | user = User.objects.create_user(username, email, password=None) | 208 | user = User.objects.create_user(username, email, password=None) |
118 | 170 | self.update_user_details(user, details) | ||
119 | 171 | |||
120 | 172 | self.associate_openid(user, openid_response) | 209 | self.associate_openid(user, openid_response) |
121 | 210 | self.update_user_details(user, details, openid_response) | ||
122 | 211 | |||
123 | 173 | return user | 212 | return user |
124 | 174 | 213 | ||
125 | 175 | def associate_openid(self, user, openid_response): | 214 | def associate_openid(self, user, openid_response): |
126 | @@ -192,7 +231,7 @@ | |||
127 | 192 | 231 | ||
128 | 193 | return user_openid | 232 | return user_openid |
129 | 194 | 233 | ||
131 | 195 | def update_user_details(self, user, details): | 234 | def update_user_details(self, user, details, openid_response): |
132 | 196 | updated = False | 235 | updated = False |
133 | 197 | if details['first_name']: | 236 | if details['first_name']: |
134 | 198 | user.first_name = details['first_name'] | 237 | user.first_name = details['first_name'] |
135 | @@ -203,6 +242,9 @@ | |||
136 | 203 | if details['email']: | 242 | if details['email']: |
137 | 204 | user.email = details['email'] | 243 | user.email = details['email'] |
138 | 205 | updated = True | 244 | updated = True |
139 | 245 | if getattr(settings, 'OPENID_FOLLOW_RENAMES', False): | ||
140 | 246 | user.username = self._get_available_username(details['nickname'], openid_response.identity_url) | ||
141 | 247 | updated = True | ||
142 | 206 | 248 | ||
143 | 207 | if updated: | 249 | if updated: |
144 | 208 | user.save() | 250 | user.save() |
145 | 209 | 251 | ||
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 | 136 | self.old_sso_server_url = getattr(settings, 'OPENID_SSO_SERVER_URL', None) | 136 | self.old_sso_server_url = getattr(settings, 'OPENID_SSO_SERVER_URL', None) |
151 | 137 | self.old_teams_map = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING', {}) | 137 | self.old_teams_map = getattr(settings, 'OPENID_LAUNCHPAD_TEAMS_MAPPING', {}) |
152 | 138 | self.old_use_as_admin_login = getattr(settings, 'OPENID_USE_AS_ADMIN_LOGIN', False) | 138 | self.old_use_as_admin_login = getattr(settings, 'OPENID_USE_AS_ADMIN_LOGIN', False) |
153 | 139 | self.old_follow_renames = getattr(settings, 'OPENID_FOLLOW_RENAMES', False) | ||
154 | 139 | 140 | ||
155 | 140 | settings.OPENID_CREATE_USERS = False | 141 | settings.OPENID_CREATE_USERS = False |
156 | 141 | settings.OPENID_STRICT_USERNAMES = False | 142 | settings.OPENID_STRICT_USERNAMES = False |
157 | @@ -143,6 +144,7 @@ | |||
158 | 143 | settings.OPENID_SSO_SERVER_URL = None | 144 | settings.OPENID_SSO_SERVER_URL = None |
159 | 144 | settings.OPENID_LAUNCHPAD_TEAMS_MAPPING = {} | 145 | settings.OPENID_LAUNCHPAD_TEAMS_MAPPING = {} |
160 | 145 | settings.OPENID_USE_AS_ADMIN_LOGIN = False | 146 | settings.OPENID_USE_AS_ADMIN_LOGIN = False |
161 | 147 | settings.OPENID_FOLLOW_RENAMES = False | ||
162 | 146 | 148 | ||
163 | 147 | def tearDown(self): | 149 | def tearDown(self): |
164 | 148 | settings.LOGIN_REDIRECT_URL = self.old_login_redirect_url | 150 | settings.LOGIN_REDIRECT_URL = self.old_login_redirect_url |
165 | @@ -152,6 +154,7 @@ | |||
166 | 152 | settings.OPENID_SSO_SERVER_URL = self.old_sso_server_url | 154 | settings.OPENID_SSO_SERVER_URL = self.old_sso_server_url |
167 | 153 | settings.OPENID_LAUNCHPAD_TEAMS_MAPPING = self.old_teams_map | 155 | settings.OPENID_LAUNCHPAD_TEAMS_MAPPING = self.old_teams_map |
168 | 154 | settings.OPENID_USE_AS_ADMIN_LOGIN = self.old_use_as_admin_login | 156 | settings.OPENID_USE_AS_ADMIN_LOGIN = self.old_use_as_admin_login |
169 | 157 | settings.OPENID_FOLLOW_RENAMES = self.old_follow_renames | ||
170 | 155 | 158 | ||
171 | 156 | setDefaultFetcher(None) | 159 | setDefaultFetcher(None) |
172 | 157 | super(RelyingPartyTests, self).tearDown() | 160 | super(RelyingPartyTests, self).tearDown() |
173 | @@ -289,6 +292,213 @@ | |||
174 | 289 | self.assertEquals(user.last_name, 'User') | 292 | self.assertEquals(user.last_name, 'User') |
175 | 290 | self.assertEquals(user.email, 'foo@example.com') | 293 | self.assertEquals(user.email, 'foo@example.com') |
176 | 291 | 294 | ||
177 | 295 | def _do_user_login(self, openid_req, openid_resp): | ||
178 | 296 | # Posting in an identity URL begins the authentication request: | ||
179 | 297 | response = self.client.post('/openid/login/', openid_req) | ||
180 | 298 | self.assertContains(response, 'OpenID transaction in progress') | ||
181 | 299 | |||
182 | 300 | # Complete the request, passing back some simple registration | ||
183 | 301 | # data. The user is redirected to the next URL. | ||
184 | 302 | openid_request = self.provider.parseFormPost(response.content) | ||
185 | 303 | sreg_request = sreg.SRegRequest.fromOpenIDRequest(openid_request) | ||
186 | 304 | openid_response = openid_request.answer(True) | ||
187 | 305 | sreg_response = sreg.SRegResponse.extractResponse( | ||
188 | 306 | sreg_request, openid_resp) | ||
189 | 307 | openid_response.addExtension(sreg_response) | ||
190 | 308 | response = self.complete(openid_response) | ||
191 | 309 | self.assertRedirects(response, 'http://testserver/getuser/') | ||
192 | 310 | |||
193 | 311 | def test_login_without_nickname(self): | ||
194 | 312 | settings.OPENID_CREATE_USERS = True | ||
195 | 313 | |||
196 | 314 | openid_req = {'openid_identifier': 'http://example.com/identity', | ||
197 | 315 | 'next': '/getuser/'} | ||
198 | 316 | openid_resp = {'nickname': '', 'fullname': 'Openid User', | ||
199 | 317 | 'email': 'foo@example.com'} | ||
200 | 318 | self._do_user_login(openid_req, openid_resp) | ||
201 | 319 | response = self.client.get('/getuser/') | ||
202 | 320 | |||
203 | 321 | # username defaults to 'openiduser' | ||
204 | 322 | self.assertEquals(response.content, 'openiduser') | ||
205 | 323 | |||
206 | 324 | # The user's full name and email have been updated. | ||
207 | 325 | user = User.objects.get(username=response.content) | ||
208 | 326 | self.assertEquals(user.first_name, 'Openid') | ||
209 | 327 | self.assertEquals(user.last_name, 'User') | ||
210 | 328 | self.assertEquals(user.email, 'foo@example.com') | ||
211 | 329 | |||
212 | 330 | def test_login_follow_rename(self): | ||
213 | 331 | settings.OPENID_FOLLOW_RENAMES = True | ||
214 | 332 | settings.OPENID_UPDATE_DETAILS_FROM_SREG = True | ||
215 | 333 | user = User.objects.create_user('testuser', 'someone@example.com') | ||
216 | 334 | useropenid = UserOpenID( | ||
217 | 335 | user=user, | ||
218 | 336 | claimed_id='http://example.com/identity', | ||
219 | 337 | display_id='http://example.com/identity') | ||
220 | 338 | useropenid.save() | ||
221 | 339 | |||
222 | 340 | openid_req = {'openid_identifier': 'http://example.com/identity', | ||
223 | 341 | 'next': '/getuser/'} | ||
224 | 342 | openid_resp = {'nickname': 'someuser', 'fullname': 'Some User', | ||
225 | 343 | 'email': 'foo@example.com'} | ||
226 | 344 | self._do_user_login(openid_req, openid_resp) | ||
227 | 345 | response = self.client.get('/getuser/') | ||
228 | 346 | |||
229 | 347 | # If OPENID_FOLLOW_RENAMES, they are logged in as | ||
230 | 348 | # someuser (the passed in nickname has changed the username) | ||
231 | 349 | self.assertEquals(response.content, 'someuser') | ||
232 | 350 | |||
233 | 351 | # The user's full name and email have been updated. | ||
234 | 352 | user = User.objects.get(username=response.content) | ||
235 | 353 | self.assertEquals(user.first_name, 'Some') | ||
236 | 354 | self.assertEquals(user.last_name, 'User') | ||
237 | 355 | self.assertEquals(user.email, 'foo@example.com') | ||
238 | 356 | |||
239 | 357 | def test_login_follow_rename_conflict(self): | ||
240 | 358 | settings.OPENID_FOLLOW_RENAMES = True | ||
241 | 359 | settings.OPENID_UPDATE_DETAILS_FROM_SREG = True | ||
242 | 360 | # Setup existing user who's name we're going to switch to | ||
243 | 361 | user = User.objects.create_user('testuser', 'someone@example.com') | ||
244 | 362 | UserOpenID.objects.get_or_create( | ||
245 | 363 | user=user, | ||
246 | 364 | claimed_id='http://example.com/existing_identity', | ||
247 | 365 | display_id='http://example.com/existing_identity') | ||
248 | 366 | |||
249 | 367 | # Setup user who is going to try to change username to 'testuser' | ||
250 | 368 | renamed_user = User.objects.create_user('renameuser', 'someone@example.com') | ||
251 | 369 | UserOpenID.objects.get_or_create( | ||
252 | 370 | user=renamed_user, | ||
253 | 371 | claimed_id='http://example.com/identity', | ||
254 | 372 | display_id='http://example.com/identity') | ||
255 | 373 | |||
256 | 374 | # identity url is for 'renameuser' | ||
257 | 375 | openid_req = {'openid_identifier': 'http://example.com/identity', | ||
258 | 376 | 'next': '/getuser/'} | ||
259 | 377 | # but returned username is for 'testuser', which already exists for another identity | ||
260 | 378 | openid_resp = {'nickname': 'testuser', 'fullname': 'Rename User', | ||
261 | 379 | 'email': 'rename@example.com'} | ||
262 | 380 | self._do_user_login(openid_req, openid_resp) | ||
263 | 381 | response = self.client.get('/getuser/') | ||
264 | 382 | |||
265 | 383 | # If OPENID_FOLLOW_RENAMES, attempt to change username to 'testuser' | ||
266 | 384 | # but since that username is already taken by someone else, we go through | ||
267 | 385 | # the process of adding +i to it, and get testuser2. | ||
268 | 386 | self.assertEquals(response.content, 'testuser2') | ||
269 | 387 | |||
270 | 388 | # The user's full name and email have been updated. | ||
271 | 389 | user = User.objects.get(username=response.content) | ||
272 | 390 | self.assertEquals(user.first_name, 'Rename') | ||
273 | 391 | self.assertEquals(user.last_name, 'User') | ||
274 | 392 | self.assertEquals(user.email, 'rename@example.com') | ||
275 | 393 | |||
276 | 394 | def test_login_follow_rename_false_onlyonce(self): | ||
277 | 395 | settings.OPENID_FOLLOW_RENAMES = True | ||
278 | 396 | settings.OPENID_UPDATE_DETAILS_FROM_SREG = True | ||
279 | 397 | # Setup existing user who's name we're going to switch to | ||
280 | 398 | user = User.objects.create_user('testuser', 'someone@example.com') | ||
281 | 399 | UserOpenID.objects.get_or_create( | ||
282 | 400 | user=user, | ||
283 | 401 | claimed_id='http://example.com/existing_identity', | ||
284 | 402 | display_id='http://example.com/existing_identity') | ||
285 | 403 | |||
286 | 404 | # Setup user who is going to try to change username to 'testuser' | ||
287 | 405 | renamed_user = User.objects.create_user('testuser2000eight', 'someone@example.com') | ||
288 | 406 | UserOpenID.objects.get_or_create( | ||
289 | 407 | user=renamed_user, | ||
290 | 408 | claimed_id='http://example.com/identity', | ||
291 | 409 | display_id='http://example.com/identity') | ||
292 | 410 | |||
293 | 411 | # identity url is for 'testuser2000eight' | ||
294 | 412 | openid_req = {'openid_identifier': 'http://example.com/identity', | ||
295 | 413 | 'next': '/getuser/'} | ||
296 | 414 | # but returned username is for 'testuser', which already exists for another identity | ||
297 | 415 | openid_resp = {'nickname': 'testuser2', 'fullname': 'Rename User', | ||
298 | 416 | 'email': 'rename@example.com'} | ||
299 | 417 | self._do_user_login(openid_req, openid_resp) | ||
300 | 418 | response = self.client.get('/getuser/') | ||
301 | 419 | |||
302 | 420 | # If OPENID_FOLLOW_RENAMES, attempt to change username to 'testuser' | ||
303 | 421 | # but since that username is already taken by someone else, we go through | ||
304 | 422 | # the process of adding +i to it. Even though it looks like the username | ||
305 | 423 | # follows the nickname+i scheme, it has non-numbers in the suffix, so | ||
306 | 424 | # it's not an auto-generated one. The regular process of renaming to | ||
307 | 425 | # 'testuser' has a conflict, so we get +2 at the end. | ||
308 | 426 | self.assertEquals(response.content, 'testuser2') | ||
309 | 427 | |||
310 | 428 | # The user's full name and email have been updated. | ||
311 | 429 | user = User.objects.get(username=response.content) | ||
312 | 430 | self.assertEquals(user.first_name, 'Rename') | ||
313 | 431 | self.assertEquals(user.last_name, 'User') | ||
314 | 432 | self.assertEquals(user.email, 'rename@example.com') | ||
315 | 433 | |||
316 | 434 | def test_login_follow_rename_conflict_onlyonce(self): | ||
317 | 435 | settings.OPENID_FOLLOW_RENAMES = True | ||
318 | 436 | settings.OPENID_UPDATE_DETAILS_FROM_SREG = True | ||
319 | 437 | # Setup existing user who's name we're going to switch to | ||
320 | 438 | user = User.objects.create_user('testuser', 'someone@example.com') | ||
321 | 439 | UserOpenID.objects.get_or_create( | ||
322 | 440 | user=user, | ||
323 | 441 | claimed_id='http://example.com/existing_identity', | ||
324 | 442 | display_id='http://example.com/existing_identity') | ||
325 | 443 | |||
326 | 444 | # Setup user who is going to try to change username to 'testuser' | ||
327 | 445 | renamed_user = User.objects.create_user('testuser2000', 'someone@example.com') | ||
328 | 446 | UserOpenID.objects.get_or_create( | ||
329 | 447 | user=renamed_user, | ||
330 | 448 | claimed_id='http://example.com/identity', | ||
331 | 449 | display_id='http://example.com/identity') | ||
332 | 450 | |||
333 | 451 | # identity url is for 'testuser2000' | ||
334 | 452 | openid_req = {'openid_identifier': 'http://example.com/identity', | ||
335 | 453 | 'next': '/getuser/'} | ||
336 | 454 | # but returned username is for 'testuser', which already exists for another identity | ||
337 | 455 | openid_resp = {'nickname': 'testuser', 'fullname': 'Rename User', | ||
338 | 456 | 'email': 'rename@example.com'} | ||
339 | 457 | self._do_user_login(openid_req, openid_resp) | ||
340 | 458 | response = self.client.get('/getuser/') | ||
341 | 459 | |||
342 | 460 | # If OPENID_FOLLOW_RENAMES, attempt to change username to 'testuser' | ||
343 | 461 | # but since that username is already taken by someone else, we go through | ||
344 | 462 | # the process of adding +i to it. Since the user for this identity url | ||
345 | 463 | # already has a name matching that pattern, check if first. | ||
346 | 464 | self.assertEquals(response.content, 'testuser2000') | ||
347 | 465 | |||
348 | 466 | # The user's full name and email have been updated. | ||
349 | 467 | user = User.objects.get(username=response.content) | ||
350 | 468 | self.assertEquals(user.first_name, 'Rename') | ||
351 | 469 | self.assertEquals(user.last_name, 'User') | ||
352 | 470 | self.assertEquals(user.email, 'rename@example.com') | ||
353 | 471 | |||
354 | 472 | def test_login_follow_rename_false_conflict(self): | ||
355 | 473 | settings.OPENID_FOLLOW_RENAMES = True | ||
356 | 474 | settings.OPENID_UPDATE_DETAILS_FROM_SREG = True | ||
357 | 475 | # Setup existing user who's username matches the name+i pattern | ||
358 | 476 | user = User.objects.create_user('testuser2', 'someone@example.com') | ||
359 | 477 | UserOpenID.objects.get_or_create( | ||
360 | 478 | user=user, | ||
361 | 479 | claimed_id='http://example.com/identity', | ||
362 | 480 | display_id='http://example.com/identity') | ||
363 | 481 | |||
364 | 482 | # identity url is for 'testuser2' | ||
365 | 483 | openid_req = {'openid_identifier': 'http://example.com/identity', | ||
366 | 484 | 'next': '/getuser/'} | ||
367 | 485 | # but returned username is for 'testuser', which looks like we've done | ||
368 | 486 | # a username+1 for them already, but 'testuser' isn't actually taken | ||
369 | 487 | openid_resp = {'nickname': 'testuser', 'fullname': 'Same User', | ||
370 | 488 | 'email': 'same@example.com'} | ||
371 | 489 | self._do_user_login(openid_req, openid_resp) | ||
372 | 490 | response = self.client.get('/getuser/') | ||
373 | 491 | |||
374 | 492 | # If OPENID_FOLLOW_RENAMES, username should be changed to 'testuser' | ||
375 | 493 | # because it wasn't currently taken | ||
376 | 494 | self.assertEquals(response.content, 'testuser') | ||
377 | 495 | |||
378 | 496 | # The user's full name and email have been updated. | ||
379 | 497 | user = User.objects.get(username=response.content) | ||
380 | 498 | self.assertEquals(user.first_name, 'Same') | ||
381 | 499 | self.assertEquals(user.last_name, 'User') | ||
382 | 500 | self.assertEquals(user.email, 'same@example.com') | ||
383 | 501 | |||
384 | 292 | def test_strict_username_no_nickname(self): | 502 | def test_strict_username_no_nickname(self): |
385 | 293 | settings.OPENID_CREATE_USERS = True | 503 | settings.OPENID_CREATE_USERS = True |
386 | 294 | settings.OPENID_STRICT_USERNAMES = True | 504 | settings.OPENID_STRICT_USERNAMES = True |
387 | @@ -354,31 +564,17 @@ | |||
388 | 354 | display_id='http://example.com/identity') | 564 | display_id='http://example.com/identity') |
389 | 355 | useropenid.save() | 565 | useropenid.save() |
390 | 356 | 566 | ||
411 | 357 | # Posting in an identity URL begins the authentication request: | 567 | openid_req = {'openid_identifier': 'http://example.com/identity', |
412 | 358 | response = self.client.post('/openid/login/', | 568 | 'next': '/getuser/'} |
413 | 359 | {'openid_identifier': 'http://example.com/identity', | 569 | openid_resp = {'nickname': 'testuser', 'fullname': 'Some User', |
414 | 360 | 'next': '/getuser/'}) | 570 | 'email': 'foo@example.com'} |
415 | 361 | self.assertContains(response, 'OpenID transaction in progress') | 571 | self._do_user_login(openid_req, openid_resp) |
396 | 362 | |||
397 | 363 | # Complete the request, passing back some simple registration | ||
398 | 364 | # data. The user is redirected to the next URL. | ||
399 | 365 | openid_request = self.provider.parseFormPost(response.content) | ||
400 | 366 | sreg_request = sreg.SRegRequest.fromOpenIDRequest(openid_request) | ||
401 | 367 | openid_response = openid_request.answer(True) | ||
402 | 368 | sreg_response = sreg.SRegResponse.extractResponse( | ||
403 | 369 | sreg_request, {'nickname': 'someuser', 'fullname': 'Some User', | ||
404 | 370 | 'email': 'foo@example.com'}) | ||
405 | 371 | openid_response.addExtension(sreg_response) | ||
406 | 372 | response = self.complete(openid_response) | ||
407 | 373 | self.assertRedirects(response, 'http://testserver/getuser/') | ||
408 | 374 | |||
409 | 375 | # And they are now logged in as testuser (the passed in | ||
410 | 376 | # nickname has not caused the username to change). | ||
416 | 377 | response = self.client.get('/getuser/') | 572 | response = self.client.get('/getuser/') |
417 | 573 | |||
418 | 378 | self.assertEquals(response.content, 'testuser') | 574 | self.assertEquals(response.content, 'testuser') |
419 | 379 | 575 | ||
420 | 380 | # The user's full name and email have been updated. | 576 | # The user's full name and email have been updated. |
422 | 381 | user = User.objects.get(username='testuser') | 577 | user = User.objects.get(username=response.content) |
423 | 382 | self.assertEquals(user.first_name, 'Some') | 578 | self.assertEquals(user.first_name, 'Some') |
424 | 383 | self.assertEquals(user.last_name, 'User') | 579 | self.assertEquals(user.last_name, 'User') |
425 | 384 | self.assertEquals(user.email, 'foo@example.com') | 580 | self.assertEquals(user.email, 'foo@example.com') |
426 | @@ -473,6 +669,7 @@ | |||
427 | 473 | self.assertEquals(user.email, 'foo@example.com') | 669 | self.assertEquals(user.email, 'foo@example.com') |
428 | 474 | 670 | ||
429 | 475 | def test_login_teams(self): | 671 | def test_login_teams(self): |
430 | 672 | settings.OPENID_LAUNCHPAD_TEAMS_MAPPING_AUTO = False | ||
431 | 476 | settings.OPENID_LAUNCHPAD_TEAMS_MAPPING = {'teamname': 'groupname', | 673 | settings.OPENID_LAUNCHPAD_TEAMS_MAPPING = {'teamname': 'groupname', |
432 | 477 | 'otherteam': 'othergroup'} | 674 | 'otherteam': 'othergroup'} |
433 | 478 | user = User.objects.create_user('testuser', 'someone@example.com') | 675 | user = User.objects.create_user('testuser', 'someone@example.com') |
Can somebody please review this, it is needed for loco.ubuntu.com and summit.ubuntu.com