From de3bd39446aad4e95275b4c0757ef0772671425b Mon Sep 17 00:00:00 2001 From: Nico von Geyso Date: Wed, 26 Sep 2012 20:36:24 +0200 Subject: added escape method and use it nearly everywhere. good old paranoia --- account.py | 93 ++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 27 deletions(-) (limited to 'account.py') diff --git a/account.py b/account.py index e78dc93..1569e2c 100644 --- a/account.py +++ b/account.py @@ -4,7 +4,7 @@ from utils import Service LDAP_HOST = 'ldap://localhost:5678' -LDAP_BASE_DN = 'dc=account,dc=spline,dc=inf,dc=fu-berlin,dc=de' +LDAP_BASE_DN = [('dc','account'),('dc','spline'),('dc','inf'),('dc','fu-berlin'),('dc','de')] LDAP_ADMIN_USER = 'admin' LDAP_ADMIN_PASS = 'admin' SERVICES = [ @@ -64,6 +64,7 @@ class AccountService: self.admin_pass = admin_pass self.services = services self.admin = False + self.binded = False def auth(self, username, password): @@ -71,16 +72,19 @@ class AccountService: Tries to authenticate a user with a given password. If the authentication is successful an Account object will be returned. """ - dn = 'uid=%s,ou=users,%s' % (username, self.base_dn) - self._bind(dn, password) + self._bind_anonymous() + dn = self._format_dn([('uid', username), ('ou','users')]) dn_user, data_user = self.connection.search_s(dn, ldap.SCOPE_SUBTREE)[0] + + self._bind_as_user(username, password) uid = data_user['uid'][0] mail = data_user['mail'][0] - dn = 'ou=services,%s' % self.base_dn - filterstr = '(uid=%s)' % uid + dn = self._format_dn([('ou', 'services')]) + filterstr = '(uid=%s)' % self._escape(uid) data_service = self.connection.search_s(dn,ldap.SCOPE_SUBTREE,filterstr) + services = [] for entry in data_service: cn = filter(lambda x: x.startswith('cn='), entry[0].split(','))[0] @@ -115,20 +119,15 @@ class AccountService: """ self._bind_anonymous() - dn = 'ou=users,%s' % self.base_dn - filters['objectClass'] = 'inetOrgPerson' - chars_to_escape = ['\\','(',')','\0'] - if not wildcard: - chars_to_escape.append('*') - escape = lambda x,y: x.replace(y,'\%s' % y) - filter_as_list = ['(%s=%s)' % (k,reduce(escape, chars_to_escape, v)) for k,v in filters.items()] + filter_as_list = ['(%s=%s)' % (k,self._escape(v, wildcard)) for k,v in filters.items()] filterstr = ''.join(filter_as_list) if len(filter_as_list) > 1: filterstr = '(&%s)' % filterstr + dn = self._format_dn([('ou','users')]) data = self.connection.search_s(dn,ldap.SCOPE_SUBTREE,filterstr) accounts = [] @@ -146,15 +145,16 @@ class AccountService: """ self._bind_as_admin() - dn = 'uid=%s,ou=users,%s' % (account.uid, self.base_dn) + dn = self._format_dn([('uid', account.uid)]) attr = [ - ('objectClass', ['top','inetOrgPerson']), ('uid', account.uid), - ('sn', ' '), ('cn', ' '), ('mail', account.mail) + ('objectClass', ['top','inetOrgPerson']), + ('uid', self._escape(account.uid)), ('sn', ' '), ('cn', ' '), + ('mail', account.mail) ] self.connection.add_s(dn, attr) account.dn = dn - account.new_password_root = (None,account.password) + account.new_password_root = (None, account.password) self._alter_passwords(account) self._unbind() @@ -167,12 +167,10 @@ class AccountService: if as_admin: self._bind_as_admin() else: - user = 'uid=%s,ou=users' % account.uid - password = account.password - self._bind('%s,%s' % (user, self.base_dn), password) + self._bind_as_user(account.uid, account.password) attr = [(ldap.MOD_REPLACE, 'mail', account.mail)] - dn = 'uid=%s,ou=users,%s' % (account.uid, self.base_dn) + dn = self._format_dn([('uid',account.uid),('ou','users')]) self.connection.modify_s(dn, attr) self._alter_passwords(account) @@ -187,15 +185,16 @@ class AccountService: if isinstance(account, basestring): raise NotImplementedError() else: - user = account.dn + user = account.uid password = account.password if as_admin: self._bind_as_admin() else: - self._bind('%s,%s' % (user, self.base_dn), password) + self._bind_as_user(user, password) - dn = ['uid=%s,cn=%s,ou=services,%s' % (account.uid,s,self.base_dn) for s.id in account.services] + uid = self._escape(uid) + dn = [self._format_dn([('uid',uid),('cn',s),('ou','services')]) for s.id in account.services] dn.append(user) for x in dn: @@ -203,6 +202,14 @@ class AccountService: self._unbind() + def _format_dn(self, attr, with_base_dn = True): + if with_base_dn: + attr.extend(self.base_dn) + + dn = ['%s=%s' % (item[0], self._escape(item[1])) for item in attr] + + return ','.join(dn) + def _bind(self, dn, password): self.connection = ldap.initialize(self.ldap_host) self.connection.version = ldap.VERSION3 @@ -210,21 +217,43 @@ class AccountService: self.connection.simple_bind_s(dn, password) def _bind_as_admin(self): + if self.binded: + self._unbind() + + dn = self._format_dn([('cn', self.admin_user)]) + self._bind(dn, self.admin_pass) + + self.admin = True + self.binded = True + + def _bind_as_user(self, username, password): + if self.binded: + self._unbind() + + dn = self._format_dn([('uid', username),('ou', 'users')]) + self._bind(dn, password) + + self.binded = True self.admin = True - self._bind('cn=%s,%s' % (self.admin_user, self.base_dn), self.admin_pass) def _bind_anonymous(self): + if self.binded: + self._unbind() + self._bind('','') + self.binded = True + def _unbind(self): self.connection.unbind_s() self.admin = False + self.binded = False def _alter_passwords(self, account): if account.new_password_root: - dn = 'uid=%s,ou=users,%s' % (account.uid, self.base_dn) + dn = self._format_dn([('uid',account.uid),('ou','users')]) old, new = account.new_password_root if self.admin: self.connection.passwd_s(dn, None, new) @@ -233,11 +262,10 @@ class AccountService: account.password = new - account.new_password_root = None for service, passwords in account.new_password_services.items(): - dn = 'uid=%s,cn=%s,ou=services,%s' % (account.uid, service, self.base_dn) + dn = self._format_dn([('uid',account.uid),('cn',service),('ou','services')]) old, new = passwords if self.admin: self.connection.passwd_s(dn, None, new) @@ -246,6 +274,17 @@ class AccountService: account.new_password_services = {} + def _escape(self, s, wildcard=False): + chars_to_escape = ['\\',',','=','+','<','>',';','"','\'','#','(',')','\0'] + + if not wildcard: + chars_to_escape.append('*') + + escape = lambda x,y: x.replace(y,'\%02X' % ord(y)) + + return reduce(escape, chars_to_escape, s) + + class Account: -- cgit v1.2.3-1-g7c22