示例#1
0
    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_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 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_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 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 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)
示例#8
0
    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_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_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_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')
示例#13
0
    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
示例#14
0
    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
示例#15
0
    def test_ssl_sasl_client_valid(self):
        """
        Attempts to connect a Proton client using a valid SASL authentication info
        and forcing the TLS protocol version, which should be accepted 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[0],
            self.is_ssl_sasl_client_accepted(self.PORT_TLS_SASL, "TLSv1"))
        self.assertEqual(
            exp_tls_results[2],
            self.is_ssl_sasl_client_accepted(self.PORT_TLS_SASL, "TLSv1.2"))
    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])
示例#17
0
    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
示例#18
0
    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])
示例#19
0
    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)

        # sslProto should be TLSv1/SSLv3
        self.assertEqual(
            u'TLSv1/SSLv3',
            local_node.query(
                type='org.apache.qpid.dispatch.connection').results[0][10])

        # 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])
示例#20
0
    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 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)
示例#23
0
    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"))
示例#25
0
class RouterTestPlainSaslOverSsl(RouterTestPlainSaslCommon):
    @staticmethod
    def ssl_file(name):
        return os.path.join(DIR, 'ssl_certs', name)

    @staticmethod
    def sasl_file(name):
        return os.path.join(DIR, 'sasl_files', name)

    @classmethod
    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': '******' + cls.sasl_file('password.txt')
                    }),
                ('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')

    @SkipIfNeeded(not SASL.extended(),
                  "Cyrus library not available. skipping test")
    def test_aaa_qdstat_connect_sasl_over_ssl(self):
        """
        Make qdstat use sasl plain authentication over ssl.
        """
        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,
            universal_newlines=True)

        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"))

    @SkipIfNeeded(not SASL.extended(),
                  "Cyrus library not available. skipping test")
    def test_inter_router_plain_over_ssl_exists(self):
        """The setUpClass sets up two routers with SASL PLAIN enabled over TLS.

        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.x was used as sslProto

        """
        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.x
        self.assertTrue(u'TLSv1' in 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])
示例#26
0
class RouterTestPlainSasl(RouterTestPlainSaslCommon):
    @classmethod
    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

        os.environ["ENV_SASL_PASSWORD"] = "******"

        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')

    @SkipIfNeeded(not SASL.extended(),
                  "Cyrus library not available. skipping test")
    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

        """

        p = self.popen(
            ['qdstat', '-b',
             str(self.routers[0].addresses[1]), '-c'],
            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)

        self.assertIn("inter-router", out)
        self.assertIn("[email protected](PLAIN)", out)

    @SkipIfNeeded(not SASL.extended(),
                  "Cyrus library not available. skipping test")
    def test_qdstat_connect_sasl(self):
        """
        Make qdstat use sasl plain authentication.
        """

        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,
                       universal_newlines=True)

        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"))

    @SkipIfNeeded(not SASL.extended(),
                  "Cyrus library not available. skipping test")
    def test_qdstat_connect_sasl_password_file(self):
        """
        Make qdstat use sasl plain authentication with client password specified in a file.
        """
        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,
                       universal_newlines=True)

        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"))
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'])
    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')
