1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 from __future__ import absolute_import
21
22 from cproton import PN_EOS, PN_OK, PN_SASL_AUTH, PN_SASL_NONE, PN_SASL_OK, PN_SASL_PERM, PN_SASL_SYS, PN_SASL_TEMP, \
23 PN_SSL_ANONYMOUS_PEER, PN_SSL_CERT_SUBJECT_CITY_OR_LOCALITY, PN_SSL_CERT_SUBJECT_COMMON_NAME, \
24 PN_SSL_CERT_SUBJECT_COUNTRY_NAME, PN_SSL_CERT_SUBJECT_ORGANIZATION_NAME, PN_SSL_CERT_SUBJECT_ORGANIZATION_UNIT, \
25 PN_SSL_CERT_SUBJECT_STATE_OR_PROVINCE, PN_SSL_MD5, PN_SSL_MODE_CLIENT, PN_SSL_MODE_SERVER, PN_SSL_RESUME_NEW, \
26 PN_SSL_RESUME_REUSED, PN_SSL_RESUME_UNKNOWN, PN_SSL_SHA1, PN_SSL_SHA256, PN_SSL_SHA512, PN_SSL_VERIFY_PEER, \
27 PN_SSL_VERIFY_PEER_NAME, PN_TRACE_DRV, PN_TRACE_FRM, PN_TRACE_OFF, PN_TRACE_RAW, pn_error_text, pn_sasl, \
28 pn_sasl_allowed_mechs, pn_sasl_config_name, pn_sasl_config_path, pn_sasl_done, pn_sasl_extended, \
29 pn_sasl_get_allow_insecure_mechs, pn_sasl_get_mech, pn_sasl_get_user, pn_sasl_outcome, \
30 pn_sasl_set_allow_insecure_mechs, pn_ssl, pn_ssl_domain, pn_ssl_domain_allow_unsecured_client, pn_ssl_domain_free, \
31 pn_ssl_domain_set_credentials, pn_ssl_domain_set_peer_authentication, pn_ssl_domain_set_trusted_ca_db, \
32 pn_ssl_get_cert_fingerprint, pn_ssl_get_cipher_name, pn_ssl_get_peer_hostname, pn_ssl_get_protocol_name, \
33 pn_ssl_get_remote_subject, pn_ssl_get_remote_subject_subfield, pn_ssl_init, pn_ssl_present, pn_ssl_resume_status, \
34 pn_ssl_set_peer_hostname, pn_transport, pn_transport_attachments, pn_transport_bind, pn_transport_capacity, \
35 pn_transport_close_head, pn_transport_close_tail, pn_transport_closed, pn_transport_condition, \
36 pn_transport_connection, pn_transport_error, pn_transport_get_channel_max, pn_transport_get_frames_input, \
37 pn_transport_get_frames_output, pn_transport_get_idle_timeout, pn_transport_get_max_frame, \
38 pn_transport_get_pytracer, pn_transport_get_remote_idle_timeout, pn_transport_get_remote_max_frame, \
39 pn_transport_get_user, pn_transport_is_authenticated, pn_transport_is_encrypted, pn_transport_log, \
40 pn_transport_peek, pn_transport_pending, pn_transport_pop, pn_transport_push, pn_transport_remote_channel_max, \
41 pn_transport_require_auth, pn_transport_require_encryption, pn_transport_set_channel_max, \
42 pn_transport_set_idle_timeout, pn_transport_set_max_frame, pn_transport_set_pytracer, pn_transport_set_server, \
43 pn_transport_tick, pn_transport_trace, pn_transport_unbind
44
45 from ._common import millis2secs, secs2millis, unicode2utf8, utf82unicode
46 from ._condition import cond2obj, obj2cond
47 from ._exceptions import EXCEPTIONS, SSLException, SSLUnavailable, SessionException, TransportException
48 from ._wrapper import Wrapper
52
55
56 - def __call__(self, trans_impl, message):
58
61 TRACE_OFF = PN_TRACE_OFF
62 TRACE_DRV = PN_TRACE_DRV
63 TRACE_FRM = PN_TRACE_FRM
64 TRACE_RAW = PN_TRACE_RAW
65
66 CLIENT = 1
67 SERVER = 2
68
69 @staticmethod
71 if impl is None:
72 return None
73 else:
74 return Transport(_impl=impl)
75
76 - def __init__(self, mode=None, _impl=pn_transport):
84
86 self._sasl = None
87 self._ssl = None
88 self._reactor = None
89
91 if err < 0:
92 exc = EXCEPTIONS.get(err, TransportException)
93 raise exc("[%s]: %s" % (err, pn_error_text(pn_transport_error(self._impl))))
94 else:
95 return err
96
99
101 adapter = pn_transport_get_pytracer(self._impl)
102 if adapter:
103 return adapter.tracer
104 else:
105 return None
106
107 tracer = property(_get_tracer, _set_tracer,
108 doc="""
109 A callback for trace logging. The callback is passed the transport and log message.
110 """)
111
112 - def log(self, message):
113 pn_transport_log(self._impl, message)
114
116 pn_transport_require_auth(self._impl, bool)
117
118 @property
120 return pn_transport_is_authenticated(self._impl)
121
123 pn_transport_require_encryption(self._impl, bool)
124
125 @property
127 return pn_transport_is_encrypted(self._impl)
128
129 @property
131 return pn_transport_get_user(self._impl)
132
133 - def bind(self, connection):
134 """Assign a connection to the transport"""
135 self._check(pn_transport_bind(self._impl, connection._impl))
136
138 """Assign a connection to the transport"""
139 pn_transport_bind(self._impl, connection._impl)
140
142 """Release the connection"""
143 self._check(pn_transport_unbind(self._impl))
144
146 pn_transport_trace(self._impl, n)
147
148 - def tick(self, now):
149 """Process any timed events (like heartbeat generation).
150 now = seconds since epoch (float).
151 """
152 return millis2secs(pn_transport_tick(self._impl, secs2millis(now)))
153
155 c = pn_transport_capacity(self._impl)
156 if c >= PN_EOS:
157 return c
158 else:
159 return self._check(c)
160
161 - def push(self, binary):
162 n = self._check(pn_transport_push(self._impl, binary))
163 if n != len(binary):
164 raise OverflowError("unable to process all bytes: %s, %s" % (n, len(binary)))
165
167 self._check(pn_transport_close_tail(self._impl))
168
170 p = pn_transport_pending(self._impl)
171 if p >= PN_EOS:
172 return p
173 else:
174 return self._check(p)
175
176 - def peek(self, size):
177 cd, out = pn_transport_peek(self._impl, size)
178 if cd == PN_EOS:
179 return None
180 else:
181 self._check(cd)
182 return out
183
184 - def pop(self, size):
185 pn_transport_pop(self._impl, size)
186
188 self._check(pn_transport_close_head(self._impl))
189
190 @property
192 return pn_transport_closed(self._impl)
193
194
196 return pn_transport_get_max_frame(self._impl)
197
199 pn_transport_set_max_frame(self._impl, value)
200
201 max_frame_size = property(_get_max_frame_size, _set_max_frame_size,
202 doc="""
203 Sets the maximum size for received frames (in bytes).
204 """)
205
206 @property
208 return pn_transport_get_remote_max_frame(self._impl)
209
211 return pn_transport_get_channel_max(self._impl)
212
214 if pn_transport_set_channel_max(self._impl, value):
215 raise SessionException("Too late to change channel max.")
216
217 channel_max = property(_get_channel_max, _set_channel_max,
218 doc="""
219 Sets the maximum channel that may be used on the transport.
220 """)
221
222 @property
224 return pn_transport_remote_channel_max(self._impl)
225
226
228 return millis2secs(pn_transport_get_idle_timeout(self._impl))
229
231 pn_transport_set_idle_timeout(self._impl, secs2millis(sec))
232
233 idle_timeout = property(_get_idle_timeout, _set_idle_timeout,
234 doc="""
235 The idle timeout of the connection (float, in seconds).
236 """)
237
238 @property
240 return millis2secs(pn_transport_get_remote_idle_timeout(self._impl))
241
242 @property
244 return pn_transport_get_frames_output(self._impl)
245
246 @property
249
252
253 - def ssl(self, domain=None, session_details=None):
254
255 if not self._ssl:
256 self._ssl = SSL(self, domain, session_details)
257 return self._ssl
258
260 return cond2obj(pn_transport_condition(self._impl))
261
263 pn_cond = pn_transport_condition(self._impl)
264 obj2cond(cond, pn_cond)
265
266 condition = property(_get_condition, _set_condition,
267 doc="""
268 The error condition (if any) of the transport.
269 """)
270
271 @property
275
279
280
281 -class SASL(Wrapper):
282 OK = PN_SASL_OK
283 AUTH = PN_SASL_AUTH
284 SYS = PN_SASL_SYS
285 PERM = PN_SASL_PERM
286 TEMP = PN_SASL_TEMP
287
288 @staticmethod
290 return pn_sasl_extended()
291
295
302
303 @property
305 return pn_sasl_get_user(self._sasl)
306
307 @property
309 return pn_sasl_get_mech(self._sasl)
310
311 @property
313 outcome = pn_sasl_outcome(self._sasl)
314 if outcome == PN_SASL_NONE:
315 return None
316 else:
317 return outcome
318
320 if isinstance(mechs, list):
321 mechs = " ".join(mechs)
322 pn_sasl_allowed_mechs(self._sasl, unicode2utf8(mechs))
323
325 return pn_sasl_get_allow_insecure_mechs(self._sasl)
326
328 pn_sasl_set_allow_insecure_mechs(self._sasl, insecure)
329
330 allow_insecure_mechs = property(_get_allow_insecure_mechs, _set_allow_insecure_mechs,
331 doc="""
332 Allow unencrypted cleartext passwords (PLAIN mech)
333 """)
334
335 - def done(self, outcome):
336 pn_sasl_done(self._sasl, outcome)
337
339 pn_sasl_config_name(self._sasl, name)
340
342 pn_sasl_config_path(self._sasl, path)
343
344
345 -class SSLDomain(object):
346 MODE_CLIENT = PN_SSL_MODE_CLIENT
347 MODE_SERVER = PN_SSL_MODE_SERVER
348 VERIFY_PEER = PN_SSL_VERIFY_PEER
349 VERIFY_PEER_NAME = PN_SSL_VERIFY_PEER_NAME
350 ANONYMOUS_PEER = PN_SSL_ANONYMOUS_PEER
351
352 - def __init__(self, mode):
353 self._domain = pn_ssl_domain(mode)
354 if self._domain is None:
355 raise SSLUnavailable()
356
357 - def _check(self, err):
358 if err < 0:
359 exc = EXCEPTIONS.get(err, SSLException)
360 raise exc("SSL failure.")
361 else:
362 return err
363
364 - def set_credentials(self, cert_file, key_file, password):
365 return self._check(pn_ssl_domain_set_credentials(self._domain,
366 cert_file, key_file,
367 password))
368
369 - def set_trusted_ca_db(self, certificate_db):
370 return self._check(pn_ssl_domain_set_trusted_ca_db(self._domain,
371 certificate_db))
372
373 - def set_peer_authentication(self, verify_mode, trusted_CAs=None):
374 return self._check(pn_ssl_domain_set_peer_authentication(self._domain,
375 verify_mode,
376 trusted_CAs))
377
379 return self._check(pn_ssl_domain_allow_unsecured_client(self._domain))
380
382 pn_ssl_domain_free(self._domain)
383
384
385 -class SSL(object):
386
387 @staticmethod
389 return pn_ssl_present()
390
397
398 - def __new__(cls, transport, domain, session_details=None):
399 """Enforce a singleton SSL object per Transport"""
400 if transport._ssl:
401
402
403
404 ssl = transport._ssl
405 if (domain and (ssl._domain is not domain) or
406 session_details and (ssl._session_details is not session_details)):
407 raise SSLException("Cannot re-configure existing SSL object!")
408 else:
409 obj = super(SSL, cls).__new__(cls)
410 obj._domain = domain
411 obj._session_details = session_details
412 session_id = None
413 if session_details:
414 session_id = session_details.get_session_id()
415 obj._ssl = pn_ssl(transport._impl)
416 if obj._ssl is None:
417 raise SSLUnavailable()
418 if domain:
419 pn_ssl_init(obj._ssl, domain._domain, session_id)
420 transport._ssl = obj
421 return transport._ssl
422
424 rc, name = pn_ssl_get_cipher_name(self._ssl, 128)
425 if rc:
426 return name
427 return None
428
430 rc, name = pn_ssl_get_protocol_name(self._ssl, 128)
431 if rc:
432 return name
433 return None
434
435 SHA1 = PN_SSL_SHA1
436 SHA256 = PN_SSL_SHA256
437 SHA512 = PN_SSL_SHA512
438 MD5 = PN_SSL_MD5
439
440 CERT_COUNTRY_NAME = PN_SSL_CERT_SUBJECT_COUNTRY_NAME
441 CERT_STATE_OR_PROVINCE = PN_SSL_CERT_SUBJECT_STATE_OR_PROVINCE
442 CERT_CITY_OR_LOCALITY = PN_SSL_CERT_SUBJECT_CITY_OR_LOCALITY
443 CERT_ORGANIZATION_NAME = PN_SSL_CERT_SUBJECT_ORGANIZATION_NAME
444 CERT_ORGANIZATION_UNIT = PN_SSL_CERT_SUBJECT_ORGANIZATION_UNIT
445 CERT_COMMON_NAME = PN_SSL_CERT_SUBJECT_COMMON_NAME
446
448 subfield_value = pn_ssl_get_remote_subject_subfield(self._ssl, subfield_name)
449 return subfield_value
450
454
458
459
462
465
468
471
474
477
479 rc, fingerprint_str = pn_ssl_get_cert_fingerprint(self._ssl, fingerprint_length, digest_name)
480 if rc == PN_OK:
481 return fingerprint_str
482 return None
483
484
487
490
494
498
501
502 @property
504 return pn_ssl_get_remote_subject(self._ssl)
505
506 RESUME_UNKNOWN = PN_SSL_RESUME_UNKNOWN
507 RESUME_NEW = PN_SSL_RESUME_NEW
508 RESUME_REUSED = PN_SSL_RESUME_REUSED
509
511 return pn_ssl_resume_status(self._ssl)
512
515
517 err, name = pn_ssl_get_peer_hostname(self._ssl, 1024)
518 self._check(err)
519 return utf82unicode(name)
520
521 peer_hostname = property(_get_peer_hostname, _set_peer_hostname,
522 doc="""
523 Manage the expected name of the remote peer. Used to authenticate the remote.
524 """)
525
528 """ Unique identifier for the SSL session. Used to resume previous session on a new
529 SSL connection.
530 """
531
533 self._session_id = session_id
534
536 return self._session_id
537