Exemplo n.º 1
0
    def write(self, file_path):
        """
        Create a DXL client configuration file from the current object. If the
        current object was created from a call to
        :meth:`create_dxl_config_from_file`, unchanged content should be
        preserved. For example, the original file may have the following:

        .. code-block:: ini

            [Certs]
            BrokerCertChain=c:\\\\certs\\\\brokercerts.crt
            CertFile=c:\\\\certs\\\\client.crt
            PrivateKey=c:\\\\certs\\\\client.key

            [Brokers]
            mybroker=mybroker;8883;mybroker.mcafee.com;192.168.1.12
            mybroker2=mybroker2;8883;mybroker2.mcafee.com;192.168.1.13

            [BrokersWebSockets]
            mybroker=mybroker;443;mybroker.mcafee.com;192.168.1.12
            mybroker2=mybroker2;443;mybroker2.mcafee.com;192.168.1.13

        The configuration could be loaded and changed as follows:

        .. code-block:: python

            from dxlclient.client_config import DxlClientConfig

            config = DxlClientConfig.create_dxl_config_from_file("c:\\\\certs\\\\dxlclient.config")
            config.cert_file = "c:\\\\\\\\certs\\\\\\\\newclient.crt"
            config.write("c:\\\\certs\\\\dxlclient.config")

        The resulting configuration should then appear as follows:

        .. code-block:: ini

            [Certs]
            BrokerCertChain=c:\\\\certs\\\\brokercerts.crt
            CertFile=c:\\\\certs\\\\newclient.crt
            PrivateKey=c:\\\\certs\\\\client.key

            [Brokers]
            mybroker=mybroker;8883;mybroker.mcafee.com;192.168.1.12
            mybroker2=mybroker2;8883;mybroker2.mcafee.com;192.168.1.13

            [BrokersWebSockets]
            mybroker=mybroker;443;mybroker.mcafee.com;192.168.1.12
            mybroker2=mybroker2;443;mybroker2.mcafee.com;192.168.1.13

        :param file_path: File at which to write the configuration. An attempt
            will be made to create any directories in the path which may not
            exist before writing the file.
        """
        self._update_broker_config_models()
        DxlUtils.makedirs(path.dirname(file_path))
        self._config.filename = file_path
        self._config.write()
    def _update_broker_cert_chain(self, svc, ca_bundle_file):
        """
        Retrieve the latest ca bundle from the management service and update
        it on disk at the location supplied as the `ca_bundle_file` argument.

        :param dxlclient._cli._management_service.ManagementService svc: the
            management service to query for the new broker cert chain
        :param str ca_bundle_file: file at which to store the latest ca bundle
        """
        cert_chain = svc.invoke_command(self._BROKER_CERT_CHAIN_COMMAND)
        validate_cert_pem(cert_chain, "Failed to process PEM for CA bundle")
        logger.info("Updating certs in %s", ca_bundle_file)
        DxlUtils.save_to_file(ca_bundle_file, cert_chain)
    def _save_pem(pem, description, target_file):
        """
        Save the content of the string in the `pem` argument to the file name
        stored in the `target_file` argument.

        :param pem: content of the pem
        :param description: description of the content of the `pem`, used in
            the content of a message for an validation `Exception`, if raised.
        :param target_file: file at which to save the pem
        :raise Exception: if the contents of `pem` does not appear to be a PEM
            wrapping a valid ASN.1-encoded certificate
        """
        validate_cert_pem(pem,
                          "Failed to process PEM for {}".format(description))
        logger.info("Saving %s file to %s", description, target_file)
        DxlUtils.save_to_file(target_file, pem)
Exemplo n.º 4
0
    def test_wildcarding_iteration(self, wildcard_number, topic):
        """
        Tests wildcarding iteration (utility method)
        """
        wildcards = []

        # define what is the callback for iteration
        def on_next_wildcard(wildcard):
            wildcards.append(wildcard)

        wildcard_callback = WildcardCallback()
        wildcard_callback.on_next_wildcard = on_next_wildcard

        DxlUtils.iterate_wildcards(wildcard_callback, topic)
        self.assertEqual(wildcard_number, len(wildcards))

        for wildcard in wildcards:
            topic = topic_splitter(topic)
            self.assertEqual(topic, wildcard)