示例#29
0
class RouterTestVerifyHostNameNo(RouterTestPlainSaslCommon):
    @staticmethod
    def ssl_file(name):
        return os.path.join(DIR, 'ssl_certs', name)

    x_listener_port = None

    @classmethod
    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')

    @staticmethod
    def ssl_file(name):
        return os.path.join(DIR, 'ssl_certs', name)

    def common_asserts(self, results):
        search = "QDR.X"
        found = False

        for N in range(0, len(results)):
            if results[N][5] == search:
                found = True
                break

        self.assertTrue(found, "Connection to %s not found" % search)

        # sslProto should be TLSv1.x
        self.assertTrue(u'TLSv1' in results[N][10])

        # role should be inter-router
        self.assertEqual(u'inter-router', results[N][3])

        # sasl must be plain
        self.assertEqual(u'PLAIN', results[N][6])

        # user must be [email protected]
        self.assertEqual(u'*****@*****.**', results[N][8])

    @SkipIfNeeded(not SASL.extended(),
                  "Cyrus library not available. skipping test")
    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'.
        """
        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)

    @SkipIfNeeded(not SASL.extended(),
                  "Cyrus library not available. skipping test")
    def test_zzz_delete_create_ssl_profile(self):
        """
        Deletes a connector and its corresponding ssl profile and recreates both
        """
        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()
        is_qdr_x = "QDR.X" in [c.container for c in connections]
        self.assertFalse(is_qdr_x)  # 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'),
            'privateKeyFile':
            self.ssl_file('client-private-key.pem'),
            'password':
            '******',
            'caCertFile':
            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)
示例#30
0
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")
示例#31
0
class RouterTestSslInterRouter(RouterTestSslBase):
    """
    Starts 5 routers with several listeners and connectors and validate if communication
    between them is working as expected.
    """
    # Listener ports for each TLS protocol definition
    PORT_NO_SSL = 0
    PORT_TLS_ALL = 0
    PORT_TLS12 = 0
    PORT_TLS1_TLS12 = 0

    @classmethod
    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 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

    @SkipIfNeeded(not SASL.extended(), "Cyrus library not available. skipping test")
    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)
        self.assertEqual(len(router_nodes), 4)
    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
示例#33
0
    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()
示例#34
0
    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_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': '******'})
        ]

        config = Qdrouterd.Config(conf)

        cls.routers.append(cls.tester.qdrouterd("A", config, wait=False))
        cls.routers[0].wait_ports()
示例#35
0
    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)
示例#36
0
    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': 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(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',
                    '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')
示例#37
0
    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)
示例#38
0
class RouterTestVerifyHostNameYes(RouterTestPlainSaslCommon):
    @staticmethod
    def ssl_file(name):
        return os.path.join(DIR, 'ssl_certs', name)

    @staticmethod
    def sasl_file(name):
        return os.path.join(DIR, 'sasl_files', name)

    @classmethod
    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': '******' + cls.sasl_file('password.txt')
                    }),
                ('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

    @SkipIfNeeded(not SASL.extended(),
                  "Cyrus library not available. skipping test")
    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'
        """
        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])
示例#39
0
        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):
