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