Revision e5966bd9
b/snf-astakos-app/astakos/im/auth_backends.py | ||
---|---|---|
47 | 47 |
""" |
48 | 48 |
def authenticate(self, email=None, auth_token=None): |
49 | 49 |
try: |
50 |
user = AstakosUser.objects.get(email__iexact=email, is_active=True)
|
|
51 |
if user.auth_token == auth_token:
|
|
52 |
return user
|
|
50 |
user = AstakosUser.objects.get_by_identifier(email, is_active=True,
|
|
51 |
auth_token=auth_token)
|
|
52 |
return user |
|
53 | 53 |
except AstakosUser.DoesNotExist: |
54 | 54 |
return None |
55 | 55 |
else: |
... | ... | |
72 | 72 |
""" |
73 | 73 |
def authenticate(self, username=None, password=None): |
74 | 74 |
# First check whether a user having this email exists |
75 |
users = AstakosUser.objects.filter(email__iexact=username) |
|
76 |
for user in users: |
|
75 |
try: |
|
76 |
user = AstakosUser.objects.get_by_identifier(username, |
|
77 |
is_active=True) |
|
77 | 78 |
if user.check_password(password): |
78 | 79 |
return user |
79 |
|
|
80 |
# Since no user has been found by email try with the username |
|
81 |
try: |
|
82 |
user = AstakosUser.objects.get(username=username) |
|
83 | 80 |
except AstakosUser.DoesNotExist: |
84 | 81 |
return None |
85 |
|
|
82 |
|
|
86 | 83 |
if user.check_password(password): |
87 | 84 |
return user |
88 | 85 |
else: |
b/snf-astakos-app/astakos/im/forms.py | ||
---|---|---|
82 | 82 |
) |
83 | 83 |
|
84 | 84 |
class StoreUserMixin(object): |
85 |
|
|
85 | 86 |
@transaction.commit_on_success |
86 | 87 |
def store_user(self, user, request): |
87 | 88 |
user.save() |
... | ... | |
141 | 142 |
mark_safe("I agree with %s" % terms_link_html) |
142 | 143 |
|
143 | 144 |
def clean_email(self): |
144 |
email = self.cleaned_data['email'].lower()
|
|
145 |
email = self.cleaned_data['email'] |
|
145 | 146 |
if not email: |
146 | 147 |
raise forms.ValidationError(_(astakos_messages.REQUIRED_FIELD)) |
147 | 148 |
if reserved_email(email): |
... | ... | |
260 | 261 |
mark_safe("I agree with %s" % terms_link_html) |
261 | 262 |
|
262 | 263 |
def clean_email(self): |
263 |
email = self.cleaned_data['email'].lower()
|
|
264 |
email = self.cleaned_data['email'] |
|
264 | 265 |
if not email: |
265 | 266 |
raise forms.ValidationError(_(astakos_messages.REQUIRED_FIELD)) |
266 | 267 |
if reserved_email(email): |
... | ... | |
385 | 386 |
username = self.cleaned_data.get('username') |
386 | 387 |
|
387 | 388 |
try: |
388 |
user = AstakosUser.objects.get(email=username)
|
|
389 |
user = AstakosUser.objects.get_by_identifier(username)
|
|
389 | 390 |
if not user.has_auth_provider('local'): |
390 | 391 |
provider = auth_providers.get_provider('local') |
391 | 392 |
raise forms.ValidationError( |
b/snf-astakos-app/astakos/im/models.py | ||
---|---|---|
324 | 324 |
def get_by_email(self, email): |
325 | 325 |
return self.get(email=email) |
326 | 326 |
|
327 |
def get_by_identifier(self, email_or_username, **kwargs): |
|
328 |
try: |
|
329 |
return self.get(email__iexact=email_or_username, **kwargs) |
|
330 |
except AstakosUser.DoesNotExist: |
|
331 |
return self.get(username__iexact=email_or_username, **kwargs) |
|
332 |
|
|
333 |
def user_exists(self, email_or_username, **kwargs): |
|
334 |
qemail = Q(email__iexact=email_or_username) |
|
335 |
qusername = Q(username__iexact=email_or_username) |
|
336 |
return self.filter(qemail | qusername).exists() |
|
337 |
|
|
338 |
|
|
327 | 339 |
class AstakosUser(User): |
328 | 340 |
""" |
329 | 341 |
Extends ``django.contrib.auth.models.User`` by defining additional fields. |
... | ... | |
501 | 513 |
|
502 | 514 |
if not self.id: |
503 | 515 |
# set username |
504 |
self.username = self.email |
|
516 |
self.username = self.email.lower()
|
|
505 | 517 |
|
506 | 518 |
self.validate_unique_email_isactive() |
507 | 519 |
|
b/snf-astakos-app/astakos/im/tests.py | ||
---|---|---|
41 | 41 |
from astakos.im.models import * |
42 | 42 |
from astakos.im import functions |
43 | 43 |
from astakos.im import settings as astakos_settings |
44 |
from astakos.im import forms |
|
44 | 45 |
|
45 | 46 |
from urllib import quote |
46 | 47 |
|
... | ... | |
156 | 157 |
astakos_settings.SHIBBOLETH_REQUIRE_NAME_INFO = False |
157 | 158 |
|
158 | 159 |
# shibboleth logged us in |
159 |
client.set_tokens(mail="kpap@grnet.gr", eppn="kpapeppn", cn="1", |
|
160 |
client.set_tokens(mail="kpap@grnet.gr", eppn="kpapeppn", |
|
161 |
cn="Kostas Papadimitriou", |
|
160 | 162 |
ep_affiliation="Test Affiliation") |
161 | 163 |
r = client.get('/im/login/shibboleth?') |
162 | 164 |
self.assertEqual(r.status_code, 200) |
... | ... | |
201 | 203 |
|
202 | 204 |
# and finally a valid signup |
203 | 205 |
post_data['email'] = 'kpap@grnet.gr' |
204 |
r = client.post('/im/signup', post_data) |
|
205 |
self.assertEqual(r.status_code, 200)
|
|
206 |
r = client.post('/im/signup', post_data, follow=True)
|
|
207 |
self.assertContains(r, messages.NOTIFICATION_SENT)
|
|
206 | 208 |
|
207 | 209 |
# everything is ok in our db |
208 | 210 |
self.assertEqual(AstakosUser.objects.count(), 1) |
... | ... | |
213 | 215 |
provider = AstakosUserAuthProvider.objects.get(module="shibboleth") |
214 | 216 |
self.assertEqual(provider.affiliation, 'Test Affiliation') |
215 | 217 |
self.assertEqual(provider.info, {u'email': u'kpap@grnet.gr', |
216 |
u'eppn': u'kpapeppn'}) |
|
218 |
u'eppn': u'kpapeppn', |
|
219 |
u'name': u'Kostas Papadimitriou'}) |
|
217 | 220 |
|
218 | 221 |
# lets login (not activated yet) |
219 |
client.set_tokens(mail="kpap@grnet.gr", eppn="kpapeppn", cn="1", ) |
|
222 |
client.set_tokens(mail="kpap@grnet.gr", eppn="kpapeppn", |
|
223 |
cn="Kostas Papadimitriou", ) |
|
220 | 224 |
r = client.get("/im/login/shibboleth?", follow=True) |
221 | 225 |
self.assertContains(r, messages.ACCOUNT_PENDING_MODERATION) |
222 | 226 |
r = client.get("/im/profile", follow=True) |
... | ... | |
242 | 246 |
|
243 | 247 |
client = ShibbolethClient() |
244 | 248 |
# shibboleth logged us in, notice that we use different email |
245 |
client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn", cn="1", ) |
|
249 |
client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn", |
|
250 |
cn="Kostas Papadimitriou", ) |
|
246 | 251 |
r = client.get("/im/login/shibboleth?") |
247 | 252 |
|
248 | 253 |
# astakos asks if we want to switch a local account to shibboleth |
... | ... | |
262 | 267 |
'key': pending_key} |
263 | 268 |
r = client.post('/im/local', post_data, follow=True) |
264 | 269 |
self.assertRedirects(r, "/im/profile") |
265 |
self.assertContains(r, "Your new login method has been added")
|
|
270 |
self.assertContains(r, messages.AUTH_PROVIDER_ADDED)
|
|
266 | 271 |
|
267 | 272 |
self.assertTrue(existing_user.has_auth_provider('shibboleth')) |
268 | 273 |
self.assertTrue(existing_user.has_auth_provider('local', |
... | ... | |
280 | 285 |
client.logout() |
281 | 286 |
|
282 | 287 |
# look Ma, i can login with both my shibboleth and local account |
283 |
client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn", cn="1") |
|
288 |
client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn", |
|
289 |
cn="Kostas Papadimitriou") |
|
284 | 290 |
r = client.get("/im/login/shibboleth?", follow=True) |
285 | 291 |
self.assertTrue(r.context['request'].user.is_authenticated()) |
286 | 292 |
self.assertTrue(r.context['request'].user.email == "kpap@grnet.gr") |
... | ... | |
303 | 309 |
self.assertEqual(r.status_code, 200) |
304 | 310 |
|
305 | 311 |
# cannot add the same eppn |
306 |
client.set_tokens(mail="secondary@shibboleth.gr", eppn="kpapeppn", cn="1", ) |
|
312 |
client.set_tokens(mail="secondary@shibboleth.gr", eppn="kpapeppn", |
|
313 |
cn="Kostas Papadimitriou", ) |
|
307 | 314 |
r = client.get("/im/login/shibboleth?", follow=True) |
308 | 315 |
self.assertRedirects(r, '/im/profile') |
309 | 316 |
self.assertTrue(r.status_code, 200) |
... | ... | |
311 | 318 |
|
312 | 319 |
# but can add additional eppn |
313 | 320 |
client.set_tokens(mail="secondary@shibboleth.gr", eppn="kpapeppn2", |
314 |
cn="1", ep_affiliation="affil2")
|
|
321 |
cn="Kostas Papadimitriou", ep_affiliation="affil2")
|
|
315 | 322 |
r = client.get("/im/login/shibboleth?", follow=True) |
316 | 323 |
new_provider = existing_user.auth_providers.get(identifier="kpapeppn2") |
317 | 324 |
self.assertRedirects(r, '/im/profile') |
... | ... | |
322 | 329 |
client.reset_tokens() |
323 | 330 |
|
324 | 331 |
# cannot login with another eppn |
325 |
client.set_tokens(mail="kpap@grnet.gr", eppn="kpapeppninvalid", cn="1") |
|
332 |
client.set_tokens(mail="kpap@grnet.gr", eppn="kpapeppninvalid", |
|
333 |
cn="Kostas Papadimitriou") |
|
326 | 334 |
r = client.get("/im/login/shibboleth?", follow=True) |
327 | 335 |
self.assertFalse(r.context['request'].user.is_authenticated()) |
328 | 336 |
|
... | ... | |
334 | 342 |
identifier='kpapeppn') |
335 | 343 |
remove_shibbo2_url = user.get_provider_remove_url('shibboleth', |
336 | 344 |
identifier='kpapeppn2') |
337 |
client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn", cn="1") |
|
345 |
client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn", |
|
346 |
cn="Kostas Papadimtriou") |
|
338 | 347 |
r = client.get("/im/login/shibboleth?", follow=True) |
339 | 348 |
client.reset_tokens() |
340 | 349 |
|
... | ... | |
380 | 389 |
user2 = get_local_user('another@grnet.gr') |
381 | 390 |
user2.add_auth_provider('shibboleth', identifier='existingeppn') |
382 | 391 |
# login |
383 |
client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn", cn="1") |
|
392 |
client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn", |
|
393 |
cn="Kostas Papadimitriou") |
|
384 | 394 |
r = client.get("/im/login/shibboleth?", follow=True) |
385 | 395 |
# try to assign existing shibboleth identifier of another user |
386 |
client.set_tokens(mail="kpap_second@shibboleth.gr", eppn="existingeppn", cn="1") |
|
396 |
client.set_tokens(mail="kpap_second@shibboleth.gr", eppn="existingeppn", |
|
397 |
cn="Kostas Papadimitriou") |
|
387 | 398 |
r = client.get("/im/login/shibboleth?", follow=True) |
388 |
self.assertContains(r, 'Account already exists') |
|
399 |
self.assertContains(r, messages.AUTH_PROVIDER_ADD_FAILED) |
|
400 |
self.assertContains(r, messages.AUTH_PROVIDER_ADD_EXISTS) |
|
389 | 401 |
|
390 | 402 |
|
391 | 403 |
class LocalUserTests(TestCase): |
... | ... | |
422 | 434 |
self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 1) |
423 | 435 |
astakos_settings.MODERATION_ENABLED = True |
424 | 436 |
|
437 |
def test_email_case(self): |
|
438 |
data = { |
|
439 |
'email': 'kPap@grnet.gr', |
|
440 |
'password1': '1234', |
|
441 |
'password2': '1234' |
|
442 |
} |
|
443 |
|
|
444 |
form = forms.LocalUserCreationForm(data) |
|
445 |
self.assertTrue(form.is_valid()) |
|
446 |
user = form.save() |
|
447 |
form.store_user(user, {}) |
|
448 |
|
|
449 |
u = AstakosUser.objects.get(pk=1) |
|
450 |
self.assertEqual(u.email, 'kPap@grnet.gr') |
|
451 |
self.assertEqual(u.username, 'kpap@grnet.gr') |
|
452 |
u.is_active = True |
|
453 |
u.email_verified = True |
|
454 |
u.save() |
|
455 |
|
|
456 |
data = {'username': 'kpap@grnet.gr', 'password': '1234'} |
|
457 |
login = forms.LoginForm(data=data) |
|
458 |
self.assertTrue(login.is_valid()) |
|
459 |
|
|
460 |
data = {'username': 'KpaP@grnet.gr', 'password': '1234'} |
|
461 |
login = forms.LoginForm(data=data) |
|
462 |
self.assertTrue(login.is_valid()) |
|
463 |
|
|
464 |
data = { |
|
465 |
'email': 'kpap@grnet.gr', |
|
466 |
'password1': '1234', |
|
467 |
'password2': '1234' |
|
468 |
} |
|
469 |
form = forms.LocalUserCreationForm(data) |
|
470 |
self.assertFalse(form.is_valid()) |
|
471 |
|
|
425 | 472 |
def test_local_provider(self): |
426 | 473 |
# enable moderation |
427 | 474 |
astakos_settings.MODERATION_ENABLED = True |
... | ... | |
494 | 541 |
self.assertContains(r, "doesn't have an associated user account") |
495 | 542 |
r = self.client.post('/im/local', {'username': 'kpap@grnet.gr', |
496 | 543 |
'password': 'password'}) |
497 |
print r |
|
498 | 544 |
self.assertContains(r, messages.ACCOUNT_PENDING_ACTIVATION) |
499 | 545 |
self.assertContains(r, 'Resend activation') |
500 | 546 |
self.assertFalse(r.context['request'].user.is_authenticated()) |
b/snf-astakos-app/astakos/im/util.py | ||
---|---|---|
107 | 107 |
""" |
108 | 108 |
Return url if having the supplied ``domain`` (if present) or one of the ``allowed_schemes``. |
109 | 109 |
Otherwise return None. |
110 |
|
|
110 |
|
|
111 | 111 |
>>> print restrict_next('/im/feedback', '.okeanos.grnet.gr') |
112 | 112 |
/im/feedback |
113 | 113 |
>>> print restrict_next('pithos.okeanos.grnet.gr/im/feedback', '.okeanos.grnet.gr') |
... | ... | |
168 | 168 |
try: |
169 | 169 |
user.save() |
170 | 170 |
except ValidationError, e: |
171 |
return HttpResponseBadRequest(e)
|
|
172 |
|
|
171 |
return HttpResponseBadRequest(e) |
|
172 |
|
|
173 | 173 |
next = restrict_next(next, domain=COOKIE_DOMAIN) |
174 |
|
|
174 |
|
|
175 | 175 |
if FORCE_PROFILE_UPDATE and not user.is_verified and not user.is_superuser: |
176 | 176 |
params = '' |
177 | 177 |
if next: |
... | ... | |
187 | 187 |
|
188 | 188 |
if not next: |
189 | 189 |
next = reverse('astakos.im.views.index') |
190 |
|
|
190 |
|
|
191 | 191 |
response['Location'] = next |
192 | 192 |
response.status_code = 302 |
193 | 193 |
return response |
... | ... | |
209 | 209 |
|
210 | 210 |
|
211 | 211 |
def reserved_email(email): |
212 |
return AstakosUser.objects.filter(email__iexact=email).count() > 0 or \ |
|
213 |
AstakosUser.objects.filter(username__iexact=email).count() > 0 |
|
212 |
return AstakosUser.objects.user_exists(email) |
|
214 | 213 |
|
215 | 214 |
|
216 | 215 |
def get_query(request): |
Also available in: Unified diff