1 import random, base64
2 from zope.interface import implements
3 from twisted.internet import defer
4 from twisted.python.util import InsensitiveDict
5 from ldaptor import interfaces, attributeset, delta
6 from ldaptor.protocols.ldap import distinguishedname, ldif, ldaperrors
7
8 try:
9 from hashlib import sha1
10 except ImportError:
11 from sha import sha as sha1
12
13
15 if salt is None:
16 salt = ''
17 for i in range(8):
18 salt += chr(random.randint(0, 255))
19
20 s = sha1()
21 s.update(passphrase)
22 s.update(salt)
23 encoded = base64.encodestring(s.digest()+salt).rstrip()
24 crypt = '{SSHA}' + encoded
25 return crypt
26
27 -class BaseLDAPEntry(object):
28 implements(interfaces.ILDAPEntry)
29 dn = None
30
31 - def __init__(self, dn, attributes={}):
32 """
33
34 Initialize the object.
35
36 @param dn: Distinguished Name of the object, as a string.
37
38 @param attributes: Attributes of the object. A dictionary of
39 attribute types to list of attribute values.
40
41 """
42 self._attributes=InsensitiveDict()
43 self.dn = distinguishedname.DistinguishedName(dn)
44
45 for k,vs in attributes.items():
46 if k not in self._attributes:
47 self._attributes[k] = []
48 self._attributes[k].extend(vs)
49
50 for k,vs in self._attributes.items():
51 self._attributes[k] = self.buildAttributeSet(k, vs)
52
53 - def buildAttributeSet(self, key, values):
55
56 - def __getitem__(self, key):
57 return self._attributes[key]
58
59 - def get(self, key, default=None):
60 return self._attributes.get(key, default)
61
62 - def has_key(self, key):
63 return key in self._attributes
64
65 - def __contains__(self, key):
66 return self.has_key(key)
67
69 return self._attributes.keys()
70
72 return self._attributes.items()
73
75 a=[]
76
77 objectClasses = list(self.get('objectClass', []))
78 objectClasses.sort()
79 a.append(('objectClass', objectClasses))
80
81 l=list(self.items())
82 l.sort()
83 for key, values in l:
84 if key.lower() != 'objectclass':
85 vs = list(values)
86 vs.sort()
87 a.append((key, vs))
88 return ldif.asLDIF(self.dn, a)
89
90 - def __eq__(self, other):
91 if not isinstance(other, BaseLDAPEntry):
92 return 0
93 if self.dn != other.dn:
94 return 0
95
96 my=self.keys()
97 my.sort()
98 its=other.keys()
99 its.sort()
100 if my!=its:
101 return 0
102 for key in my:
103 myAttr=self[key]
104 itsAttr=other[key]
105 if myAttr!=itsAttr:
106 return 0
107 return 1
108
109 - def __ne__(self, other):
110 return not self==other
111
113 return len(self.keys())
114
115 - def __nonzero__(self):
117
118 - def __repr__(self):
119 x={}
120 for key in self.keys():
121 x[key]=self[key]
122 keys=self.keys()
123 keys.sort()
124 a=[]
125 for key in keys:
126 a.append('%s: %s' % (repr(key), repr(list(self[key]))))
127 attributes=', '.join(a)
128 return '%s(%s, {%s})' % (
129 self.__class__.__name__,
130 repr(str(self.dn)),
131 attributes)
132
133 - def diff(self, other):
134 """
135 Compute differences between this and another LDAP entry.
136
137 @param other: An LDAPEntry to compare to.
138
139 @return: None if equal, otherwise a ModifyOp that would make
140 this entry look like other.
141 """
142 assert self.dn == other.dn
143 if self == other:
144 return None
145
146 r = []
147
148 myKeys = set(self.keys())
149 otherKeys = set(other.keys())
150
151 addedKeys = list(otherKeys - myKeys)
152 addedKeys.sort()
153 for added in addedKeys:
154 r.append(delta.Add(added, other[added]))
155
156 deletedKeys = list(myKeys - otherKeys)
157 deletedKeys.sort()
158 for deleted in deletedKeys:
159 r.append(delta.Delete(deleted, self[deleted]))
160
161 sharedKeys = list(myKeys & otherKeys)
162 sharedKeys.sort()
163 for shared in sharedKeys:
164
165 addedValues = list(other[shared] - self[shared])
166 if addedValues:
167 addedValues.sort()
168 r.append(delta.Add(shared, addedValues))
169
170 deletedValues = list(self[shared] - other[shared])
171 if deletedValues:
172 deletedValues.sort()
173 r.append(delta.Delete(shared, deletedValues))
174
175 return delta.ModifyOp(dn=self.dn, modifications=r)
176
177 - def bind(self, password):
178 return defer.maybeDeferred(self._bind, password)
179
180 - def _bind(self, password):
181 for digest in self.get('userPassword', ()):
182 if digest.startswith('{SSHA}'):
183 raw = base64.decodestring(digest[len('{SSHA}'):])
184 salt = raw[20:]
185 got = sshaDigest(password, salt)
186 if got == digest:
187 return self
188 raise ldaperrors.LDAPInvalidCredentials
189
190 - def hasMember(self, dn):
191 for memberDN in self.get('member', []):
192 if memberDN == dn:
193 return True
194 return False
195
196 - def __hash__(self):
198
199 -class EditableLDAPEntry(BaseLDAPEntry):
200 implements(interfaces.IEditableLDAPEntry)
201
202 - def __setitem__(self, key, value):
203 new=self.buildAttributeSet(key, value)
204 self._attributes[key] = new
205
206 - def __delitem__(self, key):
207 del self._attributes[key]
208
210 raise NotImplementedError
211
213 raise NotImplementedError
214
215 - def move(self, newDN):
216 raise NotImplementedError
217
219 raise NotImplementedError
220
221 - def setPassword(self, newPasswd, salt=None):
222 crypt = sshaDigest(newPasswd, salt)
223 self['userPassword'] = [crypt]
224