From f9e32552f80d639897257f1078e34fe8bd3f9496 Mon Sep 17 00:00:00 2001 From: Peter Hamilton Date: Tue, 17 Apr 2018 14:41:04 -0400 Subject: [PATCH] Add client support for custom configuration file paths This change adds client support for setting custom configuration file paths, allowing users and developers to place their settings file wherever they want. All client demo scripts have been updated to support a '-s' flag that can be used to set the configuration file for the demo. Client unit tests have also been updated to include this change. --- kmip/core/config_helper.py | 13 ++++-- kmip/demos/pie/create.py | 5 +- kmip/demos/pie/create_key_pair.py | 5 +- kmip/demos/pie/decrypt.py | 5 +- kmip/demos/pie/derive_key.py | 5 +- kmip/demos/pie/destroy.py | 5 +- kmip/demos/pie/encrypt.py | 5 +- kmip/demos/pie/get.py | 5 +- kmip/demos/pie/get_attribute_list.py | 5 +- kmip/demos/pie/locate.py | 5 +- kmip/demos/pie/mac.py | 5 +- kmip/demos/pie/register_certificate.py | 5 +- kmip/demos/pie/register_opaque_object.py | 5 +- kmip/demos/pie/register_private_key.py | 5 +- kmip/demos/pie/register_public_key.py | 5 +- kmip/demos/pie/register_secret_data.py | 5 +- kmip/demos/pie/register_symmetric_key.py | 5 +- kmip/demos/pie/sign.py | 5 +- kmip/demos/pie/signature_verify.py | 5 +- kmip/demos/units/activate.py | 2 +- kmip/demos/units/create.py | 2 +- kmip/demos/units/create_key_pair.py | 2 +- kmip/demos/units/destroy.py | 2 +- kmip/demos/units/discover_versions.py | 2 +- kmip/demos/units/get.py | 2 +- kmip/demos/units/locate.py | 2 +- kmip/demos/units/query.py | 2 +- kmip/demos/units/register.py | 2 +- kmip/demos/units/revoke.py | 2 +- kmip/demos/utils.py | 9 ++++ kmip/pie/client.py | 10 +++- kmip/services/kmip_client.py | 21 +++++++-- kmip/tests/unit/services/test_kmip_client.py | 48 +++++++++++++++++--- 33 files changed, 166 insertions(+), 45 deletions(-) diff --git a/kmip/core/config_helper.py b/kmip/core/config_helper.py index 6621623..38754cc 100644 --- a/kmip/core/config_helper.py +++ b/kmip/core/config_helper.py @@ -45,15 +45,20 @@ class ConfigHelper(object): # Timeout measured in seconds DEFAULT_TIMEOUT = 30 - def __init__(self): + def __init__(self, path=None): self.logger = logging.getLogger(__name__) self.conf = SafeConfigParser() - if self.conf.read(CONFIG_FILE): - self.logger.debug("Using config file at {0}".format(CONFIG_FILE)) + + filenames = path + if not path: + filenames = CONFIG_FILE + + if self.conf.read(filenames): + self.logger.debug("Using config file at {0}".format(filenames)) else: self.logger.warning( - "Config file {0} not found".format(CONFIG_FILE)) + "Config file {0} not found".format(filenames)) def get_valid_value(self, direct_value, config_section, config_option_name, default_value): diff --git a/kmip/demos/pie/create.py b/kmip/demos/pie/create.py index 70a219f..fdaea59 100644 --- a/kmip/demos/pie/create.py +++ b/kmip/demos/pie/create.py @@ -44,7 +44,10 @@ if __name__ == '__main__': algorithm = getattr(enums.CryptographicAlgorithm, algorithm, None) # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: try: uid = client.create( algorithm, diff --git a/kmip/demos/pie/create_key_pair.py b/kmip/demos/pie/create_key_pair.py index e82eae5..018e838 100644 --- a/kmip/demos/pie/create_key_pair.py +++ b/kmip/demos/pie/create_key_pair.py @@ -43,7 +43,10 @@ if __name__ == '__main__': algorithm = getattr(enums.CryptographicAlgorithm, algorithm, None) # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: try: public_uid, private_uid = client.create_key_pair( algorithm, diff --git a/kmip/demos/pie/decrypt.py b/kmip/demos/pie/decrypt.py index 1b10aa6..f1764e8 100644 --- a/kmip/demos/pie/decrypt.py +++ b/kmip/demos/pie/decrypt.py @@ -54,7 +54,10 @@ if __name__ == '__main__': message = binascii.unhexlify(message[1:]) # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: # Decrypt the cipher text with the encryption key. try: plain_text = client.decrypt( diff --git a/kmip/demos/pie/derive_key.py b/kmip/demos/pie/derive_key.py index 122799b..f66e7e9 100644 --- a/kmip/demos/pie/derive_key.py +++ b/kmip/demos/pie/derive_key.py @@ -30,7 +30,10 @@ if __name__ == '__main__': config = opts.config # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: # Create keys to use for derivation try: key_id = client.create( diff --git a/kmip/demos/pie/destroy.py b/kmip/demos/pie/destroy.py index 7e7dc33..0302282 100644 --- a/kmip/demos/pie/destroy.py +++ b/kmip/demos/pie/destroy.py @@ -37,7 +37,10 @@ if __name__ == '__main__': sys.exit() # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: try: client.destroy(uid) logger.info("Successfully destroyed secret with ID: {0}".format( diff --git a/kmip/demos/pie/encrypt.py b/kmip/demos/pie/encrypt.py index 1946eeb..4a84ffe 100644 --- a/kmip/demos/pie/encrypt.py +++ b/kmip/demos/pie/encrypt.py @@ -50,7 +50,10 @@ if __name__ == '__main__': message = bytes(message, 'utf-8') # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: # Create an encryption key. try: key_id = client.create( diff --git a/kmip/demos/pie/get.py b/kmip/demos/pie/get.py index 90fc434..aaa8962 100644 --- a/kmip/demos/pie/get.py +++ b/kmip/demos/pie/get.py @@ -37,7 +37,10 @@ if __name__ == '__main__': sys.exit() # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: try: secret = client.get(uid) logger.info("Successfully retrieved secret with ID: {0}".format( diff --git a/kmip/demos/pie/get_attribute_list.py b/kmip/demos/pie/get_attribute_list.py index 27b3dad..2c25c1b 100644 --- a/kmip/demos/pie/get_attribute_list.py +++ b/kmip/demos/pie/get_attribute_list.py @@ -37,7 +37,10 @@ if __name__ == '__main__': sys.exit() # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: try: attribute_names = client.get_attribute_list(uid) logger.info("Successfully retrieved {0} attribute names:".format( diff --git a/kmip/demos/pie/locate.py b/kmip/demos/pie/locate.py index 2c10880..bbd1336 100644 --- a/kmip/demos/pie/locate.py +++ b/kmip/demos/pie/locate.py @@ -53,7 +53,10 @@ if __name__ == '__main__': attributes = [name_obj] # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: try: uuids = client.locate(attributes=attributes) logger.info("Located uuids: {0}".format(uuids)) diff --git a/kmip/demos/pie/mac.py b/kmip/demos/pie/mac.py index d30a34d..b5288ed 100644 --- a/kmip/demos/pie/mac.py +++ b/kmip/demos/pie/mac.py @@ -48,7 +48,10 @@ if __name__ == '__main__': algorithm = getattr(enums.CryptographicAlgorithm, algorithm, None) # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: try: uid, mac_data = client.mac(data, uid, algorithm) logger.info("Successfully done MAC using key with ID: " diff --git a/kmip/demos/pie/register_certificate.py b/kmip/demos/pie/register_certificate.py index f5eeae6..ffaa38a 100644 --- a/kmip/demos/pie/register_certificate.py +++ b/kmip/demos/pie/register_certificate.py @@ -91,7 +91,10 @@ if __name__ == '__main__': cert.operation_policy_name = opts.operation_policy_name # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: try: uid = client.register(cert) logger.info("Successfully registered certificate with ID: " diff --git a/kmip/demos/pie/register_opaque_object.py b/kmip/demos/pie/register_opaque_object.py index 043a77c..e0523c8 100644 --- a/kmip/demos/pie/register_opaque_object.py +++ b/kmip/demos/pie/register_opaque_object.py @@ -39,7 +39,10 @@ if __name__ == '__main__': obj.operation_policy_name = opts.operation_policy_name # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: try: uid = client.register(obj) logger.info("Successfully registered opaque object with ID: " diff --git a/kmip/demos/pie/register_private_key.py b/kmip/demos/pie/register_private_key.py index 7807f8f..ee27ffb 100644 --- a/kmip/demos/pie/register_private_key.py +++ b/kmip/demos/pie/register_private_key.py @@ -118,7 +118,10 @@ if __name__ == '__main__': key.operation_policy_name = opts.operation_policy_name # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: try: uid = client.register(key) logger.info("Successfully registered private key with ID: " diff --git a/kmip/demos/pie/register_public_key.py b/kmip/demos/pie/register_public_key.py index b76728e..bc867dd 100644 --- a/kmip/demos/pie/register_public_key.py +++ b/kmip/demos/pie/register_public_key.py @@ -60,7 +60,10 @@ if __name__ == '__main__': key.operation_policy_name = opts.operation_policy_name # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: try: uid = client.register(key) logger.info("Successfully registered public key with ID: " diff --git a/kmip/demos/pie/register_secret_data.py b/kmip/demos/pie/register_secret_data.py index b4e3628..2ac7072 100644 --- a/kmip/demos/pie/register_secret_data.py +++ b/kmip/demos/pie/register_secret_data.py @@ -41,7 +41,10 @@ if __name__ == '__main__': secret.operation_policy_name = opts.operation_policy_name # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: try: uid = client.register(secret) logger.info( diff --git a/kmip/demos/pie/register_symmetric_key.py b/kmip/demos/pie/register_symmetric_key.py index 65c3b5e..38a0689 100644 --- a/kmip/demos/pie/register_symmetric_key.py +++ b/kmip/demos/pie/register_symmetric_key.py @@ -44,7 +44,10 @@ if __name__ == '__main__': key.operation_policy_name = opts.operation_policy_name # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: try: uid = client.register(key) logger.info("Successfully registered symmetric key with ID: " diff --git a/kmip/demos/pie/sign.py b/kmip/demos/pie/sign.py index 286319b..291de5f 100644 --- a/kmip/demos/pie/sign.py +++ b/kmip/demos/pie/sign.py @@ -31,7 +31,10 @@ if __name__ == '__main__': config = opts.config # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: # Create keys to use for derivation try: signing_key_id = client.register( diff --git a/kmip/demos/pie/signature_verify.py b/kmip/demos/pie/signature_verify.py index b3dba5c..18010e7 100644 --- a/kmip/demos/pie/signature_verify.py +++ b/kmip/demos/pie/signature_verify.py @@ -31,7 +31,10 @@ if __name__ == '__main__': config = opts.config # Build the client and connect to the server - with client.ProxyKmipClient(config=config) as client: + with client.ProxyKmipClient( + config=config, + config_file=opts.config_file + ) as client: # Create keys to use for derivation try: signing_key_id = client.register( diff --git a/kmip/demos/units/activate.py b/kmip/demos/units/activate.py index 24c8f2e..27796e7 100644 --- a/kmip/demos/units/activate.py +++ b/kmip/demos/units/activate.py @@ -40,7 +40,7 @@ if __name__ == '__main__': sys.exit() # Build the client and connect to the server - client = KMIPProxy(config=config) + client = KMIPProxy(config=config, config_file=opts.config_file) client.open() # Activate the object diff --git a/kmip/demos/units/create.py b/kmip/demos/units/create.py index b41ff00..60179ef 100644 --- a/kmip/demos/units/create.py +++ b/kmip/demos/units/create.py @@ -74,7 +74,7 @@ if __name__ == '__main__': credential = credential_factory.create_credential(credential_type, credential_value) # Build the client and connect to the server - client = KMIPProxy(config=config) + client = KMIPProxy(config=config, config_file=opts.config_file) client.open() # Build the different object attributes diff --git a/kmip/demos/units/create_key_pair.py b/kmip/demos/units/create_key_pair.py index 86e8d71..c0e4dac 100644 --- a/kmip/demos/units/create_key_pair.py +++ b/kmip/demos/units/create_key_pair.py @@ -87,7 +87,7 @@ if __name__ == '__main__': credential = credential_factory.create_credential(credential_type, credential_value) # Build the client and connect to the server - client = KMIPProxy(config=config) + client = KMIPProxy(config=config, config_file=opts.config_file) client.open() algorithm_obj = attribute_factory.create_attribute(attribute_type, diff --git a/kmip/demos/units/destroy.py b/kmip/demos/units/destroy.py index cb27336..bedaa00 100644 --- a/kmip/demos/units/destroy.py +++ b/kmip/demos/units/destroy.py @@ -59,7 +59,7 @@ if __name__ == '__main__': credential = credential_factory.create_credential(credential_type, credential_value) # Build the client and connect to the server - client = KMIPProxy(config=config) + client = KMIPProxy(config=config, config_file=opts.config_file) client.open() # Destroy the SYMMETRIC_KEY object diff --git a/kmip/demos/units/discover_versions.py b/kmip/demos/units/discover_versions.py index ad9a662..4d18087 100644 --- a/kmip/demos/units/discover_versions.py +++ b/kmip/demos/units/discover_versions.py @@ -45,7 +45,7 @@ if __name__ == '__main__': protocol_versions.append(ProtocolVersion(int(mm[0]), int(mm[1]))) # Build the client and connect to the server - client = KMIPProxy(config=config) + client = KMIPProxy(config=config, config_file=opts.config_file) client.open() result = client.discover_versions(protocol_versions=protocol_versions) diff --git a/kmip/demos/units/get.py b/kmip/demos/units/get.py index db1cc0f..8db8c83 100644 --- a/kmip/demos/units/get.py +++ b/kmip/demos/units/get.py @@ -77,7 +77,7 @@ if __name__ == '__main__': key_format_type = KeyFormatType(format_type_enum) # Build the client and connect to the server - client = KMIPProxy(config=config) + client = KMIPProxy(config=config, config_file=opts.config_file) client.open() # Retrieve the SYMMETRIC_KEY object diff --git a/kmip/demos/units/locate.py b/kmip/demos/units/locate.py index 1e882ac..7eb6057 100644 --- a/kmip/demos/units/locate.py +++ b/kmip/demos/units/locate.py @@ -64,7 +64,7 @@ if __name__ == '__main__': credential = credential_factory.create_credential(credential_type, credential_value) # Build the client and connect to the server - client = KMIPProxy(config=config) + client = KMIPProxy(config=config, config_file=opts.config_file) client.open() # Build name attribute diff --git a/kmip/demos/units/query.py b/kmip/demos/units/query.py index 144d86d..298c003 100644 --- a/kmip/demos/units/query.py +++ b/kmip/demos/units/query.py @@ -56,7 +56,7 @@ if __name__ == '__main__': QueryFunction(QueryFunctionEnum.QUERY_EXTENSION_MAP)) # Build the client and connect to the server - client = KMIPProxy(config=config) + client = KMIPProxy(config=config, config_file=opts.config_file) client.open() result = client.query(query_functions=query_functions) diff --git a/kmip/demos/units/register.py b/kmip/demos/units/register.py index 6f177f7..05d4f1a 100644 --- a/kmip/demos/units/register.py +++ b/kmip/demos/units/register.py @@ -72,7 +72,7 @@ if __name__ == '__main__': # Build the client, connect to the server, register the secret, and # disconnect from the server - client = KMIPProxy(config=config) + client = KMIPProxy(config=config, config_file=opts.config_file) client.open() result = client.register(object_type, template_attribute, secret) diff --git a/kmip/demos/units/revoke.py b/kmip/demos/units/revoke.py index 800918b..b569b98 100644 --- a/kmip/demos/units/revoke.py +++ b/kmip/demos/units/revoke.py @@ -41,7 +41,7 @@ if __name__ == '__main__': sys.exit() # Build the client and connect to the server - client = KMIPProxy(config=config) + client = KMIPProxy(config=config, config_file=opts.config_file) client.open() # Activate the object diff --git a/kmip/demos/utils.py b/kmip/demos/utils.py index 7d8c686..7401162 100644 --- a/kmip/demos/utils.py +++ b/kmip/demos/utils.py @@ -86,6 +86,15 @@ def build_cli_parser(operation=None): default="client", dest="config", help="Client configuration group to load from configuration file") + parser.add_option( + "-s", + "--config-file", + action="store", + type="str", + default=None, + dest="config_file", + help="Path to the client configuration file." + ) if operation is Operation.CREATE: parser.add_option( diff --git a/kmip/pie/client.py b/kmip/pie/client.py index f9fbd7a..95c6c08 100644 --- a/kmip/pie/client.py +++ b/kmip/pie/client.py @@ -61,7 +61,8 @@ class ProxyKmipClient(object): ssl_version=None, username=None, password=None, - config='client'): + config='client', + config_file=None): """ Construct a ProxyKmipClient. @@ -88,6 +89,9 @@ class ProxyKmipClient(object): file. Use to load a specific set of configuration settings from the configuration file, instead of specifying them manually. Optional, defaults to the default client section, 'client'. + config_file (string): The path to the client's configuration file. + Optional, defaults to None. + """ self.logger = logging.getLogger() @@ -104,7 +108,9 @@ class ProxyKmipClient(object): ssl_version=ssl_version, username=username, password=password, - config=config) + config=config, + config_file=config_file + ) # TODO (peter-hamilton) Add a multiprocessing lock for synchronization. self._is_open = False diff --git a/kmip/services/kmip_client.py b/kmip/services/kmip_client.py index f4e861a..547190e 100644 --- a/kmip/services/kmip_client.py +++ b/kmip/services/kmip_client.py @@ -59,6 +59,7 @@ from kmip.core.utils import BytearrayStream import logging import logging.config import os +import six import socket import ssl @@ -73,15 +74,27 @@ class KMIPProxy: cert_reqs=None, ssl_version=None, ca_certs=None, do_handshake_on_connect=None, suppress_ragged_eofs=None, - username=None, password=None, timeout=30, config='client'): + username=None, password=None, timeout=30, config='client', + config_file=None): self.logger = logging.getLogger(__name__) self.credential_factory = CredentialFactory() self.config = config + if config_file: + if not isinstance(config_file, six.string_types): + raise ValueError( + "The client configuration file argument must be a string." + ) + if not os.path.exists(config_file): + raise ValueError( + "The client configuration file '{}' does not " + "exist.".format(config_file) + ) + self._set_variables(host, port, keyfile, certfile, cert_reqs, ssl_version, ca_certs, do_handshake_on_connect, suppress_ragged_eofs, - username, password, timeout) + username, password, timeout, config_file) self.batch_items = [] self.conformance_clauses = [ @@ -1553,8 +1566,8 @@ class KMIPProxy: def _set_variables(self, host, port, keyfile, certfile, cert_reqs, ssl_version, ca_certs, do_handshake_on_connect, suppress_ragged_eofs, - username, password, timeout): - conf = ConfigHelper() + username, password, timeout, config_file): + conf = ConfigHelper(config_file) # TODO: set this to a host list self.host_list_str = conf.get_valid_value( diff --git a/kmip/tests/unit/services/test_kmip_client.py b/kmip/tests/unit/services/test_kmip_client.py index a4c8b17..c9c7c95 100644 --- a/kmip/tests/unit/services/test_kmip_client.py +++ b/kmip/tests/unit/services/test_kmip_client.py @@ -96,6 +96,32 @@ class TestKMIPClient(TestCase): def tearDown(self): super(TestKMIPClient, self).tearDown() + def test_init_with_invalid_config_file_value(self): + """ + Test that the right error is raised when an invalid configuration file + value is provided to the client. + """ + kwargs = {'config_file': 1} + self.assertRaisesRegexp( + ValueError, + "The client configuration file argument must be a string.", + KMIPProxy, + **kwargs + ) + + def test_init_with_invalid_config_file_path(self): + """ + Test that the right error is raised when an invalid configuration file + path is provided to the client. + """ + kwargs = {'config_file': 'invalid'} + self.assertRaisesRegexp( + ValueError, + "The client configuration file 'invalid' does not exist.", + KMIPProxy, + **kwargs + ) + def test_close(self): """ Test that calling close on the client works as expected. @@ -646,13 +672,21 @@ class TestKMIPClient(TestCase): host_list_string = '127.0.0.1,127.0.0.3, 127.0.0.5' host_list_expected = ['127.0.0.1', '127.0.0.3', '127.0.0.5'] - self.client._set_variables(host=host_list_string, - port=None, keyfile=None, certfile=None, - cert_reqs=None, ssl_version=None, - ca_certs=None, - do_handshake_on_connect=False, - suppress_ragged_eofs=None, username=None, - password=None, timeout=None) + self.client._set_variables( + host=host_list_string, + port=None, + keyfile=None, + certfile=None, + cert_reqs=None, + ssl_version=None, + ca_certs=None, + do_handshake_on_connect=False, + suppress_ragged_eofs=None, + username=None, + password=None, + timeout=None, + config_file=None + ) self.assertEqual(host_list_expected, self.client.host_list) def test_host_is_invalid_input(self):