Revision f432088a

b/snf-astakos-app/astakos/im/models.py
596 596
        else:
597 597
            return auth_providers.get_provider(provider).is_available_for_login()
598 598

  
599
    def can_add_provider(self, provider, **kwargs):
599
    def can_add_auth_provider(self, provider, **kwargs):
600 600
        provider_settings = auth_providers.get_provider(provider)
601 601
        if not provider_settings.is_available_for_login():
602 602
            return False
603

  
603 604
        if self.has_auth_provider(provider) and \
604 605
           provider_settings.one_per_user:
605 606
            return False
607

  
608
        if 'identifier' in kwargs:
609
            try:
610
                # provider with specified params already exist
611
                existing_user = AstakosUser.objects.get_auth_provider_user(provider,
612
                                                                   **kwargs)
613
            except AstakosUser.DoesNotExist:
614
                return True
615
            else:
616
                return False
617

  
606 618
        return True
607 619

  
608 620
    def can_remove_auth_provider(self, provider):
......
618 630
                                               **kwargs).count())
619 631

  
620 632
    def add_auth_provider(self, provider, **kwargs):
621
        self.auth_providers.create(module=provider, active=True, **kwargs)
633
        if self.can_add_auth_provider(provider, **kwargs):
634
            self.auth_providers.create(module=provider, active=True, **kwargs)
635
        else:
636
            raise Exception('Cannot add provider')
622 637

  
623 638
    def add_pending_auth_provider(self, pending):
624 639
        """
......
665 680
        """
666 681
        providers = []
667 682
        for module, provider_settings in auth_providers.PROVIDERS.iteritems():
668
            if self.can_add_provider(module):
683
            if self.can_add_auth_provider(module):
669 684
                providers.append(provider_settings(self))
670 685

  
671 686
        return providers
......
722 737
        self.user.save()
723 738
        return ret
724 739

  
740
    def __repr__(self):
741
        return '<AstakosUserAuthProvider %s:%s>' % (self.module, self.identifier)
742

  
725 743

  
726 744
class Membership(models.Model):
727 745
    person = models.ForeignKey(AstakosUser)
b/snf-astakos-app/astakos/im/target/local.py
44 44
from astakos.im.util import prepare_response, get_query
45 45
from astakos.im.views import requires_anonymous, signed_terms_required
46 46
from astakos.im.models import PendingThirdPartyUser
47
from astakos.im.forms import LoginForm, ExtendedPasswordChangeForm
47
from astakos.im.forms import LoginForm, ExtendedPasswordChangeForm, \
48
                             ExtendedSetPasswordForm
48 49
from astakos.im.settings import (RATELIMIT_RETRIES_ALLOWED,
49 50
                                ENABLE_LOCAL_ACCOUNT_MIGRATION)
50 51
import astakos.im.messages as astakos_messages
......
156 157
    return render_to_response(template_name, {
157 158
        'form': form,
158 159
    }, context_instance=RequestContext(request))
