You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ch...@apache.org on 2016/09/09 14:17:32 UTC

qpid-dispatch git commit: DISPATCH-468: Use computed x.509 cert display-name as authenticated id

Repository: qpid-dispatch
Updated Branches:
  refs/heads/master bba79f3c6 -> 6e9c24e95


DISPATCH-468: Use computed x.509 cert display-name as authenticated id

Add a DisplayName service interface to be called from C code.
During connection establishment use the translated display name
as the connection authenticated user_id.

This closes #97


Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/6e9c24e9
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/6e9c24e9
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/6e9c24e9

Branch: refs/heads/master
Commit: 6e9c24e954e958476fca2b0ceb5a1d9874ef1f73
Parents: bba79f3
Author: Chuck Rolke <cr...@redhat.com>
Authored: Fri Sep 9 10:07:05 2016 -0400
Committer: Chuck Rolke <cr...@redhat.com>
Committed: Fri Sep 9 10:07:05 2016 -0400

----------------------------------------------------------------------
 include/qpid/dispatch/server.h                  | 10 +++++
 python/qpid_dispatch_internal/dispatch.py       |  2 +
 .../display_name/display_name.py                | 12 +++++-
 .../qpid_dispatch_internal/management/config.py |  1 +
 src/dispatch.c                                  |  6 +++
 src/dispatch_private.h                          |  5 +++
 src/server.c                                    | 42 ++++++++++++++++++++
 src/server_private.h                            |  2 +
 tests/displayname_files/profile_names1.json     |  4 +-
 tests/displayname_files/profile_names2.json     |  3 +-
 tests/system_tests_user_id.py                   | 38 ++++++++++++++++--
 11 files changed, 119 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6e9c24e9/include/qpid/dispatch/server.h