示例#40
0
    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 bad sasl_password
        as a non-existent file.

        """
        super(RouterTestPlainSaslFailure, cls).setUpClass()

        if not SASL.extended():
            return

        super(RouterTestPlainSaslFailure, cls).createSaslFiles()

        cls.routers = []

        x_listener_port = cls.tester.get_port()
        y_listener_port = cls.tester.get_port()

        super(RouterTestPlainSaslFailure, 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(RouterTestPlainSaslFailure, 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':
                        '******',
                        # Provide a non-existen file.
                        'saslPassword':
                        '******' +
                        cls.sasl_file('non-existent-password-file.txt')
                    }),
                ('router', {
                    'workerThreads': 1,
                    'mode': 'interior',
                    'id': 'QDR.Y'
                }),
                ('listener', {
                    'host': '0.0.0.0',
                    'role': 'normal',
                    'port': y_listener_port
                }),
            ])

        cls.routers[0].wait_ports()
        cls.routers[1].wait_ports()
        try:
            # This will time out in 5 seconds because there is no inter-router connection
            cls.routers[1].wait_connectors(timeout=5)
        except:
            pass
示例#41
0
    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',
                'certDb': cls.ssl_file('ca-certificate.pem'),
                'certFile': cls.ssl_file('server-certificate.pem'),
                'keyFile': 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': '******'
            }),
            ('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')
示例#42
0
    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):
示例#43
0
    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',
                    '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(RouterTestVerifyHostNameYes, cls).router('Y', [
            ('connector', {
                'host': '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',
                '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[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
示例#44
0
    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)
示例#45
0
class RouterTestSslClient(RouterTestSslBase):
    """
    Starts a router with multiple listeners, all of them using an sslProfile.
    Then it runs multiple tests to validate that only the allowed protocol versions
    are being accepted through the related listener.
    """
    # Listener ports for each TLS protocol definition
    PORT_TLS1 = 0
    PORT_TLS11 = 0
    PORT_TLS12 = 0
    PORT_TLS1_TLS11 = 0
    PORT_TLS1_TLS12 = 0
    PORT_TLS11_TLS12 = 0
    PORT_TLS_ALL = 0
    PORT_TLS_SASL = 0
    PORT_SSL3 = 0
    TIMEOUT = 3

    @classmethod
    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_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': '******'})
        ]

        config = Qdrouterd.Config(conf)

        cls.routers.append(cls.tester.qdrouterd("A", config, wait=False))
        cls.routers[0].wait_ports()

    def get_allowed_protocols(self, listener_port):
        """
        Loops through TLSv1, TLSv1.1 and TLSv1.2 and attempts to connect
        to the listener_port using each version. The result is a boolean list
        with results in respective order for TLSv1 [0], TLSv1.1 [1] and TLSv1.2 [2].
        :param listener_port:
        :return:
        """
        results = []

        for proto in ['TLSv1', 'TLSv1.1', 'TLSv1.2']:
            results.append(self.is_proto_allowed(listener_port, proto))
        return results

    def is_proto_allowed(self, listener_port, tls_protocol):
        """
        Opens a simple proton client connection to the provided TCP port using
        a specific TLS protocol version and returns True in case connection
        was established and accepted or False otherwise.
        :param listener_port: TCP port number
        :param tls_protocol: TLSv1, TLSv1.1 or TLSv1.2 (string)
        :return:
        """
        # Management address to connect using the given TLS protocol
        url = Url("amqps://0.0.0.0:%d/$management" % listener_port)
        # Preparing SSLDomain (client cert) and SASL authentication info
        domain = SSLDomain(SSLDomain.MODE_CLIENT)
        # Enforcing given TLS protocol
        cproton.pn_ssl_domain_set_protocols(domain._domain, tls_protocol)

        # Try opening the secure and authenticated connection
        try:
            connection = BlockingConnection(url, sasl_enabled=False, ssl_domain=domain, timeout=self.TIMEOUT)
        except proton.Timeout:
            return False
        except proton.ConnectionException:
            return False

        # TLS version provided was accepted
        connection.close()
        return True

    def is_ssl_sasl_client_accepted(self, listener_port, tls_protocol):
        """
        Attempts to connect a proton client to the management address
        on the given listener_port using the specific tls_protocol provided.
        If connection was established and accepted, returns True and False otherwise.
        :param listener_port:
        :param tls_protocol:
        :return:
        """
        # Management address to connect using the given TLS protocol
        url = Url("amqps://0.0.0.0:%d/$management" % listener_port)
        # Preparing SSLDomain (client cert) and SASL authentication info
        domain = SSLDomain(SSLDomain.MODE_CLIENT)
        domain.set_credentials(self.ssl_file('client-certificate.pem'),
                               self.ssl_file('client-private-key.pem'),
                               'client-password')
        # Enforcing given TLS protocol
        cproton.pn_ssl_domain_set_protocols(domain._domain, tls_protocol)

        # Try opening the secure and authenticated connection
        try:
            connection = BlockingConnection(url,
                                            sasl_enabled=True,
                                            ssl_domain=domain,
                                            allowed_mechs='PLAIN',
                                            user='******',
                                            password='******')
        except proton.ConnectionException:
            return False

        # TLS version provided was accepted
        connection.close()
        return True

    def test_tls1_only(self):
        """
        Expects TLSv1 only is allowed
        """
        self.assertEquals([True, False, False],
                          self.get_allowed_protocols(self.PORT_TLS1))

    def test_tls11_only(self):
        """
        Expects TLSv1.1 only is allowed
        """
        self.assertEquals([False, True, False],
                          self.get_allowed_protocols(self.PORT_TLS11))

    def test_tls12_only(self):
        """
        Expects TLSv1.2 only is allowed
        """
        self.assertEquals([False, False, True],
                          self.get_allowed_protocols(self.PORT_TLS12))

    def test_tls1_tls11_only(self):
        """
        Expects TLSv1 and TLSv1.1 only are allowed
        """
        self.assertEquals([True, True, False],
                          self.get_allowed_protocols(self.PORT_TLS1_TLS11))

    def test_tls1_tls12_only(self):
        """
        Expects TLSv1 and TLSv1.2 only are allowed
        """
        self.assertEquals([True, False, True],
                          self.get_allowed_protocols(self.PORT_TLS1_TLS12))

    def test_tls11_tls12_only(self):
        """
        Expects TLSv1.1 and TLSv1.2 only are allowed
        """
        self.assertEquals([False, True, True],
                          self.get_allowed_protocols(self.PORT_TLS11_TLS12))

    def test_tls_all(self):
        """
        Expects all supported versions: TLSv1, TLSv1.1 and TLSv1.2 to be allowed
        """
        self.assertEquals([True, True, True],
                          self.get_allowed_protocols(self.PORT_TLS_ALL))

    def test_ssl_invalid(self):
        """
        Expects connection is rejected as SSL is no longer supported
        """
        self.assertEqual(False, self.is_proto_allowed(self.PORT_SSL3, 'SSLv3'))

    @SkipIfNeeded(not SASL.extended(), "Cyrus library not available. skipping test")
    def test_ssl_sasl_client_valid(self):
        """
        Attempts to connect a Proton client using a valid SASL authentication info
        and forcing the TLS protocol version, which should be accepted by the listener.
        :return:
        """
        if not SASL.extended():
            self.skipTest("Cyrus library not available. skipping test")

        self.assertTrue(self.is_ssl_sasl_client_accepted(self.PORT_TLS_SASL, "TLSv1"))
        self.assertTrue(self.is_ssl_sasl_client_accepted(self.PORT_TLS_SASL, "TLSv1.2"))

    @SkipIfNeeded(not SASL.extended(), "Cyrus library not available. skipping test")
    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")

        self.assertFalse(self.is_ssl_sasl_client_accepted(self.PORT_TLS_SASL, "TLSv1.1"))
示例#46
0
class CyrusTest(common.Test):
    """A test class for SASL authentication tests using the Cyrus SASL library
    """
    # Note: the Cyrus SASL library can only be initialized once per process, so
    # do it during definition
    CONF_DIR = None
    TEST_COUNT = 2
    if hasattr(SASL, "extended") and SASL.extended():
        CONF_DIR = tempfile.mkdtemp()
        CONF_NAME = "test-server"
        # add a user 'user@pyngus', password 'trustno1':
        db = os.path.join(CONF_DIR, 'test.sasldb')
        _t = "echo trustno1 | saslpasswd2 -c -p -f ${db} -u pyngus user"
        cmd = Template(_t).substitute(db=db)
        try:
            subprocess.check_call(args=cmd, shell=True)
        except Exception:
            shutil.rmtree(CONF_DIR, ignore_errors=True)
            CONF_DIR = None

        if CONF_DIR:
            # configure the SASL server:
            conf = os.path.join(CONF_DIR, '%s.conf' % CONF_NAME)
            t = Template("""sasldb_path: ${db}
