diff options
Diffstat (limited to 'account.py')
-rw-r--r-- | account.py | 102 |
1 files changed, 66 insertions, 36 deletions
@@ -5,7 +5,7 @@ from uuid import uuid4 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 = [ @@ -65,6 +65,7 @@ class AccountService: self.admin_pass = admin_pass self.services = services self.admin = False + self.binded = False def auth(self, username, password): @@ -72,16 +73,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] @@ -116,20 +120,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 = [] @@ -147,15 +146,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() @@ -168,12 +168,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) @@ -188,15 +186,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: @@ -204,6 +203,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 @@ -211,21 +218,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) @@ -234,20 +263,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) - if service not in account.services: - # initialize with random password because the schema requires that - attr = [('objectClass', ['top', 'servicePassword']), - ('uid', account.uid), ('userPassword', uuid4().hex)] - - sub = AccountService(self.ldap_host, self.base_dn, self.admin_user, - self.admin_pass, self.services) - self.connection.add_s(dn, attr) - + dn = self._format_dn([('uid',account.uid),('cn',service),('ou','services')]) old, new = passwords if self.admin: self.connection.passwd_s(dn, None, new) @@ -256,6 +275,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: |