Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / tests.py @ 5e992f29

History | View | Annotate | Download (24.4 kB)

1
# Copyright 2011 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
import datetime
35

    
36
from django.test import TestCase, Client
37
from django.conf import settings
38
from django.core import mail
39

    
40
from astakos.im.target.shibboleth import Tokens as ShibbolethTokens
41
from astakos.im.models import *
42
from astakos.im import functions
43
from astakos.im import settings as astakos_settings
44

    
45
from urllib import quote
46

    
47
from astakos.im import messages
48

    
49
class ShibbolethClient(Client):
50
    """
51
    A shibboleth agnostic client.
52
    """
53
    VALID_TOKENS = filter(lambda x: not x.startswith("_"), dir(ShibbolethTokens))
54

    
55
    def __init__(self, *args, **kwargs):
56
        self.tokens = kwargs.pop('tokens', {})
57
        super(ShibbolethClient, self).__init__(*args, **kwargs)
58

    
59
    def set_tokens(self, **kwargs):
60
        for key, value in kwargs.iteritems():
61
            key = 'SHIB_%s' % key.upper()
62
            if not key in self.VALID_TOKENS:
63
                raise Exception('Invalid shibboleth token')
64

    
65
            self.tokens[key] = value
66

    
67
    def unset_tokens(self, *keys):
68
        for key in keys:
69
            key = 'SHIB_%s' % param.upper()
70
            if key in self.tokens:
71
                del self.tokens[key]
72

    
73
    def reset_tokens(self):
74
        self.tokens = {}
75

    
76
    def get_http_token(self, key):
77
        http_header = getattr(ShibbolethTokens, key)
78
        return http_header
79

    
80
    def request(self, **request):
81
        """
82
        Transform valid shibboleth tokens to http headers
83
        """
84
        for token, value in self.tokens.iteritems():
85
            request[self.get_http_token(token)] = value
86

    
87
        for param in request.keys():
88
            key = 'SHIB_%s' % param.upper()
89
            if key in self.VALID_TOKENS:
90
                request[self.get_http_token(key)] = request[param]
91
                del request[param]
92

    
93
        return super(ShibbolethClient, self).request(**request)
94

    
95

    
96
def get_local_user(username, **kwargs):
97
        try:
98
            return AstakosUser.objects.get(email=username)
99
        except:
100
            user_params = {
101
                'username': username,
102
                'email': username,
103
                'is_active': True,
104
                'activation_sent': datetime.now(),
105
                'email_verified': True,
106
                'provider': 'local'
107
            }
108
            user_params.update(kwargs)
109
            user = AstakosUser(**user_params)
110
            user.set_password(kwargs.get('password', 'password'))
111
            user.save()
112
            user.add_auth_provider('local', auth_backend='astakos')
113
            if kwargs.get('is_active', True):
114
                user.is_active = True
115
            else:
116
                user.is_active = False
117
            user.save()
118
            return user
119

    
120

    
121
def get_mailbox(email):
122
    mails = []
123
    for sent_email in mail.outbox:
124
        for recipient in sent_email.recipients():
125
            if email in recipient:
126
                mails.append(sent_email)
127
    return mails
128

    
129

    
130
class ShibbolethTests(TestCase):
131
    """
132
    Testing shibboleth authentication.
133
    """
134

    
135
    fixtures = ['groups']
136

    
137
    def setUp(self):
138
        self.client = ShibbolethClient()
139
        settings.ASTAKOS_IM_MODULES = ['local', 'shibboleth']
140
        settings.ASTAKOS_MODERATION_ENABLED = True
141

    
142
    def test_create_account(self):
143

    
144
        client = ShibbolethClient()
145

    
146
        # shibboleth views validation
147
        # eepn required
148
        r = client.get('/im/login/shibboleth?', follow=True)
149
        self.assertContains(r, messages.SHIBBOLETH_MISSING_EPPN)
150
        client.set_tokens(eppn="kpapeppn")
151

    
152
        astakos_settings.SHIBBOLETH_REQUIRE_NAME_INFO = True
