summaryrefslogtreecommitdiffstats
path: root/account.py
blob: 46356d5468f3e63f336b64420c95141abd266261 (plain)
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))