160

  
b/snf-astakos-app/astakos/im/target/shibboleth.py
71 71

  
72 72
@requires_auth_provider('local', login=True)
73 73
@require_http_methods(["GET", "POST"])
74
@requires_anonymous
75 74
def login(
76 75
    request,
77 76
    template='im/third_party_check_local.html',
......
108 107

  
109 108
        # automatically add eppn provider to user
110 109
        user = request.user
111
        user.add_provider('shibboleth', identifier=eppn)
112
        return HttpResponseRedirect('edit_profile')
110
        if not request.user.can_add_auth_provider('shibboleth',
111
                                                  identifier=eppn):
112
            messages.error(request, 'Account already exists.')
113
            return HttpResponseRedirect(reverse('edit_profile'))
114

  
115
        user.add_auth_provider('shibboleth', identifier=eppn)
116
        return HttpResponseRedirect(reverse('edit_profile'))
113 117

  
114 118
    try:
115 119
        # astakos user exists ?
b/snf-astakos-app/astakos/im/tests.py
269 269
        r = client.get("/im/login/shibboleth?", follow=True)
270 270
        self.assertFalse(r.context['request'].user.is_authenticated())
271 271

  
272
        user2 = get_local_user('kpap@grnet.gr')
272
        # lets remove local password
273
        user = AstakosUser.objects.get(username="kpap@grnet.gr",
274
                                       email="kpap@grnet.gr")
275
        provider_pk = user.auth_providers.get(module='local').pk
276
        provider_shib_pk = user.auth_providers.get(module='shibboleth').pk
277
        client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn", cn="1")
278
        r = client.get("/im/login/shibboleth?", follow=True)
279
        client.reset_tokens()
280
        r = client.get("/im/remove_auth_provider/%d" % provider_pk)
281
        self.assertEqual(user.auth_providers.count(), 1)
282
        r = client.get("/im/remove_auth_provider/%d" % provider_pk)
283
        self.assertEqual(r.status_code, 404)
284
        r = client.get("/im/remove_auth_provider/%d" % provider_shib_pk)
285
        self.assertEqual(r.status_code, 403)
286

  
287
        self.client.logout()
288
        post_data = {'password': 'password',
289
                     'username': 'kpap@grnet.gr'}
290
        r = self.client.post('/im/local', post_data, follow=True)
291
        self.assertFalse(r.context['request'].user.is_authenticated())
292

  
293
        r = client.get("/im/password_change", follow=True)
294
        r = client.post("/im/password_change", {'new_password1':'111',
295
                                                'new_password2': '111'},
296
                        follow=True)
297
        user = r.context['request'].user
298
        self.assertTrue(user.has_auth_provider('local'))
299
        self.assertTrue(user.has_auth_provider('shibboleth'))
300
        self.assertTrue(user.check_password('111'))
301
        self.assertTrue(user.has_usable_password())
302
        self.client.logout()
303
        post_data = {'password': '111',
304
                     'username': 'kpap@grnet.gr'}
305
        r = self.client.post('/im/local', post_data, follow=True)
306
        self.assertTrue(r.context['request'].user.is_authenticated())
307

  
308
        client.set_tokens(mail="kpap@shibboleth.gr", eppn="kpapeppn", cn="1")
309
        r = client.get("/im/login/shibboleth?", follow=True)
310
        r = client.get("/im/login/shibboleth?", follow=True)
311
        user = AstakosUser.objects.get(username="kpap@grnet.gr",
312
                                       email="kpap@grnet.gr")
313

  
314
        user2 = get_local_user('another@grnet.gr')
315
        user2.add_auth_provider('shibboleth', identifier='existingeppn')
316

  
317
        self.assertEqual(user.auth_providers.count(), 2) # local and 1 shibboleth
318
        client.set_tokens(mail="kpap_second@shibboleth.gr", eppn="kpapeppn2", cn="1")
319
        r = client.get("/im/login/shibboleth?", follow=True)
320
        self.assertEqual(user.auth_providers.count(), 3) # local and 2 shibboleth
321

  
322
        client.set_tokens(mail="kpap_second@shibboleth.gr", eppn="kpapeppn2", cn="1")
323
        r = client.get("/im/login/shibboleth?", follow=True)
324

  
325
        client.set_tokens(mail="kpap_second@shibboleth.gr", eppn="existingeppn", cn="1")
326
        r = client.get("/im/login/shibboleth?", follow=True)
327
        self.assertContains(r, 'Account already exists')
273 328

  
274 329

  
275 330
class LocalUserTests(TestCase):
b/snf-astakos-app/astakos/im/views.py
65 65

  
66 66
from astakos.im.models import (AstakosUser, ApprovalTerms, AstakosGroup,
67 67
                               EmailChange, GroupKind, Membership,
68
                               RESOURCE_SEPARATOR)
68
                               RESOURCE_SEPARATOR, AstakosUserAuthProvider)
69 69
from astakos.im.util import get_context, prepare_response, get_query, restrict_next
70 70
from astakos.im.forms import (LoginForm, InvitationForm, ProfileForm,
71 71
                              FeedbackForm, SignApprovalTermsForm,
......
1406 1406
                           timeline_body=timeline_body)
1407 1407
    return data
1408 1408

  
1409
# TODO: action only on POST and user should confirm the removal
1409 1410
@require_http_methods(["GET", "POST"])
1410 1411
@login_required
1411 1412
@signed_terms_required
1412 1413
def remove_auth_provider(request, pk):
1413
    provider = request.user.auth_providers.get(pk=pk)
1414
    try:
1415
        provider = request.user.auth_providers.get(pk=pk)
1416
    except AstakosUserAuthProvider.DoesNotExist:
1417
        raise Http404
1418

  
1414 1419
    if provider.can_remove():
1415 1420
        provider.delete()
1416 1421
        return HttpResponseRedirect(reverse('edit_profile'))
1417 1422
    else:
1418
        messages.error(_('Authentication method cannot be removed'))
1419
        return HttpResponseRedirect(reverse('edit_profile'))
1423
        raise PermissionDenied
1424

  

Also available in: Unified diff