153
        # shibboleth user info required
154
        r = client.get('/im/login/shibboleth?', follow=True)
155
        self.assertContains(r, messages.SHIBBOLETH_MISSING_NAME)
156
        astakos_settings.SHIBBOLETH_REQUIRE_NAME_INFO = False
157

    
158
        # shibboleth logged us in
159
        client.set_tokens(mail="kpap@grnet.gr", eppn="kpapeppn", cn="1",
160
                          ep_affiliation="Test Affiliation")
161
        r = client.get('/im/login/shibboleth?')
162
        self.assertEqual(r.status_code, 200)
163

    
164
        # astakos asks if we want to add shibboleth
165
        self.assertContains(r, "Already have an account?")
166

    
167
        # a new pending user created
168
        pending_user = PendingThirdPartyUser.objects.get(
169
            third_party_identifier="kpapeppn")
170
        self.assertEqual(PendingThirdPartyUser.objects.count(), 1)
171
        # keep the token for future use
172
        token = pending_user.token
173
        # from now on no shibboleth headers are sent to the server
174
        client.reset_tokens()
175

    
176
        # this is the old way, it should fail, to avoid pending user take over
177
        r = client.get('/im/shibboleth/signup/%s' % pending_user.username)
178
        self.assertEqual(r.status_code, 404)
179

    
180
        # this is the signup unique url associated with the pending user created
181
        r = client.get('/im/signup/?third_party_token=%s' % token)
182
        form = r.context['form']
183
        post_data = {'third_party_identifier': pending_user.third_party_identifier,
184
                     'first_name': 'Kostas',
185
                     'third_party_token': token,
186
                     'last_name': 'Mitroglou',
187
                     'provider': 'shibboleth'
188
                    }
189

    
190
        # invlid email
191
        post_data['email'] = 'kpap'
192
        r = client.post('/im/signup', post_data)
193
        self.assertContains(r, token)
194

    
195
        # existing email
196
        existing_user = get_local_user('test@test.com')
197
        post_data['email'] = 'test@test.com'
198
        r = client.post('/im/signup', post_data)
199
        self.assertContains(r, messages.EMAIL_USED)
200
        existing_user.delete()
201

    
202
        # and finally a valid signup
203
        post_data['email'] = 'kpap@grnet.gr'
204
        r = client.post('/im/signup', post_data)
205
        self.assertEqual(r.status_code, 200)
206

    
207
        # everything is ok in our db
208
        self.assertEqual(AstakosUser.objects.count(), 1)
209
        self.assertEqual(AstakosUserAuthProvider.objects.count(), 1)
210
        self.assertEqual(PendingThirdPartyUser.objects.count(), 0)
211

    
212
        # provider info stored
213
        provider = AstakosUserAuthProvider.objects.get(module="shibboleth")
214
        self.assertEqual(provider.affiliation, 'Test Affiliation')
215
        self.assertEqual(provider.info, {u'email': u'kpap@grnet.gr',
216
                                         u'eppn': u'kpapeppn'})
217

    
218
        # lets login (not activated yet)
219
        client.set_tokens(mail="kpap@grnet.gr", eppn="kpapeppn", cn="1", )
220
        r = client.get("/im/login/shibboleth?", follow=True)
221
        self.assertContains(r, messages.ACCOUNT_PENDING_MODERATION)
222
        r = client.get("/im/profile", follow=True)
223
        self.assertRedirects(r, 'http://testserver/im/?next=%2Fim%2Fprofile')
224

    
225
        # admin activates our user
226
        u = AstakosUser.objects.get(username="kpap@grnet.gr")
227
        functions.activate(u)
228
        self.assertEqual(u.is_active, True)
229

    
230
        # we see our profile
231
        r = client.get("/im/login/shibboleth?", follow=True)
232
        self.assertRedirects(r, '/im/profile')
233
        self.assertEqual(r.status_code, 200)
234

    
235
    def test_existing(self):
236
        """
237
        Test adding of third party login to an existing account
238
        """
