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_SASL_AUTH, PN_SASL_PERM, PN_SASL_SYS, PN_SSL_RESUME_REUSED, PN_SASL_NONE, PN_SSL_SHA1, \
23 PN_SSL_CERT_SUBJECT_COUNTRY_NAME, PN_SASL_OK, PN_SSL_RESUME_UNKNOWN, PN_EOS, PN_SSL_ANONYMOUS_PEER, PN_SSL_MD5, \
24 PN_SSL_CERT_SUBJECT_COMMON_NAME, PN_SSL_VERIFY_PEER, PN_SSL_CERT_SUBJECT_CITY_OR_LOCALITY, PN_SSL_MODE_SERVER, \
25 PN_TRACE_DRV, PN_TRACE_RAW, pn_transport, PN_SSL_SHA256, PN_TRACE_FRM, PN_SSL_MODE_CLIENT, PN_SASL_TEMP, \
26 PN_SSL_SHA512, PN_SSL_CERT_SUBJECT_ORGANIZATION_UNIT, PN_OK, PN_SSL_CERT_SUBJECT_STATE_OR_PROVINCE, \
27 PN_SSL_VERIFY_PEER_NAME, PN_SSL_CERT_SUBJECT_ORGANIZATION_NAME, PN_SSL_RESUME_NEW, PN_TRACE_OFF, \
28 pn_transport_get_channel_max, pn_transport_capacity, pn_transport_push, pn_transport_get_user, pn_transport_tick, \
29 pn_transport_set_max_frame, pn_transport_attachments, pn_transport_unbind, pn_transport_peek, \
30 pn_transport_set_channel_max, pn_transport_close_tail, pn_transport_condition, pn_transport_is_encrypted, \
31 pn_transport_get_frames_input, pn_transport_bind, pn_transport_closed, pn_transport_get_idle_timeout, \
32 pn_transport_get_remote_idle_timeout, pn_transport_get_frames_output, pn_transport_pending, \
33 pn_transport_set_pytracer, pn_transport_close_head, pn_transport_get_remote_max_frame, \
34 pn_transport_is_authenticated, pn_transport_set_idle_timeout, pn_transport_log, pn_transport_get_pytracer, \
35 pn_transport_require_auth, pn_transport_get_max_frame, pn_transport_set_server, pn_transport_remote_channel_max, \
36 pn_transport_require_encryption, pn_transport_pop, pn_transport_connection, \
37 pn_sasl, pn_sasl_set_allow_insecure_mechs, pn_sasl_outcome, pn_transport_error, pn_sasl_get_user, \
38 pn_sasl_extended, pn_sasl_done, pn_sasl_get_allow_insecure_mechs, pn_sasl_allowed_mechs, \
39 pn_sasl_config_name, pn_sasl_config_path, \
40 pn_ssl, pn_ssl_init, pn_ssl_domain_allow_unsecured_client, pn_ssl_domain_free, \
41 pn_ssl_domain, pn_transport_trace, pn_ssl_resume_status, pn_sasl_get_mech, \
42 pn_ssl_domain_set_trusted_ca_db, pn_ssl_get_remote_subject_subfield, pn_ssl_present, \
43 pn_ssl_get_remote_subject, pn_ssl_domain_set_credentials, pn_ssl_domain_set_peer_authentication, \
44 pn_ssl_get_peer_hostname, pn_ssl_set_peer_hostname, pn_ssl_get_cipher_name, pn_ssl_get_cert_fingerprint, \
45 pn_ssl_get_protocol_name, \
46 pn_error_text
47
48 from ._common import millis2secs, secs2millis, unicode2utf8, utf82unicode
49 from ._condition import cond2obj
50 from ._exceptions import EXCEPTIONS, TransportException, SessionException, SSLException, SSLUnavailable
51 from ._wrapper import Wrapper
55
58
59 - def __call__(self, trans_impl, message):
61
64 TRACE_OFF = PN_TRACE_OFF
65 TRACE_DRV = PN_TRACE_DRV
66 TRACE_FRM = PN_TRACE_FRM
67 TRACE_RAW = PN_TRACE_RAW
68
69 CLIENT = 1
70 SERVER = 2
71
72 @staticmethod
74 if impl is None:
75 return None
76 else:
77 return Transport(_impl=impl)
78
79 - def __init__(self, mode=None, _impl=pn_transport):
87
89 self._sasl = None
90 self._ssl = None
91
93 if err < 0:
94 exc = EXCEPTIONS.get(err, TransportException)
95 raise exc("[%s]: %s" % (err, pn_error_text(pn_transport_error(self._impl))))
96 else:
97 return err
98
101
103 adapter = pn_transport_get_pytracer(self._impl)
104 if adapter:
105 return adapter.tracer
106 else:
107 return None
108
109 tracer = property(_get_tracer, _set_tracer,
110 doc="""
111 A callback for trace logging. The callback is passed the transport and log message.
112 """)
113
114 - def log(self, message):
115 pn_transport_log(self._impl, message)
116
118 pn_transport_require_auth(self._impl, bool)
119
120 @property
122 return pn_transport_is_authenticated(self._impl)
123
125 pn_transport_require_encryption(self._impl, bool)
126
127 @property
129 return pn_transport_is_encrypted(self._impl)
130
131 @property
133 return pn_transport_get_user(self._impl)
134
135 - def bind(self, connection):
136 """Assign a connection to the transport"""
137 self._check(pn_transport_bind(self._impl, connection._impl))
138
140 """Release the connection"""
141 self._check(pn_transport_unbind(self._impl))
142
144 pn_transport_trace(self._impl, n)
145
146 - def tick(self, now):
147 """Process any timed events (like heartbeat generation).
148 now = seconds since epoch (float).
149 """
150 return millis2secs(pn_transport_tick(self._impl, secs2millis(now)))
151
153 c = pn_transport_capacity(self._impl)
154 if c >= PN_EOS:
155 return c
156 else:
157 return self._check(c)
158
159 - def push(self, binary):
160 n = self._check(pn_transport_push(self._impl, binary))
161 if n != len(binary):
162 raise OverflowError("unable to process all bytes: %s, %s" % (n, len(binary)))
163
165 self._check(pn_transport_close_tail(self._impl))
166
168 p = pn_transport_pending(self._impl)
169 if p >= PN_EOS:
170 return p
171 else:
172 return self._check(p)
173
174 - def peek(self, size):
175 cd, out = pn_transport_peek(self._impl, size)
176 if cd == PN_EOS:
177 return None
178 else:
179 self._check(cd)
180 return out
181
182 - def pop(self, size):
183 pn_transport_pop(self._impl, size)
184
186 self._check(pn_transport_close_head(self._impl))
187
188 @property
190 return pn_transport_closed(self._impl)
191
192
194 return pn_transport_get_max_frame(self._impl)
195
197 pn_transport_set_max_frame(self._impl, value)
198
199 max_frame_size = property(_get_max_frame_size, _set_max_frame_size,
200 doc="""
201 Sets the maximum size for received frames (in bytes).
202 """)
203
204 @property
206 return pn_transport_get_remote_max_frame(self._impl)
207
209 return pn_transport_get_channel_max(self._impl)
210
212 if pn_transport_set_channel_max(self._impl, value):
213 raise SessionException("Too late to change channel max.")
214
215 channel_max = property(_get_channel_max, _set_channel_max,
216 doc="""
217 Sets the maximum channel that may be used on the transport.
218 """)
219
220 @property
222 return pn_transport_remote_channel_max(self._impl)
223
224
226 return millis2secs(pn_transport_get_idle_timeout(self._impl))
227
229 pn_transport_set_idle_timeout(self._impl, secs2millis(sec))
230
231 idle_timeout = property(_get_idle_timeout, _set_idle_timeout,
232 doc="""
233 The idle timeout of the connection (float, in seconds).
234 """)
235
236 @property
238 return millis2secs(pn_transport_get_remote_idle_timeout(self._impl))
239
240 @property
242 return pn_transport_get_frames_output(self._impl)
243
244 @property
247
250
251 - def ssl(self, domain=None, session_details=None):
252
253 if not self._ssl:
254 self._ssl = SSL(self, domain, session_details)
255 return self._ssl
256
257 @property
259 return cond2obj(pn_transport_condition(self._impl))
260
261 @property
265
269
270
271 -class SASL(Wrapper):
272 OK = PN_SASL_OK
273 AUTH = PN_SASL_AUTH
274 SYS = PN_SASL_SYS
275 PERM = PN_SASL_PERM
276 TEMP = PN_SASL_TEMP
277
278 @staticmethod
280 return pn_sasl_extended()
281
285
292
293 @property
295 return pn_sasl_get_user(self._sasl)
296
297 @property
299 return pn_sasl_get_mech(self._sasl)
300
301 @property
303 outcome = pn_sasl_outcome(self._sasl)
304 if outcome == PN_SASL_NONE:
305 return None
306 else:
307 return outcome
308
311
313 return pn_sasl_get_allow_insecure_mechs(self._sasl)
314
316 pn_sasl_set_allow_insecure_mechs(self._sasl, insecure)
317
318 allow_insecure_mechs = property(_get_allow_insecure_mechs, _set_allow_insecure_mechs,
319 doc="""
320 Allow unencrypted cleartext passwords (PLAIN mech)
321 """)
322
323 - def done(self, outcome):
324 pn_sasl_done(self._sasl, outcome)
325
327 pn_sasl_config_name(self._sasl, name)
328
330 pn_sasl_config_path(self._sasl, path)
331
332
333 -class SSLDomain(object):
334 MODE_CLIENT = PN_SSL_MODE_CLIENT
335 MODE_SERVER = PN_SSL_MODE_SERVER
336 VERIFY_PEER = PN_SSL_VERIFY_PEER
337 VERIFY_PEER_NAME = PN_SSL_VERIFY_PEER_NAME
338 ANONYMOUS_PEER = PN_SSL_ANONYMOUS_PEER
339
340 - def __init__(self, mode):
341 self._domain = pn_ssl_domain(mode)
342 if self._domain is None:
343 raise SSLUnavailable()
344
345 - def _check(self, err):
346 if err < 0:
347 exc = EXCEPTIONS.get(err, SSLException)
348 raise exc("SSL failure.")
349 else:
350 return err
351
352 - def set_credentials(self, cert_file, key_file, password):
353 return self._check(pn_ssl_domain_set_credentials(self._domain,
354 cert_file, key_file,
355 password))
356
357 - def set_trusted_ca_db(self, certificate_db):
358 return self._check(pn_ssl_domain_set_trusted_ca_db(self._domain,
359 certificate_db))
360
361 - def set_peer_authentication(self, verify_mode, trusted_CAs=None):
362 return self._check(pn_ssl_domain_set_peer_authentication(self._domain,
363 verify_mode,
364 trusted_CAs))
365
367 return self._check(pn_ssl_domain_allow_unsecured_client(self._domain))
368
370 pn_ssl_domain_free(self._domain)
371
372
373 -class SSL(object):
374
375 @staticmethod
377 return pn_ssl_present()
378
385
386 - def __new__(cls, transport, domain, session_details=None):
387 """Enforce a singleton SSL object per Transport"""
388 if transport._ssl:
389
390
391
392 ssl = transport._ssl
393 if (domain and (ssl._domain is not domain) or
394 session_details and (ssl._session_details is not session_details)):
395 raise SSLException("Cannot re-configure existing SSL object!")
396 else:
397 obj = super(SSL, cls).__new__(cls)
398 obj._domain = domain
399 obj._session_details = session_details
400 session_id = None
401 if session_details:
402 session_id = session_details.get_session_id()
403 obj._ssl = pn_ssl(transport._impl)
404 if obj._ssl is None:
405 raise SSLUnavailable()
406 if domain:
407 pn_ssl_init(obj._ssl, domain._domain, session_id)
408 transport._ssl = obj
409 return transport._ssl
410
412 rc, name = pn_ssl_get_cipher_name(self._ssl, 128)
413 if rc:
414 return name
415 return None
416
418 rc, name = pn_ssl_get_protocol_name(self._ssl, 128)
419 if rc:
420 return name
421 return None
422
423 SHA1 = PN_SSL_SHA1
424 SHA256 = PN_SSL_SHA256
425 SHA512 = PN_SSL_SHA512
426 MD5 = PN_SSL_MD5
427
428 CERT_COUNTRY_NAME = PN_SSL_CERT_SUBJECT_COUNTRY_NAME
429 CERT_STATE_OR_PROVINCE = PN_SSL_CERT_SUBJECT_STATE_OR_PROVINCE
430 CERT_CITY_OR_LOCALITY = PN_SSL_CERT_SUBJECT_CITY_OR_LOCALITY
431 CERT_ORGANIZATION_NAME = PN_SSL_CERT_SUBJECT_ORGANIZATION_NAME
432 CERT_ORGANIZATION_UNIT = PN_SSL_CERT_SUBJECT_ORGANIZATION_UNIT
433 CERT_COMMON_NAME = PN_SSL_CERT_SUBJECT_COMMON_NAME
434
436 subfield_value = pn_ssl_get_remote_subject_subfield(self._ssl, subfield_name)
437 return subfield_value
438
442
446
447
450
453
456
459
462
465
467 rc, fingerprint_str = pn_ssl_get_cert_fingerprint(self._ssl, fingerprint_length, digest_name)
468 if rc == PN_OK:
469 return fingerprint_str
470 return None
471
472
475
478
482
486
489
490 @property
492 return pn_ssl_get_remote_subject(self._ssl)
493
494 RESUME_UNKNOWN = PN_SSL_RESUME_UNKNOWN
495 RESUME_NEW = PN_SSL_RESUME_NEW
496 RESUME_REUSED = PN_SSL_RESUME_REUSED
497
499 return pn_ssl_resume_status(self._ssl)
500
503
505 err, name = pn_ssl_get_peer_hostname(self._ssl, 1024)
506 self._check(err)
507 return utf82unicode(name)
508
509 peer_hostname = property(_get_peer_hostname, _set_peer_hostname,
510 doc="""
511 Manage the expected name of the remote peer. Used to authenticate the remote.
512 """)
513
516 """ Unique identifier for the SSL session. Used to resume previous session on a new
517 SSL connection.
518 """
519
521 self._session_id = session_id
522
524 return self._session_id
525