Repository: OpenKMIP/PyKMIP

Issue:
Install/Run Instructions and SQLAlchemy Issue
I have installed the latest version of pykmip-server (0.5.0) but have some questions.

I noticed that the instructions on the Wiki mention to run the "run_server.py" script but it appears as though the newer versions of pykmip support installation of Pykmip-server using the easy-install/pip method (python server.py build/install).  Is the easy-install/pip the preferred method of installing now?

When I start the server (0.5.0) using the pykmip-server script in /bin, I am receiving the following message:

/usr/lib/python3.4/site-packages/SQLAlchemy-1.1.0b3-py3.4-linux-x86_64.egg/sqlalchemy/orm/mapper.py:1034: SAWarning: Reassigning polymorphic association for identity 'Certificate' from <Mapper at 0x7f2fa55a99b0; Certificate> to <Mapper at 0x7f2fa55a9eb8; X509Certificate>: Check for duplicate use of 'Certificate' as value for polymorphic_identity

I have generated certs and they are signed by a CA.  I even tried using the demo certs that were included.  It appears as though the server still runs with after this message is displayed but wasn't sure if it is a warning or is causing other issues.  I confirmed that I am binding to port 5696 on a public interface and enabled logging.  I'm not currently able to connect from my client.

The message I receive in the log when a client attempts to connect is:

2016-09-21 16:08:35,948 - kmip.server.session.00000001 - WARNING - An unexpected error occurred while processing request.
2016-09-21 16:08:35,948 - kmip.server.session.00000001 - ERROR - 'NoneType' object has no attribute 'credential'
Traceback (most recent call last):
  File "/usr/lib/python3.4/site-packages/PyKMIP-0.5.0-py3.4.egg/kmip/services/server/session.py", line 106, in _handle_message_loop
    request
  File "/usr/lib/python3.4/site-packages/PyKMIP-0.5.0-py3.4.egg/kmip/services/server/engine.py", line 142, in decorator
    return function(self, *args, **kwargs)
  File "/usr/lib/python3.4/site-packages/PyKMIP-0.5.0-py3.4.egg/kmip/services/server/engine.py", line 252, in process_request
    auth_credentials = header.authentication.credential
AttributeError: 'NoneType' object has no attribute 'credential'

Last question.  I tried going back to a previous version of PyKmip (such as 0.4.1) since this is prior to using sqlalchemy.  When I install this, there is no pykmip-server in /bin and I see no run_server.py.  I tried running the kmip/services/server/server.py script but it runs and then exits right away.  What is the preferred way to run in version 0.4.1?

Sorry for all of the questions and thanks for your hard work.  I would greatly appreciate any help you can provide.


Discussion:

Patch:
diff --git a/kmip/services/server/engine.py b/kmip/services/server/engine.py
index c90d355..5787b30 100644
--- a/kmip/services/server/engine.py
+++ b/kmip/services/server/engine.py
@@ -249,7 +249,10 @@ class KmipEngine(object):
             )
 
         # Process the authentication credentials
-        auth_credentials = header.authentication.credential
+        if header.authentication:
+            auth_credentials = header.authentication.credential
+        else:
+            auth_credentials = None
         self._verify_credential(auth_credentials, credential)
 
         # Process the batch error continuation option


Test patch:
diff --git a/kmip/tests/unit/services/server/test_engine.py b/kmip/tests/unit/services/server/test_engine.py
index f969557..d13a893 100644
--- a/kmip/tests/unit/services/server/test_engine.py
+++ b/kmip/tests/unit/services/server/test_engine.py
@@ -391,6 +391,41 @@ class TestKmipEngine(testtools.TestCase):
             *args
         )
 
+    def test_process_request_missing_credential(self):
+        """
+        Test that the engine does not immediately error out when retrieving
+        a non-existent credential from the request.
+        """
+        e = engine.KmipEngine()
+        e._logger = mock.MagicMock()
+
+        protocol = contents.ProtocolVersion.create(1, 1)
+        header = messages.RequestHeader(
+            protocol_version=protocol,
+            authentication=None,
+            batch_error_cont_option=contents.BatchErrorContinuationOption(
+                enums.BatchErrorContinuationOption.STOP
+            ),
+            batch_order_option=contents.BatchOrderOption(True),
+            time_stamp=contents.TimeStamp(int(time.time())),
+            batch_count=contents.BatchCount(1)
+        )
+        payload = discover_versions.DiscoverVersionsRequestPayload()
+        batch = list([
+            messages.RequestBatchItem(
+                operation=contents.Operation(
+                    enums.Operation.DISCOVER_VERSIONS
+                ),
+                request_payload=payload
+            )
+        ])
+        request = messages.RequestMessage(
+            request_header=header,
+            batch_items=batch
+        )
+
+        e.process_request(request)
+
     def test_build_error_response(self):
         """
         Test that a bare bones response containing a single error result can