239

    
240
        # this is our existing user
241
        existing_user = get_local_user('kpap@grnet.gr')
242

    
243
        client = ShibbolethClient()
244
        # shibboleth logged us in, notice that we use different email
245
        client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn", cn="1", )
246
        r = client.get("/im/login/shibboleth?")
247

    
248
        # astakos asks if we want to switch a local account to shibboleth
249
        self.assertContains(r, "Already have an account?")
250

    
251
        # a new pending user created
252
        pending_user = PendingThirdPartyUser.objects.get()
253
        self.assertEqual(PendingThirdPartyUser.objects.count(), 1)
254
        pending_key = pending_user.token
255
        client.reset_tokens()
256

    
257
        # we choose to add shibboleth to an our existing account
258
        # we get redirected to login page with the pending token set
259
        r = client.get('/im/login?key=%s' % pending_key)
260
        post_data = {'password': 'password',
261
                     'username': 'kpap@grnet.gr',
262
                     'key': pending_key}
263
        r = client.post('/im/local', post_data, follow=True)
264
        self.assertRedirects(r, "/im/profile")
265
        self.assertContains(r, "Your new login method has been added")
266

    
267
        self.assertTrue(existing_user.has_auth_provider('shibboleth'))
268
        self.assertTrue(existing_user.has_auth_provider('local',
269
                                                        auth_backend='astakos'))
270
        client.logout()
271

    
272
        # check that we cannot assign same third party provide twice
273
        r = client.get('/im/login?key=%s' % pending_key)
274
        post_data = {'password': 'password',
275
                     'username': 'kpap@grnet.gr',
276
                     'key': pending_key}
277
        r = self.client.post('/im/local', post_data, follow=True)
278
        self.assertContains(r, messages.AUTH_PROVIDER_ADD_FAILED)
279
        self.client.logout()
280
        client.logout()
281

    
282
        # look Ma, i can login with both my shibboleth and local account
283
        client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn", cn="1")
284
        r = client.get("/im/login/shibboleth?", follow=True)
285
        self.assertTrue(r.context['request'].user.is_authenticated())
286
        self.assertTrue(r.context['request'].user.email == "kpap@grnet.gr")
287
        self.assertRedirects(r, '/im/profile')
288
        self.assertEqual(r.status_code, 200)
289
        client.logout()
290
        client.reset_tokens()
291

    
292
        # logged out
293
        r = client.get("/im/profile", follow=True)
294
        self.assertFalse(r.context['request'].user.is_authenticated())
295

    
296
        # login with local account also works
297
        post_data = {'password': 'password',
298
                     'username': 'kpap@grnet.gr'}
299
        r = self.client.post('/im/local', post_data, follow=True)
300
        self.assertTrue(r.context['request'].user.is_authenticated())
301
        self.assertTrue(r.context['request'].user.email == "kpap@grnet.gr")
302
        self.assertRedirects(r, '/im/profile')
303
        self.assertEqual(r.status_code, 200)
304

    
305
        # cannot add the same eppn
306
        client.set_tokens(mail="secondary@shibboleth.gr", eppn="kpapeppn", cn="1", )
307
        r = client.get("/im/login/shibboleth?", follow=True)
308
        self.assertRedirects(r, '/im/profile')
309
        self.assertTrue(r.status_code, 200)
310
        self.assertEquals(existing_user.auth_providers.count(), 2)
311

    
312
        # but can add additional eppn
313
        client.set_tokens(mail="secondary@shibboleth.gr", eppn="kpapeppn2",
314
                          cn="1", ep_affiliation="affil2")
315
        r = client.get("/im/login/shibboleth?", follow=True)
316
        new_provider = existing_user.auth_providers.get(identifier="kpapeppn2")
317
        self.assertRedirects(r, '/im/profile')
318
        self.assertTrue(r.status_code, 200)
319
        self.assertEquals(existing_user.auth_providers.count(), 3)
320
        self.assertEqual(new_provider.affiliation, 'affil2')
321
        client.logout()
