Ticket #5568: 0001-Fix-LDAP-For-Active-Directory_code.patch

File 0001-Fix-LDAP-For-Active-Directory_code.patch, 7.0 KB (added by Meaulnes, 6 years ago)

LDAP Active Directory patch - code changes

  • mediagoblin/plugins/ldap/tools.py

    From 473d9abaebdf75e3bc9dc59f012a8faf070b69b7 Mon Sep 17 00:00:00 2001
    From: Kirk Gleason <kgleason@bloominsuranceagency.com>
    Date: Sun, 15 Apr 2018 13:59:12 -0400
    Subject: [PATCH] Rollback README for LDAP plugin to match stable so new patch
     can be applied. Only whitespace and capitalization changes are lost.
    
    Added in Active Directory config flags that are required. Adjusted email search so that it returns the entire user object. Made the search field variable.
    
    Updated docs to add in AD specific bits
    
    Converted the LDAP_START_TLS option from string to bool
    
    Added some explanation to all of the LDAP configuration options.
    
    Converted LDAP_ACTIVE_DIRECTORY from bool to string
    
    Converted bool config options to string
    
    Ignore PyCharm artifacts, package-lock, and pytest cache files.
    
    Added in checks for all of the possible LDAP config variables, and tested for them. It is not yet properly handling required values, but it's no different than when I started looking at it.
    
    Updated the docs to reflect the optional config values.
    
    More details on how authenitcation works are in the documentation. The logic of EMAIL_SEARCH_FIELD is more clear.
    
    EMAIL_SEARCH_FIELD defaults to None, and is used to trigger or skip the email lookup
    
    Active Direcotry configuration option is more clearly named.
    
    Can now restrcit ability to LDAP auth based on group membership.
    
    Signed-off-by: Kirk Gleason <kgleason@bloominsuranceagency.com>
    
    Correct capitalization on LDAP in documentation.
    ---
     mediagoblin/plugins/ldap/tools.py | 109 +++++++++++++++++++++++++++---
     1 file changed, 101 insertions(+), 8 deletions(-)
    
    diff --git a/mediagoblin/plugins/ldap/tools.py b/mediagoblin/plugins/ldap/tools.py
    index 2be2dcd7..4c527208 100644
    a b class LDAP(object):  
    2727    def __init__(self):
    2828        self.ldap_settings = pluginapi.get_config('mediagoblin.plugins.ldap')
    2929
     30        for k, v in six.iteritems(self.ldap_settings):
     31            try:
     32                v['LDAP_SERVER_URI']
     33            except KeyError:
     34                _log.error('LDAP_SERVER_URI was not defined in the config.')
     35                # Do something here to raise a fatal error
     36
     37            try:
     38                v['LDAP_START_TLS']
     39            except KeyError:
     40                _log.info('LDAP_START_TLS is not defined. Assuming false')
     41                self.ldap_settings[k]['LDAP_START_TLS'] = 'false'
     42
     43            try:
     44                v['LDAP_USER_DN_TEMPLATE']
     45            except KeyError:
     46                _log.error('LDAP_USER_DN_TEMPLATE '
     47                           'was not defined in the config')
     48                # Do something here to raise a fatal error
     49
     50            try:
     51                v['LDAP_IS_ACTIVE_DIRECTORY']
     52            except KeyError:
     53                _log.info('Active Directory flag was not set. Assuming false')
     54                self.ldap_settings[k]['LDAP_IS_ACTIVE_DIRECTORY'] = 'false'
     55
     56            try:
     57                v['LDAP_SEARCH_BASE']
     58            except KeyError:
     59                _log.error('LDAP_SEARCH_BASE was not defined in the config')
     60                # Do something here to raise a fatal error
     61
     62            try:
     63                v['UID_SEARCH_FIELD']
     64            except KeyError:
     65                _log.info('UID_SEARCH_FIELD was not defined in the config. '
     66                          'Assuming ''uid''.')
     67                self.ldap_settings[k]['UID_SEARCH_FIELD'] = 'uid'
     68
     69            try:
     70                v['EMAIL_SEARCH_FIELD']
     71            except KeyError:
     72                _log.info('EMAIL_SEARCH_FIELD was not defined in the config. '
     73                          'Assuming mail lookup is not wanted.')
     74                self.ldap_settings[k]['EMAIL_SEARCH_FIELD'] = None
     75
     76            try:
     77                v['LDAP_FILTER']
     78            except KeyError:
     79                _log.info('LDAP_FILTER was not defined in the config. '
     80                          'Assuming ''(objectClass=person)''')
     81                self.ldap_settings[k]['LDAP_FILTER'] = '(objectClass=person)'
     82
     83        _log.info(self.ldap_settings)
     84
    3085    def _connect(self, server):
    3186        _log.info('Connecting to {0}.'.format(server['LDAP_SERVER_URI']))
    3287        self.conn = ldap.initialize(server['LDAP_SERVER_URI'])
    3388
    34         if server['LDAP_START_TLS'] == 'true':
     89        if server['LDAP_START_TLS'].lower() == 'true':
    3590            _log.info('Initiating TLS')
    3691            self.conn.start_tls_s()
    3792
    3893    def _get_email(self, server, username):
     94        if server['EMAIL_SEARCH_FIELD']:
     95            try:
     96                filter = '{0}={1}'.format(server['UID_SEARCH_FIELD'], username)
     97                attrs = [server['EMAIL_SEARCH_FIELD']]
     98                results = self.conn.search_s(server['LDAP_SEARCH_BASE'],
     99                                            ldap.SCOPE_SUBTREE, filter, attrs)
     100
     101                email = results[0][1][server['EMAIL_SEARCH_FIELD']][0]
     102            except KeyError:
     103                email = None
     104        else:
     105            email = None
     106
     107        return email
     108
     109    def _validate_account(self, server, username):
    39110        try:
     111            filter = server['LDAP_FILTER']
     112            attrs = [server['UID_SEARCH_FIELD']]
     113
    40114            results = self.conn.search_s(server['LDAP_SEARCH_BASE'],
    41                                         ldap.SCOPE_SUBTREE, 'uid={0}'
    42                                         .format(username),
    43                                         [server['EMAIL_SEARCH_FIELD']])
     115                                         ldap.SCOPE_SUBTREE, filter, attrs)
     116
     117            valid_account = False
     118            for res in results:
     119                if res[1][server['UID_SEARCH_FIELD']][0] == username:
     120                    valid_account = True
     121                    break
    44122
    45             email = results[0][1][server['EMAIL_SEARCH_FIELD']][0]
    46123        except KeyError:
    47             email = None
     124            valid_account = False
     125        except TypeError:
     126            valid_account = False
    48127
    49         return email
     128        return valid_account
    50129
    51130    def login(self, username, password):
    52131        for k, v in six.iteritems(self.ldap_settings):
    53132            try:
    54133                self._connect(v)
    55134                user_dn = v['LDAP_USER_DN_TEMPLATE'].format(username=username)
     135
     136                if v['LDAP_IS_ACTIVE_DIRECTORY'].lower() == 'true':
     137                    self.conn.protocol_version = ldap.VERSION3
     138                    self.conn.set_option(ldap.OPT_REFERRALS, 0)
     139
     140                _log.info('Attempting to bind to {0} as {1}'.format(
     141                    v['LDAP_SERVER_URI'], user_dn))
    56142                self.conn.simple_bind_s(user_dn, password.encode('utf8'))
    57                 email = self._get_email(v, username)
     143
     144                if self._validate_account(v, username):
     145                    email = self._get_email(v, username)
     146                else:
     147                    return False, None
     148
    58149                return username, email
    59150
     151            except ValueError, e:
     152                _log.info(e)
    60153            except ldap.LDAPError, e:
    61154                _log.info(e)
    62155