mech_list: EXTERNAL DIGEST-MD5 SCRAM-SHA-1 CRAM-MD5 PLAIN ANONYMOUS
""")
            with open(conf, 'w') as f:
                f.write(t.substitute(db=db))

    def setup(self):
        """Create a simple SASL configuration. This assumes saslpasswd2 is in
        the OS path, otherwise the test will be skipped.
        """
        super(CyrusTest, self).setup()
        if not CyrusTest.CONF_DIR:
            raise common.Skipped("Cyrus SASL not supported")

        self.container1 = pyngus.Container("test-container-1")
        self.container2 = pyngus.Container("test-container-2")

    def teardown(self):
        if self.container1:
            self.container1.destroy()
        if self.container2:
            self.container2.destroy()
        if CyrusTest.CONF_DIR:
            CyrusTest.TEST_COUNT -= 1
            if CyrusTest.TEST_COUNT == 0:
                shutil.rmtree(CyrusTest.CONF_DIR, ignore_errors=True)
        super(CyrusTest, self).teardown()

    def test_cyrus_sasl_ok(self):
        server_props = {
            'x-server': True,
            'x-require-auth': True,
            'x-sasl-config-dir': CyrusTest.CONF_DIR,
            'x-sasl-config-name': CyrusTest.CONF_NAME
        }
        client_props = {
            'x-server': False,
            'x-username': '******',
            'x-password': '******'
        }

        c1_events = common.ConnCallback()
        c1 = self.container1.create_connection("c1",
                                               c1_events,
                                               properties=server_props)
        c2_events = common.ConnCallback()
        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_cyrus_sasl_fail(self):
        server_props = {
            'x-server': True,
            'x-require-auth': True,
            'x-sasl-config-dir': CyrusTest.CONF_DIR,
            'x-sasl-config-name': CyrusTest.CONF_NAME
        }
        client_props = {
            'x-server': False,
            'x-username': '******',
            'x-password': '******'
        }

        c1_events = common.ConnCallback()
        c1 = self.container1.create_connection("c1",
                                               c1_events,
                                               properties=server_props)
        c2_events = common.ConnCallback()
        c2 = self.container2.create_connection("c2",
                                               c2_events,
                                               properties=client_props)
        c1.open()
        c2.open()
        common.process_connections(c1, c2)
        assert not c1.active, c1.active
        assert c1_events.failed_ct == 1, c1_events.failed_ct
        assert not c2.active, c2.active
        assert c2_events.sasl_done_ct == 1, c2_events.sasl_done_ct
        # outcome 1 == auth error
        assert c2_events.sasl_done_outcome == 1, c2_events.sasl_done_outcome
        assert c2_events.failed_ct == 1, c2_events.failed_ct
示例#47
0
class RouterTestSslClient(RouterTestSslBase):
    """
    Starts a router with multiple listeners, all of them using an sslProfile.
    Then it runs multiple tests to validate that only the allowed protocol versions
    are being accepted through the related listener.
    """
    # Listener ports for each TLS protocol definition
    PORT_TLS1 = 0
    PORT_TLS11 = 0
    PORT_TLS12 = 0
    PORT_TLS1_TLS11 = 0
    PORT_TLS1_TLS12 = 0
    PORT_TLS11_TLS12 = 0
    PORT_TLS_ALL = 0
    PORT_TLS_SASL = 0
    PORT_SSL3 = 0
    TIMEOUT = 3

    # If using OpenSSL 1.1 or greater, TLSv1.2 is always being allowed
    OPENSSL_VER_1_1_GT = ssl.OPENSSL_VERSION_INFO[:2] >= (1, 1)

    # Following variables define TLS versions allowed by openssl
    OPENSSL_MIN_VER = 0
    OPENSSL_MAX_VER = 9999
    OPENSSL_ALLOW_TLSV1 = True
    OPENSSL_ALLOW_TLSV1_1 = True
    OPENSSL_ALLOW_TLSV1_2 = True

    # When using OpenSSL >= 1.1 and python >= 3.7, we can retrieve OpenSSL min and max protocols
    if OPENSSL_VER_1_1_GT:
        if sys.version_info >= (3, 7):
            OPENSSL_CTX = ssl.create_default_context()
            OPENSSL_MIN_VER = OPENSSL_CTX.minimum_version
            OPENSSL_MAX_VER = OPENSSL_CTX.maximum_version if OPENSSL_CTX.maximum_version > 0 else 9999
            OPENSSL_ALLOW_TLSV1 = OPENSSL_MIN_VER <= ssl.TLSVersion.TLSv1 <= OPENSSL_MAX_VER
            OPENSSL_ALLOW_TLSV1_1 = OPENSSL_MIN_VER <= ssl.TLSVersion.TLSv1_1 <= OPENSSL_MAX_VER
            OPENSSL_ALLOW_TLSV1_2 = OPENSSL_MIN_VER <= ssl.TLSVersion.TLSv1_2 <= OPENSSL_MAX_VER
        else:
            # At this point we are not able to precisely determine what are the minimum and maximum
            # TLS versions allowed in the system, so tests will be disabled
            RouterTestSslBase.DISABLE_SSL_TESTING = True

    @classmethod
    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_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': '******'})
        ]

        config = Qdrouterd.Config(conf)

        cls.routers.append(cls.tester.qdrouterd("A", config, wait=False))
        cls.routers[0].wait_ports()

    def get_allowed_protocols(self, listener_port):
        """
        Loops through TLSv1, TLSv1.1 and TLSv1.2 and attempts to connect
        to the listener_port using each version. The result is a boolean list
        with results in respective order for TLSv1 [0], TLSv1.1 [1] and TLSv1.2 [2].
        :param listener_port:
        :return:
        """
        results = []

        for proto in ['TLSv1', 'TLSv1.1', 'TLSv1.2']:
            results.append(self.is_proto_allowed(listener_port, proto))
        return results

    def is_proto_allowed(self, listener_port, tls_protocol):
        """
        Opens a simple proton client connection to the provided TCP port using
        a specific TLS protocol version and returns True in case connection
        was established and accepted or False otherwise.
        :param listener_port: TCP port number
        :param tls_protocol: TLSv1, TLSv1.1 or TLSv1.2 (string)
        :return:
        """
        # Management address to connect using the given TLS protocol
        url = Url("amqps://0.0.0.0:%d/$management" % listener_port)
        # Preparing SSLDomain (client cert) and SASL authentication info
        domain = SSLDomain(SSLDomain.MODE_CLIENT)
        # Enforcing given TLS protocol
        cproton.pn_ssl_domain_set_protocols(domain._domain, tls_protocol)

        # Try opening the secure and authenticated connection
        try:
            connection = BlockingConnection(url, sasl_enabled=False, ssl_domain=domain, timeout=self.TIMEOUT)
        except proton.Timeout:
            return False
        except proton.ConnectionException:
            return False

        # TLS version provided was accepted
        connection.close()
        return True

    def is_ssl_sasl_client_accepted(self, listener_port, tls_protocol):
        """
        Attempts to connect a proton client to the management address
        on the given listener_port using the specific tls_protocol provided.
        If connection was established and accepted, returns True and False otherwise.
        :param listener_port:
        :param tls_protocol:
        :return:
        """
        # Management address to connect using the given TLS protocol
        url = Url("amqps://0.0.0.0:%d/$management" % listener_port)
        # Preparing SSLDomain (client cert) and SASL authentication info
        domain = SSLDomain(SSLDomain.MODE_CLIENT)
        domain.set_credentials(self.ssl_file('client-certificate.pem'),
                               self.ssl_file('client-private-key.pem'),
                               'client-password')
        # Enforcing given TLS protocol
        cproton.pn_ssl_domain_set_protocols(domain._domain, tls_protocol)

        # Try opening the secure and authenticated connection
        try:
            connection = BlockingConnection(url,
                                            sasl_enabled=True,
                                            ssl_domain=domain,
                                            allowed_mechs='PLAIN',
                                            user='******',
                                            password='******')
        except proton.ConnectionException:
            return False

        # TLS version provided was accepted
        connection.close()
        return True

    def get_expected_tls_result(self, expected_results):
        """
        Expects a list with three boolean elements, representing
        TLSv1, TLSv1.1 and TLSv1.2 (in the respective order).
        When using OpenSSL >= 1.1.x, allowance of a given TLS version is
        based on MinProtocol / MaxProtocol definitions.
        It is also important
        to mention that TLSv1.2 is being allowed even when not specified in a
        listener when using OpenSSL >= 1.1.x.

        :param expected_results:
        :return:
        """
        (tlsv1, tlsv1_1, tlsv1_2) = expected_results
        return [self.OPENSSL_ALLOW_TLSV1 and tlsv1,
                self.OPENSSL_ALLOW_TLSV1_1 and tlsv1_1,
                self.OPENSSL_VER_1_1_GT or (self.OPENSSL_ALLOW_TLSV1_2 and tlsv1_2)]

    @SkipIfNeeded(RouterTestSslBase.DISABLE_SSL_TESTING, "Unable to determine MinProtocol")
    def test_tls1_only(self):
        """
        Expects TLSv1 only is allowed
        """
        self.assertEquals(self.get_expected_tls_result([True, False, False]),
                          self.get_allowed_protocols(self.PORT_TLS1))

    @SkipIfNeeded(RouterTestSslBase.DISABLE_SSL_TESTING, "Unable to determine MinProtocol")
    def test_tls11_only(self):
        """
        Expects TLSv1.1 only is allowed
        """
        self.assertEquals(self.get_expected_tls_result([False, True, False]),
                          self.get_allowed_protocols(self.PORT_TLS11))

    @SkipIfNeeded(RouterTestSslBase.DISABLE_SSL_TESTING, "Unable to determine MinProtocol")
    def test_tls12_only(self):
        """
        Expects TLSv1.2 only is allowed
        """
        self.assertEquals(self.get_expected_tls_result([False, False, True]),
                          self.get_allowed_protocols(self.PORT_TLS12))

    @SkipIfNeeded(RouterTestSslBase.DISABLE_SSL_TESTING, "Unable to determine MinProtocol")
    def test_tls1_tls11_only(self):
        """
        Expects TLSv1 and TLSv1.1 only are allowed
        """
        self.assertEquals(self.get_expected_tls_result([True, True, False]),
                          self.get_allowed_protocols(self.PORT_TLS1_TLS11))

    @SkipIfNeeded(RouterTestSslBase.DISABLE_SSL_TESTING, "Unable to determine MinProtocol")
    def test_tls1_tls12_only(self):
        """
        Expects TLSv1 and TLSv1.2 only are allowed
        """
        self.assertEquals(self.get_expected_tls_result([True, False, True]),
                          self.get_allowed_protocols(self.PORT_TLS1_TLS12))

    @SkipIfNeeded(RouterTestSslBase.DISABLE_SSL_TESTING, "Unable to determine MinProtocol")
    def test_tls11_tls12_only(self):
        """
        Expects TLSv1.1 and TLSv1.2 only are allowed
        """
        self.assertEquals(self.get_expected_tls_result([False, True, True]),
                          self.get_allowed_protocols(self.PORT_TLS11_TLS12))

    @SkipIfNeeded(RouterTestSslBase.DISABLE_SSL_TESTING, "Unable to determine MinProtocol")
    def test_tls_all(self):
        """
        Expects all supported versions: TLSv1, TLSv1.1 and TLSv1.2 to be allowed
        """
        self.assertEquals(self.get_expected_tls_result([True, True, True]),
                          self.get_allowed_protocols(self.PORT_TLS_ALL))

    @SkipIfNeeded(RouterTestSslBase.DISABLE_SSL_TESTING, "Unable to determine MinProtocol")
    def test_ssl_invalid(self):
        """
        Expects connection is rejected as SSL is no longer supported
        """
        self.assertEqual(False, self.is_proto_allowed(self.PORT_SSL3, 'SSLv3'))

    @SkipIfNeeded(not SASL.extended(), "Cyrus library not available. skipping test")
    def test_ssl_sasl_client_valid(self):
        """
        Attempts to connect a Proton client using a valid SASL authentication info
        and forcing the TLS protocol version, which should be accepted by the listener.
        :return:
        """
        if not SASL.extended():
            self.skipTest("Cyrus library not available. skipping test")

        self.assertTrue(self.is_ssl_sasl_client_accepted(self.PORT_TLS_SASL, "TLSv1"))
        self.assertTrue(self.is_ssl_sasl_client_accepted(self.PORT_TLS_SASL, "TLSv1.2"))

    @SkipIfNeeded(not SASL.extended(), "Cyrus library not available. skipping test")
    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")

        self.assertFalse(self.is_ssl_sasl_client_accepted(self.PORT_TLS_SASL, "TLSv1.1"))
示例#48
0
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 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)
示例#50
0
    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'])
示例#51
0
class AuthServicePluginAuthzTest(TestCase):
    @classmethod
    def addUser(cls, user, password):
        # Create a sasl database.
        p = Popen(['saslpasswd2', '-c', '-p', '-f', 'users.sasldb', user],
                  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)

    @classmethod
    def createSaslFiles(cls):
        cls.addUser('guest', 'guest')
        cls.addUser('admin', 'admin')
        # Create a SASL configuration file.
        with open('tests-mech-SCRAM.conf', 'w') as sasl_conf:
            sasl_conf.write("""
