def setUpClass(cls): """ Tests the delegation of sasl auth to an external auth service. Creates two routers, one acts as the authe service, the other configures the auth service plugin to point at this auth service. """ super(AuthServicePluginTest, cls).setUpClass() if not SASL.extended(): return cls.createSaslFiles() print('launching auth service...') auth_service_port = cls.tester.get_port() cls.tester.qdrouterd('auth_service', Qdrouterd.Config([ ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': auth_service_port, 'saslMechanisms':'PLAIN', 'authenticatePeer': 'yes'}), ('router', {'workerThreads': 1, 'id': 'auth_service', 'mode': 'standalone', 'saslConfigName': 'tests-mech-PLAIN', 'saslConfigPath': os.getcwd()}) ])).wait_ready() cls.router_port = cls.tester.get_port() cls.tester.qdrouterd('router', Qdrouterd.Config([ ('authServicePlugin', {'name':'myauth', 'authService': '127.0.0.1:%d' % auth_service_port}), ('listener', {'host': '0.0.0.0', 'port': cls.router_port, 'role': 'normal', 'saslPlugin':'myauth', 'saslMechanisms':'PLAIN'}), ('router', {'mode': 'standalone', 'id': 'router'}) ])).wait_ready()
def test_connected_tls_sasl_routers(self): """ Validates if all expected routers are connected in the network """ if not SASL.extended(): self.skipTest("Cyrus library not available. skipping test") router_nodes = self.get_router_nodes() self.assertTrue(router_nodes) for node in router_nodes: self.assertTrue(node in self.connected_tls_sasl_routers, "%s should not be connected" % node) # Router A and B are always expected (no tls version restriction) expected_nodes = len(self.connected_tls_sasl_routers) # Router C only if TLSv1.2 is allowed if not RouterTestSslClient.OPENSSL_ALLOW_TLSV1_2: expected_nodes -= 1 # Router D only if TLSv1.1 is allowed if not RouterTestSslClient.OPENSSL_ALLOW_TLSV1_1: expected_nodes -= 1 self.assertEqual(len(router_nodes), expected_nodes)
def test_qdstat_connect_sasl_password_file(self): """ Make qdstat use sasl plain authentication with client password specified in a file. """ if not SASL.extended(): self.skipTest("Cyrus library not available. skipping test") password_file = os.getcwd() + '/sasl-client-password-file.txt' # Create a SASL configuration file. with open(password_file, 'w') as sasl_client_password_file: sasl_client_password_file.write("password") sasl_client_password_file.close() p = self.popen( ['qdstat', '-b', str(self.routers[0].addresses[2]), '-c', '--sasl-mechanisms=PLAIN', '[email protected]', '--sasl-password-file=' + password_file], name='qdstat-'+self.id(), stdout=PIPE, expect=None) out = p.communicate()[0] assert p.returncode == 0, \ "qdstat exit status %s, output:\n%s" % (p.returncode, out) split_list = out.split() # There will be 2 connections that have authenticated using SASL PLAIN. One inter-router connection # and the other connection that this qdstat client is making self.assertEqual(2, split_list.count("[email protected](PLAIN)")) self.assertEqual(1, split_list.count("inter-router")) self.assertEqual(1, split_list.count("normal"))
def test_inter_router_plain_over_ssl_exists(self): """The setUpClass sets up two routers with SASL PLAIN enabled over TLS/SSLv3. This test makes executes a query for type='org.apache.qpid.dispatch.connection' over an unauthenticated listener to QDR.X and makes sure that the output has an "inter-router" connection to QDR.Y whose authentication is PLAIN. This ensures that QDR.Y did not somehow use SASL ANONYMOUS to connect to QDR.X Also makes sure that TLSv1/SSLv3 was used as sslProto """ if not SASL.extended(): self.skipTest("Cyrus library not available. skipping test") local_node = Node.connect(self.routers[0].addresses[1], timeout=TIMEOUT) results = local_node.query(type='org.apache.qpid.dispatch.connection').results # sslProto should be TLSv1/SSLv3 self.assertEqual(u'TLSv1/SSLv3', results[0][10]) # role should be inter-router self.assertEqual(u'inter-router', results[0][3]) # sasl must be plain self.assertEqual(u'PLAIN', results[0][6]) # user must be [email protected] self.assertEqual(u'*****@*****.**', results[0][8])
def test_aaa_qdstat_connect_sasl_over_ssl(self): """ Make qdstat use sasl plain authentication over ssl. """ if not SASL.extended(): self.skipTest("Cyrus library not available. skipping test") p = self.popen( ['qdstat', '-b', str(self.routers[0].addresses[2]), '-c', # The following are SASL args '--sasl-mechanisms=PLAIN', '[email protected]', '--sasl-password=password', # The following are SSL args '--ssl-disable-peer-name-verify', '--ssl-trustfile=' + self.ssl_file('ca-certificate.pem'), '--ssl-certificate=' + self.ssl_file('client-certificate.pem'), '--ssl-key=' + self.ssl_file('client-private-key.pem'), '--ssl-password=client-password'], name='qdstat-'+self.id(), stdout=PIPE, expect=None) out = p.communicate()[0] assert p.returncode == 0, \ "qdstat exit status %s, output:\n%s" % (p.returncode, out) split_list = out.split() # There will be 2 connections that have authenticated using SASL PLAIN. One inter-router connection # and the other connection that this qdstat client is making self.assertEqual(2, split_list.count("[email protected](PLAIN)")) self.assertEqual(1, split_list.count("inter-router")) self.assertEqual(1, split_list.count("normal"))
def setUpClass(cls): """ Creates two routers (QDR.X and QDR.Y) and sets up PLAIN authentication on QDR.X. QDR.Y connects to QDR.X by providing a sasl_username and a sasl_password. """ super(RouterTestDeprecated, cls).setUpClass() if not SASL.extended(): return super(RouterTestDeprecated, cls).createSaslFiles() cls.routers = [] x_listener_port = cls.tester.get_port() y_listener_port = cls.tester.get_port() super(RouterTestDeprecated, cls).router('X', [ ('listener', {'addr': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port, 'saslMechanisms':'PLAIN', 'authenticatePeer': 'yes'}), # This unauthenticated listener is for qdstat to connect to it. ('listener', {'addr': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port(), 'authenticatePeer': 'no'}), ('container', {'workerThreads': 1, 'containerName': 'Qpid.Dispatch.Router.A', 'saslConfigName': 'tests-mech-PLAIN', 'saslConfigPath': os.getcwd()}), ('linkRoutePattern', {'prefix': 'org.apache'}), ('router', {'routerId': 'QDR.X', 'mode': 'interior'}), ('fixedAddress', {'prefix': '/closest/', 'fanout': 'single', 'bias': 'closest'}), ('fixedAddress', {'prefix': '/spread/', 'fanout': 'single', 'bias': 'spread'}), ('fixedAddress', {'prefix': '/multicast/', 'fanout': 'multiple'}), ('fixedAddress', {'prefix': '/', 'fanout': 'multiple'}), ]) super(RouterTestDeprecated, cls).router('Y', [ ('connector', {'addr': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port, 'saslMechanisms': 'PLAIN', 'saslUsername': '******', 'saslPassword': '******'}), ('router', {'mode': 'interior', 'routerId': 'QDR.Y'}), ('linkRoutePattern', {'prefix': 'org.apache'}), ('container', {'workerThreads': 1, 'containerName': 'Qpid.Dispatch.Router.Y'}), ('listener', {'addr': '0.0.0.0', 'role': 'normal', 'port': y_listener_port}), ('fixedAddress', {'prefix': '/closest/', 'fanout': 'single', 'bias': 'closest'}), ('fixedAddress', {'prefix': '/spread/', 'fanout': 'single', 'bias': 'spread'}), ('fixedAddress', {'prefix': '/multicast/', 'fanout': 'multiple'}), ('fixedAddress', {'prefix': '/', 'fanout': 'multiple'}), ]) cls.routers[1].wait_router_connected('QDR.X')
def test_deprecated(self): """ Tests deprecated attributes like linkRoutePattern, container, fixedAddress etc. This test makes executes a query for type='org.apache.qpid.dispatch.connection' over an unauthenticated listener to QDR.X and makes sure that the output has an "inter-router" connection to QDR.Y whose authentication is PLAIN. This ensures that QDR.Y did not somehow use SASL ANONYMOUS to connect to QDR.X Also makes sure that TLSv1/SSLv3 was used as sslProto """ if not SASL.extended(): self.skipTest("Cyrus library not available. skipping test") local_node = Node.connect(self.routers[0].addresses[1], timeout=TIMEOUT) # saslConfigName and saslConfigPath were set in the ContainerEntity. This tests makes sure that the # saslConfigName and saslConfigPath were loaded properly from the ContainerEntity. # ContainerEntity has been deprecated. # role should be inter-router self.assertEqual(u'inter-router', local_node.query(type='org.apache.qpid.dispatch.connection').results[0][3]) # sasl must be plain self.assertEqual(u'PLAIN', local_node.query(type='org.apache.qpid.dispatch.connection').results[0][6]) # user must be [email protected] self.assertEqual(u'*****@*****.**', local_node.query(type='org.apache.qpid.dispatch.connection').results[0][8]) # Make sure that the deprecated linkRoutePattern is set up correctly query_response = local_node.query(type='org.apache.qpid.dispatch.router.config.linkRoute') self.assertEqual(2, len(query_response.results)) self.assertEqual("in", query_response.results[0][7]) self.assertEqual("out", query_response.results[1][7]) results = local_node.query(type='org.apache.qpid.dispatch.router.config.address').results multicast_found = False spread_found = False closest_found = False for result in results: if result[3] == 'closest': closest_found = True self.assertEqual(result[4], 'closest') if result[3] == 'spread': spread_found = True self.assertEqual(result[4], 'balanced') if result[3] == 'multicast': multicast_found = True self.assertEqual(result[4], 'multicast') self.assertTrue(multicast_found) self.assertTrue(spread_found) self.assertTrue(closest_found)
def test_ssl_sasl_client_invalid(self): """ Attempts to connect a Proton client using a valid SASL authentication info and forcing the TLS protocol version, which should be rejected by the listener. :return: """ if not SASL.extended(): self.skipTest("Cyrus library not available. skipping test") exp_tls_results = self.get_expected_tls_result([True, False, True, False]) self.assertEqual(exp_tls_results[1], self.is_ssl_sasl_client_accepted(self.PORT_TLS_SASL, "TLSv1.1"))
def test_inter_router_plain_over_ssl_exists(self): """ Tests to make sure that an inter-router connection exists between the routers since verifyHostName is 'no'. """ if not SASL.extended(): self.skipTest("Cyrus library not available. skipping test") local_node = Node.connect(self.routers[1].addresses[0], timeout=TIMEOUT) results = local_node.query(type='org.apache.qpid.dispatch.connection').results self.common_asserts(results)
def test_valid_credentials(self): """ Check authentication succeeds when valid credentials are presented. """ if not SASL.extended(): self.skipTest("Cyrus library not available. skipping test") test = SimpleConnect("127.0.0.1:%d" % self.router_port, '*****@*****.**', 'password') test.run() self.assertEqual(True, test.connected) self.assertEqual(None, test.error)
def test_invalid_credentials(self): """ Check authentication fails when invalid credentials are presented. """ if not SASL.extended(): self.skipTest("Cyrus library not available. skipping test") test = SimpleConnect("127.0.0.1:%d" % self.router_port, '*****@*****.**', 'foo') test.run() self.assertEqual(False, test.connected) self.assertEqual('amqp:unauthorized-access', test.error.name) self.assertEqual(test.error.description.startswith('Authentication failed'), True)
def setUpClass(cls): """ Tests the sasl_username, sasl_password property of the dispatch router. Creates two routers (QDR.X and QDR.Y) and sets up PLAIN authentication on QDR.X. QDR.Y connects to QDR.X by providing a sasl_username and a sasl_password. """ super(RouterTestPlainSasl, cls).setUpClass() if not SASL.extended(): return super(RouterTestPlainSasl, cls).createSaslFiles() cls.routers = [] x_listener_port = cls.tester.get_port() y_listener_port = cls.tester.get_port() super(RouterTestPlainSasl, cls).router('X', [ ('listener', {'host': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port, 'saslMechanisms':'PLAIN', 'authenticatePeer': 'yes'}), # This unauthenticated listener is for qdstat to connect to it. ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port(), 'authenticatePeer': 'no'}), ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port(), 'saslMechanisms':'PLAIN', 'authenticatePeer': 'yes'}), ('router', {'workerThreads': 1, 'id': 'QDR.X', 'mode': 'interior', 'saslConfigName': 'tests-mech-PLAIN', # Leave as saslConfigPath for testing backward compatibility 'saslConfigPath': os.getcwd()}), ]) super(RouterTestPlainSasl, cls).router('Y', [ ('connector', {'host': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port, # Provide a sasl user name and password to connect to QDR.X 'saslMechanisms': 'PLAIN', 'saslUsername': '******', 'saslPassword': '******'}), ('router', {'workerThreads': 1, 'mode': 'interior', 'id': 'QDR.Y'}), ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': y_listener_port}), ]) cls.routers[1].wait_router_connected('QDR.X')
def get_router_nodes(self): """ Retrieves connected router nodes. :return: """ if not SASL.extended(): self.skipTest("Cyrus library not available. skipping test") url = Url("amqp://0.0.0.0:%d/$management" % self.PORT_NO_SSL) node = Node.connect(url) response = node.query(type="org.apache.qpid.dispatch.router.node", attribute_names=["id"]) router_nodes = [] for resp in response.get_dicts(): router_nodes.append(resp['id']) node.close() return router_nodes
def test_no_inter_router_connection(self): """ Tests to make sure that there are no 'inter-router' connections. The connection to the other router will not happen because the connection failed due to setting 'verifyHostName': 'yes' """ if not SASL.extended(): self.skipTest("Cyrus library not available. skipping test") local_node = Node.connect(self.routers[1].addresses[0], timeout=TIMEOUT) results = local_node.query(type='org.apache.qpid.dispatch.connection').results # There should be only two connections. # There will be no inter-router connection self.assertEqual(2, len(results)) self.assertEqual('in', results[0][4]) self.assertEqual('normal', results[0][3]) self.assertEqual('anonymous', results[0][8]) self.assertEqual('normal', results[1][3]) self.assertEqual('anonymous', results[1][8])
def test_zzz_delete_create_ssl_profile(self): """ Deletes a connector and its corresponding ssl profile and recreates both """ if not SASL.extended(): self.skipTest("Cyrus library not available. skipping test") local_node = self.routers[1].management connections = local_node.query(type='org.apache.qpid.dispatch.connection').get_entities() self.assertIn("QDR.X", [c.container for c in connections]) # We can find the connection before local_node.delete(type='connector', name='connectorToX') local_node.delete(type='sslProfile', name='client-ssl-profile') connections = local_node.query(type='org.apache.qpid.dispatch.connection').get_entities() self.assertNotIn("QDR.X", [c.container for c in connections]) # Should not be present now # re-create the ssl profile local_node.create({'type': 'sslProfile', 'name': 'client-ssl-profile', 'certFile': self.ssl_file('client-certificate.pem'), 'keyFile': self.ssl_file('client-private-key.pem'), 'password': '******', 'certDb': self.ssl_file('ca-certificate.pem')}) # re-create connector local_node.create({'type': 'connector', 'name': 'connectorToX', 'host': '127.0.0.1', 'port': self.x_listener_port, 'saslMechanisms': 'PLAIN', 'sslProfile': 'client-ssl-profile', 'role': 'inter-router', 'verifyHostName': False, 'saslUsername': '******', 'saslPassword': '******'}) self.routers[1].wait_connectors() results = local_node.query(type='org.apache.qpid.dispatch.connection').results self.common_asserts(results)
def test_inter_router_plain_exists(self): """ Check authentication of inter-router link is PLAIN. This test makes executes a qdstat -c via an unauthenticated listener to QDR.X and makes sure that the output has an "inter-router" connection to QDR.Y whose authentication is PLAIN. This ensures that QDR.Y did not somehow use SASL ANONYMOUS to connect to QDR.X """ if not SASL.extended(): self.skipTest("Cyrus library not available. skipping test") p = self.popen( ['qdstat', '-b', str(self.routers[0].addresses[1]), '-c'], name='qdstat-'+self.id(), stdout=PIPE, expect=None) out = p.communicate()[0] assert p.returncode == 0, \ "qdstat exit status %s, output:\n%s" % (p.returncode, out) self.assertIn("inter-router", out) self.assertIn("[email protected](PLAIN)", out)
def test_sasl_callbacks_old(self): """Verify sasl_done() callback is invoked""" if hasattr(SASL, "extended") and SASL.extended(): raise common.Skipped("Test does not apply") server_props = {'x-server': True, 'x-require-auth': True, 'x-sasl-mechs': 'PLAIN ANONYMOUS'} client_props = {'x-server': False, 'x-username': '******', 'x-password': '******', 'x-sasl-mechs': 'PLAIN ANONYMOUS'} class SaslCallbackServer(common.ConnCallback): def sasl_step(self, connection, pn_sasl): self.sasl_step_ct += 1 creds = pn_sasl.recv() if creds == "\x00user-foo\x00pass-word": pn_sasl.done(pn_sasl.OK) c1_events = SaslCallbackServer() c1 = self.container1.create_connection("c1", c1_events, properties=server_props) class SaslCallbackClient(common.ConnCallback): def sasl_done(self, connection, pn_sasl, result): assert result == pn_sasl.OK self.sasl_done_ct += 1 c2_events = SaslCallbackClient() c2 = self.container2.create_connection("c2", c2_events, properties=client_props) c1.open() c2.open() common.process_connections(c1, c2) assert c1.active and c2.active assert c2_events.sasl_done_ct == 1, c2_events.sasl_done_ct
def test_qdstat_connect_sasl(self): """ Make qdstat use sasl plain authentication. """ if not SASL.extended(): self.skipTest("Cyrus library not available. skipping test") p = self.popen( ['qdstat', '-b', str(self.routers[0].addresses[2]), '-c', '--sasl-mechanisms=PLAIN', '[email protected]', '--sasl-password=password'], name='qdstat-'+self.id(), stdout=PIPE, expect=None) out = p.communicate()[0] assert p.returncode == 0, \ "qdstat exit status %s, output:\n%s" % (p.returncode, out) split_list = out.split() # There will be 2 connections that have authenticated using SASL PLAIN. One inter-router connection # and the other connection that this qdstat client is making self.assertEqual(2, split_list.count("[email protected](PLAIN)")) self.assertEqual(1, split_list.count("inter-router")) self.assertEqual(1, split_list.count("normal"))
def setUpClass(cls): """ Prepares 5 routers to form a network. One of them will provide listeners with multiple sslProfiles, and the other 4 will try to connect with a respective listener. It expects that routers A to D will connect successfully, while E will not succeed due to an SSL handshake failure (as allowed TLS protocol versions won't match). """ super(RouterTestSslInterRouter, cls).setUpClass() if not SASL.extended(): return # Generate authentication DB super(RouterTestSslInterRouter, cls).create_sasl_files() # Router expected to be connected cls.connected_tls_sasl_routers = ['QDR.A', 'QDR.B', 'QDR.C', 'QDR.D'] # Generated router list cls.routers = [] # Saving listener ports for each TLS definition cls.PORT_NO_SSL = cls.tester.get_port() cls.PORT_TLS_ALL = cls.tester.get_port() cls.PORT_TLS12 = cls.tester.get_port() cls.PORT_TLS1_TLS12 = cls.tester.get_port() config_a = Qdrouterd.Config([ ('router', {'id': 'QDR.A', 'mode': 'interior', 'saslConfigName': 'tests-mech-PLAIN', 'saslConfigDir': os.getcwd()}), # No auth and no SSL ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_NO_SSL}), # All TLS versions ('listener', {'host': '0.0.0.0', 'role': 'inter-router', 'port': cls.PORT_TLS_ALL, 'authenticatePeer': 'yes', 'saslMechanisms': 'PLAIN', 'requireEncryption': 'yes', 'requireSsl': 'yes', 'sslProfile': 'ssl-profile-tls-all'}), # TLSv1.2 only ('listener', {'host': '0.0.0.0', 'role': 'inter-router', 'port': cls.PORT_TLS12, 'authenticatePeer': 'yes', 'saslMechanisms': 'PLAIN', 'requireEncryption': 'yes', 'requireSsl': 'yes', 'sslProfile': 'ssl-profile-tls12'}), # TLSv1 and TLSv1.2 only ('listener', {'host': '0.0.0.0', 'role': 'inter-router', 'port': cls.PORT_TLS1_TLS12, 'authenticatePeer': 'yes', 'saslMechanisms': 'PLAIN', 'requireEncryption': 'yes', 'requireSsl': 'yes', 'sslProfile': 'ssl-profile-tls1-tls12'}), # SSL Profile for all TLS versions (protocols element not defined) ('sslProfile', {'name': 'ssl-profile-tls-all', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'password': '******'}), # SSL Profile for TLSv1.2 ('sslProfile', {'name': 'ssl-profile-tls12', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1.2', 'password': '******'}), # SSL Profile for TLSv1 and TLSv1.2 ('sslProfile', {'name': 'ssl-profile-tls1-tls12', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1 TLSv1.2', 'password': '******'}) ]) # Router B will connect to listener that allows all protocols config_b = Qdrouterd.Config([ ('router', {'id': 'QDR.B', 'mode': 'interior'}), # Connector to All TLS versions allowed listener ('connector', {'host': '0.0.0.0', 'role': 'inter-router', 'port': cls.PORT_TLS_ALL, 'verifyHostname': 'no', 'saslMechanisms': 'PLAIN', 'saslUsername': '******', 'saslPassword': '******', 'sslProfile': 'ssl-profile-tls-all'}), # SSL Profile for all TLS versions (protocols element not defined) ('sslProfile', {'name': 'ssl-profile-tls-all', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('client-certificate.pem'), 'privateKeyFile': cls.ssl_file('client-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'password': '******'}) ]) # Router C will connect to listener that allows TLSv1.2 only config_c = Qdrouterd.Config([ ('router', {'id': 'QDR.C', 'mode': 'interior'}), # Connector to listener that allows TLSv1.2 only ('connector', {'host': '0.0.0.0', 'role': 'inter-router', 'port': cls.PORT_TLS12, 'verifyHostname': 'no', 'saslMechanisms': 'PLAIN', 'saslUsername': '******', 'saslPassword': '******', 'sslProfile': 'ssl-profile-tls12'}), # SSL Profile for TLSv1.2 ('sslProfile', {'name': 'ssl-profile-tls12', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('client-certificate.pem'), 'privateKeyFile': cls.ssl_file('client-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1.2', 'password': '******'}) ]) # Router D will connect to listener that allows TLSv1 and TLS1.2 only using TLSv1 config_d = Qdrouterd.Config([ ('router', {'id': 'QDR.D', 'mode': 'interior'}), # Connector to listener that allows TLSv1 and TLSv1.2 only ('connector', {'host': '0.0.0.0', 'role': 'inter-router', 'port': cls.PORT_TLS1_TLS12, 'verifyHostname': 'no', 'saslMechanisms': 'PLAIN', 'saslUsername': '******', 'saslPassword': '******', 'sslProfile': 'ssl-profile-tls1'}), # SSL Profile for TLSv1 ('sslProfile', {'name': 'ssl-profile-tls1', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('client-certificate.pem'), 'privateKeyFile': cls.ssl_file('client-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1', 'password': '******'}) ]) # Router E will try connect to listener that allows TLSv1 and TLS1.2 only using TLSv1.1 config_e = Qdrouterd.Config([ ('router', {'id': 'QDR.E', 'mode': 'interior'}), # Connector to listener that allows TLSv1 and TLSv1.2 only ('connector', {'host': '0.0.0.0', 'role': 'inter-router', 'port': cls.PORT_TLS1_TLS12, 'verifyHostname': 'no', 'saslMechanisms': 'PLAIN', 'saslUsername': '******', 'saslPassword': '******', 'sslProfile': 'ssl-profile-tls11'}), # SSL Profile for TLSv1.1 ('sslProfile', {'name': 'ssl-profile-tls11', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('client-certificate.pem'), 'privateKeyFile': cls.ssl_file('client-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1.1', 'password': '******'}) ]) cls.routers.append(cls.tester.qdrouterd("A", config_a, wait=False)) cls.routers.append(cls.tester.qdrouterd("B", config_b, wait=False)) cls.routers.append(cls.tester.qdrouterd("C", config_c, wait=False)) cls.routers.append(cls.tester.qdrouterd("D", config_d, wait=False)) cls.routers.append(cls.tester.qdrouterd("E", config_e, wait=False)) # Wait till listener is running and all expected connectors are connected cls.routers[0].wait_ports() for router in cls.connected_tls_sasl_routers[1:]: cls.routers[0].wait_router_connected(router)
def setUpClass(cls): """ Tests the verifyHostName property of the connector. The hostname on the server certificate we use is A1.Good.Server.domain.com and the host is 0.0.0.0 on the client router initiating the SSL connection. Since the host names do not match but verifyHostName is set to false, the client router will be successfully able to make an SSL connection the server router. """ super(RouterTestVerifyHostNameNo, cls).setUpClass() if not SASL.extended(): return super(RouterTestVerifyHostNameNo, cls).createSaslFiles() cls.routers = [] x_listener_port = cls.tester.get_port() RouterTestVerifyHostNameNo.x_listener_port = x_listener_port y_listener_port = cls.tester.get_port() super(RouterTestVerifyHostNameNo, cls).router('X', [ ('listener', {'addr': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port, 'sslProfile':'server-ssl-profile', 'saslMechanisms':'PLAIN', 'authenticatePeer': 'yes'}), # This unauthenticated listener is for qdstat to connect to it. ('listener', {'addr': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port(), 'authenticatePeer': 'no'}), ('sslProfile', {'name': 'server-ssl-profile', 'certDb': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'keyFile': cls.ssl_file('server-private-key.pem'), 'password': '******'}), ('router', {'workerThreads': 1, 'routerId': 'QDR.X', 'mode': 'interior', 'saslConfigName': 'tests-mech-PLAIN', 'saslConfigPath': os.getcwd()}), ]) super(RouterTestVerifyHostNameNo, cls).router('Y', [ # This router will act like a client. First an SSL connection will be established and then # we will have SASL plain authentication over SSL. ('connector', {'name': 'connectorToX', 'addr': '127.0.0.1', 'role': 'inter-router', 'port': x_listener_port, 'sslProfile': 'client-ssl-profile', # Provide a sasl user name and password to connect to QDR.X 'saslMechanisms': 'PLAIN', 'verifyHostName': 'no', 'saslUsername': '******', 'saslPassword': '******'}), ('router', {'workerThreads': 1, 'mode': 'interior', 'routerId': 'QDR.Y'}), ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': y_listener_port}), ('sslProfile', {'name': 'client-ssl-profile', 'certDb': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('client-certificate.pem'), 'keyFile': cls.ssl_file('client-private-key.pem'), 'password': '******'}), ]) cls.routers[0].wait_ports() cls.routers[1].wait_ports() cls.routers[1].wait_router_connected('QDR.X')
def setUpClass(cls): """ Prepares a single router with multiple listeners, each one associated with a particular sslProfile and each sslProfile has its own specific set of allowed protocols. """ super(RouterTestSslClient, cls).setUpClass() cls.routers = [] if not SASL.extended(): return # Generate authentication DB super(RouterTestSslClient, cls).create_sasl_files() # Saving listener ports for each TLS definition cls.PORT_TLS1 = cls.tester.get_port() cls.PORT_TLS11 = cls.tester.get_port() cls.PORT_TLS12 = cls.tester.get_port() cls.PORT_TLS1_TLS11 = cls.tester.get_port() cls.PORT_TLS1_TLS12 = cls.tester.get_port() cls.PORT_TLS11_TLS12 = cls.tester.get_port() cls.PORT_TLS_ALL = cls.tester.get_port() cls.PORT_TLS_SASL = cls.tester.get_port() cls.PORT_SSL3 = cls.tester.get_port() config = Qdrouterd.Config([ ('router', {'id': 'QDR.A', 'mode': 'interior', 'saslConfigName': 'tests-mech-PLAIN', 'saslConfigDir': os.getcwd()}), # TLSv1 only ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS1, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-tls1'}), # TLSv1.1 only ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS11, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-tls11'}), # TLSv1.2 only ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS12, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-tls12'}), # TLSv1 and TLSv1.1 only ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS1_TLS11, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-tls1-tls11'}), # TLSv1 and TLSv1.2 only ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS1_TLS12, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-tls1-tls12'}), # TLSv1.1 and TLSv1.2 only ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS11_TLS12, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-tls11-tls12'}), # All TLS versions ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS_ALL, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-tls-all'}), # Invalid protocol version ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_SSL3, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-ssl3'}), # TLS 1 and 1.2 with SASL PLAIN authentication for proton client validation ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS_SASL, 'authenticatePeer': 'yes', 'saslMechanisms': 'PLAIN', 'requireSsl': 'yes', 'requireEncryption': 'yes', 'sslProfile': 'ssl-profile-tls1-tls12'}), # SSL Profile for TLSv1 ('sslProfile', {'name': 'ssl-profile-tls1', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1', 'password': '******'}), # SSL Profile for TLSv1.1 ('sslProfile', {'name': 'ssl-profile-tls11', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1.1', 'password': '******'}), # SSL Profile for TLSv1.2 ('sslProfile', {'name': 'ssl-profile-tls12', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1.2', 'password': '******'}), # SSL Profile for TLSv1 and TLSv1.1 ('sslProfile', {'name': 'ssl-profile-tls1-tls11', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1 TLSv1.1', 'password': '******'}), # SSL Profile for TLSv1 and TLSv1.2 ('sslProfile', {'name': 'ssl-profile-tls1-tls12', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1 TLSv1.2', 'password': '******'}), # SSL Profile for TLSv1.1 and TLSv1.2 ('sslProfile', {'name': 'ssl-profile-tls11-tls12', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1.1 TLSv1.2', 'password': '******'}), # SSL Profile for all TLS versions (protocols element not defined) ('sslProfile', {'name': 'ssl-profile-tls-all', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'password': '******'}), # SSL Profile for invalid protocol version SSLv23 ('sslProfile', {'name': 'ssl-profile-ssl3', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'SSLv23', 'password': '******'}) ]) cls.routers.append(cls.tester.qdrouterd("A", config, wait=False)) cls.routers[0].wait_ports()
def setUpClass(cls): """ Tests the verifyHostName property of the connector. The hostname on the server certificate we use is A1.Good.Server.domain.com and the host is 0.0.0.0 on the client router initiating the SSL connection. Since the host names do not match and the verifyHostName is set to true, the client router will NOT be able make a successful SSL connection the server router. """ super(RouterTestVerifyHostNameYes, cls).setUpClass() if not SASL.extended(): return super(RouterTestVerifyHostNameYes, cls).createSaslFiles() cls.routers = [] x_listener_port = cls.tester.get_port() y_listener_port = cls.tester.get_port() super(RouterTestVerifyHostNameYes, cls).router('X', [ ('listener', {'addr': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port, 'sslProfile':'server-ssl-profile', 'saslMechanisms':'PLAIN', 'authenticatePeer': 'yes'}), # This unauthenticated listener is for qdstat to connect to it. ('listener', {'addr': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port(), 'authenticatePeer': 'no'}), ('sslProfile', {'name': 'server-ssl-profile', 'certDb': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'keyFile': cls.ssl_file('server-private-key.pem'), 'password': '******'}), ('router', {'workerThreads': 1, 'routerId': 'QDR.X', 'mode': 'interior', 'saslConfigName': 'tests-mech-PLAIN', 'saslConfigPath': os.getcwd()}), ]) super(RouterTestVerifyHostNameYes, cls).router('Y', [ ('connector', {'addr': '127.0.0.1', 'role': 'inter-router', 'port': x_listener_port, 'sslProfile': 'client-ssl-profile', 'verifyHostName': 'yes', 'saslMechanisms': 'PLAIN', 'saslUsername': '******', 'saslPassword': '******'}), ('router', {'workerThreads': 1, 'mode': 'interior', 'routerId': 'QDR.Y'}), ('listener', {'addr': '0.0.0.0', 'role': 'normal', 'port': y_listener_port}), ('sslProfile', {'name': 'client-ssl-profile', 'certDb': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('client-certificate.pem'), 'keyFile': cls.ssl_file('client-private-key.pem'), 'password': '******'}), ]) cls.routers[0].wait_ports() cls.routers[1].wait_ports() try: # This will time out because there is no inter-router connection cls.routers[1].wait_connectors(timeout=3) except: pass
def test_ssl_cert_to_auth_fail_no_sasl_external(self): if not SASL.extended(): self.skipTest("Cyrus library not available. skipping test") self.ssl_test_bad('auth_s', ['client_cert_all'])
conf = os.path.join(abs_conf_dir, 'proton-server.conf') f = open(conf, 'w') f.write(t.substitute(db=db)) f.close() cmd_template = Template("echo password | ${saslpasswd} -c -p -f ${db} -u proton user") cmd = cmd_template.substitute(db=db, saslpasswd=saslpasswd) subprocess.call(args=cmd, shell=True) os.environ['PN_SASL_CONFIG_PATH'] = abs_conf_dir global createdSASLDb createdSASLDb = True # Globally initialize Cyrus SASL configuration if SASL.extended(): _cyrusSetup('sasl-conf') def ensureCanTestExtendedSASL(): if not SASL.extended(): raise Skipped('Extended SASL not supported') if not createdSASLDb: raise Skipped("Can't Test Extended SASL: Couldn't create auth db") class DefaultConfig: defines = {} class Test(TestCase):
def setUpClass(cls): """ Tests the sasl_username, sasl_password property of the dispatch router. Creates two routers (QDR.X and QDR.Y) and sets up PLAIN authentication on QDR.X. QDR.Y connects to QDR.X by providing a sasl_username and a sasl_password. """ super(RouterTestPlainSasl, cls).setUpClass() if not SASL.extended(): return super(RouterTestPlainSasl, cls).createSaslFiles() cls.routers = [] x_listener_port = cls.tester.get_port() y_listener_port = cls.tester.get_port() super(RouterTestPlainSasl, cls).router( 'X', [ ('listener', { 'host': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port, 'saslMechanisms': 'PLAIN', 'authenticatePeer': 'yes' }), # This unauthenticated listener is for qdstat to connect to it. ('listener', { 'host': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port(), 'authenticatePeer': 'no' }), ('listener', { 'host': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port(), 'saslMechanisms': 'PLAIN', 'authenticatePeer': 'yes' }), ( 'router', { 'workerThreads': 1, 'id': 'QDR.X', 'mode': 'interior', 'saslConfigName': 'tests-mech-PLAIN', # Leave as saslConfigPath for testing backward compatibility 'saslConfigPath': os.getcwd() }), ]) super(RouterTestPlainSasl, cls).router( 'Y', [ ( 'connector', { 'host': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port, # Provide a sasl user name and password to connect to QDR.X 'saslMechanisms': 'PLAIN', 'saslUsername': '******', 'saslPassword': '******' }), ('router', { 'workerThreads': 1, 'mode': 'interior', 'id': 'QDR.Y' }), ('listener', { 'host': '0.0.0.0', 'role': 'normal', 'port': y_listener_port }), ]) cls.routers[1].wait_router_connected('QDR.X')
def ensureCanTestExtendedSASL(): if not SASL.extended(): raise Skipped('Extended SASL not supported') if not createdSASLDb: raise Skipped("Can't Test Extended SASL: Couldn't create auth db")
def setUpClass(cls): """ Tests the sasl_username, sasl_password property of the dispatch router. Creates two routers (QDR.X and QDR.Y) and sets up PLAIN authentication on QDR.X. QDR.Y connects to QDR.X by providing a sasl_username and a sasl_password. This PLAIN authentication is done over a TLS connection. """ super(RouterTestPlainSaslOverSsl, cls).setUpClass() if not SASL.extended(): return super(RouterTestPlainSaslOverSsl, cls).createSaslFiles() cls.routers = [] x_listener_port = cls.tester.get_port() y_listener_port = cls.tester.get_port() super(RouterTestPlainSaslOverSsl, cls).router('X', [ ('listener', { 'host': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port, 'sslProfile': 'server-ssl-profile', 'saslMechanisms': 'PLAIN', 'authenticatePeer': 'yes' }), ('listener', { 'host': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port(), 'authenticatePeer': 'no' }), ('listener', { 'host': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port(), 'sslProfile': 'server-ssl-profile', 'saslMechanisms': 'PLAIN', 'authenticatePeer': 'yes' }), ('sslProfile', { 'name': 'server-ssl-profile', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1.1 TLSv1.2', 'password': '******' }), ('router', { 'workerThreads': 1, 'id': 'QDR.X', 'mode': 'interior', 'saslConfigName': 'tests-mech-PLAIN', 'saslConfigDir': os.getcwd() }), ]) super(RouterTestPlainSaslOverSsl, cls).router( 'Y', [ # This router will act like a client. First an SSL connection will be established and then # we will have SASL plain authentication over SSL. ( 'connector', { 'host': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port, 'sslProfile': 'client-ssl-profile', 'verifyHostname': 'no', # Provide a sasl user name and password to connect to QDR.X 'saslMechanisms': 'PLAIN', 'saslUsername': '******', 'saslPassword': '******' }), ('router', { 'workerThreads': 1, 'mode': 'interior', 'id': 'QDR.Y' }), ('listener', { 'host': '0.0.0.0', 'role': 'normal', 'port': y_listener_port }), ('sslProfile', { 'name': 'client-ssl-profile', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('client-certificate.pem'), 'privateKeyFile': cls.ssl_file('client-private-key.pem'), 'password': '******' }), ]) cls.routers[1].wait_router_connected('QDR.X')
class AuthServicePluginTest(TestCase): @classmethod def createSaslFiles(cls): # Create a sasl database. p = Popen([ 'saslpasswd2', '-c', '-p', '-f', 'qdrouterd.sasldb', '-u', 'domain.com', 'test' ], stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True) result = p.communicate('password') assert p.returncode == 0, \ "saslpasswd2 exit status %s, output:\n%s" % (p.returncode, result) # Create a SASL configuration file. with open('tests-mech-PLAIN.conf', 'w') as sasl_conf: sasl_conf.write(""" pwcheck_method: auxprop auxprop_plugin: sasldb sasldb_path: qdrouterd.sasldb mech_list: SCRAM-SHA1 PLAIN # The following line stops spurious 'sql_select option missing' errors when cyrus-sql-sasl plugin is installed sql_select: dummy select """) @classmethod def setUpClass(cls): """ Tests the delegation of sasl auth to an external auth service. Creates two routers, one acts as the authe service, the other configures the auth service plugin to point at this auth service. """ super(AuthServicePluginTest, cls).setUpClass() if not SASL.extended(): return cls.createSaslFiles() print('launching auth service...') auth_service_port = cls.tester.get_port() cls.tester.qdrouterd( 'auth_service', Qdrouterd.Config([('listener', { 'host': '0.0.0.0', 'role': 'normal', 'port': auth_service_port, 'saslMechanisms': 'PLAIN', 'authenticatePeer': 'yes' }), ('router', { 'workerThreads': 1, 'id': 'auth_service', 'mode': 'standalone', 'saslConfigName': 'tests-mech-PLAIN', 'saslConfigPath': os.getcwd() })])).wait_ready() cls.router_port = cls.tester.get_port() cls.tester.qdrouterd( 'router', Qdrouterd.Config([('authServicePlugin', { 'name': 'myauth', 'host': '127.0.0.1', 'port': auth_service_port }), ('listener', { 'host': '0.0.0.0', 'port': cls.router_port, 'role': 'normal', 'saslPlugin': 'myauth', 'saslMechanisms': 'PLAIN' }), ('router', { 'mode': 'standalone', 'id': 'router' })])).wait_ready() @SkipIfNeeded(not SASL.extended(), "Cyrus library not available. skipping test") def test_valid_credentials(self): """ Check authentication succeeds when valid credentials are presented. """ test = SimpleConnect("127.0.0.1:%d" % self.router_port, '*****@*****.**', 'password') test.run() self.assertEqual(True, test.connected) self.assertEqual(None, test.error) @SkipIfNeeded(not SASL.extended(), "Cyrus library not available. skipping test") def test_invalid_credentials(self): """ Check authentication fails when invalid credentials are presented. """ test = SimpleConnect("127.0.0.1:%d" % self.router_port, '*****@*****.**', 'foo') test.run() self.assertEqual(False, test.connected) self.assertEqual('amqp:unauthorized-access', test.error.name) self.assertEqual( test.error.description.startswith('Authentication failed'), True)
def setUpClass(cls): """ Tests the verifyHostname property of the connector. The hostname on the server certificate we use is A1.Good.Server.domain.com and the host is 0.0.0.0 on the client router initiating the SSL connection. Since the host names do not match and the verifyHostname is set to true, the client router will NOT be able make a successful SSL connection the server router. """ super(RouterTestVerifyHostNameYes, cls).setUpClass() if not SASL.extended(): return super(RouterTestVerifyHostNameYes, cls).createSaslFiles() cls.routers = [] x_listener_port = cls.tester.get_port() y_listener_port = cls.tester.get_port() super(RouterTestVerifyHostNameYes, cls).router( 'X', [ ('listener', { 'host': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port, 'sslProfile': 'server-ssl-profile', 'saslMechanisms': 'PLAIN', 'authenticatePeer': 'yes' }), # This unauthenticated listener is for qdstat to connect to it. ('listener', { 'host': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port(), 'authenticatePeer': 'no' }), ('sslProfile', { 'name': 'server-ssl-profile', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'password': '******' }), ('router', { 'workerThreads': 1, 'id': 'QDR.X', 'mode': 'interior', 'saslConfigName': 'tests-mech-PLAIN', 'saslConfigDir': os.getcwd() }), ]) super(RouterTestVerifyHostNameYes, cls).router( 'Y', [ ( 'connector', { 'host': '127.0.0.1', 'role': 'inter-router', 'port': x_listener_port, 'sslProfile': 'client-ssl-profile', # verifyHostName has been deprecated. We are using it here to test # backward compatibility. 'verifyHostName': 'yes', 'saslMechanisms': 'PLAIN', 'saslUsername': '******', 'saslPassword': '******' }), ('router', { 'workerThreads': 1, 'mode': 'interior', 'id': 'QDR.Y' }), ('listener', { 'host': '0.0.0.0', 'role': 'normal', 'port': y_listener_port }), ('sslProfile', { 'name': 'client-ssl-profile', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('client-certificate.pem'), 'privateKeyFile': cls.ssl_file('client-private-key.pem'), 'password': '******' }), ]) cls.routers[0].wait_ports() cls.routers[1].wait_ports() try: # This will time out because there is no inter-router connection cls.routers[1].wait_connectors(timeout=3) except: pass
def setUpClass(cls): """ Tests the verifyHostname property of the connector. The hostname on the server certificate we use is A1.Good.Server.domain.com and the host is 0.0.0.0 on the client router initiating the SSL connection. Since the host names do not match but verifyHostname is set to false, the client router will be successfully able to make an SSL connection the server router. """ super(RouterTestVerifyHostNameNo, cls).setUpClass() if not SASL.extended(): return super(RouterTestVerifyHostNameNo, cls).createSaslFiles() cls.routers = [] x_listener_port = cls.tester.get_port() RouterTestVerifyHostNameNo.x_listener_port = x_listener_port y_listener_port = cls.tester.get_port() super(RouterTestVerifyHostNameNo, cls).router( 'X', [ ('listener', { 'host': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port, 'sslProfile': 'server-ssl-profile', 'saslMechanisms': 'PLAIN', 'authenticatePeer': 'yes' }), # This unauthenticated listener is for qdstat to connect to it. ('listener', { 'host': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port(), 'authenticatePeer': 'no' }), ( 'sslProfile', { 'name': 'server-ssl-profile', # certDb has been deprecated. We are using it here to test backward compatibility. 'certDb': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), # keyFile has been deprecated. We are using it here to test backward compatibility. 'keyFile': cls.ssl_file('server-private-key.pem'), 'password': '******' }), ('router', { 'workerThreads': 1, 'id': 'QDR.X', 'mode': 'interior', 'saslConfigName': 'tests-mech-PLAIN', 'saslConfigDir': os.getcwd() }), ]) super(RouterTestVerifyHostNameNo, cls).router( 'Y', [ # This router will act like a client. First an SSL connection will be established and then # we will have SASL plain authentication over SSL. ( 'connector', { 'name': 'connectorToX', 'host': '127.0.0.1', 'role': 'inter-router', 'port': x_listener_port, 'sslProfile': 'client-ssl-profile', # Provide a sasl user name and password to connect to QDR.X 'saslMechanisms': 'PLAIN', 'verifyHostname': 'no', 'saslUsername': '******', 'saslPassword': '******' }), ('router', { 'workerThreads': 1, 'mode': 'interior', 'id': 'QDR.Y' }), ('listener', { 'host': '0.0.0.0', 'role': 'normal', 'port': y_listener_port }), ('sslProfile', { 'name': 'client-ssl-profile', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('client-certificate.pem'), 'privateKeyFile': cls.ssl_file('client-private-key.pem'), 'password': '******' }), ]) cls.routers[0].wait_ports() cls.routers[1].wait_ports() cls.routers[1].wait_router_connected('QDR.X')
class QdstatSslNoExternalTest(system_test.TestCase): """Test qdstat can't connect without sasl_mech EXTERNAL""" @staticmethod def ssl_file(name): return os.path.join(system_test.DIR, 'ssl_certs', name) @staticmethod def sasl_path(): return os.path.join(system_test.DIR, 'sasl_configs') @classmethod def setUpClass(cls): super(QdstatSslNoExternalTest, cls).setUpClass() # Write SASL configuration file: with open('tests-mech-NOEXTERNAL.conf', 'w') as sasl_conf: sasl_conf.write("mech_list: ANONYMOUS DIGEST-MD5 PLAIN\n") # qdrouterd configuration: config = system_test.Qdrouterd.Config([ ('router', {'id': 'QDR.C', 'saslConfigPath': os.getcwd(), 'workerThreads': 1, 'saslConfigName': 'tests-mech-NOEXTERNAL'}), ('sslProfile', {'name': 'server-ssl', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'password': '******'}), ('listener', {'port': cls.tester.get_port()}), ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl', 'authenticatePeer': 'no', 'requireSsl': 'yes'}), ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl', 'authenticatePeer': 'no', 'requireSsl': 'no'}), ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl', 'authenticatePeer': 'yes', 'requireSsl': 'yes', 'saslMechanisms': 'EXTERNAL'}) ]) cls.router = cls.tester.qdrouterd('test-router', config) def run_qdstat(self, args, regexp=None, address=None): p = self.popen( ['qdstat', '--bus', str(address or self.router.addresses[0]), '--timeout', str(system_test.TIMEOUT) ] + args, name='qdstat-'+self.id(), stdout=PIPE, expect=None, universal_newlines=True) out = p.communicate()[0] assert p.returncode == 0, \ "qdstat exit status %s, output:\n%s" % (p.returncode, out) if regexp: assert re.search(regexp, out, re.I), "Can't find '%s' in '%s'" % (regexp, out) return out def ssl_test(self, url_name, arg_names): """Run simple SSL connection test with supplied parameters. See test_ssl_* below. """ args = dict( trustfile = ['--ssl-trustfile', self.ssl_file('ca-certificate.pem')], bad_trustfile = ['--ssl-trustfile', self.ssl_file('bad-ca-certificate.pem')], client_cert = ['--ssl-certificate', self.ssl_file('client-certificate.pem')], client_key = ['--ssl-key', self.ssl_file('client-private-key.pem')], client_pass = ['--ssl-password', 'client-password']) args['client_cert_all'] = args['client_cert'] + args['client_key'] + args['client_pass'] addrs = [self.router.addresses[i] for i in range(4)]; urls = dict(zip(['none', 'strict', 'unsecured', 'auth'], addrs)) urls.update(zip(['none_s', 'strict_s', 'unsecured_s', 'auth_s'], (Url(a, scheme="amqps") for a in addrs))) self.run_qdstat(['--general'] + sum([args[n] for n in arg_names], []), regexp=r'(?s)Router Statistics.*Mode\s*Standalone', address=str(urls[url_name])) def ssl_test_bad(self, url_name, arg_names): self.assertRaises(AssertionError, self.ssl_test, url_name, arg_names) @SkipIfNeeded(not SASL.extended(), "Cyrus library not available. skipping test") def test_ssl_cert_to_auth_fail_no_sasl_external(self): self.ssl_test_bad('auth_s', ['client_cert_all']) def test_ssl_trustfile_cert_to_auth_fail_no_sasl_external(self): self.ssl_test_bad('auth_s', ['trustfile', 'client_cert_all'])
def setUpClass(cls): """ Tests the sasl_username, sasl_password property of the dispatch router. Creates two routers (QDR.X and QDR.Y) and sets up PLAIN authentication on QDR.X. QDR.Y connects to QDR.X by providing a sasl_username and a sasl_password. This PLAIN authentication is done over an TLS/SSLv3 connection. """ super(RouterTestPlainSaslOverSsl, cls).setUpClass() if not SASL.extended(): return super(RouterTestPlainSaslOverSsl, cls).createSaslFiles() cls.routers = [] x_listener_port = cls.tester.get_port() y_listener_port = cls.tester.get_port() super(RouterTestPlainSaslOverSsl, cls).router('X', [ ('listener', {'host': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port, 'sslProfile':'server-ssl-profile', 'saslMechanisms':'PLAIN', 'authenticatePeer': 'yes'}), ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port(), 'authenticatePeer': 'no'}), ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port(), 'sslProfile':'server-ssl-profile', 'saslMechanisms':'PLAIN', 'authenticatePeer': 'yes'}), ('sslProfile', {'name': 'server-ssl-profile', 'certDb': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'keyFile': cls.ssl_file('server-private-key.pem'), 'password': '******'}), ('router', {'workerThreads': 1, 'id': 'QDR.X', 'mode': 'interior', 'saslConfigName': 'tests-mech-PLAIN', 'saslConfigPath': os.getcwd()}), ]) super(RouterTestPlainSaslOverSsl, cls).router('Y', [ # This router will act like a client. First an SSL connection will be established and then # we will have SASL plain authentication over SSL. ('connector', {'host': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port, 'sslProfile': 'client-ssl-profile', 'verifyHostName': 'no', # Provide a sasl user name and password to connect to QDR.X 'saslMechanisms': 'PLAIN', 'saslUsername': '******', 'saslPassword': '******'}), ('router', {'workerThreads': 1, 'mode': 'interior', 'id': 'QDR.Y'}), ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': y_listener_port}), ('sslProfile', {'name': 'client-ssl-profile', 'certDb': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('client-certificate.pem'), 'keyFile': cls.ssl_file('client-private-key.pem'), 'password': '******'}), ]) cls.routers[1].wait_router_connected('QDR.X')
db = os.path.join(abs_conf_dir,'proton.sasldb') conf = os.path.join(abs_conf_dir,'proton-server.conf') f = open(conf, 'w') f.write(t.substitute(db=db)) f.close() cmd_template = Template("echo password | ${saslpasswd} -c -p -f ${db} -u proton user") cmd = cmd_template.substitute(db=db, saslpasswd=saslpasswd) subprocess.call(args=cmd, shell=True) os.environ['PN_SASL_CONFIG_PATH'] = abs_conf_dir global createdSASLDb createdSASLDb = True # Globally initialize Cyrus SASL configuration if SASL.extended(): _cyrusSetup('sasl_conf') def ensureCanTestExtendedSASL(): if not SASL.extended(): raise Skipped('Extended SASL not supported') if not createdSASLDb: raise Skipped("Can't Test Extended SASL: Couldn't create auth db") class DefaultConfig: defines = {} class Test(TestCase): config = DefaultConfig() def __init__(self, name):
def setUpClass(cls): """ Prepares a single router with multiple listeners, each one associated with a particular sslProfile and each sslProfile has its own specific set of allowed protocols. """ super(RouterTestSslClient, cls).setUpClass() cls.routers = [] if SASL.extended(): router = ('router', {'id': 'QDR.A', 'mode': 'interior', 'saslConfigName': 'tests-mech-PLAIN', 'saslConfigDir': os.getcwd()}) # Generate authentication DB super(RouterTestSslClient, cls).create_sasl_files() else: router = ('router', {'id': 'QDR.A', 'mode': 'interior'}) # Saving listener ports for each TLS definition cls.PORT_TLS1 = cls.tester.get_port() cls.PORT_TLS11 = cls.tester.get_port() cls.PORT_TLS12 = cls.tester.get_port() cls.PORT_TLS13 = cls.tester.get_port() cls.PORT_TLS1_TLS11 = cls.tester.get_port() cls.PORT_TLS1_TLS12 = cls.tester.get_port() cls.PORT_TLS11_TLS12 = cls.tester.get_port() cls.PORT_TLS_ALL = cls.tester.get_port() cls.PORT_TLS_SASL = cls.tester.get_port() cls.PORT_SSL3 = cls.tester.get_port() conf = [ router, # TLSv1 only ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS1, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-tls1'}), # TLSv1.1 only ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS11, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-tls11'}), # TLSv1.2 only ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS12, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-tls12'}), # TLSv1 and TLSv1.1 only ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS1_TLS11, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-tls1-tls11'}), # TLSv1 and TLSv1.2 only ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS1_TLS12, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-tls1-tls12'}), # TLSv1.1 and TLSv1.2 only ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS11_TLS12, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-tls11-tls12'}), # All TLS versions ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS_ALL, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-tls-all'}), # Invalid protocol version ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_SSL3, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-ssl3'}) ] # Adding SASL listener only when SASL is available if SASL.extended(): conf += [ # TLS 1 and 1.2 with SASL PLAIN authentication for proton client validation ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS_SASL, 'authenticatePeer': 'yes', 'saslMechanisms': 'PLAIN', 'requireSsl': 'yes', 'requireEncryption': 'yes', 'sslProfile': 'ssl-profile-tls1-tls12'}) ] # Adding SSL profiles conf += [ # SSL Profile for TLSv1 ('sslProfile', {'name': 'ssl-profile-tls1', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1', 'password': '******'}), # SSL Profile for TLSv1.1 ('sslProfile', {'name': 'ssl-profile-tls11', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1.1', 'password': '******'}), # SSL Profile for TLSv1.2 ('sslProfile', {'name': 'ssl-profile-tls12', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1.2', 'password': '******'}), # SSL Profile for TLSv1 and TLSv1.1 ('sslProfile', {'name': 'ssl-profile-tls1-tls11', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1 TLSv1.1', 'password': '******'}), # SSL Profile for TLSv1 and TLSv1.2 ('sslProfile', {'name': 'ssl-profile-tls1-tls12', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1 TLSv1.2', 'password': '******'}), # SSL Profile for TLSv1.1 and TLSv1.2 ('sslProfile', {'name': 'ssl-profile-tls11-tls12', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'TLSv1.1 TLSv1.2', 'password': '******'}), # SSL Profile for all TLS versions (protocols element not defined) ('sslProfile', {'name': 'ssl-profile-tls-all', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'password': '******'}), # SSL Profile for invalid protocol version SSLv23 ('sslProfile', {'name': 'ssl-profile-ssl3', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'ciphers': 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:' \ 'DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS', 'protocols': 'SSLv23', 'password': '******'}) ] if cls.OPENSSL_ALLOW_TLSV1_3: conf += [ # TLSv1.3 only ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.PORT_TLS13, 'authenticatePeer': 'no', 'sslProfile': 'ssl-profile-tls13'}), # SSL Profile for TLSv1.3 ('sslProfile', {'name': 'ssl-profile-tls13', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'protocols': 'TLSv1.3', 'password': '******'}) ] config = Qdrouterd.Config(conf) cls.routers.append(cls.tester.qdrouterd("A", config, wait=False)) cls.routers[0].wait_ports()
class QdstatSslNoExternalTest(QdstatTestBase): """Test qdstat can't connect without sasl_mech EXTERNAL""" @staticmethod def ssl_file(name): return os.path.join(DIR, 'ssl_certs', name) @staticmethod def sasl_path(): return os.path.join(DIR, 'sasl_configs') @classmethod def setUpClass(cls): super(QdstatSslNoExternalTest, cls).setUpClass() # Write SASL configuration file: with open('tests-mech-NOEXTERNAL.conf', 'w') as sasl_conf: sasl_conf.write("mech_list: ANONYMOUS DIGEST-MD5 PLAIN\n") # qdrouterd configuration: config = Qdrouterd.Config([('router', { 'id': 'QDR.C', 'saslConfigPath': os.getcwd(), 'workerThreads': 1, 'saslConfigName': 'tests-mech-NOEXTERNAL' }), ('sslProfile', { 'name': 'server-ssl', 'caCertFile': cls.ssl_file('ca-certificate.pem'), 'certFile': cls.ssl_file('server-certificate.pem'), 'privateKeyFile': cls.ssl_file('server-private-key.pem'), 'password': '******' }), ('listener', { 'port': cls.tester.get_port() }), ('listener', { 'port': cls.tester.get_port(), 'sslProfile': 'server-ssl', 'authenticatePeer': 'no', 'requireSsl': 'yes' }), ('listener', { 'port': cls.tester.get_port(), 'sslProfile': 'server-ssl', 'authenticatePeer': 'no', 'requireSsl': 'no' }), ('listener', { 'port': cls.tester.get_port(), 'sslProfile': 'server-ssl', 'authenticatePeer': 'yes', 'requireSsl': 'yes', 'saslMechanisms': 'EXTERNAL' })]) cls.router = cls.tester.qdrouterd('test-router', config) def ssl_test(self, url_name, arg_names): """Run simple SSL connection test with supplied parameters. See test_ssl_* below. """ args = dict( trustfile=['--ssl-trustfile', self.ssl_file('ca-certificate.pem')], bad_trustfile=[ '--ssl-trustfile', self.ssl_file('bad-ca-certificate.pem') ], client_cert=[ '--ssl-certificate', self.ssl_file('client-certificate.pem') ], client_key=['--ssl-key', self.ssl_file('client-private-key.pem')], client_pass=['--ssl-password', 'client-password']) args['client_cert_all'] = args['client_cert'] + args[ 'client_key'] + args['client_pass'] addrs = [self.router.addresses[i] for i in range(4)] urls = dict(zip(['none', 'strict', 'unsecured', 'auth'], addrs)) urls.update( zip(['none_s', 'strict_s', 'unsecured_s', 'auth_s'], (Url(a, scheme="amqps") for a in addrs))) self.run_qdstat(['--general'] + sum([args[n] for n in arg_names], []), address=str(urls[url_name]), regex=r'(?s)Router Statistics.*Mode\s*Standalone') def ssl_test_bad(self, url_name, arg_names): self.assertRaises(RuntimeError, self.ssl_test, url_name, arg_names) @unittest.skipIf(not SASL.extended(), "Cyrus library not available. skipping test") def test_ssl_cert_to_auth_fail_no_sasl_external(self): self.ssl_test_bad('auth_s', ['client_cert_all']) def test_ssl_trustfile_cert_to_auth_fail_no_sasl_external(self): self.ssl_test_bad('auth_s', ['trustfile', 'client_cert_all'])