Ticket #926: 0001-LDAP-URL-based-on-RFC-2255.patch
File 0001-LDAP-URL-based-on-RFC-2255.patch, 7.4 KB (added by , 10 years ago) |
---|
-
mediagoblin/plugins/ldap/README.rst
From dc6658bae6ec07f1ff71a1d6ed9fdb3425fae043 Mon Sep 17 00:00:00 2001 From: Lars Kruse <devel@sumpfralle.de> Date: Fri, 25 Jul 2014 22:53:04 +0200 Subject: [PATCH] LDAP URL based on RFC 2255 --- mediagoblin/plugins/ldap/README.rst | 17 ++++-- mediagoblin/plugins/ldap/tools.py | 101 ++++++++++++++++++++++++++++------- 2 files changed, 97 insertions(+), 21 deletions(-) diff --git a/mediagoblin/plugins/ldap/README.rst b/mediagoblin/plugins/ldap/README.rst index ea9a34b..a2072ec 100644
a b under the ldap plugin:: 50 50 Make any necessary changes to the above to work with your sever. Make sure 51 51 ``{username}`` is where the username should be in LDAP_USER_DN_TEMPLATE. 52 52 53 Starting with MediaGoblin v0.7 the following syntax is allows even more details:: 54 55 [[mediagoblin.plugins.ldap]] 56 [[[server1]]] 57 LDAP_USER_URL = 'ldap://ldap.testathon.net:389/ou=users,dc=testathon,dc=net?uid?sub?(objectClass=*)' 58 [[[server2]]] 59 ... 60 61 `RFC 2255 <http://www.ietf.org/rfc/rfc2255.txt>` describes the above 62 ``LDAP_USER_URL`` in more detail. 63 53 64 If you would like to fetch the users email from the ldap server upon account 54 registration, add ``LDAP_SEARCH_BASE = 'ou=users,dc=testathon,dc=net'`` and55 ``EMAIL_SEARCH_FIELD = 'mail'`` under you server configuration in your 56 MediaGoblin .ini file.65 registration, add ``LDAP_SEARCH_BASE = 'ou=users,dc=testathon,dc=net'`` 66 (only if you use ``LDAP_SERVER_URI``) and ``EMAIL_SEARCH_FIELD = 'mail'`` 67 under you server configuration in your MediaGoblin .ini file. 57 68 58 69 .. Warning:: 59 70 By default, this plugin provides no encryption when communicating with the -
mediagoblin/plugins/ldap/tools.py
diff --git a/mediagoblin/plugins/ldap/tools.py b/mediagoblin/plugins/ldap/tools.py index 1c43679..1ae5655 100644
a b 15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>. 16 16 import ldap 17 17 import logging 18 import re 19 import urllib2 18 20 19 21 from mediagoblin.tools import pluginapi 20 22 … … _log = logging.getLogger(__name__) 24 26 class LDAP(object): 25 27 def __init__(self): 26 28 self.ldap_settings = pluginapi.get_config('mediagoblin.plugins.ldap') 29 self.conn = None 27 30 28 def _connect(self, server ):29 _log.info('Connecting to {0}.'.format(server ['LDAP_SERVER_URI']))30 self.conn = ldap.initialize(server ['LDAP_SERVER_URI'])31 def _connect(self, server_uri, use_start_tls): 32 _log.info('Connecting to {0}.'.format(server_uri)) 33 self.conn = ldap.initialize(server_uri) 31 34 32 if server['LDAP_START_TLS']== 'true':35 if use_start_tls == 'true': 33 36 _log.info('Initiating TLS') 34 37 self.conn.start_tls_s() 35 38 36 def _get_e mail(self, server, username):39 def _get_entry_value(self, user_dn, field_name): 37 40 try: 38 results = self.conn.search_s(server['LDAP_SEARCH_BASE'], 39 ldap.SCOPE_SUBTREE, 'uid={0}' 40 .format(username), 41 [server['EMAIL_SEARCH_FIELD']]) 42 43 email = results[0][1][server['EMAIL_SEARCH_FIELD']][0] 41 results = self.conn.search_s(user_dn, ldap.SCOPE_BASE, 42 attrlist=[field_name]) 43 return results[0][1][field_name][0] 44 44 except KeyError: 45 email =None45 return None 46 46 47 return email 47 def _parse_ldap_url(self, url): 48 url_regex = re.compile(r'^([\w+.-]+://[\w.-]+(?:\d+)?)/(.*)$') 49 match = re.search(url_regex, url) 50 if match: 51 server_uri, query = match.groups() 52 result = {'SERVER_URI': server_uri} 53 tokens = query.split('?') 54 result['BASE_DN'] = '' 55 # 'base' is the default scope 56 result['SCOPE'] = ldap.SCOPE_BASE 57 attribute = '' 58 scope = '' 59 result['FILTERS'] = '(objectClass=*)' 60 try: 61 result['BASE_DN'] = tokens.pop(0) 62 # 'uid' is the default attribute 63 result['ATTRIBUTES'] = tokens.pop(0).split(",") or ['uid'] 64 scope = tokens.pop(0) 65 result['FILTERS'] = tokens.pop(0) 66 except IndexError: 67 pass 68 try: 69 result['SCOPE'] = {'': ldap.SCOPE_BASE, 70 'base': ldap.SCOPE_BASE, 71 'one': ldap.SCOPE_ONELEVEL, 72 'sub': ldap.SCOPE_SUBTREE}[scope] 73 except KeyError as err: 74 _log.info(err) 75 return result 76 else: 77 return None 78 79 def _get_dn(self, username, attribute, base_dn, scope, filters): 80 if filters: 81 if filters.startswith("("): 82 # remove surrounding braces - otherwise the filter string fails 83 filters = filters.lstrip("(").rstrip(")") 84 filters = "(&({0})({1}={2}))".format(filters, attribute, username) 85 else: 86 filters = "{0}={1}".format(attribute, username) 87 try: 88 results = self.conn.search_s(base_dn, scope, filters) 89 return results[0][0] 90 except KeyError: 91 return None 48 92 49 93 def login(self, username, password): 50 94 for k, v in self.ldap_settings.iteritems(): 95 _log.debug("Server settings: {1}".format(k, v)) 96 server_uri = None 51 97 try: 52 self._connect(v) 53 user_dn = v['LDAP_USER_DN_TEMPLATE'].format(username=username) 98 if 'LDAP_USER_URL' in v: 99 login_settings = self._parse_ldap_url(v['LDAP_USER_URL']) 100 _log.debug("Parsed LDAP_USER_URL: {0}".format(login_settings)) 101 server_uri = login_settings["SERVER_URI"] 102 self._connect(server_uri, v.get('LDAP_START_TLS', None)) 103 user_dn = self._get_dn(username, 104 login_settings["ATTRIBUTES"][0], 105 login_settings["BASE_DN"], 106 login_settings["SCOPE"], 107 login_settings["FILTERS"]) 108 else: 109 # use LDAP_USER_DN_TEMPLATE and LDAP_SERVER_URI 110 server_uri = v["LDAP_SERVER_URI"] 111 self._connect(server_uri, v.get('LDAP_START_TLS', None)) 112 user_dn = v['LDAP_USER_DN_TEMPLATE'].format(username=username) 113 _log.debug("DN of user: {0}".format(user_dn)) 54 114 self.conn.simple_bind_s(user_dn, password.encode('utf8')) 55 email = self._get_email(v, username) 115 if 'EMAIL_SEARCH_FIELD' in v: 116 email = self._get_entry_value(user_dn, v['EMAIL_SEARCH_FIELD']) 117 else: 118 email = None 56 119 return username, email 57 120 58 121 except ldap.LDAPError, e: 59 122 _log.info(e) 60 123 61 124 finally: 62 _log.info('Unbinding {0}.'.format(v['LDAP_SERVER_URI'])) 63 self.conn.unbind() 125 _log.info('Unbinding {0}.'.format(server_uri)) 126 if self.conn: 127 self.conn.unbind() 64 128 65 129 return False, None 130