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