1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
# -*- coding: utf-8 -*-
import ldap
LDAP_HOST = 'ldap://localhost'
LDAP_BASE_DN = 'dc=nodomain,dc=local'
LDAP_ADMIN_USER = 'root'
LDAP_ADMIN_PASS = 'root'
class AccountService:
"""
To simplify account management through ldap this class can be used.
"""
def __init__(self, ldap_host, base_dn, admin_user, admin_pass):
self.ldap_host = ldap_host
self.base_dn = base_dn
self.admin_cn = 'cn=%s,%s' % (admin_user, self.base_dn)
self.admin_pass = admin_pass
self.binded = False
self.connection = ldap.initialize(ldap_host)
self.connection.version = ldap.VERSION3
def auth(self, username, password):
"""
Tries to authenticate a user with a given password. If the
authentication is successful an Account object will be returned.
"""
dn = 'uid=%s,%s' % (username, self.base_dn)
self._bind(dn, password)
dn, data = self.connection.search_s(dn, ldap.SCOPE_BASE)[0]
acc = Account(dn, data['cn'][0], data['sn'][0])
self._unbind()
return acc
def register(self, account):
"""
Persists an account in the ldap backend
"""
self._bind(self.admin_cn, self.admin_pass)
dn = 'uid=%s,%s' % (account.uid, self.base_dn)
self.connection.add_s(dn, account.to_ldif())
account.dn = dn
self._alter_passwords(account)
self._unbind()
def update(self, account):
"""
Updates account informations like passwords or email.
"""
self._bind(self.admin_cn, self.admin_pass)
attr = [(ldap.MOD_REPLACE, 'mail', account.mail)]
dn = 'uid=%s,%s' % (account.uid, self.base_dn)
self.connection.modify_s(dn, attr)
self._alter_passwords(account)
self._unbind()
def delete(self, uid):
"""
Deletes an account permanently.
"""
self._bind(self.admin_cn, self.admin_pass)
dn = 'uid=%s,%s' % (uid, self.base_dn)
self.connection.delete_s(dn)
self._unbind()
def _bind(self, dn, password):
if not self.binded:
self.connection.simple_bind_s(dn, password)
self.binded = True
def _unbind(self):
if self.binded:
self.connection.unbind_s()
self.binded = False
def _alter_passwords(self, account):
if self.binded and 'root' in account.passwords:
attr = [
(ldap.MOD_REPLACE, 'userPassword', account.passwords['root'])
]
dn = 'uid=%s,%s' % (account.uid, self.base_dn)
self.connection.modify_s(dn, attr)
class Account:
"""
An Account represents a complex ldap tree entry for spline users.
For each service a spline user can have a different password.
"""
def __init__(self, uid, mail, services = [], dn = None, password = None):
self.uid = uid
self.mail = mail
self.services = services
self.dn = dn
self.passwords = {}
if password:
self.change_password(password)
def __str__(self):
return "Account(uid=%s)" % self.uid
def change_password(self, new_password, service = None):
"""
Changes a password for a given service. You have to use the Ldap class
to make the changes permanent. If no service is given, the root
password will be changed.
"""
if not service:
service = 'root'
self.passwords[service] = new_password
def change_email(self, new_mail):
"""
Changes the mail address of an account. You have to use the Ldap class
to make changes permanent.
"""
self.mail = new_mail
def to_ldif(self):
"""
Returns basic account data as a list of tuples (ldif format)
"""
return [
('objectClass', ['top','inetOrgPerson']), ('uid',self.uid),
('sn', self.uid), ('cn', self.uid), ('mail', self.mail)
]
service = AccountService(LDAP_HOST, LDAP_BASE_DN, LDAP_ADMIN_USER, LDAP_ADMIN_PASS)
#print(service.auth('testaccountt6', 'secret'))
#service.delete('testaccountt5')
#a = Account('testaccountt6', 'test@test.de', password='secret')
a = Account('testaccount4', 'mail@mail.de', password='secret')
service.update(a)
#print(service.register(a))
|