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 _handle_message_loop(self): request_data = self._receive_request() request = messages.RequestMessage() max_size = self._max_response_size try: shared_ciphers = self._connection.shared_ciphers() self._logger.debug("Possible session ciphers: {0}".format( len(shared_ciphers))) for cipher in shared_ciphers: self._logger.debug(cipher) self._logger.debug("Session cipher selected: {0}".format( self._connection.cipher())) client_identity = self._get_client_identity() request.read(request_data) except Exception as e: self._logger.warning("Failure parsing request message.") self._logger.exception(e) response = self._engine.build_error_response( contents.ProtocolVersion.create(1, 0), enums.ResultReason.INVALID_MESSAGE, "Error parsing request message. See server logs for more " "information.") else: try: response, max_response_size = self._engine.process_request( request, client_identity) if max_response_size: max_size = max_response_size except exceptions.KmipError as e: response = self._engine.build_error_response( request.request_header.protocol_version, e.reason, str(e)) except Exception as e: self._logger.warning( "An unexpected error occurred while processing request.") self._logger.exception(e) response = self._engine.build_error_response( request.request_header.protocol_version, enums.ResultReason.GENERAL_FAILURE, "An unexpected error occurred while processing request. " "See server logs for more information.") response_data = utils.BytearrayStream() response.write(response_data) if len(response_data) > max_size: self._logger.warning("Response message length too large: " "{0} bytes, max {1} bytes".format( len(response_data), self._max_response_size)) response = self._engine.build_error_response( request.request_header.protocol_version, enums.ResultReason.RESPONSE_TOO_LARGE, "Response message length too large. See server logs for " "more information.") response_data = utils.BytearrayStream() response.write(response_data) self._send_response(response_data.buffer)
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_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 _build_request_message(self, credential, batch_items): protocol_version = ProtocolVersion.create(1, 2) if credential is None: credential = self._build_credential() authentication = None if credential is not None: authentication = Authentication(credential) batch_count = BatchCount(len(batch_items)) req_header = messages.RequestHeader(protocol_version=protocol_version, authentication=authentication, batch_count=batch_count) return messages.RequestMessage(request_header=req_header, batch_items=batch_items)
def _handle_message_loop(self): request_data = self._receive_request() request = messages.RequestMessage() max_size = self._max_response_size kmip_version = contents.protocol_version_to_kmip_version( self._engine.default_protocol_version) try: if hasattr(self._connection, 'shared_ciphers'): shared_ciphers = self._connection.shared_ciphers() self._logger.debug("Possible session ciphers: {0}".format( len(shared_ciphers))) for cipher in shared_ciphers: self._logger.debug(cipher) self._logger.debug("Session cipher selected: {0}".format( self._connection.cipher())) certificate = auth.get_certificate_from_connection( self._connection) if certificate is None: raise exceptions.PermissionDenied( "The client certificate could not be loaded from the " "session connection.") if self._enable_tls_client_auth: extension = auth.get_extended_key_usage_from_certificate( certificate) if extension is None: raise exceptions.PermissionDenied( "The extended key usage extension is missing from " "the client certificate.") if x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH not in extension: raise exceptions.PermissionDenied( "The extended key usage extension is not marked for " "client authentication in the client certificate.") request.read(request_data, kmip_version=kmip_version) except exceptions.PermissionDenied as e: self._logger.warning("Failure verifying the client certificate.") self._logger.exception(e) response = self._engine.build_error_response( contents.ProtocolVersion(1, 0), enums.ResultReason.AUTHENTICATION_NOT_SUCCESSFUL, "Error verifying the client certificate. " "See server logs for more information.") except Exception as e: self._logger.warning("Failure parsing request message.") self._logger.exception(e) response = self._engine.build_error_response( contents.ProtocolVersion(1, 0), enums.ResultReason.INVALID_MESSAGE, "Error parsing request message. See server logs for more " "information.") else: try: client_identity = self.authenticate(certificate, request) self._logger.info("Session client identity: {}".format( client_identity[0])) except Exception: self._logger.warning("Authentication failed.") response = self._engine.build_error_response( request.request_header.protocol_version, enums.ResultReason.AUTHENTICATION_NOT_SUCCESSFUL, "An error occurred during client authentication. " "See server logs for more information.") else: try: results = self._engine.process_request( request, client_identity) response, max_response_size, protocol_version = results kmip_version = contents.protocol_version_to_kmip_version( protocol_version) if max_response_size: max_size = max_response_size except exceptions.KmipError as e: response = self._engine.build_error_response( request.request_header.protocol_version, e.reason, str(e)) except Exception as e: self._logger.warning( "An unexpected error occurred while processing " "request.") self._logger.exception(e) response = self._engine.build_error_response( request.request_header.protocol_version, enums.ResultReason.GENERAL_FAILURE, "An unexpected error occurred while processing " "request. See server logs for more information.") response_data = utils.BytearrayStream() response.write(response_data, kmip_version=kmip_version) if len(response_data) > max_size: self._logger.warning("Response message length too large: " "{0} bytes, max {1} bytes".format( len(response_data), self._max_response_size)) response = self._engine.build_error_response( request.request_header.protocol_version, enums.ResultReason.RESPONSE_TOO_LARGE, "Response message length too large. See server logs for " "more information.") response_data = utils.BytearrayStream() response.write(response_data, kmip_version=kmip_version) self._send_response(response_data.buffer)