mech_list: SCRAM-SHA-1 PLAIN
""")
        with open('proton-server.conf', 'w') as sasl_conf:
            sasl_conf.write("""
pwcheck_method: auxprop
auxprop_plugin: sasldb
sasldb_path: users.sasldb
mech_list: SCRAM-SHA-1 PLAIN
""")

    @staticmethod
    def ssl_file(name):
        return os.path.join(system_test.DIR, 'ssl_certs', name)

    @classmethod
    def setUpClass(cls):
        """
        Tests the delegation of sasl auth to an external auth service.
        """
        super(AuthServicePluginAuthzTest, cls).setUpClass()

        if not SASL.extended():
            return

        cls.createSaslFiles()

        cls.auth_service_port = cls.tester.get_port()
        cls.tester.popen([sys.executable, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'authservice.py'),
                          '-a', 'amqps://*****:*****@unittest.skipIf(not SASL.extended(), "Cyrus library not available. skipping test")
    def test_authorized(self):
        container = Container()
        client = ConnectionHandler('foo', 1)
        container.connect("guest:[email protected]:%d" % self.router_port, handler=client)
        container.run()
        self.assertEqual(1, client.sent)
        self.assertEqual(1, client.received)
        self.assertEqual(0, len(client.errors))

    @unittest.skipIf(not SASL.extended(), "Cyrus library not available. skipping test")
    def test_unauthorized(self):
        container = Container()
        client = ConnectionHandler('bar', 1)
        container.connect("guest:[email protected]:%d" % self.router_port, handler=client)
        container.run()
        self.assertEqual(0, client.sent)
        self.assertEqual(0, client.received)
        self.assertEqual(2, len(client.errors))
        self.assertEqual('amqp:unauthorized-access', client.errors[0])
        self.assertEqual('amqp:unauthorized-access', client.errors[1])

    @unittest.skipIf(not SASL.extended(), "Cyrus library not available. skipping test")
    def test_wildcard(self):
        container = Container()
        client = ConnectionHandler('whatever', 1)
        container.connect("admin:[email protected]:%d" % self.router_port, handler=client)
        container.run()
        self.assertEqual(1, client.sent)
        self.assertEqual(1, client.received)
        self.assertEqual(0, len(client.errors))

    @unittest.skipIf(not SASL.extended(), "Cyrus library not available. skipping test")
    def test_dynamic_source_anonymous_sender(self):
        container = Container()
        client = DynamicSourceAnonymousSender()
        container.connect("admin:[email protected]:%d" % self.router_port, handler=client)
        container.run()
        self.assertEqual(1, client.accepted)
        self.assertEqual('hello', client.message)
        self.assertEqual(0, len(client.errors))

    @unittest.skipIf(not SASL.extended(), "Cyrus library not available. skipping test")
    def test_unauthorized_anonymous_sender_target(self):
        container = Container()
        client = DynamicSourceAnonymousSender()
        container.connect("guest:[email protected]:%d" % self.router_port, handler=client)
        container.run()
        self.assertEqual(0, client.accepted)
        self.assertEqual(1, client.rejected)
        self.assertIsNone(client.message)
示例#52
0
    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 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')
示例#54
0
    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',
                    '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')
示例#55
0
class RouterTestPlainSaslFailure(RouterTestPlainSaslCommon):
    @staticmethod
    def sasl_file(name):
        return os.path.join(DIR, 'sasl_files', name)


    @classmethod
    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 bad sasl_password
        as a non-existent file.

        """
        super(RouterTestPlainSaslFailure, cls).setUpClass()

        if not SASL.extended():
            return

        super(RouterTestPlainSaslFailure, cls).createSaslFiles()

        cls.routers = []

        x_listener_port = cls.tester.get_port()
        y_listener_port = cls.tester.get_port()

        super(RouterTestPlainSaslFailure, 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(RouterTestPlainSaslFailure, 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': '******',
                                    # Provide a non-existen file.
                                    'saslPassword': '******' + cls.sasl_file('non-existent-password-file.txt')}),
                     ('router', {'workerThreads': 1,
                                 'mode': 'interior',
                                 'id': 'QDR.Y'}),
                     ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': y_listener_port}),
        ])

        cls.routers[0].wait_ports()
        cls.routers[1].wait_ports()
        try:
            # This will time out in 5 seconds because there is no inter-router connection
            cls.routers[1].wait_connectors(timeout=5)
        except:
            pass

    @SkipIfNeeded(not SASL.extended(), "Cyrus library not available. skipping test")
    def test_inter_router_sasl_fail(self):
        passed = False
        long_type = 'org.apache.qpid.dispatch.connection'
        qd_manager = QdManager(self, address=self.routers[1].addresses[0])
        connections = qd_manager.query(long_type)
        for connection in connections:
            if connection['role'] == 'inter-router':
                passed = True
                break

        # There was no inter-router connection established.
        self.assertFalse(passed)

        qd_manager = QdManager(self, address=self.routers[1].addresses[0])
        logs = qd_manager.get_log()

        sasl_failed = False
        file_open_failed = False
        for log in logs:
            if log[0] == 'SERVER' and log[1] == "info" and "amqp:unauthorized-access Authentication failed [mech=PLAIN]" in log[2]:
                sasl_failed = True
            if log[0] == "CONN_MGR" and log[1] == "error" and "Unable to open password file" in log[2] and "error: No such file or directory" in log[2]:
                file_open_failed = True

        self.assertTrue(sasl_failed)
        self.assertTrue(file_open_failed)