Project

General

Profile

0001-backends-add-SAML-LDAP-authentication-backend-30125.patch

Serghei Mihai, 28 Jan 2019 06:17 PM

Download (7.05 KB)

View differences:

Subject: [PATCH] backends: add SAML LDAP authentication backend (#30125)

 src/authentic2/backends/ldap_backend.py       | 29 +++++++------
 src/authentic2_auth_saml/__init__.py          |  3 +-
 .../app_ldap_saml_settings.py                 | 31 ++++++++++++++
 src/authentic2_auth_saml/app_settings.py      |  4 ++
 src/authentic2_auth_saml/backends.py          | 41 +++++++++++++++++++
 5 files changed, 95 insertions(+), 13 deletions(-)
 create mode 100644 src/authentic2_auth_saml/app_ldap_saml_settings.py
src/authentic2/backends/ldap_backend.py
316 316
        'connect_with_user_credentials': True,
317 317
        # can reset password
318 318
        'can_reset_password': False,
319
        # entity id of the IDP based on the same LDAP
320
        'entity_id': ''
319 321
    }
320 322
    _REQUIRED = ('url', 'basedn')
321 323
    _TO_ITERABLE = ('url', 'groupsu', 'groupstaff', 'groupactive')
......
947 949
                yield user_dn, user
948 950

  
949 951
    @classmethod
950
    def get_users(cls):
952
    def get_ldap_users(cls, blocks, user_filter=None):
951 953
        logger = logging.getLogger(__name__)
952
        for block in cls.get_config():
954
        for block in blocks:
953 955
            conn = cls.get_connection(block)
954 956
            if conn is None:
955 957
                logger.warning(u'unable to synchronize with LDAP servers %r', block['url'])
956 958
                continue
957 959
            user_basedn = block.get('user_basedn') or block['basedn']
958
            user_filter = block['sync_ldap_users_filter'] or block['user_filter']
960
            user_filter = user_filter or block['sync_ldap_users_filter'] or block['user_filter']
959 961
            user_filter = user_filter.replace('%s', '*')
960 962
            attrs = cls.get_ldap_attributes_names(block)
961
            users = cls.paged_search(conn, user_basedn, ldap.SCOPE_SUBTREE, user_filter,
963
            return cls.paged_search(conn, user_basedn, ldap.SCOPE_SUBTREE, user_filter,
962 964
                                     attrlist=attrs)
963
            backend = cls()
964
            for user_dn, data in users:
965
                # ignore referrals
966
                if not user_dn:
967
                    continue
968
                data = cls.normalize_ldap_results(data)
969
                data['dn'] = user_dn
970
                yield backend._return_user(user_dn, None, conn, block, data)
965

  
966
    @classmethod
967
    def get_users(cls):
968
        blocks = cls.get_config()
969
        for user_dn, data in cls.get_ldap_users(blocks):
970
            # ignore referrals
971
            if not user_dn:
972
                continue
973
            data = cls.normalize_ldap_results(data)
974
            data['dn'] = user_dn
975
            yield backend._return_user(user_dn, None, conn, block, data)
971 976

  
972 977
    @classmethod
973 978
    def ad_encoding(cls, s):
src/authentic2_auth_saml/__init__.py
7 7
        return ['mellon', __name__]
8 8

  
9 9
    def get_authentication_backends(self):
10
        return ['authentic2_auth_saml.backends.SAMLBackend']
10
        return ['authentic2_auth_saml.backends.SAMLLdapBackend',
11
                'authentic2_auth_saml.backends.SAMLBackend']
11 12

  
12 13
    def get_auth_frontends(self):
13 14
        return ['authentic2_auth_saml.auth_frontends.SAMLFrontend']
src/authentic2_auth_saml/app_ldap_saml_settings.py
1

  
2
class AppSettings(object):
3
    '''Thanks django-allauth'''
4
    __SENTINEL = object()
5

  
6
    def __init__(self, prefix):
7
        self.prefix = prefix
8

  
9
    def _setting(self, name, dflt=__SENTINEL):
10
        from django.conf import settings
11
        from django.core.exceptions import ImproperlyConfigured
12

  
13
        v = getattr(settings, self.prefix + name, dflt)
14
        if v is self.__SENTINEL:
15
            raise ImproperlyConfigured('Missing setting %r' % (self.prefix + name))
16
        return v
17

  
18
    @property
19
    def enable(self):
20
        return self._setting('ENABLE', False)
21

  
22
    @property
23
    def enable_condition(self):
24
        return self._setting('ENABLE_CONDITION', None)
25

  
26

  
27
import sys
28

  
29
app_settings = AppSettings('A2_AUTH_SAML_LDAP')
30
app_settings.__name__ = __name__
31
sys.modules[__name__] = app_settings
src/authentic2_auth_saml/app_settings.py
19 19
    def enable(self):
20 20
        return self._setting('ENABLE', False)
21 21

  
22
    @property
23
    def ldap_enable(self):
24
        return self._setting('LDAP_ENABLE', False)
25

  
22 26

  
23 27
import sys
24 28

  
src/authentic2_auth_saml/backends.py
1
import re
2

  
3
from django.conf import settings
4

  
1 5
from mellon.backends import SAMLBackend
2 6

  
3 7
from authentic2.middleware import StoreRequestMiddleware
8
from authentic2.backends.ldap_backend import LDAPBackend
4 9

  
5 10
from . import app_settings
6 11

  
......
22 27

  
23 28
        import lasso
24 29
        return lasso.SAML2_AUTHN_CONTEXT_PREVIOUS_SESSION
30

  
31

  
32
class SAMLLdapBackend(SAMLBackend):
33

  
34
    def authenticate(self, saml_attributes, **credentials):
35
        if not app_settings.ldap_enable:
36
            return None
37
        if not getattr(settings, 'LDAP_AUTH_SETTINGS', []):
38
            return None
39
        no_ldap_for_entity_id = True
40
        for block in settings.LDAP_AUTH_SETTINGS:
41
            if block.get('entity_id', '') == saml_attributes['issuer']:
42
                no_ldap_for_entity_id = False
43
                break
44
        if no_ldap_for_entity_id:
45
            return None
46

  
47
        user_filter = block['sync_ldap_users_filter'] or block['user_filter']
48

  
49
        args = []
50
        # get user filter attribute names
51
        for group in re.findall('\w+=%\w+', user_filter):
52
            filter_name, filter_value = group.split('=')
53
            args.append(saml_attributes[filter_name][0])
54
        user_filter = user_filter % tuple(args)
55

  
56
        users = LDAPBackend.get_ldap_users([block], user_filter)
57

  
58
        for user_dn, data in users:
59
            backend = LDAPBackend()
60
            data = backend.normalize_ldap_results(data)
61
            data['dn'] = user_dn
62
            conn = LDAPBackend.get_connection(block)
63
            return backend._return_user(user_dn, None, conn,block, data)
64
        else:
65
            return None
25
-