1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """LDAP protocol client"""
18
19 from ldaptor.protocols import pureldap, pureber
20 from ldaptor.protocols.ldap import ldaperrors
21
22 from twisted.python import log
23 from twisted.internet import protocol, defer, ssl, reactor
24
27 return 'Connection lost'
28
30 - def __init__(self, onwire, message=None):
33
35 return 'Cannot STARTTLS while operations on wire: %r' % self.onwire
36
38 """An LDAP client"""
39 debug = False
40
42 self.onwire = {}
43 self.buffer = ''
44 self.connected = None
45
46 berdecoder = pureldap.LDAPBERDecoderContext_TopLevel(
47 inherit=pureldap.LDAPBERDecoderContext_LDAPMessage(
48 fallback=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext()),
49 inherit=pureldap.LDAPBERDecoderContext(fallback=pureber.BERDecoderContext())))
50
62
64 """TCP connection has opened"""
65 self.connected = 1
66
68 """Called when TCP connection has been lost"""
69 self.connected = 0
70
71 while self.onwire:
72 k, v = self.onwire.popitem()
73 d, _, _, _ = v
74 d.errback(reason)
75
84
86 d.callback(msg)
87 return True
88
90 """
91 Send an LDAP operation to the server.
92
93 @param op: the operation to send
94
95 @type op: LDAPProtocolRequest
96
97 @return: the response from server
98
99 @rtype: Deferred LDAPProtocolResponse
100 """
101 msg = self._send(op)
102 assert op.needs_answer
103 d = defer.Deferred()
104 self.onwire[msg.id]=(d, None, None, None)
105 self.transport.write(str(msg))
106 return d
107
109 """
110 Send an LDAP operation to the server, expecting one or more
111 responses.
112
113 @param op: the operation to send
114
115 @type op: LDAPProtocolRequest
116
117 @param handler: a callable that will be called for each
118 response. It should return a boolean, whether this was the
119 final response.
120
121 @param args: positional arguments to pass to handler
122
123 @param kwargs: keyword arguments to pass to handler
124
125 @return: the result from the last handler as a deferred that
126 completes when the last response has been received
127
128 @rtype: Deferred LDAPProtocolResponse
129 """
130 msg = self._send(op)
131 assert op.needs_answer
132 d = defer.Deferred()
133 self.onwire[msg.id]=(d, handler, args, kwargs)
134 self.transport.write(str(msg))
135 return d
136
138 """
139 Send an LDAP operation to the server, with no response
140 expected.
141
142 @param op: the operation to send
143 @type op: LDAPProtocolRequest
144 """
145 msg = self._send(op)
146 assert not op.needs_answer
147 self.transport.write(str(msg))
148
150 log.msg("Got unsolicited notification: %s" % repr(msg))
151
153 assert isinstance(msg.value, pureldap.LDAPProtocolResponse)
154 if self.debug:
155 log.msg('C<-S %s' % repr(msg))
156
157 if msg.id==0:
158 self.unsolicitedNotification(msg.value)
159 else:
160 d, handler, args, kwargs = self.onwire[msg.id]
161
162 if handler is None:
163 assert args is None
164 assert kwargs is None
165 d.callback(msg.value)
166 del self.onwire[msg.id]
167 else:
168 assert args is not None
169 assert kwargs is not None
170
171 if handler(msg.value, *args, **kwargs):
172 del self.onwire[msg.id]
173
174
175 - def bind(self, dn='', auth=''):
188
195
196
203
212
214 """
215 Start Transport Layer Security.
216
217 It is the callers responsibility to make sure other things
218 are not happening at the same time.
219
220 @todo: server hostname check, see rfc2830 section 3.6.
221
222 """
223 if ctx is None:
224 ctx = ssl.ClientContextFactory()
225
226
227
228 d=defer.Deferred()
229 d.addCallback(self._startTLS)
230 reactor.callLater(0, d.callback, ctx)
231 return d
232
243