322
        client.reset_tokens()
323

    
324
        # cannot login with another eppn
325
        client.set_tokens(mail="kpap@grnet.gr", eppn="kpapeppninvalid", cn="1")
326
        r = client.get("/im/login/shibboleth?", follow=True)
327
        self.assertFalse(r.context['request'].user.is_authenticated())
328

    
329
        # lets remove local password
330
        user = AstakosUser.objects.get(username="kpap@grnet.gr",
331
                                       email="kpap@grnet.gr")
332
        remove_local_url = user.get_provider_remove_url('local')
333
        remove_shibbo_url = user.get_provider_remove_url('shibboleth',
334
                                                         identifier='kpapeppn')
335
        remove_shibbo2_url = user.get_provider_remove_url('shibboleth',
336
                                                         identifier='kpapeppn2')
337
        client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn", cn="1")
338
        r = client.get("/im/login/shibboleth?", follow=True)
339
        client.reset_tokens()
340

    
341
        # TODO: this view should use POST
342
        r = client.get(remove_local_url)
343
        # 2 providers left
344
        self.assertEqual(user.auth_providers.count(), 2)
345
        r = client.get(remove_shibbo2_url)
346
        # 1 provider left
347
        self.assertEqual(user.auth_providers.count(), 1)
348
        # cannot remove last provider
349
        r = client.get(remove_shibbo_url)
350
        self.assertEqual(r.status_code, 403)
351
        self.client.logout()
352

    
353
        # cannot login using local credentials (notice we use another client)
354
        post_data = {'password': 'password',
355
                     'username': 'kpap@grnet.gr'}
356
        r = self.client.post('/im/local', post_data, follow=True)
357
        self.assertFalse(r.context['request'].user.is_authenticated())
358

    
359
        # we can reenable the local provider by setting a password
360
        r = client.get("/im/password_change", follow=True)
361
        r = client.post("/im/password_change", {'new_password1':'111',
362
                                                'new_password2': '111'},
363
                        follow=True)
364
        user = r.context['request'].user
365
        self.assertTrue(user.has_auth_provider('local'))
366
        self.assertTrue(user.has_auth_provider('shibboleth'))
367
        self.assertTrue(user.check_password('111'))
368
        self.assertTrue(user.has_usable_password())
369
        self.client.logout()
370

    
371
        # now we can login
372
        post_data = {'password': '111',
373
                     'username': 'kpap@grnet.gr'}
374
        r = self.client.post('/im/local', post_data, follow=True)
375
        self.assertTrue(r.context['request'].user.is_authenticated())
376

    
377
        client.reset_tokens()
378

    
379
        # we cannot take over another shibboleth identifier
380
        user2 = get_local_user('another@grnet.gr')
381
        user2.add_auth_provider('shibboleth', identifier='existingeppn')
382
        # login
383
        client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn", cn="1")
384
        r = client.get("/im/login/shibboleth?", follow=True)
385
        # try to assign existing shibboleth identifier of another user
386
        client.set_tokens(mail="kpap_second@shibboleth.gr", eppn="existingeppn", cn="1")
387
        r = client.get("/im/login/shibboleth?", follow=True)
388
        self.assertContains(r, 'Account already exists')
389

    
390

    
391
class LocalUserTests(TestCase):
392

    
393
    fixtures = ['groups']
394

    
395
    def setUp(self):
396
        from django.conf import settings
397
        settings.ADMINS = (('admin', 'support@cloud.grnet.gr'),)
398
        settings.SERVER_EMAIL = 'no-reply@grnet.gr'
399

    
400
    def test_no_moderation(self):
401
        # disable moderation
402
        astakos_settings.MODERATION_ENABLED = False
403

    
404
        # create a new user
405
        r = self.client.get("/im/signup")
406
        self.assertEqual(r.status_code, 200)
407
        data = {'email':'kpap@grnet.gr', 'password1':'password',
408
                'password2':'password', 'first_name': 'Kostas',
409
                'last_name': 'Mitroglou', 'provider': 'local'}