----------------------------------------------------------------------
diff --git a/include/qpid/dispatch/server.h b/include/qpid/dispatch/server.h
index 03d4e4b..a0ee4b5 100644
--- a/include/qpid/dispatch/server.h
+++ b/include/qpid/dispatch/server.h
@@ -659,6 +659,16 @@ qd_connector_t *qd_server_connect(qd_dispatch_t *qd, const qd_server_config_t *c
  */
 void qd_server_connector_free(qd_connector_t* ct);
 
+
+
+/**
+ * Store address of display name service py object for C code use
+ *
+ * @param qd The dispatch handle returned by qd_dispatch.
+ * @param display_name_service address of python object
+ */
+qd_error_t qd_register_display_name_service(qd_dispatch_t *qd, void *display_name_service);
+
 /**
  * @}
  */

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6e9c24e9/python/qpid_dispatch_internal/dispatch.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/dispatch.py b/python/qpid_dispatch_internal/dispatch.py
index 11fe6ed..e397f86 100644
--- a/python/qpid_dispatch_internal/dispatch.py
+++ b/python/qpid_dispatch_internal/dispatch.py
@@ -80,6 +80,8 @@ class QdDll(ctypes.PyDLL):
         self._prototype(self.qd_dispatch_policy_c_counts_free, None, [c_long], check=False)
         self._prototype(self.qd_dispatch_policy_c_counts_refresh, None, [c_long, py_object])
 
+        self._prototype(self.qd_dispatch_register_display_name_service, None, [self.qd_dispatch_p, py_object])
+
         self._prototype(self.qd_dispatch_set_agent, None, [self.qd_dispatch_p, py_object])
 
         self._prototype(self.qd_router_setup_late, None, [self.qd_dispatch_p])

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6e9c24e9/python/qpid_dispatch_internal/display_name/display_name.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/display_name/display_name.py b/python/qpid_dispatch_internal/display_name/display_name.py
index 5ecb867..9cce3a7 100644
--- a/python/qpid_dispatch_internal/display_name/display_name.py
+++ b/python/qpid_dispatch_internal/display_name/display_name.py
@@ -92,7 +92,6 @@ class DisplayNameService(object):
             body = {'user_name': user_name if user_name else user_id}
         else:
             body = {'user_name': user_id}
-
         return body
 
     def receive(self, message, unused_link_id, unused_cost):
@@ -123,3 +122,14 @@ class DisplayNameService(object):
 
         self.io_adapter[0].send(response)
 
+
+def display_name_local_query(displaynameservice, profile_name, user_id):
+    """
+    Local query interface for reading cached name translations from C code
+    @param displaynameservice: DisplayNameService python instance
+    @param profile_name: connection's sslProfile name
+    @param user_id: Name formatted from SSL cert fields
+    @return: Name to be used as connection's authenticated user
+    """
+    body = displaynameservice.query(profile_name, user_id)
+    return body['user_name']

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6e9c24e9/python/qpid_dispatch_internal/management/config.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/management/config.py b/python/qpid_dispatch_internal/management/config.py
index a7b82c7..9df1dad 100644
--- a/python/qpid_dispatch_internal/management/config.py
+++ b/python/qpid_dispatch_internal/management/config.py
@@ -155,6 +155,7 @@ def configure_dispatch(dispatch, lib_handle, filename):
 
     from qpid_dispatch_internal.display_name.display_name import DisplayNameService
     displayname_service = DisplayNameService("$displayname")
+    qd.qd_dispatch_register_display_name_service(dispatch, displayname_service)
     policyDir = config.by_type('policy')[0]['policyDir']
     policyDefaultVhost = config.by_type('policy')[0]['defaultVhost']
     # Remaining configuration

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6e9c24e9/src/dispatch.c
----------------------------------------------------------------------
diff --git a/src/dispatch.c b/src/dispatch.c
index 1b39228..902f097 100644
--- a/src/dispatch.c
+++ b/src/dispatch.c
@@ -190,6 +190,12 @@ qd_error_t qd_dispatch_register_policy_manager(qd_dispatch_t *qd, qd_entity_t *e
 }
 
 
+qd_error_t qd_dispatch_register_display_name_service(qd_dispatch_t *qd, void *object)
+{
+    return qd_register_display_name_service(qd, object);
+}
+
+
 long qd_dispatch_policy_c_counts_alloc()
 {
     return qd_policy_c_counts_alloc();

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6e9c24e9/src/dispatch_private.h
----------------------------------------------------------------------
diff --git a/src/dispatch_private.h b/src/dispatch_private.h
index 27a454f..99c35d7 100644
--- a/src/dispatch_private.h
+++ b/src/dispatch_private.h
@@ -117,6 +117,11 @@ qd_error_t qd_dispatch_configure_policy(qd_dispatch_t *qd, qd_entity_t *entity);
 qd_error_t qd_dispatch_register_policy_manager(qd_dispatch_t *qd, qd_entity_t *entity);
 
 /**
+ * Configure display name service, must be called after qd_dispatch_prepare
+ */
+qd_error_t qd_dispatch_register_display_name_service(qd_dispatch_t *qd, void *object);
+
+/**
  * \brief Configure the logging module from the
  *        parsed configuration file.  This must be called after the
  *        call to qd_dispatch_prepare completes.

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6e9c24e9/src/server.c
----------------------------------------------------------------------
diff --git a/src/server.c b/src/server.c
index aa08ae6..e78978d 100644
--- a/src/server.c
+++ b/src/server.c
@@ -23,6 +23,7 @@
 #include <qpid/dispatch/log.h>
 #include <qpid/dispatch/amqp.h>
 #include <qpid/dispatch/server.h>
+#include "qpid/dispatch/python_embedded.h"
 #include "entity.h"
 #include "entity_cache.h"
 #include "dispatch_private.h"
@@ -133,6 +134,19 @@ static qd_error_t connection_entity_update_host(qd_entity_t* entity, qd_connecti
         return qd_entity_set_string(entity, "host", qdpn_connector_name(conn->pn_cxtr));
 }
 
+
+/**
+ * Save displayNameService object instance and ImportModule address
+ * Called with qd_python_lock held
+ */
+qd_error_t qd_register_display_name_service(qd_dispatch_t *qd, void *displaynameservice)
+{
+    qd->server->py_displayname_obj    = displaynameservice;
+    qd->server->py_displayname_module = PyImport_ImportModule("qpid_dispatch_internal.display_name.display_name");
+    return qd->server->py_displayname_module ? QD_ERROR_NONE : qd_error(QD_ERROR_RUNTIME, "Fail importing DisplayNameService module");
+}
+
+
 /**
  * Returns a char pointer to a user id which is constructed from components specified in the config->ssl_uid_format.
  * Parses through each component and builds a semi-colon delimited string which is returned as the user id.
@@ -310,6 +324,32 @@ static const char *qd_transport_get_user(qd_connection_t *conn, pn_transport_t *
                     }
                 }
             }
+            if (config->ssl_display_name_file) {
+                // Translate extracted id into display name
+                qd_python_lock_state_t lock_state = qd_python_lock();
+                PyObject *module = (PyObject*)conn->server->py_displayname_module;
+                PyObject *query = PyObject_GetAttrString(module, "display_name_local_query");
+                if (query) {
+                    PyObject *result = PyObject_CallFunction(query, "(Oss)",
+                                                            (PyObject *)conn->server->py_displayname_obj,
+                                                            config->ssl_profile, user_id);
+                    if (result) {
+                        const char *res_string = PyString_AsString(result);
+                        free(user_id);
+                        user_id = malloc(strlen(res_string) + 1);
+                        user_id[0] = '\0';
+                        strcat(user_id, res_string);
+                        Py_XDECREF(result);
+                    } else {
+                        qd_log(conn->server->log_source, QD_LOG_DEBUG, "Internal: failed to read displaynameservice query result");
+                    }
+                    Py_XDECREF(query);
+                } else {
+                    qd_log(conn->server->log_source, QD_LOG_DEBUG, "Internal: failed to locate query function");
+                }
+                Py_XDECREF(module);
+                qd_python_unlock(lock_state);
+            }
             qd_log(conn->server->log_source, QD_LOG_DEBUG, "User id is '%s' ", user_id);
             return user_id;
         }
@@ -1351,6 +1391,8 @@ qd_server_t *qd_server(qd_dispatch_t *qd, int thread_count, const char *containe
     qd_server->signal_handler_running = false;
     qd_server->heartbeat_timer        = 0;
     qd_server->next_connection_id     = 1;
+    qd_server->py_displayname_module  = 0;
+    qd_server->py_displayname_obj     = 0;
 
     qd_log(qd_server->log_source, QD_LOG_INFO, "Container Name: %s", qd_server->container_name);
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6e9c24e9/src/server_private.h
----------------------------------------------------------------------
diff --git a/src/server_private.h b/src/server_private.h
index 008ed2b..caa3471 100644
--- a/src/server_private.h
+++ b/src/server_private.h
@@ -180,6 +180,8 @@ struct qd_server_t {
     qd_connection_list_t      connections;
     qd_timer_t               *heartbeat_timer;
     uint64_t                 next_connection_id;
+    void                     *py_displayname_module;
+    void                     *py_displayname_obj;
 };
 
 ALLOC_DECLARE(qd_work_item_t);

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6e9c24e9/tests/displayname_files/profile_names1.json
----------------------------------------------------------------------
diff --git a/tests/displayname_files/profile_names1.json b/tests/displayname_files/profile_names1.json
index 21337db..f0f0dd4 100644
--- a/tests/displayname_files/profile_names1.json
+++ b/tests/displayname_files/profile_names1.json
@@ -1,5 +1,7 @@
 {
     "14845961c5646ee0129536b3a9ef1eea0d8d2f26f8c3ed08ece4f8f3027ba9d5": "gmurthy",
     "94745961c5646ee0129536b3acef1eea0d8d2f26f8c3ed08ece4f8f3027bcd47": "janedoe",
-    "94745961c5646ee0129536b3acef1eea0d8d2f26f8c3ed08ece4f8f3027bcd48": "johndoe"
+    "94745961c5646ee0129536b3acef1eea0d8d2f26f8c3ed08ece4f8f3027bcd48": "johndoe",
+    "60f5dbd7ed14a5ea243785e81745ac8463494298": "user13",
+    "82244216b6d02ffdfb886c8da3c803e0f7a7b330a7b665dccabd30bd25d0f35e2a4fff5f0a2a01d56eb7dbae085c108e71a32b84bab16c9ec243a1f6d014900d" : "user14"
 }

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6e9c24e9/tests/displayname_files/profile_names2.json
----------------------------------------------------------------------
diff --git a/tests/displayname_files/profile_names2.json b/tests/displayname_files/profile_names2.json
index 497543e..152f705 100644
--- a/tests/displayname_files/profile_names2.json
+++ b/tests/displayname_files/profile_names2.json
@@ -1,5 +1,6 @@
 {
     "14845961c5646ee0129536b3a9ef1eea0d8d2f26f8c3ed08ece4f5546546": "jerry",
     "94745961c5646ee0129536b3acef1eea0d8d2f26f8c353455233027bcd47": "elaine",
-    "94745961c5646ee0129536b3acef1eea0d8d2f26f8c3ed08ece3027bcd48": "george"
+    "94745961c5646ee0129536b3acef1eea0d8d2f26f8c3ed08ece3027bcd48": "george",
+    "7c87f0c974f9e1aa5cb98f13fae9675625f240c98034b888753140da28094879": "user12"
 }

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/6e9c24e9/tests/system_tests_user_id.py
----------------------------------------------------------------------
diff --git a/tests/system_tests_user_id.py b/tests/system_tests_user_id.py
index 8b70470..ddd4f67 100644
--- a/tests/system_tests_user_id.py
+++ b/tests/system_tests_user_id.py
@@ -20,7 +20,6 @@
 
 import os
 import unittest
-from time import sleep
 from system_test import TestCase, Qdrouterd, DIR, main_module
 from qpid_dispatch.management.client import Node
 from proton import SSLDomain, Message
@@ -138,6 +137,23 @@ class QdSSLUseridTest(TestCase):
                              'displayNameFile': ssl_profile1_json,
                              'password': 'server-password'}),
 
+            # should translate a display name
+            ('sslProfile', {'name': 'server-ssl13',
+                            'certDb': cls.ssl_file('ca-certificate.pem'),
+                            'certFile': cls.ssl_file('server-certificate.pem'),
+                            'keyFile': cls.ssl_file('server-private-key.pem'),
+                            'uidFormat': '2',
+                            'displayNameFile': ssl_profile2_json,
+                            'password': 'server-password'}),
+
+            ('sslProfile', {'name': 'server-ssl14',
+                            'certDb': cls.ssl_file('ca-certificate.pem'),
+                            'certFile': cls.ssl_file('server-certificate.pem'),
+                            'keyFile': cls.ssl_file('server-private-key.pem'),
+                            'uidFormat': '1',
+                            'displayNameFile': ssl_profile1_json,
+                            'password': 'server-password'}),
+
             ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl1', 'authenticatePeer': 'yes',
                           'requireSsl': 'yes', 'saslMechanisms': 'EXTERNAL'}),
 
@@ -176,6 +192,12 @@ class QdSSLUseridTest(TestCase):
             ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl12', 'authenticatePeer': 'no',
                           'requireSsl': 'yes', 'saslMechanisms': 'ANONYMOUS'}),
 
+            ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl13', 'authenticatePeer': 'yes',
+                          'requireSsl': 'yes', 'saslMechanisms': 'EXTERNAL'}),
+
+            ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl14', 'authenticatePeer': 'yes',
+                          'requireSsl': 'yes', 'saslMechanisms': 'EXTERNAL'}),
+
             ('listener', {'port': cls.tester.get_port(), 'authenticatePeer': 'no'})
 
         ])
@@ -277,8 +299,18 @@ class QdSSLUseridTest(TestCase):
         user = node.query(type='org.apache.qpid.dispatch.connection', attribute_names=['user']).results[11][0]
         self.assertEqual("anonymous", user)
 
+        addr = self.address(12).replace("amqp", "amqps")
+        node = Node.connect(addr, ssl_domain=domain)
+        user = node.query(type='org.apache.qpid.dispatch.connection', attribute_names=['user']).results[12][0]
+        self.assertEqual("user12", str(user))
+
+        addr = self.address(13).replace("amqp", "amqps")
+        node = Node.connect(addr, ssl_domain=domain)
+        user_id = node.query(type='org.apache.qpid.dispatch.connection', attribute_names=['user']).results[13][0]
+        self.assertEqual("user13", user_id)
+
         M1 = self.messenger()
-        M1.route("amqp:/*", self.address(12)+"/$1")
+        M1.route("amqp:/*", self.address(14)+"/$1")
 
         subscription = M1.subscribe("amqp:/#")
 
@@ -301,7 +333,7 @@ class QdSSLUseridTest(TestCase):
         rm = Message()
         tm.address = addr
         tm.reply_to = reply_to
-        tm.body =  {'profilename': 'server-ssl14', 'opcode': 'QUERY', 'userid': '94745961c5646ee0129536b3acef1eea0d8d2f26f8c3ed08ece4f8f3027bcd48'}
+        tm.body =  {'profilename': 'server-ssl-unknown', 'opcode': 'QUERY', 'userid': '94745961c5646ee0129536b3acef1eea0d8d2f26f8c3ed08ece4f8f3027bcd48'}
         M1.put(tm)
         M1.send()
         M1.recv(1)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org