summaryrefslogtreecommitdiffstats
path: root/account.py
diff options
context:
space:
mode:
authorNico von Geyso <Nico.Geyso@FU-Berlin.de>2012-09-26 20:36:24 +0200
committerNico von Geyso <Nico.Geyso@FU-Berlin.de>2012-09-26 20:36:24 +0200
commitde3bd39446aad4e95275b4c0757ef0772671425b (patch)
treeb348401748a671ec86351f6b8002cd4d81235444 /account.py
parentb914225af239041c77bc4557a12e259a78d6025a (diff)
downloadweb-de3bd39446aad4e95275b4c0757ef0772671425b.tar.gz
web-de3bd39446aad4e95275b4c0757ef0772671425b.tar.bz2
web-de3bd39446aad4e95275b4c0757ef0772671425b.zip
added escape method and use it nearly everywhere. good old paranoia
Diffstat (limited to 'account.py')
-rw-r--r--account.py93
1 files changed, 66 insertions, 27 deletions
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: