Projet

Général

Profil

0001-add-rest_framework-authentication-module-for-authent.patch

Benjamin Dauvergne, 14 décembre 2015 14:07

Télécharger (5,87 ko)

Voir les différences:

Subject: [PATCH] add rest_framework authentication module for authentic2

 hobo/rest_authentication.py                 | 63 +++++++++++++++++++++++++++++
 tests_authentic/conftest.py                 |  3 ++
 tests_authentic/test_rest_authentication.py | 41 +++++++++++++++++++
 3 files changed, 107 insertions(+)
 create mode 100644 hobo/rest_authentication.py
 create mode 100644 tests_authentic/test_rest_authentication.py
hobo/rest_authentication.py
1
import logging
2

  
3
from rest_framework import authentication, exceptions
4

  
5
from hobo import signature
6

  
7
from authentic2.saml import models as saml_models
8
from django.contrib.auth import get_user_model
9
from django.conf import settings
10
from django.contrib.auth.models import AnonymousUser
11

  
12
class AnonymousServiceUser(AnonymousUser):
13
    '''This virtual user hold permissions for other publik services'''
14
    def is_authenticated(self):
15
        return True
16

  
17
    def has_perm(self, perm_or_perms, obj=None):
18
        return 'a2_rbac.change_role' == perm_or_perms
19

  
20
    def __unicode__(self):
21
        return 'Publik Authentikation Service User'
22

  
23

  
24
class PublikAuthentication(authentication.BaseAuthentication):
25
    def __init__(self, *args, **kwargs):
26
        self.logger = logging.getLogger(__name__)
27
        super(PublikAuthentication, self).__init__(*args, **kwargs)
28

  
29
    def resolve_user(self, request):
30
        if 'NameID' in request.GET:
31
            name_id = request.GET['NameID']
32
            User = get_user_model()
33
            try:
34
                return User.objects.get(uuid=name_id)
35
            except User.DoesNotExist:
36
                self.logger.warning('no user found %r', uuid)
37
                raise exceptions.AuthenticationFailed('No user matches uuid=%r' % uuid)
38
        else:
39
            self.logger.info('anonymous signature validated')
40
            return AnonymousServiceUser()
41

  
42
    def get_orig_key(self, orig):
43
        if not hasattr(settings, 'KNOWN_SERVICES'):
44
            self.logger.warning('no known services')
45
            raise exceptions.AuthenticationFailed('No KNOWN_SERVICES setting')
46
        for service_id in settings.KNOWN_SERVICES:
47
            for slug, service in settings.KNOWN_SERVICES[service_id].iteritems():
48
                if service.get('verif_orig') == orig and service.get('secret'):
49
                    return service['secret']
50
        self.logger.warning('no secret found for origin %r', orig)
51
        raise exceptions.AuthenticationFailed('no secret found for origin %r' % orig)
52

  
53
    def authenticate(self, request):
54
        full_path = request.get_full_path()
55
        if not request.GET.get('orig') or not request.GET.get('signature'):
56
            return None
57
        key = self.get_orig_key(request.GET['orig'])
58
        if not signature.check_url(full_path, key):
59
            self.logger.warning('invalid signature')
60
            raise exceptions.AuthenticationFailed('Invalid signature')
61
        user = self.resolve_user(request)
62
        self.logger.info('user authenticated with signature %s', user)
63
        return (user, None)
tests_authentic/conftest.py
31 31
                },
32 32
                'services': [
33 33
                    {'slug': 'test',
34
                     'service-id': 'authentic',
34 35
                     'title': 'Test',
35 36
                     'this': True,
36 37
                     'secret_key': '12345',
......
41 42
                    },
42 43
                    {'slug': 'other',
43 44
                     'title': 'Other',
45
                     'service-id': 'welco',
46
                     'secret_key': 'abcdef',
44 47
                     'base_url': 'http://other.example.net'},
45 48
                    ]}, fd)
46 49
        t = Tenant(domain_url=name,
tests_authentic/test_rest_authentication.py
1
import pytest
2
import urllib
3

  
4
from rest_framework.exceptions import AuthenticationFailed
5
from django.contrib.auth import get_user_model
6
from django.test import RequestFactory
7
from tenant_schemas.utils import tenant_context
8

  
9
from hobo import signature, rest_authentication
10

  
11
pytestmark = pytest.mark.django_db
12

  
13
def test_publik_authentication(tenant, settings):
14
    with tenant_context(tenant):
15
        key = settings.KNOWN_SERVICES['welco']['other']['secret']
16

  
17
        settings.HOBO_ROLE_EXPORT = False
18
        User = get_user_model()
19
        user = User.objects.create(username='foo', password='foo')
20
        ORIG = 'other.example.net'
21
        AUTH_QUERY = '&NameID=%s&&orig=%s' % (user.uuid, urllib.quote(ORIG))
22

  
23
        URL = '/api/?coucou=zob'
24
        factory = RequestFactory()
25
        request = factory.get(signature.sign_url(URL + AUTH_QUERY, key))
26

  
27
        publik_authentication = rest_authentication.PublikAuthentication()
28
        result = publik_authentication.authenticate(request)
29
        assert result is not None
30
        assert isinstance(result, tuple)
31
        assert len(result) == 2
32
        assert result[0] == user
33
        assert result[1] == None
34

  
35
        # Failure
36
        request = factory.get(signature.sign_url(URL + AUTH_QUERY, key+'zob'))
37

  
38
        publik_authentication = rest_authentication.PublikAuthentication()
39
        with pytest.raises(AuthenticationFailed):
40
            publik_authentication.authenticate(request)
41

  
0
-