|
23 | 23 | InvalidRequest, Unauthorized, AuthenticationFailed, OperationTimedOut, UnsupportedOperation, RequestValidationException, ConfigurationException, ProtocolVersion |
24 | 24 | from cassandra.cluster import _Scheduler, Session, Cluster, default_lbp_factory, \ |
25 | 25 | ExecutionProfile, _ConfigMode, EXEC_PROFILE_DEFAULT |
| 26 | +from cassandra.connection import SSLSessionCache |
26 | 27 | from cassandra.pool import Host |
27 | 28 | from cassandra.policies import HostDistance, RetryPolicy, RoundRobinPolicy, DowngradingConsistencyRetryPolicy, SimpleConvictionPolicy |
28 | 29 | from cassandra.query import SimpleStatement, named_tuple_factory, tuple_factory |
@@ -634,3 +635,95 @@ def test_no_warning_adding_lbp_ep_to_cluster_with_contact_points(self): |
634 | 635 | ) |
635 | 636 |
|
636 | 637 | patched_logger.warning.assert_not_called() |
| 638 | + |
| 639 | + |
| 640 | +class TestSSLSessionCacheAutoCreation(unittest.TestCase): |
| 641 | + |
| 642 | + def test_cache_created_when_ssl_context_set(self): |
| 643 | + import ssl |
| 644 | + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) |
| 645 | + ctx.check_hostname = False |
| 646 | + ctx.verify_mode = ssl.CERT_NONE |
| 647 | + cluster = Cluster(contact_points=['127.0.0.1'], ssl_context=ctx) |
| 648 | + assert isinstance(cluster.ssl_session_cache, SSLSessionCache) |
| 649 | + |
| 650 | + def test_cache_created_when_ssl_options_set(self): |
| 651 | + cluster = Cluster(contact_points=['127.0.0.1'], ssl_options={'ca_certs': '/dev/null'}) |
| 652 | + assert isinstance(cluster.ssl_session_cache, SSLSessionCache) |
| 653 | + |
| 654 | + def test_no_cache_when_tls_not_enabled(self): |
| 655 | + cluster = Cluster(contact_points=['127.0.0.1']) |
| 656 | + assert cluster.ssl_session_cache is None |
| 657 | + |
| 658 | + def test_explicit_none_disables_cache(self): |
| 659 | + import ssl |
| 660 | + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) |
| 661 | + ctx.check_hostname = False |
| 662 | + ctx.verify_mode = ssl.CERT_NONE |
| 663 | + cluster = Cluster(contact_points=['127.0.0.1'], ssl_context=ctx, |
| 664 | + ssl_session_cache=None) |
| 665 | + assert cluster.ssl_session_cache is None |
| 666 | + |
| 667 | + def test_explicit_custom_cache_used(self): |
| 668 | + import ssl |
| 669 | + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) |
| 670 | + ctx.check_hostname = False |
| 671 | + ctx.verify_mode = ssl.CERT_NONE |
| 672 | + custom = SSLSessionCache() |
| 673 | + cluster = Cluster(contact_points=['127.0.0.1'], ssl_context=ctx, |
| 674 | + ssl_session_cache=custom) |
| 675 | + assert cluster.ssl_session_cache is custom |
| 676 | + |
| 677 | + def test_cache_passed_to_connection_factory(self): |
| 678 | + import ssl |
| 679 | + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) |
| 680 | + ctx.check_hostname = False |
| 681 | + ctx.verify_mode = ssl.CERT_NONE |
| 682 | + endpoint = Mock(address='127.0.0.1') |
| 683 | + with patch.object(Cluster.connection_class, 'factory', autospec=True, return_value='connection') as factory: |
| 684 | + cluster = Cluster(contact_points=['127.0.0.1'], ssl_context=ctx) |
| 685 | + cluster.connection_factory(endpoint) |
| 686 | + |
| 687 | + assert factory.call_args.kwargs['ssl_session_cache'] is cluster.ssl_session_cache |
| 688 | + |
| 689 | + def test_warning_for_eventlet_connection_class(self): |
| 690 | + """A warning is logged when ssl_session_cache is set with EventletConnection.""" |
| 691 | + import ssl |
| 692 | + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) |
| 693 | + ctx.check_hostname = False |
| 694 | + ctx.verify_mode = ssl.CERT_NONE |
| 695 | + |
| 696 | + # Create a real class so issubclass() works throughout Cluster.__init__ |
| 697 | + from cassandra.connection import Connection as BaseConn |
| 698 | + class FakeEventletConnection(BaseConn): |
| 699 | + pass |
| 700 | + |
| 701 | + with patch('cassandra.cluster.EventletConnection', FakeEventletConnection, create=True), \ |
| 702 | + patch('cassandra.cluster.log') as patched_logger: |
| 703 | + Cluster(contact_points=['127.0.0.1'], ssl_context=ctx, |
| 704 | + connection_class=FakeEventletConnection) |
| 705 | + |
| 706 | + # At least one warning about pyOpenSSL |
| 707 | + warning_calls = [c for c in patched_logger.warning.call_args_list |
| 708 | + if 'pyOpenSSL' in str(c)] |
| 709 | + assert len(warning_calls) == 1 |
| 710 | + |
| 711 | + def test_warning_for_twisted_connection_class(self): |
| 712 | + """A warning is logged when ssl_session_cache is set with TwistedConnection.""" |
| 713 | + import ssl |
| 714 | + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) |
| 715 | + ctx.check_hostname = False |
| 716 | + ctx.verify_mode = ssl.CERT_NONE |
| 717 | + |
| 718 | + from cassandra.connection import Connection as BaseConn |
| 719 | + class FakeTwistedConnection(BaseConn): |
| 720 | + pass |
| 721 | + |
| 722 | + with patch('cassandra.cluster.TwistedConnection', FakeTwistedConnection, create=True), \ |
| 723 | + patch('cassandra.cluster.log') as patched_logger: |
| 724 | + Cluster(contact_points=['127.0.0.1'], ssl_context=ctx, |
| 725 | + connection_class=FakeTwistedConnection) |
| 726 | + |
| 727 | + warning_calls = [c for c in patched_logger.warning.call_args_list |
| 728 | + if 'pyOpenSSL' in str(c)] |
| 729 | + assert len(warning_calls) == 1 |
0 commit comments