Update the PyKMIP clients to support changing their KMIP version

This change updates the PyKMIP clients, adding support for getting
and setting the KMIP version they use when making KMIP requests.
You can now do:

>>> client.kmip_version

to get the KMIP version enumeration the client is using. Use:

>>> client.kmip_version = enums.KMIPVersion.KMIP_1_1

to set the KMIP version the client uses.

The client unit tests have been updated to check and cover these
changes.

Fixes #470
This commit is contained in:
Peter Hamilton 2018-12-04 14:09:07 -05:00 committed by Peter Hamilton
parent 40c064a290
commit c5e4c4a290
5 changed files with 167 additions and 5 deletions

View File

@ -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

View File

@ -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.

View File

@ -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()

View File

@ -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):

View File

@ -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