def test_get_client_identity_with_incorrect_extended_key_usage(self): """ Test that the right error is generated when the client certificate does not have client authentication set in its extended key usage extension. """ client_certificate = build_certificate( [u'Test Identity'], bad_extension=True ) der_encoding = client_certificate.public_bytes( serialization.Encoding.DER ) kmip_session = session.KmipSession(None, None, 'name') kmip_session._logger = mock.MagicMock() kmip_session._connection = mock.MagicMock() kmip_session._connection.getpeercert.return_value = der_encoding self.assertRaisesRegexp( exceptions.PermissionDenied, "The extended key usage extension is not marked for client " "authentication in the client certificate. Session client " "identity unavailable.", kmip_session._get_client_identity )
def test_run_with_failure(self): """ Test that the correct logging and error handling occurs when the thread encounters an error with the message handling loop. """ kmip_session = session.KmipSession(None, None, 'name') kmip_session._logger = mock.MagicMock() kmip_session._connection = mock.MagicMock() test_exception = Exception("test") kmip_session._handle_message_loop = mock.MagicMock( side_effect=[test_exception, exceptions.ConnectionClosed()]) kmip_session.run() kmip_session._logger.info.assert_any_call("Starting session: name") self.assertTrue(kmip_session._handle_message_loop.called) kmip_session._logger.info.assert_any_call( "Failure handling message loop") kmip_session._logger.exception.assert_called_once_with(test_exception) kmip_session._connection.shutdown.assert_called_once_with( socket.SHUT_RDWR) kmip_session._connection.close.assert_called_once_with() kmip_session._logger.info.assert_called_with("Stopping session: name")
def test_handle_message_loop_with_response_too_long(self, request_mock, cert_mock): """ Test that the correct logging and error handling occurs during the message handling loop. """ data = utils.BytearrayStream(()) cert_mock.return_value = 'test_certificate' kmip_engine = engine.KmipEngine() kmip_session = session.KmipSession( kmip_engine, None, None, name='name', enable_tls_client_auth=False ) kmip_session.authenticate = mock.MagicMock() kmip_session.authenticate.return_value = ( 'test', ['group A', 'group B'] ) kmip_session._logger = mock.MagicMock() kmip_session._connection = mock.MagicMock() kmip_session._receive_request = mock.MagicMock(return_value=data) kmip_session._send_response = mock.MagicMock() kmip_session._max_response_size = 0 kmip_session._handle_message_loop() kmip_session._receive_request.assert_called_once_with() self.assertTrue(kmip_session._logger.warning.called) kmip_session._logger.exception.assert_not_called() self.assertTrue(kmip_session._send_response.called)
def test_handle_message_loop_with_unexpected_error(self, request_mock, cert_mock): """ Test that the correct logging and error handling occurs when an unexpected error is generated while processing a request. """ data = utils.BytearrayStream(()) cert_mock.return_value = 'test_certificate' kmip_engine = engine.KmipEngine() kmip_engine._logger = mock.MagicMock() kmip_session = session.KmipSession(kmip_engine, None, None, name='name', enable_tls_client_auth=False) kmip_session.authenticate = mock.MagicMock() kmip_session.authenticate.return_value = ('test', ['group A', 'group B']) kmip_session._engine = mock.MagicMock() test_exception = Exception("Unexpected error.") kmip_session._engine.process_request = mock.MagicMock( side_effect=test_exception) kmip_session._logger = mock.MagicMock() kmip_session._connection = mock.MagicMock() kmip_session._receive_request = mock.MagicMock(return_value=data) kmip_session._send_response = mock.MagicMock() kmip_session._handle_message_loop() kmip_session._receive_request.assert_called_once_with() kmip_session._logger.warning.assert_called_once_with( "An unexpected error occurred while processing request.") kmip_session._logger.exception.assert_called_once_with(test_exception) self.assertTrue(kmip_session._send_response.called)
def test_receive_bytes(self): """ Test that the session can receive a message. """ content = b'\x00\x00\x00\x00\x00\x00\x00\x00' kmip_session = session.KmipSession(None, None, 'name') kmip_session._connection = mock.MagicMock() kmip_session._connection.recv = mock.MagicMock( side_effect=[content, content] ) observed = kmip_session._receive_bytes(16) kmip_session._connection.recv.assert_any_call(16) kmip_session._connection.recv.assert_called_with(8) self.assertEqual(content + content, observed) kmip_session._connection.recv = mock.MagicMock( side_effect=[''] ) args = (8, ) self.assertRaises( exceptions.ConnectionClosed, kmip_session._receive_bytes, *args )
def test_authenticate_against_unrecognized_plugin(self): """ Test that the session correctly handles an unrecognized plugin configuration. """ kmip_session = session.KmipSession( None, None, None, name='TestSession', auth_settings=[("auth:unrecognized", {})] ) kmip_session._logger = mock.MagicMock() fake_request = messages.RequestMessage( request_header=messages.RequestHeader() ) args = ("fake_certificate", fake_request) self.assertRaisesRegexp( exceptions.PermissionDenied, "Authentication failed.", kmip_session.authenticate, *args ) kmip_session._logger.warning.assert_any_call( "Authentication plugin 'auth:unrecognized' is not supported." )
def _setup_connection_handler(self, connection, address): self._logger.info("Receiving incoming connection from: {0}:{1}".format( address[0], address[1])) session_name = "{0:08}".format(self._session_id) self._session_id += 1 self._logger.info("Dedicating session {0} to {1}:{2}".format( session_name, address[0], address[1])) try: s = session.KmipSession( self._engine, connection, address, name=session_name, enable_tls_client_auth=self.config.settings.get( 'enable_tls_client_auth'), auth_settings=self.config.settings.get('auth_plugins')) s.daemon = True s.start() except Exception as e: self._logger.warning( "Failure occurred while starting session: {0}".format( session_name)) self._logger.exception(e)
def test_authenticate(self, mock_get): """ Test that the session correctly uses the authentication plugin framework to authenticate new connections. """ mock_get.return_value = "John Doe" kmip_session = session.KmipSession( None, None, None, name='TestSession' ) kmip_session._logger = mock.MagicMock() fake_request = messages.RequestMessage( request_header=messages.RequestHeader() ) session_identity = kmip_session.authenticate( "fake_certificate", fake_request ) kmip_session._logger.debug.assert_any_call( "No authentication plugins are enabled. The client identity will " "be extracted from the client certificate." ) mock_get.assert_any_call("fake_certificate") kmip_session._logger.debug.assert_any_call( "Extraction succeeded for client identity: John Doe" ) self.assertEqual(("John Doe", None), session_identity)
def test_handle_message_loop_with_unexpected_error(self, request_mock): """ Test that the correct logging and error handling occurs when an unexpected error is generated while processing a request. """ data = utils.BytearrayStream(()) kmip_engine = engine.KmipEngine() kmip_engine._logger = mock.MagicMock() kmip_session = session.KmipSession(kmip_engine, None, 'name') kmip_session._engine = mock.MagicMock() test_exception = Exception("Unexpected error.") kmip_session._engine.process_request = mock.MagicMock( side_effect=test_exception) kmip_session._logger = mock.MagicMock() kmip_session._connection = mock.MagicMock() kmip_session._receive_request = mock.MagicMock(return_value=data) kmip_session._send_response = mock.MagicMock() kmip_session._handle_message_loop() kmip_session._receive_request.assert_called_once_with() kmip_session._logger.info.assert_not_called() kmip_session._logger.warning.assert_called_once_with( "An unexpected error occurred while processing request.") kmip_session._logger.exception.assert_called_once_with(test_exception) self.assertTrue(kmip_session._send_response.called)
def test_get_client_identity_with_multiple_common_names(self): """ Test that the right client identity is returned when the client certificate has multiple subject common names. """ client_certificate = build_certificate([ u'Test Identity 1', u'Test Identity 2' ]) der_encoding = client_certificate.public_bytes( serialization.Encoding.DER ) kmip_session = session.KmipSession(None, None, 'name') kmip_session._logger = mock.MagicMock() kmip_session._connection = mock.MagicMock() kmip_session._connection.getpeercert.return_value = der_encoding identity = kmip_session._get_client_identity() self.assertEqual(u'Test Identity 1', identity) kmip_session._logger.info.assert_called_once_with( "Session client identity: Test Identity 1" ) kmip_session._logger.warning.assert_called_once_with( "Multiple client identities found. Using the first one processed." )
def test_handle_message_loop_with_parse_failure(self): """ Test that the correct logging and error handling occurs during the message handling loop. """ data = utils.BytearrayStream(()) kmip_engine = engine.KmipEngine() kmip_session = session.KmipSession(kmip_engine, None, 'name') kmip_session._get_client_identity = mock.MagicMock() kmip_session._get_client_identity.return_value = 'test' kmip_session._logger = mock.MagicMock() kmip_session._connection = mock.MagicMock() kmip_session._receive_request = mock.MagicMock(return_value=data) kmip_session._send_response = mock.MagicMock() kmip_session._handle_message_loop() kmip_session._receive_request.assert_called_once_with() kmip_session._logger.warning.assert_called_once_with( "Failure parsing request message." ) self.assertTrue(kmip_session._logger.exception.called) kmip_session._logger.error.assert_not_called() self.assertTrue(kmip_session._send_response.called)
def test_handle_message_loop(self, request_mock): """ Test that the correct logging and error handling occurs during the message handling loop. """ data = utils.BytearrayStream() # Build a response and use it as a dummy processing result. batch_item = messages.ResponseBatchItem( result_status=contents.ResultStatus(enums.ResultStatus.SUCCESS), result_reason=contents.ResultReason( enums.ResultReason.OBJECT_ARCHIVED), result_message=contents.ResultMessage("Test message.")) batch_items = [batch_item] header = messages.ResponseHeader( protocol_version=contents.ProtocolVersion(1, 0), time_stamp=contents.TimeStamp(int(time.time())), batch_count=contents.BatchCount(len(batch_items))) message = messages.ResponseMessage(response_header=header, batch_items=batch_items) kmip_engine = engine.KmipEngine() kmip_engine._logger = mock.MagicMock() kmip_session = session.KmipSession(kmip_engine, None, 'name') kmip_session._engine = mock.MagicMock() kmip_session._get_client_identity = mock.MagicMock() kmip_session._get_client_identity.return_value = 'test' kmip_session._engine.process_request = mock.MagicMock( return_value=(message, kmip_session._max_response_size)) kmip_session._logger = mock.MagicMock() kmip_session._connection = mock.MagicMock() kmip_session._connection.shared_ciphers = mock.MagicMock( return_value=[('AES128-SHA256', 'TLSv1/SSLv3', 128), ('AES256-SHA256', 'TLSv1/SSLv3', 256)]) kmip_session._connection.cipher = mock.MagicMock( return_value=('AES128-SHA256', 'TLSv1/SSLv3', 128)) kmip_session._receive_request = mock.MagicMock(return_value=data) kmip_session._send_response = mock.MagicMock() kmip_session._handle_message_loop() kmip_session._receive_request.assert_called_once_with() kmip_session._logger.info.assert_not_called() kmip_session._logger.debug.assert_any_call( "Possible session ciphers: 2") kmip_session._logger.debug.assert_any_call( ('AES128-SHA256', 'TLSv1/SSLv3', 128)) kmip_session._logger.debug.assert_any_call( ('AES256-SHA256', 'TLSv1/SSLv3', 256)) kmip_session._logger.debug.assert_any_call( "Session cipher selected: {0}".format( ('AES128-SHA256', 'TLSv1/SSLv3', 128))) kmip_session._logger.warning.assert_not_called() kmip_session._logger.exception.assert_not_called() self.assertTrue(kmip_session._send_response.called)
def test_handle_message_loop_with_authentication_failure( self, request_mock, cert_mock): """ Test that the correct logging and error handling occurs when an authentication error is generated while processing a request. """ data = utils.BytearrayStream(()) cert_mock.return_value = 'test_certificate' kmip_engine = engine.KmipEngine() kmip_engine._logger = mock.MagicMock() kmip_session = session.KmipSession(kmip_engine, None, None, name='name', enable_tls_client_auth=False) kmip_session.authenticate = mock.MagicMock() kmip_session.authenticate.side_effect = exceptions.PermissionDenied( "Authentication failed.") kmip_session._engine = mock.MagicMock() kmip_session._engine.default_protocol_version = \ kmip_engine.default_protocol_version kmip_session._logger = mock.MagicMock() kmip_session._connection = mock.MagicMock() kmip_session._receive_request = mock.MagicMock(return_value=data) kmip_session._send_response = mock.MagicMock() fake_version = contents.ProtocolVersion(1, 2) fake_credential = objects.Credential( credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, credential_value=objects.UsernamePasswordCredential( username="******", password="******")) fake_header = messages.RequestHeader( protocol_version=fake_version, authentication=contents.Authentication( credentials=[fake_credential])) fake_request = messages.RequestMessage() fake_request.request_header = fake_header fake_request.read = mock.MagicMock() request_mock.return_value = fake_request kmip_session._handle_message_loop() kmip_session._receive_request.assert_called_once_with() fake_request.read.assert_called_once_with( data, kmip_version=enums.KMIPVersion.KMIP_1_2) kmip_session.authenticate.assert_called_once_with( "test_certificate", fake_request) kmip_session._logger.warning.assert_called_once_with( "Authentication failed.") kmip_session._engine.build_error_response.assert_called_once_with( fake_version, enums.ResultReason.AUTHENTICATION_NOT_SUCCESSFUL, "An error occurred during client authentication. " "See server logs for more information.") kmip_session._logger.exception.assert_not_called() self.assertTrue(kmip_session._send_response.called)
def test_authenticate_against_slugs(self, mock_connector): """ Test that the session correctly handles authentication with SLUGS. """ mock_instance = mock.MagicMock() mock_instance.authenticate.return_value = ("John Doe", ["Group A"]) mock_connector.return_value = mock_instance kmip_session = session.KmipSession( None, None, ("127.0.0.1", 48026), name='TestSession', auth_settings=[( "auth:slugs", {"enabled": "True", "url": "test_url"} )] ) kmip_session._logger = mock.MagicMock() fake_credential = objects.Credential( credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, credential_value=objects.UsernamePasswordCredential( username="******", password="******" ) ) fake_request = messages.RequestMessage( request_header=messages.RequestHeader( authentication=contents.Authentication( credentials=[fake_credential] ) ) ) result = kmip_session.authenticate( "fake_certificate", fake_request ) mock_connector.assert_any_call("test_url") kmip_session._logger.debug.assert_any_call( "Authenticating with plugin: auth:slugs" ) mock_instance.authenticate.assert_any_call( "fake_certificate", (("127.0.0.1", 48026), kmip_session._session_time), fake_request.request_header.authentication.credentials ) kmip_session._logger.debug( "Authentication succeeded for client identity: John Doe" ) self.assertEqual(2, len(result)) self.assertEqual("John Doe", result[0]) self.assertEqual(["Group A"], result[1])
def test_authenticate_against_slugs_with_failure(self, mock_connector): """ Test that the session correctly handles a SLUGS authentication error. """ mock_instance = mock.MagicMock() test_exception = exceptions.PermissionDenied( "Unrecognized user ID: John Doe" ) mock_instance.authenticate.side_effect = test_exception mock_connector.return_value = mock_instance kmip_session = session.KmipSession( None, None, ("127.0.0.1", 48026), name='TestSession', auth_settings=[( "auth:slugs", {"enabled": "True", "url": "test_url"} )] ) kmip_session._logger = mock.MagicMock() fake_credential = objects.Credential( credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, credential_value=objects.UsernamePasswordCredential( username="******", password="******" ) ) fake_request = messages.RequestMessage( request_header=messages.RequestHeader( authentication=contents.Authentication( credentials=[fake_credential] ) ) ) args = ("fake_certificate", fake_request) self.assertRaisesRegexp( exceptions.PermissionDenied, "Authentication failed.", kmip_session.authenticate, *args ) mock_connector.assert_any_call("test_url") kmip_session._logger.debug.assert_any_call( "Authenticating with plugin: auth:slugs" ) kmip_session._logger.warning.assert_any_call("Authentication failed.") kmip_session._logger.exception.assert_any_call(test_exception)
def test_get_client_identity_with_no_certificate(self): """ Test that the right error is generated when no certificate is available to provide the client identity. """ kmip_session = session.KmipSession(None, None, 'name') kmip_session._logger = mock.MagicMock() kmip_session._connection = mock.MagicMock() kmip_session._connection.getpeercert.return_value = None self.assertRaisesRegexp( exceptions.PermissionDenied, "Failure loading the client certificate from the session " "connection. Could not retrieve client identity.", kmip_session._get_client_identity)
def test_handle_message_loop_invalid_certificate_extension(self, request_mock, cert_mock, ext_mock): """ Test that the correct logging and error handling occurs when an invalid certificate is encountered while processing a request. """ data = utils.BytearrayStream(()) cert_mock.return_value = 'test_certificate' ext_mock.return_value = [] kmip_engine = engine.KmipEngine() kmip_engine._logger = mock.MagicMock() kmip_session = session.KmipSession( kmip_engine, None, None, name='name', enable_tls_client_auth=True ) kmip_session.authenticate = mock.MagicMock() kmip_session._engine = mock.MagicMock() kmip_session._logger = mock.MagicMock() kmip_session._connection = mock.MagicMock() kmip_session._receive_request = mock.MagicMock(return_value=data) kmip_session._send_response = mock.MagicMock() kmip_session._handle_message_loop() kmip_session._receive_request.assert_called_once_with() kmip_session._logger.warning( "Failure verifying the client certificate." ) kmip_session._logger.exception.assert_called_once_with( exceptions.PermissionDenied( "The extended key usage extension is not marked for client " "authentication in the client certificate." ) ) kmip_session._engine.build_error_response.assert_called_once_with( contents.ProtocolVersion(1, 0), enums.ResultReason.AUTHENTICATION_NOT_SUCCESSFUL, "Error verifying the client certificate. " "See server logs for more information." ) self.assertTrue(kmip_session._send_response.called)
def test_send_message(self): """ Test that a data buffer, regardless of length, is sent correctly. """ buffer_full = utils.BytearrayStream( (b'\x00\x00\x00\x00\x00\x00\x00\x00')) buffer_empty = utils.BytearrayStream() kmip_session = session.KmipSession(None, None, 'name') kmip_session._connection = mock.MagicMock() kmip_session._send_response(buffer_empty.buffer) kmip_session._connection.sendall.assert_not_called() kmip_session._send_response(buffer_full.buffer) kmip_session._connection.sendall.assert_called_once_with( bytes(buffer_full.buffer))
def test_receive_bytes_with_bad_length(self): """ Test that the session generates an error on an incorrectly sized message. """ content = b'\x00\x00\x00\x00\x00\x00\x00\x00' kmip_session = session.KmipSession(None, None, 'name') kmip_session._connection = mock.MagicMock() kmip_session._connection.recv = mock.MagicMock( side_effect=[content, content, None]) args = [32] self.assertRaises(ValueError, kmip_session._receive_bytes, *args) kmip_session._connection.recv.assert_any_call(16) kmip_session._connection.recv.assert_called_with(16)
def test_receive_request(self): """ Test that the session can correctly receive and parse a message encoding. """ content = b'\x00\x00\x00\x00\x00\x00\x00\x00' expected = utils.BytearrayStream((content)) kmip_session = session.KmipSession(None, None, 'name') kmip_session._receive_bytes = mock.MagicMock( side_effect=[content, b'']) observed = kmip_session._receive_request() kmip_session._receive_bytes.assert_any_call(8) kmip_session._receive_bytes.assert_any_call(0) self.assertEqual(expected.buffer, observed.buffer)
def test_run(self): """ Test that the message handling loop is handled properly on normal execution. """ kmip_session = session.KmipSession(None, None, 'name') kmip_session._logger = mock.MagicMock() kmip_session._handle_message_loop = mock.MagicMock( side_effect=[None, exceptions.ConnectionClosed()]) kmip_session._connection = mock.MagicMock() kmip_session.run() kmip_session._logger.info.assert_any_call("Starting session: name") self.assertTrue(kmip_session._handle_message_loop.called) kmip_session._connection.shutdown.assert_called_once_with( socket.SHUT_RDWR) kmip_session._connection.close.assert_called_once_with() kmip_session._logger.info.assert_called_with("Stopping session: name")
def test_get_client_identity_with_no_common_name(self): """ Test that the right error is generated when the client certificate does not define a subject common name. """ client_certificate = build_certificate([]) der_encoding = client_certificate.public_bytes( serialization.Encoding.DER) kmip_session = session.KmipSession(None, None, 'name') kmip_session._logger = mock.MagicMock() kmip_session._connection = mock.MagicMock() kmip_session._connection.getpeercert.return_value = der_encoding self.assertRaisesRegexp( exceptions.PermissionDenied, "The client certificate does not define a subject common " "name. Session client identity unavailable.", kmip_session._get_client_identity)
def test_get_client_identity(self): """ Test that a client identity is obtained from a valid client certificate. """ client_certificate = build_certificate([u'Test Identity']) der_encoding = client_certificate.public_bytes( serialization.Encoding.DER) kmip_session = session.KmipSession(None, None, 'name') kmip_session._logger = mock.MagicMock() kmip_session._connection = mock.MagicMock() kmip_session._connection.getpeercert.return_value = der_encoding identity = kmip_session._get_client_identity() self.assertEqual(u'Test Identity', identity) kmip_session._logger.info.assert_called_once_with( "Session client identity: Test Identity") kmip_session._logger.warning.assert_not_called()
def test_handle_message_loop_with_response_too_long(self, request_mock): """ Test that the correct logging and error handling occurs during the message handling loop. """ data = utils.BytearrayStream(()) kmip_engine = engine.KmipEngine() kmip_session = session.KmipSession(kmip_engine, None, 'name') kmip_session._logger = mock.MagicMock() kmip_session._connection = mock.MagicMock() kmip_session._receive_request = mock.MagicMock(return_value=data) kmip_session._send_response = mock.MagicMock() kmip_session._max_response_size = 0 kmip_session._handle_message_loop() kmip_session._receive_request.assert_called_once_with() kmip_session._logger.info.assert_not_called() self.assertTrue(kmip_session._logger.warning.called) kmip_session._logger.exception.assert_not_called() self.assertTrue(kmip_session._send_response.called)
def test_handle_message_loop(self, request_mock): """ Test that the correct logging and error handling occurs during the message handling loop. """ data = utils.BytearrayStream() # Build a response and use it as a dummy processing result. batch_item = messages.ResponseBatchItem( result_status=contents.ResultStatus(enums.ResultStatus.SUCCESS), result_reason=contents.ResultReason( enums.ResultReason.OBJECT_ARCHIVED), result_message=contents.ResultMessage("Test message.")) batch_items = [batch_item] header = messages.ResponseHeader( protocol_version=contents.ProtocolVersion.create(1, 0), time_stamp=contents.TimeStamp(int(time.time())), batch_count=contents.BatchCount(len(batch_items))) message = messages.ResponseMessage(response_header=header, batch_items=batch_items) kmip_engine = engine.KmipEngine() kmip_engine._logger = mock.MagicMock() kmip_session = session.KmipSession(kmip_engine, None, 'name') kmip_session._engine = mock.MagicMock() kmip_session._engine.process_request = mock.MagicMock( return_value=(message, kmip_session._max_response_size)) kmip_session._logger = mock.MagicMock() kmip_session._connection = mock.MagicMock() kmip_session._receive_request = mock.MagicMock(return_value=data) kmip_session._send_response = mock.MagicMock() kmip_session._handle_message_loop() kmip_session._receive_request.assert_called_once_with() kmip_session._logger.info.assert_not_called() kmip_session._logger.warning.assert_not_called() kmip_session._logger.exception.assert_not_called() self.assertTrue(kmip_session._send_response.called)
def test_init_without_name(self): """ Test that a KmipSession without 'name' can be created without errors. """ session.KmipSession(None, None, None)
def test_init(self): """ Test that a KmipSession can be created without errors. """ session.KmipSession(None, None, 'name')