Exemple #1
0
 def setUp(self):
     self.test_op = TestOperation()
     self.sock = socket.socket()
     self.sock.bind(("localhost", 0))
     self.sock.listen(0)
     self.shutdown = True
     self.test_op.start()
Exemple #2
0
    def setUp(self):
        fd, self.keyfile = tempfile.mkstemp(prefix='test_ca_', suffix='.key')
        subprocess.check_call(['openssl', 'genpkey', '-algorithm', 'RSA',
                               '-out', self.keyfile], stdout=subprocess.DEVNULL,
                              stderr=subprocess.DEVNULL)
        os.close(fd)

        fd, self.certfile = tempfile.mkstemp(prefix='test_ca_', suffix='.pem')
        subprocess.check_call(['openssl', 'req', '-x509', '-new',
                               '-subj', '/CN=localhost',
                               '-key', self.keyfile, '-out', self.certfile],
                              stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        os.close(fd)

        fd, self.keyfile2 = tempfile.mkstemp(prefix='test_ca_', suffix='.key')
        subprocess.check_call(['openssl', 'genpkey', '-algorithm', 'RSA',
                               '-out', self.keyfile2], stdout=subprocess.DEVNULL,
                              stderr=subprocess.DEVNULL)
        os.close(fd)

        fd, self.certfile2 = tempfile.mkstemp(prefix='test_ca_', suffix='.pem')
        subprocess.check_call(['openssl', 'req', '-x509', '-new',
                               '-subj', '/CN=localhost',
                               '-key', self.keyfile2, '-out', self.certfile2],
                              stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        os.close(fd)

        self.test_op = TestOperation()
        self.sock = None
        self.test_op.start()
Exemple #3
0
class TestTCPConnectOperation(unittest.TestCase):
    def setUp(self):
        self.test_op = TestOperation()
        self.sock = socket.socket()
        self.sock.bind(("localhost", 0))
        self.sock.listen(0)
        self.shutdown = True
        self.test_op.start()

    def tearDown(self):
        if self.shutdown:
            self.sock.shutdown(socket.SHUT_RDWR)
        self.sock.close()

    def accept(self):
        class Accept:
            def __init__(self):
                self.thread = None
                self.sock = None
                self.addr = None

        accept = Accept()

        def aux(accept):
            accept.sock, accept.addr = self.sock.accept()

        accept.thread = threading.Thread(target=aux, args=(accept,))
        accept.thread.start()
        return accept

    def test_success(self):
        """
        Test a successful connection.
        """
        op = TCPConnectOperation(self.test_op, self.sock.getsockname())
        op.callback = op_callback()
        op.start()
        accept = self.accept()
        while not op.callback.called:
            self.test_op.run_selector()
        accept.thread.join()
        try:
            op.callback.assert_called_once_with(op)
            self.assertIsNotNone(op.socket)
            op.socket.close()
        finally:
            accept.sock.close()
        self.assertTrue(self.test_op.is_done())

    def test_gaierror(self):
        """
        Test a connection that fails on socket.connect() because of a name
        resolution error.
        """
        # See RFC 6761 for the .test TLD -- unless the DNS server is doing
        # something weird, this name should not resolve.
        op = TCPConnectOperation(self.test_op, ("example.test", 666))
        op.callback = op_callback()
        op.start()
        op.callback.assert_called_once_with(op)
        self.assertIsNone(op.socket)
        self.assertTrue(self.test_op.is_done())

    def test_connection_refused(self):
        """
        Test a connection that fails because the server refuses the connection.
        """
        self.sock.shutdown(socket.SHUT_RD)
        self.shutdown = False
        op = TCPConnectOperation(self.test_op, self.sock.getsockname())
        op.callback = op_callback()
        op.start()
        self.test_op.run_selector()
        op.callback.assert_called_once_with(op)
        self.assertIsNone(op.socket)
        self.assertTrue(self.test_op.updated_with("Connection refused"))
        self.assertTrue(self.test_op.is_done())

    @tests.timed_test
    @tests.root_test
    def test_timeout(self):
        """
        Test a connection that times out and fails.
        """
        with drop_connection(port=self.sock.getsockname()[1]):
            op = TCPConnectOperation(self.test_op, self.sock.getsockname(), 0.01)
            op.callback = op_callback()
            op.start()
            time.sleep(0.01)
            self.test_op.run_selector()
            op.callback.assert_called_once_with(op)
            self.assertIsNone(op.socket)
            self.assertTrue(self.test_op.updated_with("Timed out"))
            self.assertTrue(self.test_op.is_done())

    @tests.timed_test
    def test_connect_and_timeout(self):
        """
        Test the case where the connection succeeds but the timerfd still fires
        before we call select. This is the case where the socket comes before
        the timerfd in the list of events, so the connection should succeed.
        """
        op = TCPConnectOperation(self.test_op, self.sock.getsockname(), 0.01)
        op.callback = op_callback()
        op.start()
        accept = self.accept()
        time.sleep(0.01)
        while not op.callback.called:
            self.test_op.run_selector(priority="socket")
        try:
            op.callback.assert_called_once_with(op)
            self.assertIsNotNone(op.socket)
            op.socket.close()
            self.assertTrue(self.test_op.is_done())
        finally:
            accept.sock.close()

    @tests.timed_test
    def test_timeout_and_connect(self):
        """
        Test the same case as test_connect_and_timeout but where the timerfd
        event comes before the socket event.
        """
        op = TCPConnectOperation(self.test_op, self.sock.getsockname(), 0.01)
        op.callback = op_callback()
        op.start()
        accept = self.accept()
        time.sleep(0.01)
        while not op.callback.called:
            self.test_op.run_selector(priority="timer")
        try:
            op.callback.assert_called_once_with(op)
            self.assertIsNone(op.socket)
            self.assertTrue(self.test_op.updated_with("Timed out"))
            self.assertTrue(self.test_op.is_done())
        finally:
            accept.sock.close()
Exemple #4
0
class TestSSLHandshakeOperation(unittest.TestCase):
    def setUp(self):
        fd, self.keyfile = tempfile.mkstemp(prefix='test_ca_', suffix='.key')
        subprocess.check_call(['openssl', 'genpkey', '-algorithm', 'RSA',
                               '-out', self.keyfile], stdout=subprocess.DEVNULL,
                              stderr=subprocess.DEVNULL)
        os.close(fd)

        fd, self.certfile = tempfile.mkstemp(prefix='test_ca_', suffix='.pem')
        subprocess.check_call(['openssl', 'req', '-x509', '-new',
                               '-subj', '/CN=localhost',
                               '-key', self.keyfile, '-out', self.certfile],
                              stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        os.close(fd)

        fd, self.keyfile2 = tempfile.mkstemp(prefix='test_ca_', suffix='.key')
        subprocess.check_call(['openssl', 'genpkey', '-algorithm', 'RSA',
                               '-out', self.keyfile2], stdout=subprocess.DEVNULL,
                              stderr=subprocess.DEVNULL)
        os.close(fd)

        fd, self.certfile2 = tempfile.mkstemp(prefix='test_ca_', suffix='.pem')
        subprocess.check_call(['openssl', 'req', '-x509', '-new',
                               '-subj', '/CN=localhost',
                               '-key', self.keyfile2, '-out', self.certfile2],
                              stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        os.close(fd)

        self.test_op = TestOperation()
        self.sock = None
        self.test_op.start()

    def tearDown(self):
        if self.sock:
            if self.shutdown:
                self.sock.shutdown(socket.SHUT_RDWR)
            self.sock.close()
        os.unlink(self.keyfile)
        os.unlink(self.certfile)
        os.unlink(self.keyfile2)
        os.unlink(self.certfile2)

    def start_server(self, wrap_ssl=True):
        self.sock = socket.socket()
        if wrap_ssl:
            context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
            context.load_cert_chain(certfile=self.certfile, keyfile=self.keyfile)
            self.sock = context.wrap_socket(self.sock, server_side=True)
        self.sock.bind(('localhost', 0))
        self.sock.listen(0)
        self.shutdown = True

    def accept(self, send=None):
        class Accept:
            def __init__(self):
                self.thread = None
                self.sock = None
                self.addr = None
        accept = Accept()
        def aux(accept):
            try:
                accept.sock, accept.addr = self.sock.accept()
                if send:
                    accept.sock.sendall(send)
            except ssl.SSLError:
                pass
        accept.thread = threading.Thread(target=aux, args=(accept,))
        accept.thread.start()
        return accept

    def connect_client(self):
        sock = socket.socket()
        sock.connect(self.sock.getsockname())
        sock.setblocking(False)
        return sock

    def test_success(self):
        """
        Test a successful handshake.
        """
        self.start_server()
        sock = self.connect_client()
        op = SSLHandshakeOperation(self.test_op, sock, 'localhost',
                                   self.certfile)
        op.callback = op_callback()
        op.start()
        accept = self.accept()
        while not op.callback.called:
            self.test_op.run_selector()
        accept.thread.join()
        try:
            op.callback.assert_called_once_with(op)
            self.assertIsNotNone(op.socket)
            op.socket.close()
            self.assertTrue(self.test_op.is_done())
        finally:
            accept.sock.close()

    def test_certificate_verify(self):
        """
        Test a handshake that fails because the certificate is not trusted.
        """
        self.start_server()
        sock = self.connect_client()
        # Notice that we're using ca2.pem as the CA file here.
        op = SSLHandshakeOperation(self.test_op, sock, 'localhost',
                                   self.certfile2)
        op.callback = op_callback()
        op.start()
        accept = self.accept()
        while not op.callback.called:
            self.test_op.run_selector()
        accept.thread.join()
        try:
            op.callback.assert_called_once_with(op)
            self.assertIsNone(op.socket)
            self.assertTrue(self.test_op.updated_with('CERTIFICATE_VERIFY_FAILED'))
            self.assertTrue(self.test_op.is_done())
        finally:
            if accept.sock:
                accept.sock.close()

    def test_hostname_verify(self):
        """
        Test a handshake that fails because the server hostname does not match.
        """
        self.start_server()
        sock = self.connect_client()
        # We're passing 'localghost' instead of 'localhost' as the server
        # hostname.
        op = SSLHandshakeOperation(self.test_op, sock, 'localghost',
                                   self.certfile)
        op.callback = op_callback()
        op.start()
        accept = self.accept()
        while not op.callback.called:
            self.test_op.run_selector()
        accept.thread.join()
        try:
            op.callback.assert_called_once_with(op)
            self.assertIsNone(op.socket)
            self.assertTrue(self.test_op.updated_with('hostname'))
            self.assertTrue(self.test_op.is_done())
        finally:
            if accept.sock:
                accept.sock.close()

    def test_missing_cafile(self):
        """
        Test a handshake that fails because the CA file doesn't exist.
        """
        self.start_server()
        sock = self.connect_client()
        op = SSLHandshakeOperation(self.test_op, sock, 'localhost',
                                   tempfile.mktemp())
        op.callback = op_callback()
        op.start()
        op.callback.assert_called_once_with(op)
        self.assertIsNone(op.socket)
        self.assertTrue(self.test_op.updated_with('No such file'))
        self.assertTrue(self.test_op.is_done())

    def test_invalid_handshake(self):
        """
        Test a handshake that fails because the server does something invalid
        (e.g., the server is not actually using SSL).
        """
        self.start_server(wrap_ssl=False)
        sock = self.connect_client()
        op = SSLHandshakeOperation(self.test_op, sock, 'localhost',
                                   self.certfile)
        op.callback = op_callback()
        op.start()
        accept = self.accept(send=b'* OK Hello\r\n')
        while not op.callback.called:
            self.test_op.run_selector()
        accept.thread.join()
        try:
            op.callback.assert_called_once_with(op)
            self.assertIsNone(op.socket)
            self.assertTrue(self.test_op.is_done())
        finally:
            if accept.sock:
                accept.sock.close()

    @tests.timed_test
    @tests.root_test
    def test_timeout(self):
        """
        Test a handshake that fails because it times out.
        """
        self.start_server()
        sock = self.connect_client()
        with drop_connection(port=self.sock.getsockname()[1]):
            op = SSLHandshakeOperation(self.test_op, sock, 'localhost',
                                       self.certfile, 0.01)
            op.callback = op_callback()
            op.start()
            time.sleep(0.01)
            self.test_op.run_selector()
            op.callback.assert_called_once_with(op)
            self.assertIsNone(op.socket)
            self.assertTrue(self.test_op.updated_with('Timed out'))
            self.assertTrue(self.test_op.is_done())