410
        r = self.client.post("/im/signup", data)
411

    
412
        # user created
413
        self.assertEqual(AstakosUser.objects.count(), 1)
414
        user = AstakosUser.objects.get(username="kpap@grnet.gr",
415
                                       email="kpap@grnet.gr")
416
        self.assertEqual(user.username, 'kpap@grnet.gr')
417
        self.assertEqual(user.has_auth_provider('local'), True)
418
        self.assertFalse(user.is_active)
419

    
420
        # user (but not admin) gets notified
421
        self.assertEqual(len(get_mailbox('support@cloud.grnet.gr')), 0)
422
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 1)
423
        astakos_settings.MODERATION_ENABLED = True
424

    
425
    def test_local_provider(self):
426
        # enable moderation
427
        astakos_settings.MODERATION_ENABLED = True
428

    
429
        # create a user
430
        r = self.client.get("/im/signup")
431
        self.assertEqual(r.status_code, 200)
432
        data = {'email':'kpap@grnet.gr', 'password1':'password',
433
                'password2':'password', 'first_name': 'Kostas',
434
                'last_name': 'Mitroglou', 'provider': 'local'}
435
        r = self.client.post("/im/signup", data)
436

    
437
        # user created
438
        self.assertEqual(AstakosUser.objects.count(), 1)
439
        user = AstakosUser.objects.get(username="kpap@grnet.gr",
440
                                       email="kpap@grnet.gr")
441
        self.assertEqual(user.username, 'kpap@grnet.gr')
442
        self.assertEqual(user.has_auth_provider('local'), True)
443
        self.assertFalse(user.is_active) # not activated
444
        self.assertFalse(user.email_verified) # not verified
445
        self.assertFalse(user.activation_sent) # activation automatically sent
446

    
447
        # admin gets notified and activates the user from the command line
448
        self.assertEqual(len(get_mailbox('support@cloud.grnet.gr')), 1)
449
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
450
                                                 'password': 'password'})
451
        self.assertContains(r, messages.ACCOUNT_PENDING_MODERATION)
452
        functions.send_activation(user)
453

    
454
        # user activation fields updated and user gets notified via email
455
        user = AstakosUser.objects.get(pk=user.pk)
456
        self.assertTrue(user.activation_sent)
457
        self.assertFalse(user.email_verified)
458
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 1)
459

    
460
        # user forgot she got registered and tries to submit registration
461
        # form. Notice the upper case in email
462
        data = {'email':'KPAP@grnet.gr', 'password1':'password',
463
                'password2':'password', 'first_name': 'Kostas',
464
                'last_name': 'Mitroglou', 'provider': 'local'}
465
        r = self.client.post("/im/signup", data)
466
        self.assertContains(r, messages.EMAIL_USED)
467

    
468
        # hmmm, email exists; lets get the password
469
        r = self.client.get('/im/local/password_reset')
470
        self.assertEqual(r.status_code, 200)
471
        r = self.client.post('/im/local/password_reset', {'email':
472
                                                          'kpap@grnet.gr'})
473
        # she can't because account is not active yet
474
        self.assertContains(r, "doesn't have an associated user account")
475

    
476
        # moderation is enabled so no automatic activation can be send
477
        r = self.client.get('/im/send/activation/%d' % user.pk)
478
        self.assertEqual(r.status_code, 403)
479
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 1)
480

    
481
        # also she cannot login
482
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
483
                                                 'password': 'password'})
484
        self.assertContains(r, messages.ACCOUNT_PENDING_ACTIVATION_HELP)
485
        self.assertContains(r, messages.ACCOUNT_PENDING_ACTIVATION)
486
        self.assertNotContains(r, 'Resend activation')
487
        self.assertFalse(r.context['request'].user.is_authenticated())
488
        self.assertFalse('_pithos2_a' in self.client.cookies)
489

    
490
        # same with disabled moderation
491
        astakos_settings.MODERATION_ENABLED = False
492
        r = self.client.post('/im/local/password_reset', {'email':
493
                                                          'kpap@grnet.gr'})
