]>
Commit | Line | Data |
---|---|---|
940227cb | 1 | #!/usr/bin/python |
78fdedae | 2 | # encoding: utf-8 |
940227cb MT |
3 | |
4 | import hashlib | |
5 | import ldap | |
27066195 | 6 | import logging |
940227cb MT |
7 | import urllib |
8 | ||
9 | from misc import Singleton | |
10 | from settings import Settings | |
11 | ||
12 | class Accounts(object): | |
13 | __metaclass__ = Singleton | |
14 | ||
27066195 MT |
15 | @property |
16 | def settings(self): | |
17 | return Settings() | |
18 | ||
940227cb MT |
19 | def __init__(self): |
20 | self.__db = None | |
21 | ||
22 | self._init() | |
23 | ||
24 | @property | |
25 | def search_base(self): | |
26 | return Settings().get("ldap_search_base") | |
27 | ||
28 | @property | |
29 | def db(self): | |
30 | if not self.__db: | |
27066195 | 31 | ldap_uri = self.settings.get("ldap_uri") |
940227cb MT |
32 | |
33 | self.__db = ldap.initialize(ldap_uri) | |
34 | ||
27066195 MT |
35 | bind_dn = self.settings.get("ldap_bind_dn") |
36 | ||
940227cb | 37 | if bind_dn: |
27066195 | 38 | bind_pw = self.settings.get("ldap_bind_pw") |
940227cb MT |
39 | |
40 | self.__db.simple_bind(bind_dn, bind_pw) | |
41 | ||
42 | return self.__db | |
43 | ||
44 | def get(self, dn): | |
45 | return self._accounts[dn] | |
46 | ||
47 | def _init(self): | |
48 | self._accounts = {} | |
49 | results = self.db.search_s(self.search_base, ldap.SCOPE_SUBTREE, | |
50 | "(objectClass=posixAccount)", ["loginShell"]) | |
51 | ||
52 | for dn, attrs in results: | |
53 | #if attrs["loginShell"] == ["/bin/bash"]: | |
54 | self._accounts[dn] = Account(dn) | |
55 | ||
56 | def list(self): | |
57 | return sorted(self._accounts.values()) | |
58 | ||
59 | def find(self, uid): | |
60 | for account in self.list(): | |
61 | if account.uid == uid: | |
62 | return account | |
63 | ||
64 | def delete(self, uid): | |
65 | account = self.find(uid) | |
66 | # XXX | |
67 | ||
68 | search = find | |
69 | ||
70 | ||
71 | class Account(object): | |
72 | def __init__(self, dn): | |
73 | self.dn = dn | |
74 | ||
75 | self.__attributes = {} | |
76 | ||
77 | def __repr__(self): | |
78 | return "<%s %s>" % (self.__class__.__name__, self.dn) | |
79 | ||
80 | def __cmp__(self, other): | |
81 | return cmp(self.cn, other.cn) | |
82 | ||
83 | @property | |
84 | def db(self): | |
85 | return Accounts().db | |
86 | ||
87 | @property | |
88 | def attributes(self): | |
89 | if not self.__attributes: | |
90 | self.fetch_attributes() | |
91 | ||
92 | return self.__attributes | |
93 | ||
94 | def fetch_attributes(self): | |
95 | result = self.db.search_ext_s(self.dn, ldap.SCOPE_SUBTREE, sizelimit=1) | |
96 | dn, self.__attributes = result[0] | |
97 | ||
98 | def get(self, key): | |
99 | try: | |
100 | attribute = self.attributes[key] | |
101 | except KeyError: | |
102 | raise AttributeError(key) | |
103 | ||
104 | if len(attribute) == 1: | |
105 | return attribute[0] | |
106 | ||
107 | return attribute | |
108 | ||
109 | __getattr__ = get | |
110 | ||
111 | def set(self, key, value): | |
112 | mod_op = ldap.MOD_ADD | |
113 | if self.attributes.has_key(key): | |
114 | mod_op = ldap.MOD_REPLACE | |
115 | ||
116 | self._modify(mod_op, key, value) | |
117 | ||
118 | def _modify(self, op, key, value): | |
119 | modlist = [(op, key, value)] | |
120 | ||
121 | self.db.modify_s(self.dn, modlist) | |
122 | ||
123 | # Update local cache of attributes | |
124 | self.fetch_attributes() | |
125 | ||
126 | def delete(self, key, value=None): | |
127 | self._modify(ldap.MOD_DELETE, key, value) | |
128 | ||
129 | def check_password(self, password): | |
130 | """ | |
131 | Bind to the server with given credentials and return | |
132 | true if password is corrent and false if not. | |
133 | ||
134 | Raises exceptions from the server on any other errors. | |
135 | """ | |
136 | ||
137 | logging.debug("Checking credentials for %s" % self.dn) | |
138 | try: | |
60024cc8 | 139 | self.db.simple_bind_s(self.dn, password.encode("utf-8")) |
940227cb | 140 | except ldap.INVALID_CREDENTIALS: |
60024cc8 | 141 | logging.debug("Account credentials are invalid.") |
940227cb MT |
142 | return False |
143 | ||
60024cc8 | 144 | logging.debug("Successfully authenticated.") |
940227cb MT |
145 | return True |
146 | ||
147 | @property | |
148 | def is_admin(self): | |
149 | return True # XXX todo | |
150 | ||
151 | @property | |
152 | def email(self): | |
153 | name = self.cn.lower() | |
154 | name = name.replace(" ", ".") | |
78fdedae MT |
155 | name = name.replace("Ä", "Ae") |
156 | name = name.replace("Ö", "Oe") | |
157 | name = name.replace("Ü", "Ue") | |
158 | name = name.replace("ä", "ae") | |
159 | name = name.replace("ö", "oe") | |
160 | name = name.replace("ü", "ue") | |
940227cb MT |
161 | |
162 | for mail in self.mail: | |
163 | if mail.startswith(name + "@"): | |
164 | return mail | |
165 | ||
166 | raise Exception, "Cannot figure out email address" | |
167 | ||
168 | def gravatar_icon(self, size=128): | |
169 | # construct the url | |
170 | gravatar_url = "http://www.gravatar.com/avatar/" + \ | |
171 | hashlib.md5(self.email.lower()).hexdigest() + "?" | |
172 | gravatar_url += urllib.urlencode({'d': "mm", 's': str(size)}) | |
173 | ||
174 | return gravatar_url | |
175 | ||
60024cc8 | 176 | |
940227cb MT |
177 | if __name__ == "__main__": |
178 | a = Accounts() | |
179 | ||
180 | print a.list() |