Exemplo n.º 5
0
    def save_csr_and_private_key(self,
                                 csr_filename,
                                 private_key_filename,
                                 passphrase=None):
        """
        Save the certificate request and private key to disk in PEM format

        :param csr_filename: filename of the certificate request
        :param private_key_filename: filename of the private key
        :param passphrase: If a `str` object is supplied, encrypt the private
            key with the passphrase before converting it to PEM format. If
            `None` is supplied, convert it to PEM format without performing any
            encryption.
        """
        logger.info("Saving csr file to %s", csr_filename)
        DxlUtils.save_to_file(csr_filename, self._csr.dump_to_pem())
        logger.info("Saving private key file to %s", private_key_filename)
        DxlUtils.save_to_file(private_key_filename,
                              self._key_pair.private_key_as_pem(passphrase),
                              0o600)
Exemplo n.º 6
0
    def test_updateconfig_with_prompt_for_server_user_and_password(self):
        responses = {
            "Enter server username:"******"myuser",
            "Enter server password:"******"mypass"
        }

        def prompt_response(arg):
            return responses[arg]

        with _TempDir("updateconfig_no_server_creds") as temp_dir, \
                patch("sys.argv", command_args(["updateconfig",
                                                temp_dir,
                                                "myhost"])), \
                patch.object(getpass, "getpass",
                             side_effect=prompt_response) as mock_getpass, \
                requests_mock.mock(case_sensitive=True) as req_mock:
            ca_bundle_file = os.path.join(temp_dir, "ca-bundle.crt")
            DxlUtils.save_to_file(ca_bundle_file, "old ca")

            config_file = os.path.join(temp_dir, "dxlclient.config")
            DxlUtils.save_to_file(config_file, make_config())

            client_ca_url = get_server_client_ca_url("myhost")
            broker_list_url = get_server_broker_list_url("myhost")
            req_mock.get(client_ca_url,
                         text=get_mock_ca_bundle_response_func())
            req_mock.get(broker_list_url,
                         text=get_mock_broker_list_response_func())

            cli_run()

            self.assertEqual(2, len(req_mock.request_history))

            # Validate auth credentials sent in requests
            expected_creds = "Basic {}".format(
                base64.b64encode(b"myuser:mypass").decode("utf8"))
            for request in req_mock.request_history:
                self.assertEqual(expected_creds,
                                 request.headers["Authorization"])

            self.assertEqual(2, mock_getpass.call_count)
Exemplo n.º 7
0
    def test_provisionconfig_with_csr(self):
        csr_file = "myclient.csr"
        with _TempDir("provconfig_csr") as temp_dir, \
                patch("sys.argv", command_args(["provisionconfig",
                                                temp_dir,
                                                "myhost",
                                                os.path.join(temp_dir,
                                                             csr_file),
                                                "-u", "myuser",
                                                "-p", "mypass",
                                                "-r"])), \
                requests_mock.mock(case_sensitive=True) as req_mock:
            client_cert_for_response = FAKE_CERTIFICATE
            csr_to_test = FAKE_CSR
            full_csr_file_path = os.path.join(temp_dir, csr_file)
            DxlUtils.save_to_file(full_csr_file_path, csr_to_test)
            req_mock.get(get_server_provision_url("myhost"),
                         text=get_mock_provision_response_func(
                             client_cert=client_cert_for_response))

            cli_run()

            self.assertEqual(1, len(req_mock.request_history))
            request = req_mock.request_history[0]

            # Validate csr saved to disk was not regenerated and matches csr
            # submitted for signing
            csr_bytes_from_file = slurp_file_into_bytes(full_csr_file_path)
            csr_bytes_in_request = flattened_query_params(request).get(
                "csrString")
            self.assertEqual(csr_bytes_in_request.encode("utf8"),
                             csr_bytes_from_file)
            self.assertEqual(csr_to_test.encode("utf8"),
                             csr_bytes_from_file)

            # Validate client cert returned for request matches stored file
            client_cert_file = os.path.join(temp_dir, "client.crt")
            self.assertTrue(os.path.exists(client_cert_file))
            client_cert_from_file = slurp_file_into_bytes(client_cert_file)
            self.assertEqual(client_cert_for_response.encode("utf8"),
                             client_cert_from_file)
