diff --git a/kmip/core/enums.py b/kmip/core/enums.py index fb3fdce..dd0d888 100644 --- a/kmip/core/enums.py +++ b/kmip/core/enums.py @@ -18,6 +18,7 @@ import copy import enum +import six class OrderedEnum(enum.Enum): @@ -1669,6 +1670,151 @@ class WrappingMethod(enum.Enum): TR_31 = 0x00000005 +attribute_name_tag_table = [ + ("Activation Date", Tags.ACTIVATION_DATE), + ("Alternative Name", Tags.ALTERNATIVE_NAME), + ("Always Sensitive", Tags.ALWAYS_SENSITIVE), + ("Application Specific Information", Tags.APPLICATION_SPECIFIC_INFORMATION), + ("Archive Date", Tags.ARCHIVE_DATE), + ("Attribute", Tags.ATTRIBUTE), + ("Certificate Identifier", Tags.CERTIFICATE_IDENTIFIER), + ("Certificate Issuer", Tags.CERTIFICATE_ISSUER), + ("Certificate Issuer C", Tags.CERTIFICATE_ISSUER_C), + ("Certificate Issuer CN", Tags.CERTIFICATE_ISSUER_CN), + ("Certificate Issuer DC", Tags.CERTIFICATE_ISSUER_DC), + ("Certificate Issuer DN Qualifier", Tags.CERTIFICATE_ISSUER_DN_QUALIFIER), + ("Certificate Issuer Email", Tags.CERTIFICATE_ISSUER_EMAIL), + ("Certificate Issuer L", Tags.CERTIFICATE_ISSUER_L), + ("Certificate Issuer O", Tags.CERTIFICATE_ISSUER_O), + ("Certificate Issuer OU", Tags.CERTIFICATE_ISSUER_OU), + ("Certificate Issuer Serial Number", Tags.CERTIFICATE_ISSUER_SERIAL_NUMBER), + ("Certificate Issuer ST", Tags.CERTIFICATE_ISSUER_ST), + ("Certificate Issuer Title", Tags.CERTIFICATE_ISSUER_TITLE), + ("Certificate Issuer UID", Tags.CERTIFICATE_ISSUER_UID), + ("Certificate Length", Tags.CERTIFICATE_LENGTH), + ("Certificate Subject", Tags.CERTIFICATE_SUBJECT), + ("Certificate Subject C", Tags.CERTIFICATE_SUBJECT_C), + ("Certificate Subject CN", Tags.CERTIFICATE_SUBJECT_CN), + ("Certificate Subject DC", Tags.CERTIFICATE_SUBJECT_DC), + ("Certificate Subject DN Qualifier", Tags.CERTIFICATE_SUBJECT_DN_QUALIFIER), + ("Certificate Subject Email", Tags.CERTIFICATE_SUBJECT_EMAIL), + ("Certificate Subject L", Tags.CERTIFICATE_SUBJECT_L), + ("Certificate Subject O", Tags.CERTIFICATE_SUBJECT_O), + ("Certificate Subject OU", Tags.CERTIFICATE_SUBJECT_OU), + ("Certificate Subject Serial Number", Tags.CERTIFICATE_SUBJECT_SERIAL_NUMBER), + ("Certificate Subject ST", Tags.CERTIFICATE_SUBJECT_ST), + ("Certificate Subject Title", Tags.CERTIFICATE_SUBJECT_TITLE), + ("Certificate Subject UID", Tags.CERTIFICATE_SUBJECT_UID), + ("Certificate Type", Tags.CERTIFICATE_TYPE), + ("Comment", Tags.COMMENT), + ("Compromise Date", Tags.COMPROMISE_DATE), + ("Compromise Occurrence Date", Tags.COMPROMISE_OCCURRENCE_DATE), + ("Contact Information", Tags.CONTACT_INFORMATION), + ("Cryptographic Algorithm", Tags.CRYPTOGRAPHIC_ALGORITHM), + ("Cryptographic Domain Parameters", Tags.CRYPTOGRAPHIC_DOMAIN_PARAMETERS), + ("Cryptographic Length", Tags.CRYPTOGRAPHIC_LENGTH), + ("Cryptographic Parameters", Tags.CRYPTOGRAPHIC_PARAMETERS), + ("Cryptographic Usage Mask", Tags.CRYPTOGRAPHIC_USAGE_MASK), + ("Custom Attribute", Tags.CUSTOM_ATTRIBUTE), + ("Deactivation Date", Tags.DEACTIVATION_DATE), + ("Description", Tags.DESCRIPTION), + ("Destroy Date", Tags.DESTROY_DATE), + ("Digest", Tags.DIGEST), + ("Digital Signature Algorithm", Tags.DIGITAL_SIGNATURE_ALGORITHM), + ("Extractable", Tags.EXTRACTABLE), + ("Fresh", Tags.FRESH), + ("Initial Date", Tags.INITIAL_DATE), + ("Key Format Type", Tags.KEY_FORMAT_TYPE), + ("Key Value Location", Tags.KEY_VALUE_LOCATION), + ("Key Value Present", Tags.KEY_VALUE_PRESENT), + ("Last Change Date", Tags.LAST_CHANGE_DATE), + ("Lease Time", Tags.LEASE_TIME), + ("Link", Tags.LINK), + ("Name", Tags.NAME), + ("Never Extractable", Tags.NEVER_EXTRACTABLE), + ("NIST Key Type", Tags.NIST_KEY_TYPE), + ("Object Group", Tags.OBJECT_GROUP), + ("Object Type", Tags.OBJECT_TYPE), + ("Opaque Data Type", Tags.OPAQUE_DATA_TYPE), + ("Operation Policy Name", Tags.OPERATION_POLICY_NAME), + ("Original Creation Date", Tags.ORIGINAL_CREATION_DATE), + ("PKCS#12 Friendly Name", Tags.PKCS12_FRIENDLY_NAME), + ("Process Start Date", Tags.PROCESS_START_DATE), + ("Protect Stop Date", Tags.PROTECT_STOP_DATE), + ("Protection Level", Tags.PROTECTION_LEVEL), + ("Protection Period", Tags.PROTECTION_PERIOD), + ("Protection Storage Mask", Tags.PROTECTION_STORAGE_MASK), + ("Quantum Safe", Tags.QUANTUM_SAFE), + ("Random Number Generator", Tags.RANDOM_NUMBER_GENERATOR), + ("Revocation Reason", Tags.REVOCATION_REASON), + ("Sensitive", Tags.SENSITIVE), + ("Short Unique Identifier", Tags.SHORT_UNIQUE_IDENTIFIER), + ("State", Tags.STATE), + ("Unique Identifier", Tags.UNIQUE_IDENTIFIER), + ("Usage Limits", Tags.USAGE_LIMITS), + ("X.509 Certificate Identifier", Tags.X_509_CERTIFICATE_IDENTIFIER), + ("X.509 Certificate Issuer", Tags.X_509_CERTIFICATE_ISSUER), + ("X.509 Certificate Subject", Tags.X_509_CERTIFICATE_SUBJECT) +] + + +def convert_attribute_name_to_tag(value): + """ + A utility function that converts an attribute name string into the + corresponding attribute tag. + + For example: 'State' -> enums.Tags.STATE + + Args: + value (string): The string name of the attribute. + + Returns: + enum: The Tags enumeration value that corresponds to the attribute + name string. + + Raises: + ValueError: if the attribute name string is not a string or if it is + an unrecognized attribute name + """ + if not isinstance(value, six.string_types): + raise ValueError("The attribute name must be a string.") + + for entry in attribute_name_tag_table: + if value == entry[0]: + return entry[1] + + raise ValueError("Unrecognized attribute name: '{}'".format(value)) + + +def convert_attribute_tag_to_name(value): + """ + A utility function that converts an attribute tag into the corresponding + attribute name string. + + For example: enums.Tags.STATE -> 'State' + + Args: + value (enum): The Tags enumeration value of the attribute. + + Returns: + string: The attribute name string that corresponds to the attribute + tag. + + Raises: + ValueError: if the attribute tag is not a Tags enumeration or if it + is unrecognized attribute tag + """ + if not isinstance(value, Tags): + raise ValueError("The attribute tag must be a Tags enumeration.") + + for entry in attribute_name_tag_table: + if value == entry[1]: + return entry[0] + + raise ValueError("Unrecognized attribute tag: {}".format(value)) + + + def is_enum_value(enum_class, potential_value): """ A utility function that checks if the enumeration class contains the diff --git a/kmip/core/objects.py b/kmip/core/objects.py index 76ac378..2287b95 100644 --- a/kmip/core/objects.py +++ b/kmip/core/objects.py @@ -2974,6 +2974,56 @@ class PublicKeyTemplateAttribute(TemplateAttribute): names, attributes, Tags.PUBLIC_KEY_TEMPLATE_ATTRIBUTE) +def convert_template_attribute_to_attributes(value): + if not isinstance(value, TemplateAttribute): + raise TypeError("Input must be a TemplateAttribute structure.") + + tag = enums.Tags.ATTRIBUTES + if isinstance(value, CommonTemplateAttribute): + tag = enums.Tags.COMMON_ATTRIBUTES + elif isinstance(value, PrivateKeyTemplateAttribute): + tag = enums.Tags.PRIVATE_KEY_ATTRIBUTES + elif isinstance(value, PublicKeyTemplateAttribute): + tag = enums.Tags.PUBLIC_KEY_ATTRIBUTES + + attribute_values = [] + for attribute in value.attributes: + attribute_tag = enums.convert_attribute_name_to_tag( + attribute.attribute_name.value + ) + attribute_value = attribute.attribute_value + attribute_value.tag = attribute_tag + attribute_values.append(attribute_value) + + return Attributes(attributes=attribute_values, tag=tag) + + +def convert_attributes_to_template_attribute(value): + if not isinstance(value, Attributes): + raise TypeError("Input must be an Attributes structure.") + + attribute_structures = [] + for attribute_value in value.attributes: + attribute_name = enums.convert_attribute_tag_to_name( + attribute_value.tag + ) + attribute_structures.append( + Attribute( + attribute_name=Attribute.AttributeName(attribute_name), + attribute_value=attribute_value + ) + ) + + if value.tag == enums.Tags.COMMON_ATTRIBUTES: + return CommonTemplateAttribute(attributes=attribute_structures) + elif value.tag == enums.Tags.PRIVATE_KEY_ATTRIBUTES: + return PrivateKeyTemplateAttribute(attributes=attribute_structures) + elif value.tag == enums.Tags.PUBLIC_KEY_ATTRIBUTES: + return PublicKeyTemplateAttribute(attributes=attribute_structures) + else: + return TemplateAttribute(attributes=attribute_structures) + + # 2.1.9 class ExtensionName(TextString): """ diff --git a/kmip/tests/unit/core/objects/test_objects.py b/kmip/tests/unit/core/objects/test_objects.py index 1a98a5a..30e90a9 100644 --- a/kmip/tests/unit/core/objects/test_objects.py +++ b/kmip/tests/unit/core/objects/test_objects.py @@ -781,6 +781,301 @@ class TestAttributes(TestCase): self.assertTrue(b != a) +class TestAttributeUtilities(testtools.TestCase): + + def setUp(self): + super(TestAttributeUtilities, self).setUp() + + def tearDown(self): + super(TestAttributeUtilities, self).tearDown() + + def test_convert_template_attribute_to_attributes(self): + template_attribute = objects.TemplateAttribute( + attributes=[ + objects.Attribute( + attribute_name=objects.Attribute.AttributeName( + "State" + ), + attribute_value=primitives.Enumeration( + enums.State, + value=enums.State.PRE_ACTIVE, + tag=enums.Tags.STATE + ) + ) + ] + ) + + value = objects.convert_template_attribute_to_attributes( + template_attribute + ) + + self.assertIsInstance(value, objects.Attributes) + self.assertEqual(enums.Tags.ATTRIBUTES, value.tag) + self.assertIsInstance(value.attributes, list) + self.assertEqual(1, len(value.attributes)) + self.assertEqual( + primitives.Enumeration( + enums.State, + value=enums.State.PRE_ACTIVE, + tag=enums.Tags.STATE + ), + value.attributes[0] + ) + + def test_convert_common_template_attribute_to_attributes(self): + template_attribute = objects.CommonTemplateAttribute( + attributes=[ + objects.Attribute( + attribute_name=objects.Attribute.AttributeName( + "Cryptographic Algorithm" + ), + attribute_value=primitives.Enumeration( + enums.CryptographicAlgorithm, + value=enums.CryptographicAlgorithm.AES, + tag=enums.Tags.CRYPTOGRAPHIC_ALGORITHM + ) + ) + ] + ) + + value = objects.convert_template_attribute_to_attributes( + template_attribute + ) + + self.assertIsInstance(value, objects.Attributes) + self.assertEqual(enums.Tags.COMMON_ATTRIBUTES, value.tag) + self.assertIsInstance(value.attributes, list) + self.assertEqual(1, len(value.attributes)) + self.assertEqual( + primitives.Enumeration( + enums.CryptographicAlgorithm, + value=enums.CryptographicAlgorithm.AES, + tag=enums.Tags.CRYPTOGRAPHIC_ALGORITHM + ), + value.attributes[0] + ) + + def test_convert_private_key_template_attribute_to_attributes(self): + template_attribute = objects.PrivateKeyTemplateAttribute( + attributes=[ + objects.Attribute( + attribute_name=objects.Attribute.AttributeName( + "Key Format Type" + ), + attribute_value=primitives.Enumeration( + enums.KeyFormatType, + value=enums.KeyFormatType.RAW, + tag=enums.Tags.KEY_FORMAT_TYPE + ) + ) + ] + ) + + value = objects.convert_template_attribute_to_attributes( + template_attribute + ) + + self.assertIsInstance(value, objects.Attributes) + self.assertEqual(enums.Tags.PRIVATE_KEY_ATTRIBUTES, value.tag) + self.assertIsInstance(value.attributes, list) + self.assertEqual(1, len(value.attributes)) + self.assertEqual( + primitives.Enumeration( + enums.KeyFormatType, + value=enums.KeyFormatType.RAW, + tag=enums.Tags.KEY_FORMAT_TYPE + ), + value.attributes[0] + ) + + def test_convert_public_key_template_attribute_to_attributes(self): + template_attribute = objects.PublicKeyTemplateAttribute( + attributes=[ + objects.Attribute( + attribute_name=objects.Attribute.AttributeName( + "Object Type" + ), + attribute_value=primitives.Enumeration( + enums.ObjectType, + value=enums.ObjectType.PUBLIC_KEY, + tag=enums.Tags.OBJECT_TYPE + ) + ) + ] + ) + + value = objects.convert_template_attribute_to_attributes( + template_attribute + ) + + self.assertIsInstance(value, objects.Attributes) + self.assertEqual(enums.Tags.PUBLIC_KEY_ATTRIBUTES, value.tag) + self.assertIsInstance(value.attributes, list) + self.assertEqual(1, len(value.attributes)) + self.assertEqual( + primitives.Enumeration( + enums.ObjectType, + value=enums.ObjectType.PUBLIC_KEY, + tag=enums.Tags.OBJECT_TYPE + ), + value.attributes[0] + ) + + def test_convert_template_attribute_to_attributes_invalid(self): + args = ("invalid", ) + self.assertRaisesRegex( + TypeError, + "Input must be a TemplateAttribute structure.", + objects.convert_template_attribute_to_attributes, + *args + ) + + def test_convert_attributes_to_template_attribute(self): + attributes = objects.Attributes( + attributes=[ + primitives.Enumeration( + enums.State, + value=enums.State.PRE_ACTIVE, + tag=enums.Tags.STATE + ) + ], + tag=enums.Tags.ATTRIBUTES + ) + + value = objects.convert_attributes_to_template_attribute(attributes) + + self.assertIsInstance(value, objects.TemplateAttribute) + self.assertIsInstance(value.attributes, list) + self.assertEqual(1, len(value.attributes)) + self.assertIsInstance( + value.attributes[0], + objects.Attribute + ) + self.assertEqual( + "State", + value.attributes[0].attribute_name.value + ) + self.assertEqual( + primitives.Enumeration( + enums.State, + value=enums.State.PRE_ACTIVE, + tag=enums.Tags.ATTRIBUTE_VALUE + ), + value.attributes[0].attribute_value + ) + + def test_convert_attributes_to_common_template_attribute(self): + attributes = objects.Attributes( + attributes=[ + primitives.Enumeration( + enums.CryptographicAlgorithm, + value=enums.CryptographicAlgorithm.AES, + tag=enums.Tags.CRYPTOGRAPHIC_ALGORITHM + ) + ], + tag=enums.Tags.COMMON_ATTRIBUTES + ) + + value = objects.convert_attributes_to_template_attribute(attributes) + + self.assertIsInstance(value, objects.CommonTemplateAttribute) + self.assertIsInstance(value.attributes, list) + self.assertEqual(1, len(value.attributes)) + self.assertIsInstance( + value.attributes[0], + objects.Attribute + ) + self.assertEqual( + "Cryptographic Algorithm", + value.attributes[0].attribute_name.value + ) + self.assertEqual( + primitives.Enumeration( + enums.CryptographicAlgorithm, + value=enums.CryptographicAlgorithm.AES, + tag=enums.Tags.ATTRIBUTE_VALUE + ), + value.attributes[0].attribute_value + ) + + def test_convert_attributes_to_private_key_template_attribute(self): + attributes = objects.Attributes( + attributes=[ + primitives.Enumeration( + enums.KeyFormatType, + value=enums.KeyFormatType.RAW, + tag=enums.Tags.KEY_FORMAT_TYPE + ) + ], + tag=enums.Tags.PRIVATE_KEY_ATTRIBUTES + ) + + value = objects.convert_attributes_to_template_attribute(attributes) + + self.assertIsInstance(value, objects.PrivateKeyTemplateAttribute) + self.assertIsInstance(value.attributes, list) + self.assertEqual(1, len(value.attributes)) + self.assertIsInstance( + value.attributes[0], + objects.Attribute + ) + self.assertEqual( + "Key Format Type", + value.attributes[0].attribute_name.value + ) + self.assertEqual( + primitives.Enumeration( + enums.KeyFormatType, + value=enums.KeyFormatType.RAW, + tag=enums.Tags.ATTRIBUTE_VALUE + ), + value.attributes[0].attribute_value + ) + + def test_convert_attributes_to_public_key_template_attribute(self): + attributes = objects.Attributes( + attributes=[ + primitives.Enumeration( + enums.ObjectType, + value=enums.ObjectType.PUBLIC_KEY, + tag=enums.Tags.OBJECT_TYPE + ) + ], + tag=enums.Tags.PUBLIC_KEY_ATTRIBUTES + ) + + value = objects.convert_attributes_to_template_attribute(attributes) + + self.assertIsInstance(value, objects.PublicKeyTemplateAttribute) + self.assertIsInstance(value.attributes, list) + self.assertEqual(1, len(value.attributes)) + self.assertIsInstance( + value.attributes[0], + objects.Attribute + ) + self.assertEqual( + "Object Type", + value.attributes[0].attribute_name.value + ) + self.assertEqual( + primitives.Enumeration( + enums.ObjectType, + value=enums.ObjectType.PUBLIC_KEY, + tag=enums.Tags.ATTRIBUTE_VALUE + ), + value.attributes[0].attribute_value + ) + + def test_convert_attributes_to_template_attribute_invalid(self): + args = ("invalid", ) + self.assertRaisesRegex( + TypeError, + "Input must be an Attributes structure.", + objects.convert_attributes_to_template_attribute, + *args + ) + + class TestKeyMaterialStruct(TestCase): """ A test suite for the KeyMaterialStruct. diff --git a/kmip/tests/unit/core/test_enums.py b/kmip/tests/unit/core/test_enums.py index 517af20..db67943 100644 --- a/kmip/tests/unit/core/test_enums.py +++ b/kmip/tests/unit/core/test_enums.py @@ -100,6 +100,50 @@ class TestEnumUtilityFunctions(testtools.TestCase): ) self.assertFalse(result) + def test_convert_attribute_name_to_tag(self): + self.assertEqual( + enums.Tags.OBJECT_TYPE, + enums.convert_attribute_name_to_tag("Object Type") + ) + + args = (enums.Tags.COMMON_ATTRIBUTES, ) + self.assertRaisesRegex( + ValueError, + "The attribute name must be a string.", + enums.convert_attribute_name_to_tag, + *args + ) + + args = ("invalid", ) + self.assertRaisesRegex( + ValueError, + "Unrecognized attribute name: 'invalid'".format(args[0]), + enums.convert_attribute_name_to_tag, + *args + ) + + def test_convert_attribute_tag_to_name(self): + self.assertEqual( + "Always Sensitive", + enums.convert_attribute_tag_to_name(enums.Tags.ALWAYS_SENSITIVE) + ) + + args = ("invalid", ) + self.assertRaisesRegex( + ValueError, + "The attribute tag must be a Tags enumeration.", + enums.convert_attribute_tag_to_name, + *args + ) + + args = (enums.Tags.COMMON_ATTRIBUTES, ) + self.assertRaisesRegex( + ValueError, + "Unrecognized attribute tag: {}".format(args[0]), + enums.convert_attribute_tag_to_name, + *args + ) + def test_is_attribute(self): # Test an attribute introduced in KMIP 1.0 result = enums.is_attribute(enums.Tags.UNIQUE_IDENTIFIER)