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