494
        self.assertContains(r, "doesn't have an associated user account")
495
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
496
                                                 'password': 'password'})
497
        print r
498
        self.assertContains(r, messages.ACCOUNT_PENDING_ACTIVATION)
499
        self.assertContains(r, 'Resend activation')
500
        self.assertFalse(r.context['request'].user.is_authenticated())
501
        self.assertFalse('_pithos2_a' in self.client.cookies)
502

    
503
        # user sees the message and resends activation
504
        r = self.client.get('/im/send/activation/%d' % user.pk)
505
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 2)
506

    
507
        # switch back moderation setting
508
        astakos_settings.MODERATION_ENABLED = True
509
        r = self.client.get(user.get_activation_url(), follow=True)
510
        self.assertRedirects(r, "/im/profile")
511
        self.assertContains(r, "kpap@grnet.gr")
512
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 3)
513

    
514
        user = AstakosUser.objects.get(pk=user.pk)
515
        # user activated and logged in, token cookie set
516
        self.assertTrue(r.context['request'].user.is_authenticated())
517
        self.assertTrue('_pithos2_a' in self.client.cookies)
518
        cookies = self.client.cookies
519
        self.assertTrue(quote(user.auth_token) in cookies.get('_pithos2_a').value)
520
        r = self.client.get('/im/logout', follow=True)
521
        r = self.client.get('/im/')
522
        # user logged out, token cookie removed
523
        self.assertFalse(r.context['request'].user.is_authenticated())
524
        self.assertFalse(self.client.cookies.get('_pithos2_a').value)
525
        # https://docs.djangoproject.com/en/dev/topics/testing/#persistent-state
526
        del self.client.cookies['_pithos2_a']
527

    
528
        # user can login
529
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
530
                                           'password': 'password'},
531
                                          follow=True)
532
        self.assertTrue(r.context['request'].user.is_authenticated())
533
        self.assertTrue('_pithos2_a' in self.client.cookies)
534
        cookies = self.client.cookies
535
        self.assertTrue(quote(user.auth_token) in cookies.get('_pithos2_a').value)
536
        self.client.get('/im/logout', follow=True)
537

    
538
        # user forgot password
539
        old_pass = user.password
540
        r = self.client.get('/im/local/password_reset')
541
        self.assertEqual(r.status_code, 200)
542
        r = self.client.post('/im/local/password_reset', {'email':
543
                                                          'kpap@grnet.gr'})
544
        self.assertEqual(r.status_code, 302)
545
        # email sent
546
        self.assertEqual(len(get_mailbox('kpap@grnet.gr')), 4)
547

    
548
        # user visits change password link
549
        r = self.client.get(user.get_password_reset_url())
550
        r = self.client.post(user.get_password_reset_url(),
551
                            {'new_password1':'newpass',
552
                             'new_password2':'newpass'})
553

    
554
        user = AstakosUser.objects.get(pk=user.pk)
555
        self.assertNotEqual(old_pass, user.password)
556

    
557
        # old pass is not usable
558
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
559
                                           'password': 'password'})
560
        self.assertContains(r, 'Please enter a correct username and password')
561
        r = self.client.post('/im/local', {'username': 'kpap@grnet.gr',
562
                                           'password': 'newpass'},
563
                                           follow=True)
564
        self.assertTrue(r.context['request'].user.is_authenticated())
565
        self.client.logout()
566

    
567
        # tests of special local backends
568
        user = AstakosUser.objects.get(pk=user.pk)
569
        user.auth_providers.filter(module='local').update(auth_backend='ldap')
570
        user.save()
571

    
572
        # non astakos local backends do not support password reset
573
        r = self.client.get('/im/local/password_reset')
574
        self.assertEqual(r.status_code, 200)
575
        r = self.client.post('/im/local/password_reset', {'email':
576
                                                          'kpap@grnet.gr'})
577
        # she can't because account is not active yet
578
        self.assertContains(r, "Password change for this account is not"
579
                                " supported")
580