Exemplo n.º 8
0
    def test_updateconfig_with_trusted_ca_cert_and_port(self):
        with _TempDir("updateconfig_ca_port") as temp_dir, \
                patch("sys.argv", command_args(["updateconfig",
                                                temp_dir,
                                                "myhost",
                                                "-t", "58443",
                                                "-u", "myuser",
                                                "-p", "mypass",
                                                "-e", "mytruststore.pem"])), \
                requests_mock.mock(case_sensitive=True) as req_mock:
            ca_bundle_file = os.path.join(temp_dir, "ca-bundle.crt")
            DxlUtils.save_to_file(ca_bundle_file, "old ca")

            config_file = os.path.join(temp_dir, "dxlclient.config")
            DxlUtils.save_to_file(config_file, make_config())

            client_ca_url = get_server_client_ca_url("myhost", 58443)
            broker_list_url = get_server_broker_list_url("myhost", 58443)
            req_mock.get(client_ca_url,
                         text=get_mock_ca_bundle_response_func())
            req_mock.get(broker_list_url,
                         text=get_mock_broker_list_response_func())

            cli_run()

            self.assertEqual(2, len(req_mock.request_history))

            request_urls = []
            for request in req_mock.request_history:
                self.assertEqual("mytruststore.pem", request.verify)
                request_urls.append("{}://{}:{}{}".format(
                    request.scheme,
                    request.hostname,
                    request.port,
                    request.path))

            # If each mock endpoint was hit once, the request should have been
            # made to the right port
            self.assertIn(client_ca_url, request_urls)
            self.assertIn(broker_list_url, request_urls)
Exemplo n.º 9
0
    def test_updateconfig_basic(self):
        with _TempDir("updateconfig_basic") as temp_dir, \
                patch("sys.argv", command_args(["updateconfig",
                                                temp_dir,
                                                "myhost",
                                                "-u", "myuser",
                                                "-p", "mypass"])), \
                requests_mock.mock(case_sensitive=True) as req_mock:
            base_broker_lines = broker_lines_for_config_file(
                make_broker_lines(2), add_comments=True)
            base_config_lines = make_basic_config(
                ca_bundle_file="mycabundle.pem", add_comments=True)
            base_config_content = make_config(base_config_lines,
                                              base_broker_lines)

            # Before the broker config update is done, there should be entries
            # for broker1 and broker2. The updated config contains entries for
            # broker2 (pre-existing), broker3 (new), and broker4 (new). broker1
            # is expected to be deleted from the config on disk during the
            # update. The comment line above the entry for broker2 in the
            # config file should be preserved after the update.
            updated_brokers = make_broker_dict(4)
            del updated_brokers["brokers"][0]
            expected_brokers = make_broker_lines(4)
            del expected_brokers[0]
            expected_broker_lines = "# This is broker 2\n{}".format(
                broker_lines_for_config_file(expected_brokers))
            expected_config_content = make_config(base_config_lines,
                                                  expected_broker_lines)

            ca_bundle_file = os.path.join(temp_dir, "mycabundle.pem")
            DxlUtils.save_to_file(ca_bundle_file, "old ca")
            updated_ca_bundle = make_fake_ca_bundle(2)

            config_file = os.path.join(temp_dir, "dxlclient.config")
            DxlUtils.save_to_file(config_file, base_config_content)

            req_mock.get(
                get_server_client_ca_url("myhost"),
                text=get_mock_ca_bundle_response_func(updated_ca_bundle))
            req_mock.get(
                get_server_broker_list_url("myhost"),
                text=get_mock_broker_list_response_func(updated_brokers))

            cli_run()

            self.assertEqual(2, len(req_mock.request_history))

            # Validate auth credentials sent in requests
            expected_creds = "Basic {}".format(
                base64.b64encode(b"myuser:mypass").decode("utf8"))
            for request in req_mock.request_history:
                self.assertEqual(expected_creds,
                                 request.headers["Authorization"])

            # Validate updates to the ca bundle file
            self.assertTrue(os.path.exists(ca_bundle_file))
            ca_bundle_from_file = slurp_file_into_bytes(ca_bundle_file)
            self.assertEqual(updated_ca_bundle.encode("utf8"),
                             ca_bundle_from_file)

            # Validate updates to the config file
            self.assertTrue(os.path.exists(config_file))
            config_from_file = slurp_file_into_bytes(config_file)
            self.assertEqual(expected_config_content, config_from_file)