diff --git a/kmip/core/enums.py b/kmip/core/enums.py index 30e8a99..502e27a 100644 --- a/kmip/core/enums.py +++ b/kmip/core/enums.py @@ -391,6 +391,14 @@ class KeyWrapType(enum.Enum): AS_REGISTERED = 0x00000002 +class KMIPVersion(enum.Enum): + KMIP_1_0 = "KMIP 1.0" + KMIP_1_1 = "KMIP 1.1" + KMIP_1_2 = "KMIP 1.2" + KMIP_1_3 = "KMIP 1.3" + KMIP_1_4 = "KMIP 1.4" + + class LinkType(enum.Enum): CERTIFICATE_LINK = 0x00000101 PUBLIC_KEY_LINK = 0x00000102 diff --git a/kmip/pie/client.py b/kmip/pie/client.py index f01f5fe..0506700 100644 --- a/kmip/pie/client.py +++ b/kmip/pie/client.py @@ -62,7 +62,8 @@ class ProxyKmipClient(object): username=None, password=None, config='client', - config_file=None): + config_file=None, + kmip_version=None): """ Construct a ProxyKmipClient. @@ -91,6 +92,9 @@ class ProxyKmipClient(object): Optional, defaults to the default client section, 'client'. config_file (string): The path to the client's configuration file. Optional, defaults to None. + kmip_version (KMIPVersion): The KMIP version the client should use + when making requests. Optional, defaults to None. If None at + request time, the client will use KMIP 1.2. """ self.logger = logging.getLogger(__name__) @@ -109,12 +113,47 @@ class ProxyKmipClient(object): username=username, password=password, config=config, - config_file=config_file + config_file=config_file, + kmip_version=kmip_version ) # TODO (peter-hamilton) Add a multiprocessing lock for synchronization. self._is_open = False + @property + def kmip_version(self): + """ + Get the KMIP version for the client. + + Return: + kmip_version (KMIPVersion): The KMIPVersion enumeration used by + the client for KMIP requests. + """ + return self.proxy.kmip_version + + @kmip_version.setter + def kmip_version(self, value): + """ + Set the KMIP version for the client. + + Args: + value (KMIPVersion): A KMIPVersion enumeration + + Return: + None + + Raises: + ValueError: if value is not a KMIPVersion enumeration + + Example: + >>> client.kmip_version = enums.KMIPVersion.KMIP_1_1 + >>> + """ + if isinstance(value, enums.KMIPVersion): + self.proxy.kmip_version = value + else: + raise ValueError("KMIP version must be a KMIPVersion enumeration") + def open(self): """ Open the client connection. diff --git a/kmip/services/kmip_client.py b/kmip/services/kmip_client.py index 5b54f1d..88674ac 100644 --- a/kmip/services/kmip_client.py +++ b/kmip/services/kmip_client.py @@ -13,6 +13,8 @@ # License for the specific language governing permissions and limitations # under the License. +from __future__ import print_function + from kmip.services.results import ActivateResult from kmip.services.results import CreateResult from kmip.services.results import CreateKeyPairResult @@ -68,7 +70,7 @@ FILE_PATH = os.path.dirname(os.path.abspath(__file__)) CONFIG_FILE = os.path.normpath(os.path.join(FILE_PATH, '../kmipconfig.ini')) -class KMIPProxy: +class KMIPProxy(object): def __init__(self, host=None, port=None, keyfile=None, certfile=None, @@ -76,7 +78,8 @@ class KMIPProxy: do_handshake_on_connect=None, suppress_ragged_eofs=None, username=None, password=None, timeout=30, config='client', - config_file=None): + config_file=None, + kmip_version=None): self.logger = logging.getLogger(__name__) self.credential_factory = CredentialFactory() self.config = config @@ -85,6 +88,12 @@ class KMIPProxy: # Otherwise, we can hit AttributeErrors when __del__ is called. self.socket = None + self._kmip_version = None + if kmip_version: + self.kmip_version = kmip_version + else: + self.kmip_version = enums.KMIPVersion.KMIP_1_2 + if config_file: if not isinstance(config_file, six.string_types): raise ValueError( @@ -109,6 +118,40 @@ class KMIPProxy: AuthenticationSuite.BASIC, AuthenticationSuite.TLS12] + @property + def kmip_version(self): + """ + Get the KMIP version for the client. + + Return: + kmip_version (KMIPVersion): The KMIPVersion enumeration used by + the client for KMIP requests. + """ + return self._kmip_version + + @kmip_version.setter + def kmip_version(self, value): + """ + Set the KMIP version for the client. + + Args: + value (KMIPVersion): A KMIPVersion enumeration + + Return: + None + + Raises: + ValueError: if value is not a KMIPVersion enumeration + + Example: + >>> client.kmip_version = enums.KMIPVersion.KMIP_1_1 + >>> + """ + if isinstance(value, enums.KMIPVersion): + self._kmip_version = value + else: + raise ValueError("KMIP version must be a KMIPVersion enumeration") + def get_supported_conformance_clauses(self): """ Get the list of conformance clauses supported by the client. @@ -1534,8 +1577,20 @@ class KMIPProxy: credential_value) return credential + def _build_protocol_version(self): + if self.kmip_version == enums.KMIPVersion.KMIP_1_0: + return ProtocolVersion(1, 0) + elif self.kmip_version == enums.KMIPVersion.KMIP_1_1: + return ProtocolVersion(1, 1) + elif self.kmip_version == enums.KMIPVersion.KMIP_1_2: + return ProtocolVersion(1, 2) + elif self.kmip_version == enums.KMIPVersion.KMIP_1_3: + return ProtocolVersion(1, 3) + else: + return ProtocolVersion(1, 4) + def _build_request_message(self, credential, batch_items): - protocol_version = ProtocolVersion(1, 2) + protocol_version = self._build_protocol_version() if credential is None: credential = self._build_credential() diff --git a/kmip/tests/unit/pie/test_client.py b/kmip/tests/unit/pie/test_client.py index 819b3c6..7c8964a 100644 --- a/kmip/tests/unit/pie/test_client.py +++ b/kmip/tests/unit/pie/test_client.py @@ -68,6 +68,36 @@ class TestProxyKmipClient(testtools.TestCase): password='password', config='test') + def test_kmip_version_get(self): + """ + Test that the KMIP version can be obtained from the client. + """ + client = ProxyKmipClient() + self.assertEqual(client.kmip_version, enums.KMIPVersion.KMIP_1_2) + + def test_kmip_version_set(self): + """ + Test that the KMIP version of the client can be set to a new value. + """ + client = ProxyKmipClient() + self.assertEqual(client.kmip_version, enums.KMIPVersion.KMIP_1_2) + client.kmip_version = enums.KMIPVersion.KMIP_1_1 + self.assertEqual(client.kmip_version, enums.KMIPVersion.KMIP_1_1) + + def test_kmip_version_set_error(self): + """ + Test that the right error gets raised when setting the client KMIP + version with an invalid value. + """ + client = ProxyKmipClient() + args = (client, "kmip_version", None) + self.assertRaisesRegexp( + ValueError, + "KMIP version must be a KMIPVersion enumeration", + setattr, + *args + ) + @mock.patch('kmip.pie.client.KMIPProxy', mock.MagicMock(spec_set=KMIPProxy)) def test_open(self): diff --git a/kmip/tests/unit/services/test_kmip_client.py b/kmip/tests/unit/services/test_kmip_client.py index 1d89c92..f8f76f8 100644 --- a/kmip/tests/unit/services/test_kmip_client.py +++ b/kmip/tests/unit/services/test_kmip_client.py @@ -96,6 +96,36 @@ class TestKMIPClient(TestCase): def tearDown(self): super(TestKMIPClient, self).tearDown() + def test_kmip_version_get(self): + """ + Test that the KMIP version can be obtained from the client. + """ + client = KMIPProxy() + self.assertEqual(client.kmip_version, enums.KMIPVersion.KMIP_1_2) + + def test_kmip_version_set(self): + """ + Test that the KMIP version of the client can be set to a new value. + """ + client = KMIPProxy() + self.assertEqual(client.kmip_version, enums.KMIPVersion.KMIP_1_2) + client.kmip_version = enums.KMIPVersion.KMIP_1_1 + self.assertEqual(client.kmip_version, enums.KMIPVersion.KMIP_1_1) + + def test_kmip_version_set_error(self): + """ + Test that the right error gets raised when setting the client KMIP + version with an invalid value. + """ + client = KMIPProxy() + args = (client, "kmip_version", None) + self.assertRaisesRegexp( + ValueError, + "KMIP version must be a KMIPVersion enumeration", + setattr, + *args + ) + def test_init_with_invalid_config_file_value(self): """ Test that the right error is raised when an invalid configuration file