diff --git a/kmip/core/enums.py b/kmip/core/enums.py index f01b069..3f7f3f1 100644 --- a/kmip/core/enums.py +++ b/kmip/core/enums.py @@ -61,6 +61,42 @@ class AttributeType(Enum): CUSTOM_ATTRIBUTE = 'Custom Attribute' +class ConformanceClause(Enum): + """ + The specification of KMIP features supported by KMIP clients and servers. + + The conformance clause defines the KMIP objects and operations that need + to be supported for a specific feature set. The clause is one of two core + components that make up a KMIP client/server profile. For more information, + see Section 5 of the KMIP 1.1 profiles document. + """ + DISCOVER_VERSIONS = 1 + BASELINE = 2 + SECRET_DATA = 3 + SYMMETRIC_KEY_STORE = 4 + SYMMETRIC_KEY_FOUNDRY = 5 + ASYMMETRIC_KEY_STORE = 6 + ASYMMETRIC_KEY_AND_CERTIFICATE_STORE = 7 + ASYMMETRIC_KEY_FOUNDRY = 8 + CERTIFICATE = 9 + ASYMMETRIC_KEY_FOUNDRY_AND_CERTIFICATE = 10 + STORAGE = 11 + + +class AuthenticationSuite(Enum): + """ + The type of authentication suite used by KMIP clients and servers. + + The authentication suite defines the protocol versions and cipher suites + that should be used to secure KMIP client/server communications. An + authentication suite is one of two core components that make up a KMIP + client/server profile. For more information, see Section 3 of the KMIP + 1.1 profiles document. + """ + BASIC = 1 + TLS12 = 2 + + # 9.1.1.2 class Types(Enum): DEFAULT = 0x00 diff --git a/kmip/services/kmip_client.py b/kmip/services/kmip_client.py index 141b4e3..a32703c 100644 --- a/kmip/services/kmip_client.py +++ b/kmip/services/kmip_client.py @@ -25,8 +25,10 @@ from kmip.services.results import RekeyKeyPairResult from kmip.core import attributes as attr -from kmip.core.enums import Operation as OperationEnum +from kmip.core.enums import AuthenticationSuite +from kmip.core.enums import ConformanceClause from kmip.core.enums import CredentialType +from kmip.core.enums import Operation as OperationEnum from kmip.core.factories.credentials import CredentialFactory @@ -84,6 +86,105 @@ class KMIPProxy(KMIP): username, password) self.batch_items = [] + self.conformance_clauses = [ + ConformanceClause.DISCOVER_VERSIONS] + + self.authentication_suites = [ + AuthenticationSuite.BASIC, + AuthenticationSuite.TLS12] + + def get_supported_conformance_clauses(self): + """ + Get the list of conformance clauses supported by the client. + + Returns: + list: A shallow copy of the list of supported conformance clauses. + + Example: + >>> client.get_supported_conformance_clauses() + [] + """ + return self.conformance_clauses[:] + + def get_supported_authentication_suites(self): + """ + Get the list of authentication suites supported by the client. + + Returns: + list: A shallow copy of the list of supported authentication + suites. + + Example: + >>> client.get_supported_authentication_suites() + [, ] + """ + return self.authentication_suites[:] + + def is_conformance_clause_supported(self, conformance_clause): + """ + Check if a ConformanceClause is supported by the client. + + Args: + conformance_clause (ConformanceClause): A ConformanceClause + enumeration to check against the list of supported + ConformanceClauses. + + Returns: + bool: True if the ConformanceClause is supported, False otherwise. + + Example: + >>> clause = ConformanceClause.DISCOVER_VERSIONS + >>> client.is_conformance_clause_supported(clause) + True + >>> clause = ConformanceClause.BASELINE + >>> client.is_conformance_clause_supported(clause) + False + """ + return conformance_clause in self.conformance_clauses + + def is_authentication_suite_supported(self, authentication_suite): + """ + Check if an AuthenticationSuite is supported by the client. + + Args: + authentication_suite (AuthenticationSuite): An AuthenticationSuite + enumeration to check against the list of supported + AuthenticationSuites. + + Returns: + bool: True if the AuthenticationSuite is supported, False + otherwise. + + Example: + >>> suite = AuthenticationSuite.BASIC + >>> client.is_authentication_suite_supported(suite) + True + >>> suite = AuthenticationSuite.TLS12 + >>> client.is_authentication_suite_supported(suite) + False + """ + return authentication_suite in self.authentication_suites + + def is_profile_supported(self, conformance_clause, authentication_suite): + """ + Check if a profile is supported by the client. + + Args: + conformance_clause (ConformanceClause): + authentication_suite (AuthenticationSuite): + + Returns: + bool: True if the profile is supported, False otherwise. + + Example: + >>> client.is_profile_supported( + ... ConformanceClause.DISCOVER_VERSIONS, + ... AuthenticationSuite.BASIC) + True + """ + return (self.is_conformance_clause_supported(conformance_clause) and + self.is_authentication_suite_supported(authentication_suite)) + def open(self): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) diff --git a/kmip/tests/services/test_kmip_client.py b/kmip/tests/services/test_kmip_client.py index 8592859..2d9f659 100644 --- a/kmip/tests/services/test_kmip_client.py +++ b/kmip/tests/services/test_kmip_client.py @@ -26,6 +26,8 @@ from kmip.core.attributes import CryptographicLength from kmip.core.attributes import PrivateKeyUniqueIdentifier from kmip.core.enums import AttributeType +from kmip.core.enums import AuthenticationSuite +from kmip.core.enums import ConformanceClause from kmip.core.enums import CredentialType from kmip.core.enums import CryptographicAlgorithm as CryptoAlgorithmEnum from kmip.core.enums import CryptographicUsageMask @@ -837,3 +839,115 @@ class TestKMIPClient(TestCase): def test_process_discover_versions_batch_item_no_results(self): protocol_versions = None self._test_process_discover_versions_batch_item(protocol_versions) + + +class TestClientProfileInformation(TestCase): + """ + A test suite for client profile information support. + """ + + def setUp(self): + super(TestClientProfileInformation, self).setUp() + + self.client = KMIPProxy() + + self.conformance_clauses = [ConformanceClause.DISCOVER_VERSIONS] + self.authentication_suites = [AuthenticationSuite.BASIC] + + self.client.conformance_clauses = self.conformance_clauses + self.client.authentication_suites = self.authentication_suites + + def tearDown(self): + super(TestClientProfileInformation, self).tearDown() + + def test_get_supported_conformance_clauses(self): + """ + Test that the list of supporting conformance clauses can be retrieved. + """ + conformance_clauses = self.client.get_supported_conformance_clauses() + self.assertEqual(self.conformance_clauses, conformance_clauses) + + def test_get_supported_authentication_suites(self): + """ + Test that the list of supporting authentication suites can be + retrieved. + """ + auth_suites = self.client.get_supported_authentication_suites() + self.assertEqual(self.authentication_suites, auth_suites) + + def test_is_conformance_clause_supported_with_valid(self): + """ + Test that the conformance clause support predicate returns True for + a ConformanceClause that is supported. + """ + clause = ConformanceClause.DISCOVER_VERSIONS + supported = self.client.is_conformance_clause_supported(clause) + self.assertTrue(supported) + + def test_is_conformance_clause_supported_with_invalid(self): + """ + Test that the conformance clause support predicate returns False for + a ConformanceClause that is not supported. + """ + clause = ConformanceClause.BASELINE + supported = self.client.is_conformance_clause_supported(clause) + self.assertFalse(supported) + + def test_is_authentication_suite_supported_with_valid(self): + """ + Test that the authentication suite support predicate returns True for + an AuthenticationSuite that is supported. + """ + suite = AuthenticationSuite.BASIC + supported = self.client.is_authentication_suite_supported(suite) + self.assertTrue(supported) + + def test_is_authentication_suite_supported_with_invalid(self): + """ + Test that the authentication suite support predicate returns False for + an AuthenticationSuite that is not supported. + """ + suite = AuthenticationSuite.TLS12 + supported = self.client.is_authentication_suite_supported(suite) + self.assertFalse(supported) + + def test_is_profile_supported(self): + """ + Test that the profile support predicate returns True for valid profile + components. + """ + supported = self.client.is_profile_supported( + ConformanceClause.DISCOVER_VERSIONS, + AuthenticationSuite.BASIC) + self.assertTrue(supported) + + # TODO (peter-hamilton) Replace following 3 tests with 1 parameterized test + def test_is_profile_supported_with_invalid_conformance_clause(self): + """ + Test that the profile support predicate returns False for an invalid + conformance clause. + """ + supported = self.client.is_profile_supported( + ConformanceClause.BASELINE, + AuthenticationSuite.BASIC) + self.assertFalse(supported) + + def test_is_profile_supported_with_invalid_authentication_suite(self): + """ + Test that the profile support predicate returns False for an invalid + authentication suite. + """ + supported = self.client.is_profile_supported( + ConformanceClause.DISCOVER_VERSIONS, + AuthenticationSuite.TLS12) + self.assertFalse(supported) + + def test_is_profile_supported_with_invalid_profile_components(self): + """ + Test that the profile support predicate returns False for invalid + profile components. + """ + supported = self.client.is_profile_supported( + ConformanceClause.BASELINE, + AuthenticationSuite.TLS12) + self.assertFalse(supported)