def test_gossip_proxy(intercepted_two_node_network): nodes = intercepted_two_node_network.docker_nodes node = nodes[0] tls_certificate_path = node.config.tls_certificate_local_path() tls_parameters = { "--certificate-file": tls_certificate_path, "--node-id": extract_common_name(tls_certificate_path), } cli = CLI(nodes[0], tls_parameters=tls_parameters) account = cli.node.genesis_account cli.set_default_deploy_args( "--from", account.public_key_hex, "--private-key", cli.private_key_path(account), "--public-key", cli.public_key_path(account), "--payment", cli.resource(Contract.STANDARD_PAYMENT), "--payment-args", cli.payment_json, ) cli("deploy", "--session", cli.resource(Contract.HELLO_NAME_DEFINE)) block_hash = cli("propose") wait_for_block_hash_propagated_to_all_nodes(nodes, block_hash)
def address(self) -> str: if self.config.behind_proxy: if not os.environ.get("TAG_NAME"): # Local run host_name = "172.17.0.1" # this works locally else: # Test suite is in a docker container if in CI host_name = f"test-{os.environ.get('TAG_NAME')}" certificate_path = self.config.tls_certificate_local_path() logging.info(f"certificate_path: {certificate_path}") node_id = extract_common_name(certificate_path) protocol_port = self.server_proxy_port discovery_port = self.kademlia_proxy_port addr = f"casperlabs://{node_id}@{host_name}?protocol={protocol_port}&discovery={discovery_port}" logging.info(f"Address of the proxy: {addr}") return addr m = re.search( f"Listening for traffic on (casperlabs://.+@{self.container.name}\\?protocol=\\d+&discovery=\\d+)\\.$", self.logs(), re.MULTILINE | re.DOTALL, ) if m is None: raise CasperLabsNodeAddressNotFoundError() address = m.group(1) return address
def invoke_client(self, command: str, decode_stdout: bool = True, add_host: bool = True) -> str: volumes = { self.node.host_mount_dir: { "bind": "/data", "mode": "ro" }, "/tmp": { "bind": "/tmp", "mode": "rw" }, } if add_host: command = f"--host {self.node.container_name} {command}" if self.node.cl_network.grpc_encryption: node_id = extract_common_name( self.node.config.tls_certificate_local_path()) command = f"--node-id {node_id} {command}" self.logger.info(f"COMMAND {command}") status_code = None container = None try: container = self.docker_client.containers.run( image=f"casperlabs/client:{self.node.docker_tag}", name=f"client-{self.node.config.number}-{random_string(5)}", command=command, network=self.node.config.network, volumes=volumes, detach=True, stderr=True, stdout=True, ) r = container.wait() status_code = r["StatusCode"] stdout_raw = container.logs(stdout=True, stderr=False) stdout = decode_stdout and stdout_raw.decode("utf-8") or stdout_raw stderr = container.logs(stdout=False, stderr=True).decode("utf-8") # TODO: I don't understand why but if I just call `self.logger.debug` then # it doesn't print anything, even though the level is clearly set. if self.log_level == "DEBUG" or status_code != 0: self.logger.info( f"EXITED exit_code: {status_code} STDERR: {stderr} STDOUT: {stdout}" ) if status_code: raise NonZeroExitCodeError(command=(command, status_code), exit_code=status_code, output=stderr) return stdout finally: try: if container: container.remove() except docker.errors.APIError as e: self.logger.warning( f"Exception while removing docker client container: {str(e)}" )
def update_credentials(self, certificate_file, key_file, node_id=None): self.node_id = node_id or extract_common_name(certificate_file) self.certificate_file = certificate_file self.key_file = key_file self.credentials = grpc.ssl_channel_credentials( root_certificates=read_binary(certificate_file), private_key=read_binary(key_file), certificate_chain=read_binary(certificate_file), ) self.secure_channel_options = self.node_id and [ ("grpc.ssl_target_name_override", self.node_id), ("grpc.default_authority", self.node_id), ]
def test_grpc_encryption_scala_cli(encrypted_two_node_network): node = encrypted_two_node_network.docker_nodes[0] cli = DockerCLI( node, tls_parameters={ "--node-id": extract_common_name(node.config.tls_certificate_local_path()) }, ) logging.info( f"EXECUTING {' '.join(cli.expand_args(['show-blocks', '--depth', 1]))}" ) blocks = cli("show-blocks", "--depth", 1) logging.debug(f"{blocks}")
def test_grpc_encryption_python_lib(encrypted_two_node_network): node = encrypted_two_node_network.docker_nodes[0] host = os.environ.get("TAG_NAME", None) and node.container_name or "localhost" client = CasperLabsClient( host, node.grpc_external_docker_port, node.grpc_internal_docker_port, extract_common_name(node.config.tls_certificate_local_path()), node.config.tls_certificate_local_path(), ) blocks = list(client.showBlocks(1)) assert len(blocks) > 0 logging.debug(f"{blocks}")
def test_grpc_encryption_python_cli(encrypted_two_node_network): nodes = encrypted_two_node_network.docker_nodes tls_parameters = { "--certificate-file": nodes[0].config.tls_certificate_local_path(), "--node-id": extract_common_name(nodes[0].config.tls_certificate_local_path()), } cli = CLI(nodes[0], tls_parameters=tls_parameters) logging.info( f"""EXECUTING {' '.join(cli.expand_args(["show-blocks", "--depth", 1]))}""" ) blocks = cli("show-blocks", "--depth", 1) assert len(blocks) > 0 logging.debug(f"{blocks}")
def test_equivocation(intercepted_two_node_network): """ Generate an equivocating block and check the system can detect it. """ nodes = intercepted_two_node_network.docker_nodes for node in nodes: node.proxy_server.set_interceptor( GenerateEquivocatingBlocksGossipInterceptor) node = nodes[0] account = node.genesis_account tls_certificate_path = node.config.tls_certificate_local_path() tls_parameters = {"--node-id": extract_common_name(tls_certificate_path)} cli = DockerCLI(nodes[0], tls_parameters=tls_parameters) cli.set_default_deploy_args( "--from", account.public_key_hex, "--private-key", cli.private_key_path(account), "--public-key", cli.public_key_path(account), "--payment", cli.resource(Contract.STANDARD_PAYMENT), "--payment-args", cli.payment_json, ) cli("deploy", "--session", cli.resource(Contract.HELLO_NAME_DEFINE)) block_hash = cli("propose") logging.info(f" =============> REAL BLOCK: {block_hash}") wait_for_block_hash_propagated_to_all_nodes(nodes, block_hash) block_hash = None if nodes[0].proxy_server.interceptor.equivocating_block: block_hash = nodes[ 0].proxy_server.interceptor.equivocating_block.block_hash receiver_node = nodes[1] logging.info( f" =============> EQUIVOCATING BLOCK: {block_hash.hex()}") wait_for_block_hash_propagated_to_all_nodes([receiver_node], block_hash.hex()) assert "Found equivocation:" in receiver_node.logs()
def test_check_deploy_signatures(intercepted_two_node_network): """ This test uses an interceptor that modifies block retrieved by node-1 from node-0 with GetBlockChunked method of the gossip service and removes approvals from deploys in the block. node-1 should not accept this block. """ nodes = intercepted_two_node_network.docker_nodes for node in nodes: node.proxy_server.set_interceptor(RemoveSignatureGossipInterceptor) node = nodes[0] account = node.genesis_account tls_certificate_path = node.config.tls_certificate_local_path() tls_parameters = { # Currently only Python client requires --certificate-file # It may not need it in the future. # "--certificate-file": tls_certificate_path, "--node-id": extract_common_name(tls_certificate_path) } cli = DockerCLI(nodes[0], tls_parameters=tls_parameters) cli.set_default_deploy_args( "--from", account.public_key_hex, "--private-key", cli.private_key_path(account), "--public-key", cli.public_key_path(account), "--payment", cli.resource(Contract.STANDARD_PAYMENT), "--payment-args", cli.payment_json, ) cli("deploy", "--session", cli.resource(Contract.HELLO_NAME_DEFINE)) block_hash = cli("propose") with raises(Exception): wait_for_block_hash_propagated_to_all_nodes(nodes, block_hash) assert "InvalidDeploySignature" in nodes[1].logs()
def test_grpc_encryption_python_cli_and_proxy(encrypted_two_node_network): node = encrypted_two_node_network.docker_nodes[0] tls_certificate_path = node.config.tls_certificate_local_path() tls_key_path = local_path(node.config.tls_key_path()) tls_parameters = { "--certificate-file": tls_certificate_path, "--node-id": extract_common_name(tls_certificate_path), } cli = CLI(node, tls_parameters=tls_parameters) cli.port = 50401 # We will be talking to proxy on 50401, node is on 40401 proxy_client = grpc_proxy.proxy_client( node, node_port=40401, node_host=cli.host, proxy_port=50401, client_certificate_file=tls_certificate_path, client_key_file=tls_key_path, server_certificate_file=tls_certificate_path, server_key_file=tls_key_path, ) cli.host = "localhost" logging.info( f"""EXECUTING {' '.join(cli.expand_args(["show-blocks", "--depth", 1]))}""" ) block_infos = cli("show-blocks", "--depth", 1) logging.info(f"{block_infos[0]}") assert len(block_infos) > 0 block_info = cli("show-block", block_infos[0].summary.block_hash) logging.info(f"{block_info}") proxy_client.stop() with raises(CLIErrorExit) as excinfo: block_info = cli("show-block", block_infos[0].summary.block_hash) # Expected grpc error: UNAVAILABLE assert '"grpc_status":14' in str(excinfo.value)
def __init__(self, node: "DockerNode"): # NOQA super(PythonClient, self).__init__() self.node = node self.abi = ABI host = node.node_host certificate_file = None node_id = None if self.node.config.grpc_encryption: certificate_file = self.node.config.tls_certificate_local_path() node_id = extract_common_name(certificate_file) self.client = CasperLabsClient( host=host, port_internal=self.node.grpc_internal_docker_port, port=self.node.grpc_external_docker_port, node_id=node_id, certificate_file=certificate_file, ) logging.info(f"PythonClient(host={self.client.host}, " f"port={self.node.grpc_external_docker_port}, " f"port_internal={self.node.grpc_internal_docker_port})")
def __init__( self, service_stub, add_servicer_to_server, node_host: str, node_port: int, proxy_port: int, encrypted_connection: bool = True, server_certificate_file: str = None, server_key_file: str = None, client_certificate_file: str = None, client_key_file: str = None, interceptor=None, ): super().__init__() self.service_stub = service_stub self.add_servicer_to_server = add_servicer_to_server self.node_host = node_host self.node_port = node_port self.proxy_port = proxy_port self.server_certificate_file = server_certificate_file self.server_key_file = server_key_file self.client_certificate_file = client_certificate_file self.client_key_file = client_key_file self.encrypted_connection = encrypted_connection self.node_id = None if self.encrypted_connection: self.node_id = extract_common_name(self.client_certificate_file) self.servicer = ProxyServicer( node_host=self.node_host, node_port=self.node_port, proxy_port=self.proxy_port, encrypted_connection=self.encrypted_connection, certificate_file=self.client_certificate_file, key_file=self.client_key_file, node_id=self.node_id, service_stub=self.service_stub, interceptor=interceptor, )
def test_grpc_encryption_python_cli(encrypted_two_node_network): nodes = encrypted_two_node_network.docker_nodes # The idea of the test was to check if it is possible to provide the client # with a certificate other than the node's certificate, and overwrite it with # node_id (CN in node's certificate). Unfortunately, it doesn't work, i.e. # we can do it but connection will fail with: # "Handshake failed with fatal error SSL_ERROR_SSL: error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED." # If not for the above the "--certificate-file" option would point to certficate of the nodes[1] # in this test. tls_parameters = { "--certificate-file": nodes[0].config.tls_certificate_local_path(), "--node-id": extract_common_name(nodes[0].config.tls_certificate_local_path()), } cli = CLI(nodes[0], tls_parameters=tls_parameters) logging.info( f"""EXECUTING {' '.join(cli.expand_args(["show-blocks", "--depth", 1]))}""" ) blocks = cli("show-blocks", "--depth", 1) assert len(blocks) logging.debug(f"{blocks}")
def __init__(self, node: "DockerNode"): # NOQA super(PythonClient, self).__init__() self.node = node self.abi = ABI # If $TAG_NAME is set it means we are running in docker, see docker_run_test.sh host = (os.environ.get("TAG_NAME", None) and self.node.container_name or "localhost") certificate_file = None node_id = None if self.node.config.grpc_encryption: certificate_file = self.node.config.tls_certificate_local_path() node_id = extract_common_name(certificate_file) self.client = CasperLabsClient( host=host, internal_port=self.node.grpc_internal_docker_port, port=self.node.grpc_external_docker_port, node_id=node_id, certificate_file=certificate_file, ) logging.info(f"PythonClient(host={self.client.host}, " f"port={self.node.grpc_external_docker_port}, " f"internal_port={self.node.grpc_internal_docker_port})")
def _node_address(self, config): node_id = extract_common_name(config.tls_certificate_local_path()) return f"casperlabs://{node_id}@node-{config.number}-{config.rand_str}-{self._docker_tag(config)}-{config.unique_run_num}?protocol=40400&discovery=40404"
def node_id(self) -> str: return extract_common_name(self.config.tls_certificate_local_path())