You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by tr...@apache.org on 2016/03/30 14:24:15 UTC

[1/2] qpid-dispatch git commit: DISPATCH-200 - Add a flexible mapping from x.509 certificate fields to an identity

Repository: qpid-dispatch
Updated Branches:
  refs/heads/master b0ad2eb2f -> 122eeec34


DISPATCH-200 - Add a flexible mapping from x.509 certificate fields to an identity


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

Branch: refs/heads/master
Commit: 56e56ce2ee00fcca49d574c276f8e7dba2ca6187
Parents: b0ad2eb
Author: Ganesh Murthy <gm...@redhat.com>
Authored: Tue Mar 29 18:03:29 2016 -0400
Committer: Ganesh Murthy <gm...@redhat.com>
Committed: Tue Mar 29 18:03:59 2016 -0400

----------------------------------------------------------------------
 include/qpid/dispatch/server.h                  |  26 +-
 python/qpid_dispatch/management/qdrouter.json   |  17 +-
 .../display_name/__init__.py                    |  19 ++
 .../display_name/display_name.py                | 124 +++++++
 .../qpid_dispatch_internal/management/config.py |  19 +-
 python/qpid_dispatch_internal/tools/command.py  |   6 +-
 src/connection_manager.c                        |   4 +
 src/container.c                                 |   2 +
 src/server.c                                    | 217 +++++++++++-
 src/server_private.h                            |  46 +--
 tests/CMakeLists.txt                            |   3 +
 tests/displayname_files/profile_names1.json     |   5 +
 tests/displayname_files/profile_names2.json     |   5 +
 tests/management/qdrouter.py                    |  52 ++-
 tests/ssl_certs/bad-ca-certificate.pem          |  18 +-
 tests/ssl_certs/bad-ca.pkcs12                   | Bin 1516 -> 1516 bytes
 tests/ssl_certs/ca-certificate.pem              |  22 +-
 tests/ssl_certs/ca.pkcs12                       | Bin 1492 -> 1508 bytes
 tests/ssl_certs/client-certificate.pem          |  27 +-
 tests/ssl_certs/client-private-key.pem          |  20 +-
 tests/ssl_certs/client-request.pem              |  23 +-
 tests/ssl_certs/client.pkcs12                   | Bin 1540 -> 1652 bytes
 tests/ssl_certs/gencerts.sh                     |  16 +-
 tests/ssl_certs/server-certificate.pem          |  28 +-
 tests/ssl_certs/server-private-key.pem          |  20 +-
 tests/ssl_certs/server-request.pem              |  22 +-
 tests/ssl_certs/server.pkcs12                   | Bin 1580 -> 1564 bytes
 tests/system_tests_two_routers.py               |  41 ++-
 tests/system_tests_user_id.py                   | 340 +++++++++++++++++++
 29 files changed, 956 insertions(+), 166 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/include/qpid/dispatch/server.h
----------------------------------------------------------------------
diff --git a/include/qpid/dispatch/server.h b/include/qpid/dispatch/server.h
index e6c42ca..134dc30 100644
--- a/include/qpid/dispatch/server.h
+++ b/include/qpid/dispatch/server.h
@@ -335,6 +335,30 @@ typedef struct qd_server_config_t {
     char *ssl_private_key_file;
 
     /**
+     * Holds the list of component fields of the client certificate from which a unique identifier is constructed.
+     * For e.g, this field could have the format of 'cou' indicating that the uid will consist of
+     * c - common name concatenated with o - organization-company name concatenated with u - organization unit
+     * Allowed components are
+     * Allowed values can be any combination of comma separated
+     * 'c'( ISO3166 two character country code),
+     * 's'(state or province),
+     * 'l'(Locality; generally - city),
+     * 'o'(Organization - Company Name),
+     * 'u'(Organization Unit - typically certificate type or brand),
+     * 'n'(CommonName - typically a user name for client certificates) and
+     * '1'(sha1 certificate fingerprint, the fingerprint, as displayed in the fingerprints section when looking at a certificate
+     *  with say a web browser is the hash of the entire certificate in DER form)
+     * '2'(sha256 certificate fingerprint)
+     * '5'(sha512 certificate fingerprint)
+     */
+    char *ssl_uid_format;
+
+    /**
+     * Full path to the file that contains the uid to display name mapping.
+     */
+    char *ssl_display_name_file;
+
+    /**
      * The password used to sign the private key, or NULL if the key is not protected.
      */
     char *ssl_password;
@@ -433,7 +457,7 @@ void qd_server_set_conn_handler(qd_dispatch_t *qd, qd_conn_handler_cb_t conn_han
 /**
  * Set the user context for a connection.
  *
- * @param conn Connection object supplied in QD_CONN_EVENT_{LISTENER,CONNETOR}_OPEN
+ * @param conn Connection object supplied in QD_CONN_EVENT_{LISTENER,CONNECTOR}_OPEN
  * @param context User context to be stored with the connection.
  */
 void qd_connection_set_context(qd_connection_t *conn, void *context);

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/python/qpid_dispatch/management/qdrouter.json
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch/management/qdrouter.json b/python/qpid_dispatch/management/qdrouter.json
index 4112b89..8ff352a 100644
--- a/python/qpid_dispatch/management/qdrouter.json
+++ b/python/qpid_dispatch/management/qdrouter.json
@@ -79,7 +79,22 @@
                     "description": "An alternative to storing the password in a file referenced by passwordFile is to supply the password right here in the configuration file.  This option can be used by supplying the password in the 'password' option.  Don't use both password and passwordFile in the same profile.",
                     "create": true
 
-                }
+                },
+                "uidFormat": {
+                    "type": "string",
+                    "description": "A list of x509 client certificate fields that will be used to build a string that will uniquely identify the client certificate owner. For e.g. a value of 'cou' indicates that the uid will consist of c - common name concatenated with o - organization-company name concatenated with u - organization unit; or a value of 'oF' indicates that the uid will consist of o (organization name) concatenated with F (the sha256 fingerprint of the entire certificate) . Allowed values can be any combination of comma separated 'c'( ISO3166 two character country code), 's'(state or province), 'l'(Locality; generally - city), 'o'(Organization - Company Name), 'u'(Organization Unit - typically certificate type or brand), 'n'(CommonName - typically a user name for client certificates) and '1'(sha1 certificate fingerprint, as displayed in the fingerprints section when looking at a certificate with say a web browser is the hash of the entire certificate) and 2 (sha256 ce
 rtificate fingerprint) and 5 (sha512 certificate fingerprint). ",
+                    "create": true
+                },
+                "displayNameFile": {
+                    "type": "string",
+                    "description": "The path to the file containing the unique id to dispay name mapping",
+                    "create": true
+                },
+                "sslProfileName": {
+                    "type": "string",
+                    "description": "The name of the ssl profile",
+                    "create": false
+                }                
             }
         }
     },

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/python/qpid_dispatch_internal/display_name/__init__.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/display_name/__init__.py b/python/qpid_dispatch_internal/display_name/__init__.py
new file mode 100644
index 0000000..cb85def
--- /dev/null
+++ b/python/qpid_dispatch_internal/display_name/__init__.py
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+"Qpid Dispatch internal display name service"

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/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
new file mode 100644
index 0000000..340e69d
--- /dev/null
+++ b/python/qpid_dispatch_internal/display_name/display_name.py
@@ -0,0 +1,124 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License
+#
+
+"""
+DisplayNameService provides the mapping needed to associate an un-friendly user identifier to a more friendly
+user nick name.
+Maintains a dict (profile_dict) of ssl profile names to SSLProfile objects. The SSLProfile objects are built using
+the file name which contains a mapping of user identifiers to user names.
+"""
+import traceback
+from traceback import format_exc
+
+from ..router.message import Message
+
+from ..dispatch import IoAdapter, LogAdapter, LOG_INFO, LOG_ERROR, LOG_TRACE, LOG_STACK_LIMIT
+import json
+
+class SSLProfile(object):
+    def __init__(self, profile_name, profile_file):
+        super(SSLProfile, self).__init__()
+        self.profile_name = profile_name
+        self.profile_file = profile_file
+        self.cache = {}
+        with open(profile_file) as json_data:
+            d = json.load(json_data)
+            for key in d.keys():
+                self.cache[key] = d[key]
+
+class DisplayNameService(object):
+
+    def __init__(self, address):
+        super(DisplayNameService, self).__init__()
+        # profile_dict will be a mapping from ssl_profile_name to the SSLProfile object
+        self.profile_dict = {}
+        self.io_adapter = None
+        self.log_adapter = LogAdapter("DISPLAYNAME")
+        if address:
+            self._activate(address)
+
+    def log(self, level, text):
+        info = traceback.extract_stack(limit=2)[0] # Caller frame info
+        self.log_adapter.log(level, text, info[0], info[1])
+
+    def _activate(self, address):
+        self.log(LOG_INFO, "Activating DisplayNameService on %s" % address)
+        self.io_adapter = [IoAdapter(self.receive, address)]
+
+    def add(self, profile_name, profile_file_location):
+        ssl_profile = SSLProfile(profile_name, profile_file_location)
+        self.profile_dict[profile_name] = ssl_profile
+        self.log(LOG_INFO, "Added profile name %s, profile file location %s to DisplayNameService" % (profile_name, profile_file_location))
+
+    def remove(self, profile_name):
+        try:
+            del self.profile_dict[profile_name]
+        except KeyError:
+            pass
+
+    def reload_all(self):
+        for profile_name in self.profile_dict.keys():
+            self.add(profile_name, self.profile_dict[profile_name].profile_file)
+
+    def reload(self, profile_name=None):
+        if profile_name:
+            self.add(profile_name, self.profile_dict[profile_name].profile_file)
+        else:
+            self.reload_all()
+
+    def query(self, profile_name, user_id):
+        self.log(LOG_TRACE, "Received query for profile name %s, user id %s to DisplayNameService" %
+                 (profile_name, user_id))
+        ssl_profile = self.profile_dict.get(profile_name)
+        if ssl_profile:
+            profile_cache = self.profile_dict.get(profile_name).cache
+            user_name = profile_cache.get(user_id)
+            body = {'user_name': user_name if user_name else user_id}
+        else:
+            body = {'user_name': user_id}
+
+        return body
+
+    def receive(self, message, link_id):
+        """
+        This is the IOAdapter's callback function. Will be invoked when the IOAdapter receives a request.
+        Will only accept QUERY requests.
+        Matches the passed in profilename and userid to user name. If a matching user name is not found, returns the
+        passed in userid as the user name.
+        :param message:
+        :param link_id:
+        """
+        body = {}
+
+        try:
+            opcode = message.body.get('opcode')
+            profile_name = message.body.get('profilename')
+            user_id = message.body.get('userid')
+            if opcode == 'QUERY' and profile_name and user_id:
+                body = self.query(profile_name, user_id)
+        except Exception:
+            self.log(LOG_ERROR, "Exception in raw message processing: body=%r\n%s" %
+                     (message.body, format_exc(LOG_STACK_LIMIT)))
+
+        response = Message(address=message.reply_to,
+                           body=body,
+                           correlation_id=message.correlation_id)
+
+        self.io_adapter[0].send(response)
+

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/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 aedd8d5..1ae8f6c 100644
--- a/python/qpid_dispatch_internal/management/config.py
+++ b/python/qpid_dispatch_internal/management/config.py
@@ -24,6 +24,7 @@ Configuration file parsing
 import json, re, sys
 from copy import copy
 from qpid_dispatch.management.entity import camelcase
+
 from ..dispatch import QdDll
 from .qdrouter import QdSchema
 
@@ -80,12 +81,15 @@ class Config(object):
         def _expand_section(section, annotations):
             """Expand one section"""
             attrs = section[1]
+
             for k in attrs.keys(): # Iterate over keys() because we will modify attr
                 inc = [i[1] for i in annotations if i[0] == k and i[1]['name'] == attrs[k]]
                 if inc:
                     assert len(inc) == 1
                     inc = copy(inc[0])
-                    del inc['name'] # Not a real attribute, just an annotation id.
+                    if k == u'sslProfile':
+                        inc[u'sslProfileName'] = inc[u'name']
+                    del inc['name']
                     attrs.update(inc)
                     del attrs[k] # Delete the annotation attribute.
             return section
@@ -143,7 +147,8 @@ def configure_dispatch(dispatch, lib_handle, filename):
         modules.remove(l["module"])
 
     # Add default entities for any log modules not configured.
-    for m in modules: agent.configure(attributes=dict(type="log", module=m))
+    for m in modules:
+        agent.configure(attributes=dict(type="log", module=m))
 
     # Configure and prepare container and router before we can activate the agent.
     configure(config.by_type('container')[0])
@@ -152,11 +157,19 @@ def configure_dispatch(dispatch, lib_handle, filename):
     qd.qd_router_setup_late(dispatch) # Actions requiring active management agent.
     agent.activate("$_management_internal")
 
+    from qpid_dispatch_internal.display_name.display_name import DisplayNameService
+    displayname_service = DisplayNameService("$displayname")
     # Remaining configuration
     for t in "fixedAddress", "listener", "connector", "waypoint", "linkRoutePattern", \
-        "router.config.address", "router.config.linkRoute", "router.config.autoLink":
+             "router.config.address", "router.config.linkRoute", "router.config.autoLink":
         for a in config.by_type(t):
             configure(a)
+            if t == "listener":
+                display_file_name = a.get('displayNameFile')
+                if display_file_name:
+                    ssl_profile_name = a.get('sslProfileName')
+                    displayname_service.add(ssl_profile_name, display_file_name)
+
     for e in config.entities:
         configure(e)
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/python/qpid_dispatch_internal/tools/command.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/tools/command.py b/python/qpid_dispatch_internal/tools/command.py
index 86abfc0..7b941ef 100644
--- a/python/qpid_dispatch_internal/tools/command.py
+++ b/python/qpid_dispatch_internal/tools/command.py
@@ -107,10 +107,10 @@ def opts_ssl_domain(opts, mode=SSLDomain.MODE_CLIENT):
     if not (certificate or trustfile): return None
     domain = SSLDomain(mode)
     if trustfile:
-        domain.set_trusted_ca_db(trustfile)
-        domain.set_peer_authentication(SSLDomain.VERIFY_PEER, trustfile)
+        domain.set_trusted_ca_db(str(trustfile))
+        domain.set_peer_authentication(SSLDomain.VERIFY_PEER, str(trustfile))
     if certificate:
-        domain.set_credentials(certificate, key, password)
+        domain.set_credentials(str(certificate), str(key), str(password))
     return domain
 
 class Option(optparse.Option):

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/src/connection_manager.c
----------------------------------------------------------------------
diff --git a/src/connection_manager.c b/src/connection_manager.c
index c5b12e4..ee0b126 100644
--- a/src/connection_manager.c
+++ b/src/connection_manager.c
@@ -176,6 +176,10 @@ static qd_error_t load_server_config(qd_dispatch_t *qd, qd_server_config_t *conf
             qd_entity_opt_string(entity, "certDb", 0); CHECK();
         config->ssl_trusted_certificates =
             qd_entity_opt_string(entity, "trustedCerts", 0); CHECK();
+        config->ssl_uid_format =
+            qd_entity_opt_string(entity, "uidFormat", 0); CHECK();
+        config->ssl_display_name_file =
+            qd_entity_opt_string(entity, "displayNameFile", 0); CHECK();
     }
 
     free(stripAnnotations);

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/src/container.c
----------------------------------------------------------------------
diff --git a/src/container.c b/src/container.c
index c63a077..0d789b0 100644
--- a/src/container.c
+++ b/src/container.c
@@ -21,6 +21,7 @@
 #include <string.h>
 #include "dispatch_private.h"
 #include "connection_manager_private.h"
+#include "server_private.h"
 #include <qpid/dispatch/container.h>
 #include <qpid/dispatch/server.h>
 #include <qpid/dispatch/message.h>
@@ -369,6 +370,7 @@ int pn_event_handler(void *handler_context, void *conn_context, pn_event_t *even
     case PN_CONNECTION_REMOTE_OPEN :
         if (pn_connection_state(conn) & PN_LOCAL_UNINIT)
             pn_connection_open(conn);
+        qd_connection_set_user(qd_conn);
         qd_connection_manager_connection_opened(qd_conn);
         notify_opened(container, qd_conn, conn_context);
         break;

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/src/server.c
----------------------------------------------------------------------
diff --git a/src/server.c b/src/server.c
index bfe704f..0cd4bc7 100644
--- a/src/server.c
+++ b/src/server.c
@@ -46,6 +46,19 @@ ALLOC_DEFINE(qd_connection_t);
 ALLOC_DEFINE(qd_user_fd_t);
 
 const char *QD_CONNECTION_TYPE = "connection";
+const char *MECH_EXTERNAL = "EXTERNAL";
+
+//Allowed uidFormat fields.
+const char CERT_COUNTRY_CODE = 'c';
+const char CERT_STATE = 's';
+const char CERT_CITY_LOCALITY = 'l';
+const char CERT_ORGANIZATION_NAME = 'o';
+const char CERT_ORGANIZATION_UNIT = 'u';
+const char CERT_COMMON_NAME = 'n';
+const char CERT_FINGERPRINT_SHA1 = '1';
+const char CERT_FINGERPRINT_SHA256 = '2';
+const char CERT_FINGERPRINT_SHA512 = '5';
+char *COMPONENT_SEPARATOR = ";";
 
 static qd_thread_t *thread(qd_server_t *qd_server, int id)
 {
@@ -87,6 +100,205 @@ 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));
 }
 
+/**
+ * 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.
+ */
+static const char *qd_transport_get_user(qd_connection_t *conn, pn_transport_t *tport)
+{
+    const qd_server_config_t *config =
+            conn->connector ? conn->connector->config : conn->listener->config;
+
+    if (config->ssl_uid_format) {
+
+        // The ssl_uid_format length cannot be greater that 7
+        assert(strlen(config->ssl_uid_format) < 8);
+
+        //
+        // The tokens in the uidFormat strings are delimited by comma. Load the individual components of the uidFormat
+        // into the components[] array. The maximum number of components that are allowed are 7 namely, c, s, l, o, u, n, (1 or 2 or 5)
+        //
+        char components[7];
+
+        //The strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'), to the buffer pointed to by dest.
+        strcpy(components, config->ssl_uid_format);
+
+        const char *country_code = 0;
+        const char *state = 0;
+        const char *locality_city = 0;
+        const char *organization = 0;
+        const char *org_unit = 0;
+        const char *common_name = 0;
+        //
+        // SHA1 is 20 octets (40 hex characters); SHA256 is 32 octets (64 hex characters).
+        // SHA512 is 64 octets (128 hex characters)
+        //
+        char fingerprint[129];
+
+        int uid_length = 0;
+        int semi_colon_count = -1;
+
+        int component_count = strlen(components);
+
+        for (int x = 0; x < component_count ; x++) {
+            // accumulate the length into uid_length on each pass so we definitively know the number of octets to malloc.
+            if (components[x] == CERT_COUNTRY_CODE) {
+                country_code =  pn_ssl_get_remote_subject_subfield(pn_ssl(tport), PN_SSL_CERT_SUBJECT_COUNTRY_NAME);
+                if (country_code) {
+                    uid_length += strlen((const char *)country_code);
+                    semi_colon_count++;
+                }
+            }
+            else if (components[x] == CERT_STATE) {
+                state =  pn_ssl_get_remote_subject_subfield(pn_ssl(tport), PN_SSL_CERT_SUBJECT_STATE_OR_PROVINCE);
+                if (state) {
+                    uid_length += strlen((const char *)state);
+                    semi_colon_count++;
+                }
+            }
+            else if (components[x] == CERT_CITY_LOCALITY) {
+                locality_city =  pn_ssl_get_remote_subject_subfield(pn_ssl(tport), PN_SSL_CERT_SUBJECT_CITY_OR_LOCALITY);
+                if (locality_city) {
+                    uid_length += strlen((const char *)locality_city);
+                    semi_colon_count++;
+                }
+            }
+            else if (components[x] == CERT_ORGANIZATION_NAME) {
+                organization =  pn_ssl_get_remote_subject_subfield(pn_ssl(tport), PN_SSL_CERT_SUBJECT_ORGANIZATION_NAME);
+                if(organization) {
+                    uid_length += strlen((const char *)organization);
+                    semi_colon_count++;
+                }
+            }
+            else if (components[x] == CERT_ORGANIZATION_UNIT) {
+                org_unit =  pn_ssl_get_remote_subject_subfield(pn_ssl(tport), PN_SSL_CERT_SUBJECT_ORGANIZATION_UNIT);
+                if(org_unit) {
+                    uid_length += strlen((const char *)org_unit);
+                    semi_colon_count++;
+                }
+            }
+            else if (components[x] == CERT_COMMON_NAME) {
+                common_name =  pn_ssl_get_remote_subject_subfield(pn_ssl(tport), PN_SSL_CERT_SUBJECT_COMMON_NAME);
+                if(common_name) {
+                    uid_length += strlen((const char *)common_name);
+                    semi_colon_count++;
+                }
+            }
+            else if (components[x] == CERT_FINGERPRINT_SHA1 || components[x] == CERT_FINGERPRINT_SHA256 || components[x] == CERT_FINGERPRINT_SHA512) {
+                // Allocate the memory for message digest
+                int out = 0;
+
+                int fingerprint_length = 0;
+                if(components[x] == CERT_FINGERPRINT_SHA1) {
+                    fingerprint_length = 40;
+                    out = pn_ssl_get_cert_fingerprint(pn_ssl(tport), fingerprint, fingerprint_length + 1, PN_SSL_SHA1);
+                }
+                else if (components[x] == CERT_FINGERPRINT_SHA256) {
+                    fingerprint_length = 64;
+                    out = pn_ssl_get_cert_fingerprint(pn_ssl(tport), fingerprint, fingerprint_length + 1, PN_SSL_SHA256);
+                }
+                else if (components[x] == CERT_FINGERPRINT_SHA512) {
+                    fingerprint_length = 128;
+                    out = pn_ssl_get_cert_fingerprint(pn_ssl(tport), fingerprint, fingerprint_length + 1, PN_SSL_SHA512);
+                }
+
+                assert (out != PN_ERR);
+
+                uid_length += fingerprint_length;
+                semi_colon_count++;
+            }
+            else {
+                // This is an unrecognized component. log a critical error
+                qd_log(conn->server->log_source, QD_LOG_CRITICAL, "Unrecognized component '%c' in uidFormat ", components[x]);
+                return 0;
+            }
+        }
+
+        if(uid_length > 0) {
+            char *user_id = malloc((uid_length + semi_colon_count + 1) * sizeof(char)); // the +1 is for the '\0' character
+            memset(user_id, 0, uid_length + semi_colon_count + 1);
+
+            // The components in the user id string must appear in the same order as it appears in the component string. that is
+            // why we have this loop
+            for (int x=0; x < component_count ; x++) {
+                if (components[x] == CERT_COUNTRY_CODE) {
+                    if (country_code) {
+                        if(*user_id != '\0')
+                            strcat(user_id, COMPONENT_SEPARATOR);
+                        strcat(user_id, (char *) country_code);
+                    }
+                }
+                else if (components[x] == CERT_STATE) {
+                    if (state) {
+                        if(*user_id != '\0')
+                            strcat(user_id, COMPONENT_SEPARATOR);
+                        strcat(user_id, (char *) state);
+                    }
+                }
+                else if (components[x] == CERT_CITY_LOCALITY) {
+                    if (locality_city) {
+                        if(*user_id != '\0')
+                            strcat(user_id, COMPONENT_SEPARATOR);
+                        strcat(user_id, (char *) locality_city);
+                    }
+                }
+                else if (components[x] == CERT_ORGANIZATION_NAME) {
+                    if (organization) {
+                        if(*user_id != '\0')
+                            strcat(user_id, COMPONENT_SEPARATOR);
+                        strcat(user_id, (char *) organization);
+                    }
+                }
+                else if (components[x] == CERT_ORGANIZATION_UNIT) {
+                    if (org_unit) {
+                        if(*user_id != '\0')
+                            strcat(user_id, COMPONENT_SEPARATOR);
+                        strcat(user_id, (char *) org_unit);
+                    }
+                }
+                else if (components[x] == CERT_COMMON_NAME) {
+                    if (common_name) {
+                        if(*user_id != '\0')
+                            strcat(user_id, COMPONENT_SEPARATOR);
+                        strcat(user_id, (char *) common_name);
+                    }
+                }
+                else if (components[x] == CERT_FINGERPRINT_SHA1 || components[x] == CERT_FINGERPRINT_SHA256 || components[x] == CERT_FINGERPRINT_SHA512) {
+                    if (strlen((char *) fingerprint) > 0) {
+                        if(*user_id != '\0')
+                            strcat(user_id, COMPONENT_SEPARATOR);
+                        strcat(user_id, (char *) fingerprint);
+                    }
+                }
+            }
+            qd_log(conn->server->log_source, QD_LOG_DEBUG, "User id is '%s' ", user_id);
+            return user_id;
+        }
+    }
+    else //config->ssl_uid_format not specified, just return the username provided by the proton transport.
+        return pn_transport_get_user(tport);
+
+    return 0;
+}
+
+
+void qd_connection_set_user(qd_connection_t *conn)
+{
+    pn_transport_t *tport = pn_connection_transport(conn->pn_conn);
+    pn_sasl_t      *sasl  = pn_sasl(tport);
+    if (sasl) {
+        const char *mech = pn_sasl_get_mech(sasl);
+        conn->user_id = pn_transport_get_user(tport);
+        // We want to set the user name only if it is not already set and the selected sasl mechanism is EXTERNAL
+        if (mech && strcmp(mech, MECH_EXTERNAL) == 0) {
+            // TODO - Make sure you free the user_id when conn is freed ?
+            const char *user_id = qd_transport_get_user(conn, tport);
+            if (user_id)
+                conn->user_id = user_id;
+        }
+    }
+}
+
 qd_error_t qd_entity_refresh_connection(qd_entity_t* entity, void *impl)
 {
     qd_connection_t *conn = (qd_connection_t*)impl;
@@ -104,7 +316,10 @@ qd_error_t qd_entity_refresh_connection(qd_entity_t* entity, void *impl)
     }
     if (tport) {
         sasl = pn_sasl(tport);
-        user = pn_transport_get_user(tport);
+        if(conn->user_id)
+            user = conn->user_id;
+        else
+            user = pn_transport_get_user(tport);
     }
     if (sasl)
         mech = pn_sasl_get_mech(sasl);

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/src/server_private.h
----------------------------------------------------------------------
diff --git a/src/server_private.h b/src/server_private.h
index a40a503..930f271 100644
--- a/src/server_private.h
+++ b/src/server_private.h
@@ -83,25 +83,25 @@ DEQ_DECLARE(qd_deferred_call_t, qd_deferred_call_list_t);
  */
 struct qd_connection_t {
     DEQ_LINKS(qd_connection_t);
-    qd_server_t      *server;
-    bool              opened; // An open callback was invoked for this connection
-    bool              closed;
-    int               owner_thread;
-    int               enqueued;
-    qdpn_connector_t *pn_cxtr;
-    pn_connection_t  *pn_conn;
-    pn_collector_t   *collector;
-    pn_ssl_t         *ssl;
-    qd_listener_t    *listener;
-    qd_connector_t   *connector;
-    void             *context; // Copy of context from listener or connector
-    void             *user_context;
-    void             *link_context; // Context shared by this connection's links
-    qd_user_fd_t     *ufd;
-    uint64_t         connection_id; // A unique identifier for the qd_connection_t. The underlying pn_connection already has one but it is long and clunky.
-
-    qd_deferred_call_list_t  deferred_calls;
-    sys_mutex_t             *deferred_call_lock;
+    qd_server_t              *server;
+    bool                      opened; // An open callback was invoked for this connection
+    bool                      closed;
+    int                       owner_thread;
+    int                       enqueued;
+    qdpn_connector_t         *pn_cxtr;
+    pn_connection_t          *pn_conn;
+    pn_collector_t           *collector;
+    pn_ssl_t                 *ssl;
+    qd_listener_t            *listener;
+    qd_connector_t           *connector;
+    void                     *context; // Copy of context from listener or connector
+    void                     *user_context;
+    void                     *link_context; // Context shared by this connection's links
+    qd_user_fd_t             *ufd;
+    uint64_t                  connection_id; // A unique identifier for the qd_connection_t. The underlying pn_connection already has one but it is long and clunky.
+    const char               *user_id; // A unique identifier for the user on the connection. This is currently populated  from the client ssl cert. See ssl_uid_format in server.h for more info
+    qd_deferred_call_list_t   deferred_calls;
+    sys_mutex_t              *deferred_call_lock;
 };
 
 DEQ_DECLARE(qd_connection_t, qd_connection_list_t);
@@ -173,4 +173,12 @@ ALLOC_DECLARE(qd_connector_t);
 ALLOC_DECLARE(qd_connection_t);
 ALLOC_DECLARE(qd_user_fd_t);
 
+/**
+ * Sets the user id on the connection.
+ * If the sasl mech is EXTERNAL, set the user_id on the connection as the concatenated list of fields specified in the uidFormat field of qdrouter.json
+ * If no uidFormat is specified, the user is set to the pn_transport_user
+ * @param conn Connection object
+ */
+void qd_connection_set_user(qd_connection_t *conn);
+
 #endif

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 75c7c4b..f4f35d9 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -76,6 +76,7 @@ foreach(py_test_module
     system_tests_qdmanage
     system_tests_qdstat
     system_tests_sasl_plain
+    system_tests_user_id
     system_tests_two_routers)
 
   add_test(${py_test_module} ${TEST_WRAP} -m unittest -v ${py_test_module})
@@ -92,7 +93,9 @@ list(APPEND SYSTEM_TEST_FILES
 
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-2/A-ssl.conf.in ${CMAKE_CURRENT_BINARY_DIR}/config-2/A-ssl.conf)
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-2/B-ssl.conf.in ${CMAKE_CURRENT_BINARY_DIR}/config-2/B-ssl.conf)
+
 file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/ssl_certs DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/displayname_files DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
 
 # following install() functions will be called only if you do a make "install"
 install(FILES ${SYSTEM_TEST_FILES}

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/displayname_files/profile_names1.json
----------------------------------------------------------------------
diff --git a/tests/displayname_files/profile_names1.json b/tests/displayname_files/profile_names1.json
new file mode 100644
index 0000000..21337db
--- /dev/null
+++ b/tests/displayname_files/profile_names1.json
@@ -0,0 +1,5 @@
+{
+    "14845961c5646ee0129536b3a9ef1eea0d8d2f26f8c3ed08ece4f8f3027ba9d5": "gmurthy",
+    "94745961c5646ee0129536b3acef1eea0d8d2f26f8c3ed08ece4f8f3027bcd47": "janedoe",
+    "94745961c5646ee0129536b3acef1eea0d8d2f26f8c3ed08ece4f8f3027bcd48": "johndoe"
+}

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/displayname_files/profile_names2.json
----------------------------------------------------------------------
diff --git a/tests/displayname_files/profile_names2.json b/tests/displayname_files/profile_names2.json
new file mode 100644
index 0000000..497543e
--- /dev/null
+++ b/tests/displayname_files/profile_names2.json
@@ -0,0 +1,5 @@
+{
+    "14845961c5646ee0129536b3a9ef1eea0d8d2f26f8c3ed08ece4f5546546": "jerry",
+    "94745961c5646ee0129536b3acef1eea0d8d2f26f8c353455233027bcd47": "elaine",
+    "94745961c5646ee0129536b3acef1eea0d8d2f26f8c3ed08ece3027bcd48": "george"
+}

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/management/qdrouter.py
----------------------------------------------------------------------
diff --git a/tests/management/qdrouter.py b/tests/management/qdrouter.py
index 5275827..1be6510 100644
--- a/tests/management/qdrouter.py
+++ b/tests/management/qdrouter.py
@@ -1,21 +1,21 @@
-##
-## Licensed to the Apache Software Foundation (ASF) under one
-## or more contributor license agreements.  See the NOTICE file
-## distributed with this work for additional information
-## regarding copyright ownership.  The ASF licenses this file
-## to you under the Apache License, Version 2.0 (the
-## "License"); you may not use this file except in compliance
-## with the License.  You may obtain a copy of the License at
-##
-##   http://www.apache.org/licenses/LICENSE-2.0
-##
-## Unless required by applicable law or agreed to in writing,
-## software distributed under the License is distributed on an
-## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-## KIND, either express or implied.  See the License for the
-## specific language governing permissions and limitations
-## under the License
-##
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License
+#
 
 #pylint: disable=wildcard-import,unused-wildcard-import,missing-docstring,too-many-public-methods
 
@@ -74,7 +74,6 @@ listener {
 }
 """
 
-
 class QdrouterTest(unittest.TestCase):
     """Tests for qpid_dispatch_internal.config.qdrouter"""
 
@@ -82,22 +81,11 @@ class QdrouterTest(unittest.TestCase):
         conf = Config()
         content = conf._parse(text.split("\n"))
         self.maxDiff = None
-        expect = [
-            [u"router", {u"mode":u"standalone"}],
-            [u"sslProfile", {u"name":u"test-profile", u"password":u"secret"}],
-            [u"listener", {u"name":u"l0", u"saslMechanisms":u"ANONYMOUS", u"sslProfile":u"test-profile"}],
-            [u"listener", {u"identity":u"l1", u"saslMechanisms":u"ANONYMOUS", u"port":u"1234"}],
-            [u"listener", {u"saslMechanisms":u"ANONYMOUS", u"port":u"4567"}]
-        ]
+        expect = [[u'router', {u'mode': u'standalone'}], [u'sslProfile', {u'password': u'secret', u'name': u'test-profile'}], [u'listener', {u'sslProfile': u'test-profile', u'name': u'l0', u'saslMechanisms': u'ANONYMOUS'}], [u'listener', {u'saslMechanisms': u'ANONYMOUS', u'identity': u'l1', u'port': u'1234'}], [u'listener', {u'saslMechanisms': u'ANONYMOUS', u'port': u'4567'}]]
         self.assertEqual(content, expect)
 
         content = conf._expand(content)
-        expect = [
-            [u"router", {u"mode":u"standalone"}],
-            [u"listener", {u"name":u"l0", u"saslMechanisms":u"ANONYMOUS", u"password":u"secret"}],
-            [u"listener", {u"identity":u"l1", u"saslMechanisms":u"ANONYMOUS", u"port":u"1234"}],
-            [u"listener", {u"saslMechanisms":u"ANONYMOUS", u"port":u"4567"}]
-        ]
+        expect = [[u'router', {u'mode': u'standalone'}], [u'listener', {u'password': u'secret', u'name': u'l0', u'sslProfileName': u'test-profile', u'saslMechanisms': u'ANONYMOUS'}], [u'listener', {u'port': u'1234', u'identity': u'l1', u'saslMechanisms': u'ANONYMOUS'}], [u'listener', {u'port': u'4567', u'saslMechanisms': u'ANONYMOUS'}]]
         self.assertEqual(content, expect)
 
         conf.load(text.split(u"\n"))

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/ssl_certs/bad-ca-certificate.pem
----------------------------------------------------------------------
diff --git a/tests/ssl_certs/bad-ca-certificate.pem b/tests/ssl_certs/bad-ca-certificate.pem
index 9e9cc8c..5064d04 100644
--- a/tests/ssl_certs/bad-ca-certificate.pem
+++ b/tests/ssl_certs/bad-ca-certificate.pem
@@ -1,12 +1,12 @@
 Bag Attributes
     friendlyName: bad-ca
-    localKeyID: 54 69 6D 65 20 31 34 32 34 32 39 30 35 36 31 33 36 37 
+    localKeyID: 54 69 6D 65 20 31 34 35 39 32 36 38 35 31 31 36 32 34 
 subject=/CN=Trusted.CA.com/O=Trust Me Inc.
 issuer=/CN=Trusted.CA.com/O=Trust Me Inc.
 -----BEGIN CERTIFICATE-----
-MIICwzCCAn+gAwIBAgIELtSXGTALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1
-c3RlZC5DQS5jb20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTUwMjE4MjAx
-NjAxWhgPMjI4ODEyMDIyMDE2MDFaMDExFzAVBgNVBAMTDlRydXN0ZWQuQ0EuY29t
+MIICwTCCAn+gAwIBAgIEWj5y+TALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1
+c3RlZC5DQS5jb20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTYwMzI5MTYy
+MTUxWhgPMjI5MDAxMTExNjIxNTFaMDExFzAVBgNVBAMTDlRydXN0ZWQuQ0EuY29t
 MRYwFAYDVQQKEw1UcnVzdCBNZSBJbmMuMIIBuDCCASwGByqGSM44BAEwggEfAoGB
 AP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6
 MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E
@@ -14,9 +14,9 @@ MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E
 ouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeO
 utRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/
 C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUA
-AoGBAK+JQLqbF+x5dDi9LZkMCW5e3PTLgUUwyu3Btq1b5VUFrDRtl6h5vm7QNIRW
-yTyfKxCNlSK1Hdy6qULyE6x3V3sFCAD+dTVxz8wHZk//APVEDVdMLu8I3QMuZgnX
-H7JoU/pfidXWKFZgAq5QolSwJdKDIwf9BAP0dh34yF2frNFjoyEwHzAdBgNVHQ4E
-FgQUFCScwiq/dz6vYznC+IMAymlYT1AwCwYHKoZIzjgEAwUAAzEAMC4CFQCL8ZhR
-LkxFS8phA/EO16PyYpvb7QIVAI7RaHqOK/2mXoQFRKXF1GkKRK/d
+AoGBAO2x7npgI1oKOEYdOYkXeYoXkMXw2Xch206mXVG50ToswpCLvNEwjzzLzDsU
+PLdZaAFyoO6xLrvuDCOZAW0uilXtWt22qGkhw6vS8xDizjm6+3qPc6dk7LNfeHx9
+gMxAhYMaslg55XPPVfzBVvtyO/8zafHXuKIh6k6X28/fDZkYoyEwHzAdBgNVHQ4E
+FgQUFIexDFPJZgleiFRJ71xEpYERcwIwCwYHKoZIzjgEAwUAAy8AMCwCFEDTnwaO
+/AHKtXLrKJcpEsnVe2FDAhRLBdVJ06l2lbk7iGJhQVemitpPQA==
 -----END CERTIFICATE-----

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/ssl_certs/bad-ca.pkcs12
----------------------------------------------------------------------
diff --git a/tests/ssl_certs/bad-ca.pkcs12 b/tests/ssl_certs/bad-ca.pkcs12
index 073fbce..ec7e063 100644
Binary files a/tests/ssl_certs/bad-ca.pkcs12 and b/tests/ssl_certs/bad-ca.pkcs12 differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/ssl_certs/ca-certificate.pem
----------------------------------------------------------------------
diff --git a/tests/ssl_certs/ca-certificate.pem b/tests/ssl_certs/ca-certificate.pem
index af00b3d..0bf774b 100644
--- a/tests/ssl_certs/ca-certificate.pem
+++ b/tests/ssl_certs/ca-certificate.pem
@@ -1,22 +1,22 @@
 Bag Attributes
     friendlyName: ca
-    localKeyID: 54 69 6D 65 20 31 34 32 34 32 39 30 35 36 31 31 35 38 
+    localKeyID: 54 69 6D 65 20 31 34 35 39 32 36 38 35 31 31 33 34 32 
 subject=/CN=Trusted.CA.com/O=Trust Me Inc.
 issuer=/CN=Trusted.CA.com/O=Trust Me Inc.
 -----BEGIN CERTIFICATE-----
-MIICwDCCAn6gAwIBAgIEFuNUXDALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1
-c3RlZC5DQS5jb20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTUwMjE4MjAx
-NjAxWhgPMjI4ODEyMDIyMDE2MDFaMDExFzAVBgNVBAMTDlRydXN0ZWQuQ0EuY29t
-MRYwFAYDVQQKEw1UcnVzdCBNZSBJbmMuMIIBtzCCASwGByqGSM44BAEwggEfAoGB
+MIICwTCCAn+gAwIBAgIEUNmkzzALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1
+c3RlZC5DQS5jb20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTYwMzI5MTYy
+MTUxWhgPMjI5MDAxMTExNjIxNTFaMDExFzAVBgNVBAMTDlRydXN0ZWQuQ0EuY29t
+MRYwFAYDVQQKEw1UcnVzdCBNZSBJbmMuMIIBuDCCASwGByqGSM44BAEwggEfAoGB
 AP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6
 MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E
 +4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmC
 ouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeO
 utRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/
-C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQA
-AoGAf+CpzXdAeZYqn55ZmWX45rib30CRI5VHJQgmkjg/FCG3/jjU7oG+N7xuVYun
-ktV4uaQBsB4TCRIw+ZW5fxDEO+QoUm/wZqFTb6puaNdQWDqyOoo5Mm18iHiHpF0o
-rFPllG1O9+V5AH4CmS7/G5qBGTiYksIWQHVwUOrZKgDApQajITAfMB0GA1UdDgQW
-BBTL/nFsubLlCB4LQ7ojixa6tluYZDALBgcqhkjOOAQDBQADLwAwLAIUFGKM43rh
-FEt8yIdTtjYx/jrX+EoCFHuOrw6hzJ8s2i2kN2SSOGbLMCK7
+C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUA
+AoGBANdKychVgwfcLcE4CL7a91cLsSIhJb9UXUtfX7d410q9YPJF6PTGHZhV1PrA
+YihpHs1YJwBfrLMqaLcxUDWtaqefA5Wuk02rd8cSXf6Pccb7+nFg4EKo+UY11t2Q
+KWaN9TDWoosg45xuLNFr8fnrtMCaIO7K/q2KptfT+/q3gObRoyEwHzAdBgNVHQ4E
+FgQU8n8a0i23sdfC/MOaGiupCuJkuQowCwYHKoZIzjgEAwUAAy8AMCwCFFW+PR//
+24wKzjiE8+6IkOPsZb8ZAhQhJEjPV9HG8ufk+wV3ifntOkwSNw==
 -----END CERTIFICATE-----

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/ssl_certs/ca.pkcs12
----------------------------------------------------------------------
diff --git a/tests/ssl_certs/ca.pkcs12 b/tests/ssl_certs/ca.pkcs12
index d2e4a6f..0a2eba0 100644
Binary files a/tests/ssl_certs/ca.pkcs12 and b/tests/ssl_certs/ca.pkcs12 differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/ssl_certs/client-certificate.pem
----------------------------------------------------------------------
diff --git a/tests/ssl_certs/client-certificate.pem b/tests/ssl_certs/client-certificate.pem
index d9c3ca8..e1b7ff3 100644
--- a/tests/ssl_certs/client-certificate.pem
+++ b/tests/ssl_certs/client-certificate.pem
@@ -1,15 +1,16 @@
 -----BEGIN CERTIFICATE-----
-MIIC1TCCApOgAwIBAgIEeN2OojALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1c3RlZC5DQS5j
-b20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTUwMjE4MjAxNjAyWhgPMjI4ODEyMDIyMDE2
-MDJaMCUxEjAQBgNVBAMTCTEyNy4wLjAuMTEPMA0GA1UEChMGQ2xpZW50MIIBtzCCASwGByqGSM44
-BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6
-MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1
-VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+Gghdab
-Pd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim
-4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1Ul
-ZAFMO/7PSSoDgYQAAoGAVkQ9SdE7AFFFnc3i+W1TZkbERnX2Hf6LuA8KzAZFssPanVA7nbD4H1D5
-LirNN3V2txvnqc1l8w1alDDX7e2XfZGyzAeWymmQpq0bzkp26nnXwOadcEsLbNgRgopu6PcprCn7
-IXtRzJEcTErcl6m0mHW4MMZf5nLv9eNorOV4+6ijQjBAMB8GA1UdIwQYMBaAFMv+cWy5suUIHgtD
-uiOLFrq2W5hkMB0GA1UdDgQWBBTf5tXr2SQuzjbsziPw26w1iUZLVzALBgcqhkjOOAQDBQADLwAw
-LAIUTP69DQUv1oSofzTrqGhf2rOEafICFCkn3xyd7y/JEla5R+4XzmHZaCud
+MIIDEDCCAs6gAwIBAgIERkVU1DALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1c3RlZC5DQS5j
+b20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTYwMzI5MTYyMTUzWhgPMjI5MDAxMTExNjIx
+NTNaMF8xEjAQBgNVBAMTCTEyNy4wLjAuMTEPMA0GA1UEChMGQ2xpZW50MQwwCgYDVQQLEwNEZXYx
+EDAOBgNVBAcTB1JhbGVpZ2gxCzAJBgNVBAgTAk5DMQswCQYDVQQGEwJVUzCCAbgwggEsBgcqhkjO
+OAQBMIIBHwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1
+ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMC
+NVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXW
+mz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozI
+puE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtV
+JWQBTDv+z0kqA4GFAAKBgQDLYt5hOqaGIBxDo9gVQHdmHqTFpoXRezDVQlv+wlHFRBj8n/N/B1qb
+KkgSEePyu6xGTlR4WGB3QLKYyRXySlKaA973m0/QLNjBv/erwLirfRDIEZ34HTIidlRgEDpHzalM
+ZvO2KWb91PePjj9+UUPmNp4fC7OwvGbH053glNLavaNCMEAwHwYDVR0jBBgwFoAU8n8a0i23sdfC
+/MOaGiupCuJkuQowHQYDVR0OBBYEFNgKh0K+EJuwWHfhD7NZTdqhaIioMAsGByqGSM44BAMFAAMv
+ADAsAhR0kxE4dB1CzdPSERQTYmzmZgNStQIUPVhNPUqCoqvjaolpdzXcdk9tPJ4=
 -----END CERTIFICATE-----

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/ssl_certs/client-private-key.pem
----------------------------------------------------------------------
diff --git a/tests/ssl_certs/client-private-key.pem b/tests/ssl_certs/client-private-key.pem
index 6cfae0c..77103f9 100644
--- a/tests/ssl_certs/client-private-key.pem
+++ b/tests/ssl_certs/client-private-key.pem
@@ -1,15 +1,15 @@
 Bag Attributes
     friendlyName: client-certificate
-    localKeyID: 54 69 6D 65 20 31 34 32 34 32 39 30 35 36 32 32 31 34 
+    localKeyID: 54 69 6D 65 20 31 34 35 39 32 36 38 35 31 32 37 35 37 
 Key Attributes: <No Attributes>
 -----BEGIN ENCRYPTED PRIVATE KEY-----
-MIIBljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIQjGMD5Xq/WECAggA
-MBQGCCqGSIb3DQMHBAh73tcUMDKzhgSCAVCFivkeNt46vAX2u1fNQyM8ogQoZIez
-k2op33WH/XXyFLpDIa98+6uCj0yPo1IwcTw/LmL34ExZ17lW9MD/52t7ZVb9Qi+b
-bPZBHJfGw0J+EycEceFoaCzdXwUICaH6jB26ilJzGWZyJyQlydofGOz8SxxbPdt9
-Rmnb+7WzEjl99T1+nkuMEcfGixZJZtCAB3XwWcG6TuerhuAkpfrXoT6pfwEtT7ZE
-o9zfwpd2OMMB5hHfJ3IOvFW8hpvKZ4L/AtnnOd+G2VIS+Ga2BXQZIwAzw1nvKdvk
-JPw2bdgHnNE6MlQR4RNdL9RcxRSBlLjmQ6PaQyIp6CD+W1eUqDRL+DxL0o1VOWQl
-Y7XhklePvrJWaervroBEtCkCYYmZ8vurWNnk97f5gnY66dwI3i2f/t2X8F4Fdjol
-xvyuVJENU/mQESESe8OFcVG50iSfVxtd5I8=
+MIIBljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIQOxA9s2N+1kCAggA
+MBQGCCqGSIb3DQMHBAjvrDgMFHHotQSCAVAmcDw8AX52Bd58sW5fUMwbBkgRwkar
++VTIcyS4CjHmYiWHyXjbbAb/HXuFaOI+nPl1U+SVr9Ji/e1OmRQctPeG+kCJBPOr
+Fy2Dd7ckLzqFY1zYHEpT6CYRmn+wOqszQZ6qYuaWYDJreCHaA3eVFY6WYO3PTCZG
+xqDmWqGVJAShQlUf8OvbpApYa+pAHM+OuU8wTOCHUxrIrvRSwNxW9ju3x3jMABOD
+i6HLMMeUkSJP3lFgiJX7rciVkVIOEYR2pCJfrVVDMlrKzOaDlmzJeWgnvCVbgu7T
+t0HJz7Shx5fauLDzlTcPSmqzyseWkxfNlWVls4ATdu7ufLW4BKgparCo8/Zem9z8
+iZYJLdEWy5f37qQaow9xcf5BAw9bdWHqr2oC1T+YBESNcxqo84d6ULCVlbC0JkyN
+QY2M7IuLhkqSzmPsZgcK2Tv+YXQ7SRQG6MY=
 -----END ENCRYPTED PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/ssl_certs/client-request.pem
----------------------------------------------------------------------
diff --git a/tests/ssl_certs/client-request.pem b/tests/ssl_certs/client-request.pem
index 9597549..025a7e1 100644
--- a/tests/ssl_certs/client-request.pem
+++ b/tests/ssl_certs/client-request.pem
@@ -1,13 +1,14 @@
 -----BEGIN NEW CERTIFICATE REQUEST-----
-MIICWjCCAhcCAQAwJTESMBAGA1UEAxMJMTI3LjAuMC4xMQ8wDQYDVQQKEwZDbGllbnQwggG3MIIB
-LAYHKoZIzjgEATCCAR8CgYEA/X9TgR11EilS30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZ
-PY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7
-g/bTxR7DAjVUE1oWkTL2dfOuK2HXKu/yIgMZndFIAccCFQCXYFCPFSMLzLKSuYKi64QL8Fgc9QKB
-gQD34aCF1ps93su8q1w2uFe5eZSvu/o66oL5V0wLPQeCZ1FZV4661FlP5nEHEIGAtEkWcSPoTCgW
-E7fPCTKMyKbhPBZ6i1R8jSjgo64eK7OmdZFuo38L+iE1YvH7YnoBJDvMpPG+qFGQiaiD3+Fa5Z8G
-kotmXoB7VSVkAUw7/s9JKgOBhAACgYBWRD1J0TsAUUWdzeL5bVNmRsRGdfYd/ou4DwrMBkWyw9qd
-UDudsPgfUPkuKs03dXa3G+epzWXzDVqUMNft7Zd9kbLMB5bKaZCmrRvOSnbqedfA5p1wSwts2BGC
-im7o9ymsKfshe1HMkRxMStyXqbSYdbgwxl/mcu/142is5Xj7qKAwMC4GCSqGSIb3DQEJDjEhMB8w
-HQYDVR0OBBYEFN/m1evZJC7ONuzOI/DbrDWJRktXMAsGByqGSM44BAMFAAMwADAtAhUAgZrGKu/I
-eeeUIKHRRJj5VVLW9usCFEwzXpaAouip4wMRrGhIxtbqL09K
+MIIClDCCAlICAQAwXzESMBAGA1UEAxMJMTI3LjAuMC4xMQ8wDQYDVQQKEwZDbGllbnQxDDAKBgNV
+BAsTA0RldjEQMA4GA1UEBxMHUmFsZWlnaDELMAkGA1UECBMCTkMxCzAJBgNVBAYTAlVTMIIBuDCC
+ASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7
+WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E
++4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUC
+gYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6Ewo
+FhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWf
+BpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAMti3mE6poYgHEOj2BVAd2YepMWmhdF7MNVCW/7CUcVE
+GPyf838HWpsqSBIR4/K7rEZOVHhYYHdAspjJFfJKUpoD3vebT9As2MG/96vAuKt9EMgRnfgdMiJ2
+VGAQOkfNqUxm87YpZv3U94+OP35RQ+Y2nh8Ls7C8ZsfTneCU0tq9oDAwLgYJKoZIhvcNAQkOMSEw
+HzAdBgNVHQ4EFgQU2AqHQr4Qm7BYd+EPs1lN2qFoiKgwCwYHKoZIzjgEAwUAAy8AMCwCFHmRXqL8
+xEzJPZX2cbvSKyGaBErNAhRFxRMO1VKe1K1i8PMCtYgwf/cGgQ==
 -----END NEW CERTIFICATE REQUEST-----

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/ssl_certs/client.pkcs12
----------------------------------------------------------------------
diff --git a/tests/ssl_certs/client.pkcs12 b/tests/ssl_certs/client.pkcs12
index a832e99..6405c53 100644
Binary files a/tests/ssl_certs/client.pkcs12 and b/tests/ssl_certs/client.pkcs12 differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/ssl_certs/gencerts.sh
----------------------------------------------------------------------
diff --git a/tests/ssl_certs/gencerts.sh b/tests/ssl_certs/gencerts.sh
index 14ab550..e242419 100755
--- a/tests/ssl_certs/gencerts.sh
+++ b/tests/ssl_certs/gencerts.sh
@@ -1,5 +1,7 @@
 #!/bin/bash -ex
 
+rm -f *.pem *.pkcs12 *.p12
+
 export SERVER=A1.Good.Server.domain.com
 export CLIENT=127.0.0.1
 
@@ -14,7 +16,19 @@ keytool -storetype pkcs12 -keystore server.pkcs12 -storepass server-password -al
 keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -gencert -rfc -validity 99999 -infile server-request.pem -outfile server-certificate.pem
 openssl pkcs12 -nocerts -passin pass:server-password -in server.pkcs12 -passout pass:server-password -out server-private-key.pem
 
-keytool -storetype pkcs12 -keystore client.pkcs12 -storepass client-password -alias client-certificate -keypass client-password -genkey  -dname "O=Client,CN=$CLIENT" -validity 99999
+# Generate a PKCS12 key which will be used for client side cert
+keytool -storetype pkcs12 -keystore client.pkcs12 -storepass client-password -alias client-certificate -keypass client-password -genkey  -dname "C=US,ST=NC,L=Raleigh,OU=Dev,O=Client,CN=$CLIENT" -validity 99999
+# Create a certificate request file
 keytool -storetype pkcs12 -keystore client.pkcs12 -storepass client-password -alias client-certificate -keypass client-password -certreq -file client-request.pem
+# Create a client certificate
 keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -gencert -rfc -validity 99999 -infile client-request.pem -outfile client-certificate.pem
+# Create a client private key file.
 openssl pkcs12 -nocerts -passin pass:client-password -in client.pkcs12 -passout pass:client-password -out client-private-key.pem
+
+
+##########################################################################################################################
+
+#keytool -storetype pkcs12 -keystore client1.pkcs12 -storepass client-password -alias client-certificate1 -keypass client-password -genkey  -dname "O=Client,CN=$CLIENT" -validity 99999
+#keytool -storetype pkcs12 -keystore client1.pkcs12 -storepass client-password -alias client-certificate1 -keypass client-password -certreq -file client-request1.pem
+#keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -gencert -rfc -validity 99999 -infile client-request1.pem -outfile client-certificate1.pem
+#openssl pkcs12 -nocerts -passin pass:client-password -in client1.pkcs12 -passout pass:client-password -out client-private-key1.pem

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/ssl_certs/server-certificate.pem
----------------------------------------------------------------------
diff --git a/tests/ssl_certs/server-certificate.pem b/tests/ssl_certs/server-certificate.pem
index 495d18a..5a8bf81 100644
--- a/tests/ssl_certs/server-certificate.pem
+++ b/tests/ssl_certs/server-certificate.pem
@@ -1,16 +1,16 @@
 -----BEGIN CERTIFICATE-----
-MIIC5jCCAqSgAwIBAgIEVVAmOTALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1c3RlZC5DQS5j
-b20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTUwMjE4MjAxNjAyWhgPMjI4ODEyMDIyMDE2
-MDJaMDUxIjAgBgNVBAMTGUExLkdvb2QuU2VydmVyLmRvbWFpbi5jb20xDzANBgNVBAoTBlNlcnZl
-cjCCAbgwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEm
-aUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX
-58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLr
-hAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0
-SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJ
-qIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqA4GFAAKBgQCc1Yj1CsxEYyO5JjUs/FB2KNWAdYH3VJPN
-IFb9TJ/ts6OsroChGqPULZIbp5YnC5bH+3sVD4khXGZTuW8pdBxENNlP2sEKfO/xDqLLgZhvYpsS
-iLWiYQ8bShJOC/hOui2mw3g6V2DXQXWbjxLNrMIyWPRBkp2z+O6ivEq+Qr0Yq6NCMEAwHwYDVR0j
-BBgwFoAUy/5xbLmy5QgeC0O6I4sWurZbmGQwHQYDVR0OBBYEFOSGQHg1K8opwYxpYoo/FDOmmOyx
-MAsGByqGSM44BAMFAAMvADAsAhRoUUpTu3CLYTk6r4M0YAk78gVu8wIUCSqprLCmxNkn93/GHiQJ
-uCBF3bI=
+MIIC5jCCAqOgAwIBAgIEQsGiKTALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1c3RlZC5DQS5j
+b20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTYwMzI5MTYyMTUyWhgPMjI5MDAxMTExNjIx
+NTJaMDUxIjAgBgNVBAMTGUExLkdvb2QuU2VydmVyLmRvbWFpbi5jb20xDzANBgNVBAoTBlNlcnZl
+cjCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEm
+aUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX
+58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLr
+hAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0
+SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJ
+qIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqA4GEAAKBgDmrk0+Ei5+cGfjEXflZCFiq3SnlKlBgdsmX
+mmug1WABhdgkshSvTjPOxKQ/snvxlndQoA3qHq/qLWMKWWJgLkspKEK9AwII5X9GidIhpO8Qc37f
+vwB1mbq79O7QpM7L9Ij640TWZCQZ+2rbze2Uyvh3yggcyPrKlwrTo73N0jU1o0IwQDAfBgNVHSME
+GDAWgBTyfxrSLbex18L8w5oaK6kK4mS5CjAdBgNVHQ4EFgQUrlNxC4cY402bx5dRIcEM8wj6d5Qw
+CwYHKoZIzjgEAwUAAzAAMC0CFQCRJJtNHz/VRX4dDe32QBeUYsIhlwIUFcFlTvavo6JXOJGgKTKw
+1UbboFg=
 -----END CERTIFICATE-----

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/ssl_certs/server-private-key.pem
----------------------------------------------------------------------
diff --git a/tests/ssl_certs/server-private-key.pem b/tests/ssl_certs/server-private-key.pem
index db10d89..761df08 100644
--- a/tests/ssl_certs/server-private-key.pem
+++ b/tests/ssl_certs/server-private-key.pem
@@ -1,15 +1,15 @@
 Bag Attributes
     friendlyName: server-certificate
-    localKeyID: 54 69 6D 65 20 31 34 32 34 32 39 30 35 36 31 35 38 34 
+    localKeyID: 54 69 6D 65 20 31 34 35 39 32 36 38 35 31 31 39 30 31 
 Key Attributes: <No Attributes>
 -----BEGIN ENCRYPTED PRIVATE KEY-----
-MIIBnjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIEw01j8nUhqoCAggA
-MBQGCCqGSIb3DQMHBAiznulHT3IkUwSCAVi3LpaVmwYUlU7PlBVBc0NDkvmeYEJT
-xBRa0FkJs7mIk7eXIJU898gcZA88WTyNlPMmy3gxje6c8tp6U1xlHBZKnMnMHA9G
-KfHPkkacsZe8zGhI+3jwd1myyWuVXlZL5Su6DEXnCh4y1PVSD4Jl0z5ExbgGQkMV
-FNcZQc4XeJI8dlXpW7on9fX8z7deWiHyS3Sqvb/RRCTtIqfFl6VkwpEhs+TNxGDo
-SnFlno1/PDjKbhnq6o2pUZRGU31/M6QFCW0VXs+eksNBXo9oyZUa4CnaggMGdcBx
-EcfRtWx0pM+KJx1jLRp2X72NR/NIZ3H1jL4lVrbwOqlULKfZMMFPNzR61AtlWjWO
-laTUo7PqOv7VB60vtwZkxmJjj+JwBsm/+WQMzZS6A4abBCQKz6lgJToTb72mNvln
-k0ZsFLtZYCK3i0++vQ6gAriE4SYKqvxIaLK0TD/AY2s04A==
+MIIBljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI7x2lcMshKzgCAggA
+MBQGCCqGSIb3DQMHBAhBsRvnJv3zZwSCAVApXO6v8VBDKtIObvKjlGhuAqNh1njI
+YkvWzsDJvOPLGvwduGak+wDM/Y/3uVfa7ZReodhOCiCIO9O9IMxr36Yisf4kqqQK
+ENZYecQ1/w2krA0pQY9d8wCVTp1dEvit4jvZV8qaKyqOcpq7mInOmnfuh7QLzO5j
+/dVgevC7g4Ant+bXhDInNZAp9CK9TuSupqChytRG12M+5nmX6/TSoyj5dLXnfA3c
+n0WI5rYp6Q5Xnn6D8WHQ95z17c6HgIuemgTY4wiY8fOfW0PGP0VtJvMQ9Gk/3eDN
+zGo/XqTDpkSqD1gBvMporxjL+tn4cxP+gdArXmKHQ9Xsi3oE+NBTkYEM0PpB6Dni
+a5U/7ouYw7soKi/F0Xnw4gxm6NwRzLhDBlAWr2X+744kNpxFwfp4esikQIts1n70
+oipv5Z7V/cFmtnreB4c0AYRvKTCPd/Vg4Vs=
 -----END ENCRYPTED PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/ssl_certs/server-request.pem
----------------------------------------------------------------------
diff --git a/tests/ssl_certs/server-request.pem b/tests/ssl_certs/server-request.pem
index ed84b3a..6ba388f 100644
--- a/tests/ssl_certs/server-request.pem
+++ b/tests/ssl_certs/server-request.pem
@@ -1,13 +1,13 @@
 -----BEGIN NEW CERTIFICATE REQUEST-----
-MIICazCCAigCAQAwNTEiMCAGA1UEAxMZQTEuR29vZC5TZXJ2ZXIuZG9tYWluLmNvbTEPMA0GA1UE
-ChMGU2VydmVyMIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9E
-AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up
-1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUj
-C8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZ
-T+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7
-zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAJzViPUKzERjI7kmNSz8UHYo
-1YB1gfdUk80gVv1Mn+2zo6yugKEao9QtkhunlicLlsf7exUPiSFcZlO5byl0HEQ02U/awQp87/EO
-osuBmG9imxKItaJhDxtKEk4L+E66LabDeDpXYNdBdZuPEs2swjJY9EGSnbP47qK8Sr5CvRiroDAw
-LgYJKoZIhvcNAQkOMSEwHzAdBgNVHQ4EFgQU5IZAeDUryinBjGliij8UM6aY7LEwCwYHKoZIzjgE
-AwUAAzAAMC0CFQCAJ5LLNjsgzKHEK7B1ITo3g+33BgIUV4pXlouKfzbBX/TiYFaSXaiPvbs=
+MIICajCCAicCAQAwNTEiMCAGA1UEAxMZQTEuR29vZC5TZXJ2ZXIuZG9tYWluLmNvbTEPMA0GA1UE
+ChMGU2VydmVyMIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9E
+AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up
+1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUj
+C8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZ
+T+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7
+zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAOauTT4SLn5wZ+MRd+VkIWKrd
+KeUqUGB2yZeaa6DVYAGF2CSyFK9OM87EpD+ye/GWd1CgDeoer+otYwpZYmAuSykoQr0DAgjlf0aJ
+0iGk7xBzft+/AHWZurv07tCkzsv0iPrjRNZkJBn7atvN7ZTK+HfKCBzI+sqXCtOjvc3SNTWgMDAu
+BgkqhkiG9w0BCQ4xITAfMB0GA1UdDgQWBBSuU3ELhxjjTZvHl1EhwQzzCPp3lDALBgcqhkjOOAQD
+BQADMAAwLQIUcpYmgcElp/QzRLNmTBvoXIiOTAkCFQCL1UPLa2Q2mxNef8x3UhR9j/nKkQ==
 -----END NEW CERTIFICATE REQUEST-----

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/ssl_certs/server.pkcs12
----------------------------------------------------------------------
diff --git a/tests/ssl_certs/server.pkcs12 b/tests/ssl_certs/server.pkcs12
index 3f67f52..92ee10c 100644
Binary files a/tests/ssl_certs/server.pkcs12 and b/tests/ssl_certs/server.pkcs12 differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/system_tests_two_routers.py
----------------------------------------------------------------------
diff --git a/tests/system_tests_two_routers.py b/tests/system_tests_two_routers.py
index aceb1a4..f7938e3 100644
--- a/tests/system_tests_two_routers.py
+++ b/tests/system_tests_two_routers.py
@@ -19,7 +19,7 @@
 
 import unittest, os
 from proton import Message, PENDING, ACCEPTED, REJECTED, RELEASED, SSLDomain, SSLUnavailable, Timeout
-from system_test import TestCase, Qdrouterd, main_module
+from system_test import TestCase, Qdrouterd, main_module, DIR
 
 # PROTON-828:
 try:
@@ -29,17 +29,19 @@ except ImportError:
 
 
 class RouterTest(TestCase):
+
+    @staticmethod
+    def ssl_config(client_server, connection):
+        return [] # Over-ridden by RouterTestSsl
+
     @classmethod
     def setUpClass(cls):
         """Start a router and a messenger"""
         super(RouterTest, cls).setUpClass()
 
-        def ssl_config(client_server, connection): 
-            return [] # Over-ridden by RouterTestSsl
-
         def router(name, client_server, connection):
             
-            config = ssl_config(client_server, connection) + [
+            config = cls.ssl_config(client_server, connection) + [
                 ('container', {'workerThreads': 4, 'containerName': 'Qpid.Dispatch.Router.%s'%name}),
                 ('router', {'mode': 'interior', 'routerId': 'QDR.%s'%name}),
                 
@@ -62,6 +64,7 @@ class RouterTest(TestCase):
             ]
             
             config = Qdrouterd.Config(config)
+
             cls.routers.append(cls.tester.qdrouterd(name, config, wait=True))
 
         cls.routers = []
@@ -995,18 +998,24 @@ class RouterTest(TestCase):
 
 try:
     SSLDomain(SSLDomain.MODE_CLIENT)
+
     class RouterTestSsl(RouterTest):
-        def ssl_config(self, client_server, connection):
-            connection[1]['ssl-profile'] = 'ssl-profile-name'
-            def ssl_file(name):
-                return os.path.join(system_test.DIR, 'config-2', name)
-            return [
-                ('ssl-profile', {
-                    'name': 'ssl-profile-name',
-                    'cert-db': ssl_file('ca-certificate.pem'),
-                    'cert-file': ssl_file(client_server+'-certificate.pem'),
-                    'key-file': ssl_file(client_server+'-private-key.pem'),
-                    'password': client_server+'-password'})]
+
+        @staticmethod
+        def ssl_config(client_server, connection):
+                connection[1]['ssl-profile'] = 'ssl-profile-name'
+
+                def ssl_file(name):
+                    return os.path.join(DIR, 'ssl_certs', name)
+                return [
+                    ('ssl-profile', {
+                        'name': 'ssl-profile-name',
+                        'cert-db': ssl_file('ca-certificate.pem'),
+                        'cert-file': ssl_file(client_server+'-certificate.pem'),
+                        'key-file': ssl_file(client_server+'-private-key.pem'),
+                        'password': client_server+'-password'})]
+
+
 
 except SSLUnavailable:
     class RouterTestSsl(TestCase):

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/56e56ce2/tests/system_tests_user_id.py
----------------------------------------------------------------------
diff --git a/tests/system_tests_user_id.py b/tests/system_tests_user_id.py
new file mode 100644
index 0000000..c7464a1
--- /dev/null
+++ b/tests/system_tests_user_id.py
@@ -0,0 +1,340 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License
+#
+
+
+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
+
+class QdSSLUseridTest(TestCase):
+
+    @staticmethod
+    def ssl_file(name):
+        return os.path.join(DIR, 'ssl_certs', name)
+
+    @classmethod
+    def setUpClass(cls):
+        super(QdSSLUseridTest, cls).setUpClass()
+
+        ssl_profile1_json = os.path.join(DIR, 'displayname_files', 'profile_names1.json')
+        ssl_profile2_json = os.path.join(DIR, 'displayname_files', 'profile_names2.json')
+
+        port = cls.tester.get_port()
+
+        config = Qdrouterd.Config([
+
+            # sha1
+            ('sslProfile', {'name': 'server-ssl1',
+                             'cert-db': cls.ssl_file('ca-certificate.pem'),
+                             'cert-file': cls.ssl_file('server-certificate.pem'),
+                             'key-file': cls.ssl_file('server-private-key.pem'),
+                             'uidFormat': '1',
+                             'password': 'server-password'}),
+
+            # sha256
+            ('sslProfile', {'name': 'server-ssl2',
+                             'cert-db': cls.ssl_file('ca-certificate.pem'),
+                             'cert-file': cls.ssl_file('server-certificate.pem'),
+                             'key-file': cls.ssl_file('server-private-key.pem'),
+                             'uidFormat': '2',
+                             'password': 'server-password'}),
+
+            # sha512
+            ('sslProfile', {'name': 'server-ssl3',
+                             'cert-db': cls.ssl_file('ca-certificate.pem'),
+                             'cert-file': cls.ssl_file('server-certificate.pem'),
+                             'key-file': cls.ssl_file('server-private-key.pem'),
+                             'uidFormat': '5',
+                             'password': 'server-password'}),
+
+            # sha256 combination
+            ('sslProfile', {'name': 'server-ssl4',
+                             'cert-db': cls.ssl_file('ca-certificate.pem'),
+                             'cert-file': cls.ssl_file('server-certificate.pem'),
+                             'key-file': cls.ssl_file('server-private-key.pem'),
+                             'uidFormat': '2noucs',
+                             'password': 'server-password'}),
+
+            # sha1 combination
+            ('sslProfile', {'name': 'server-ssl5',
+                             'cert-db': cls.ssl_file('ca-certificate.pem'),
+                             'cert-file': cls.ssl_file('server-certificate.pem'),
+                             'key-file': cls.ssl_file('server-private-key.pem'),
+                             'uidFormat': '1cs',
+                             'password': 'server-password'}),
+
+            # sha512 combination
+            ('sslProfile', {'name': 'server-ssl6',
+                             'cert-db': cls.ssl_file('ca-certificate.pem'),
+                             'cert-file': cls.ssl_file('server-certificate.pem'),
+                             'key-file': cls.ssl_file('server-private-key.pem'),
+                             'uidFormat': 'cs5',
+                             'password': 'server-password'}),
+
+            # no fingerprint field
+            ('sslProfile', {'name': 'server-ssl7',
+                             'cert-db': cls.ssl_file('ca-certificate.pem'),
+                             'cert-file': cls.ssl_file('server-certificate.pem'),
+                             'key-file': cls.ssl_file('server-private-key.pem'),
+                             'uidFormat': 'nsuco',
+                             'password': 'server-password'}),
+
+            # no fingerprint field variation
+            ('sslProfile', {'name': 'server-ssl8',
+                             'cert-db': cls.ssl_file('ca-certificate.pem'),
+                             'cert-file': cls.ssl_file('server-certificate.pem'),
+                             'key-file': cls.ssl_file('server-private-key.pem'),
+                             'uidFormat': 'scounl',
+                             'password': 'server-password'}),
+
+            #no uidFormat
+            ('sslProfile', {'name': 'server-ssl9',
+                             'cert-db': cls.ssl_file('ca-certificate.pem'),
+                             'cert-file': cls.ssl_file('server-certificate.pem'),
+                             'key-file': cls.ssl_file('server-private-key.pem'),
+                             'password': 'server-password'}),
+
+            # one component of uidFormat is invalid (x), the unrecognized component will be ignored,
+            # this will be treated like 'uidFormat': '1'
+            ('sslProfile', {'name': 'server-ssl10',
+                             'cert-db': cls.ssl_file('ca-certificate.pem'),
+                             'cert-file': cls.ssl_file('server-certificate.pem'),
+                             'key-file': cls.ssl_file('server-private-key.pem'),
+                             'uidFormat': '1x',
+                             'displayNameFile': ssl_profile2_json,
+                             'password': 'server-password'}),
+
+            # All components in the uidFormat are unrecognized, pn_get_transport_user will be returned
+            ('sslProfile', {'name': 'server-ssl11',
+                             'cert-db': cls.ssl_file('ca-certificate.pem'),
+                             'cert-file': cls.ssl_file('server-certificate.pem'),
+                             'key-file': cls.ssl_file('server-private-key.pem'),
+                             'uidFormat': 'abxd',
+                             'password': 'server-password'}),
+
+            ('sslProfile', {'name': 'server-ssl12',
+                             'cert-db': cls.ssl_file('ca-certificate.pem'),
+                             'cert-file': cls.ssl_file('server-certificate.pem'),
+                             'key-file': 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'}),
+
+            ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl2', 'authenticatePeer': 'yes',
+                          'requireSsl': 'yes', 'saslMechanisms': 'EXTERNAL'}),
+
+            ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl3', 'authenticatePeer': 'yes',
+                          'requireSsl': 'yes', 'saslMechanisms': 'EXTERNAL'}),
+
+            ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl4', 'authenticatePeer': 'yes',
+                          'requireSsl': 'yes', 'saslMechanisms': 'EXTERNAL'}),
+
+            ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl5', 'authenticatePeer': 'yes',
+                          'requireSsl': 'yes', 'saslMechanisms': 'EXTERNAL'}),
+
+            ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl6', 'authenticatePeer': 'yes',
+                          'requireSsl': 'yes', 'saslMechanisms': 'EXTERNAL'}),
+
+            ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl7', 'authenticatePeer': 'yes',
+                          'requireSsl': 'yes', 'saslMechanisms': 'EXTERNAL'}),
+
+            ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl8', 'authenticatePeer': 'yes',
+                          'requireSsl': 'yes', 'saslMechanisms': 'EXTERNAL'}),
+
+            ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl9', 'authenticatePeer': 'yes',
+                          'requireSsl': 'yes', 'saslMechanisms': 'EXTERNAL'}),
+
+            ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl10', 'authenticatePeer': 'yes',
+                          'requireSsl': 'yes', 'saslMechanisms': 'EXTERNAL'}),
+
+            ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl11', 'authenticatePeer': 'yes',
+                          'requireSsl': 'yes', 'saslMechanisms': 'EXTERNAL'}),
+
+            # peer is not being authenticated here. the user must "anonymous" which is what pn_transport_get_user
+            # returns
+            ('listener', {'port': cls.tester.get_port(), 'sslProfile': 'server-ssl12', 'authenticatePeer': 'no',
+                          'requireSsl': 'yes', 'saslMechanisms': 'ANONYMOUS'}),
+
+            ('listener', {'port': cls.tester.get_port(), 'authenticatePeer': 'no'})
+
+        ])
+
+        cls.router = cls.tester.qdrouterd('ssl-test-router', config, wait=True)
+
+    def address(self, index):
+        return self.router.addresses[index]
+
+    def create_ssl_domain(self, ssl_options_dict, mode=SSLDomain.MODE_CLIENT):
+        """Return proton.SSLDomain from command line options or None if no SSL options specified.
+            @param opts: Parsed optoins including connection_options()
+        """
+        certificate, key, trustfile, password = ssl_options_dict.get('ssl-certificate'), \
+                                                ssl_options_dict.get('ssl-key'), \
+                                                ssl_options_dict.get('ssl-trustfile'), \
+                                                ssl_options_dict.get('ssl-password')
+
+        if not (certificate or trustfile):
+            return None
+        domain = SSLDomain(mode)
+        if trustfile:
+            domain.set_trusted_ca_db(str(trustfile))
+            domain.set_peer_authentication(SSLDomain.VERIFY_PEER, str(trustfile))
+        if certificate:
+            domain.set_credentials(str(certificate), str(key), str(password))
+
+        return domain
+
+    def test_ssl_user_id(self):
+        ssl_opts = dict()
+        ssl_opts['ssl-trustfile'] = self.ssl_file('ca-certificate.pem')
+        ssl_opts['ssl-certificate'] = self.ssl_file('client-certificate.pem')
+        ssl_opts['ssl-key'] = self.ssl_file('client-private-key.pem')
+        ssl_opts['ssl-password'] = 'client-password'
+
+        # create the SSL domain object
+        domain = self.create_ssl_domain(ssl_opts)
+
+        addr = self.address(0).replace("amqp", "amqps")
+
+        node = Node.connect(addr, ssl_domain=domain)
+        user_id = node.query(type='org.apache.qpid.dispatch.connection', attribute_names=['user']).results[0][0]
+        self.assertEqual("60f5dbd7ed14a5ea243785e81745ac8463494298",
+                         user_id)
+
+        addr = self.address(1).replace("amqp", "amqps")
+        node = Node.connect(addr, ssl_domain=domain)
+        self.assertEqual("7c87f0c974f9e1aa5cb98f13fae9675625f240c98034b888753140da28094879",
+                         node.query(type='org.apache.qpid.dispatch.connection', attribute_names=['user']).results[1][0])
+
+        addr = self.address(2).replace("amqp", "amqps")
+        node = Node.connect(addr, ssl_domain=domain)
+        self.assertEqual("82244216b6d02ffdfb886c8da3c803e0f7a7b330a7b665dccabd30bd25d0f35e2a4fff5f0a2a01d56eb7dbae085c108e71a32b84bab16c9ec243a1f6d014900d",
+                         node.query(type='org.apache.qpid.dispatch.connection', attribute_names=['user']).results[2][0])
+
+        addr = self.address(3).replace("amqp", "amqps")
+        node = Node.connect(addr, ssl_domain=domain)
+        self.assertEqual("7c87f0c974f9e1aa5cb98f13fae9675625f240c98034b888753140da28094879;127.0.0.1;Client;Dev;US;NC",
+        node.query(type='org.apache.qpid.dispatch.connection', attribute_names=['user']).results[3][0])
+
+        addr = self.address(4).replace("amqp", "amqps")
+        node = Node.connect(addr, ssl_domain=domain)
+        self.assertEqual("60f5dbd7ed14a5ea243785e81745ac8463494298;US;NC",
+        node.query(type='org.apache.qpid.dispatch.connection', attribute_names=['user']).results[4][0])
+
+        addr = self.address(5).replace("amqp", "amqps")
+        node = Node.connect(addr, ssl_domain=domain)
+        self.assertEqual("US;NC;82244216b6d02ffdfb886c8da3c803e0f7a7b330a7b665dccabd30bd25d0f35e2a4fff5f0a2a01d56eb7dbae085c108e71a32b84bab16c9ec243a1f6d014900d",
+        node.query(type='org.apache.qpid.dispatch.connection', attribute_names=['user']).results[5][0])
+
+        addr = self.address(6).replace("amqp", "amqps")
+        node = Node.connect(addr, ssl_domain=domain)
+        self.assertEqual("127.0.0.1;NC;Dev;US;Client",
+        node.query(type='org.apache.qpid.dispatch.connection', attribute_names=['user']).results[6][0])
+
+        addr = self.address(7).replace("amqp", "amqps")
+        node = Node.connect(addr, ssl_domain=domain)
+        self.assertEqual("NC;US;Client;Dev;127.0.0.1;Raleigh",
+        node.query(type='org.apache.qpid.dispatch.connection', attribute_names=['user']).results[7][0])
+
+        addr = self.address(8).replace("amqp", "amqps")
+        node = Node.connect(addr, ssl_domain=domain)
+        self.assertEqual("C=US,ST=NC,L=Raleigh,OU=Dev,O=Client,CN=127.0.0.1",
+        node.query(type='org.apache.qpid.dispatch.connection', attribute_names=['user']).results[8][0])
+
+        addr = self.address(9).replace("amqp", "amqps")
+        node = Node.connect(addr, ssl_domain=domain)
+        self.assertEqual("C=US,ST=NC,L=Raleigh,OU=Dev,O=Client,CN=127.0.0.1",
+        node.query(type='org.apache.qpid.dispatch.connection', attribute_names=['user']).results[9][0])
+
+        addr = self.address(10).replace("amqp", "amqps")
+        node = Node.connect(addr, ssl_domain=domain)
+        user = node.query(type='org.apache.qpid.dispatch.connection', attribute_names=['user']).results[10][0]
+        self.assertEqual("C=US,ST=NC,L=Raleigh,OU=Dev,O=Client,CN=127.0.0.1", str(user))
+
+        addr = self.address(11).replace("amqp", "amqps")
+        node = Node.connect(addr)
+        user = node.query(type='org.apache.qpid.dispatch.connection', attribute_names=['user']).results[11][0]
+        self.assertEqual("anonymous", user)
+
+        M1 = self.messenger()
+        M1.route("amqp:/*", self.address(12)+"/$1")
+
+        subscription = M1.subscribe("amqp:/#")
+
+        reply_to = subscription.address
+        addr = 'amqp:/_local/$displayname'
+
+        tm = Message()
+        rm = Message()
+        tm.address = addr
+        tm.reply_to = reply_to
+        tm.body = {'profilename': 'server-ssl10', 'opcode': 'QUERY', 'userid': '94745961c5646ee0129536b3acef1eea0d8d2f26f8c353455233027bcd47'}
+        M1.put(tm)
+
+        M1.send()
+        M1.recv(1)
+        M1.get(rm)
+        self.assertEqual('elaine', rm.body['user_name'])
+
+        tm = Message()
+        rm = Message()
+        tm.address = addr
+        tm.reply_to = reply_to
+        tm.body =  {'profilename': 'server-ssl14', 'opcode': 'QUERY', 'userid': '94745961c5646ee0129536b3acef1eea0d8d2f26f8c3ed08ece4f8f3027bcd48'}
+        M1.put(tm)
+        M1.send()
+        M1.recv(1)
+        M1.get(rm)
+        self.assertEqual('94745961c5646ee0129536b3acef1eea0d8d2f26f8c3ed08ece4f8f3027bcd48', rm.body['user_name'])
+
+        # The profile name, userid pair have a matching user name
+        tm = Message()
+        rm = Message()
+        tm.address = addr
+        tm.reply_to = reply_to
+        tm.body = {'profilename': 'server-ssl12', 'opcode': 'QUERY', 'userid': '94745961c5646ee0129536b3acef1eea0d8d2f26f8c3ed08ece4f8f3027bcd48'}
+        M1.put(tm)
+        M1.send()
+        M1.recv(1)
+        M1.get(rm)
+        self.assertEqual('johndoe', rm.body['user_name'])
+
+        tm = Message()
+        rm = Message()
+        tm.address = addr
+        tm.reply_to = reply_to
+        tm.body =  {'profilename': 'server-ssl10', 'opcode': 'QUERY', 'userid': '12345'}
+        M1.put(tm)
+        M1.send()
+        M1.recv(1)
+        M1.get(rm)
+        self.assertEqual('12345', rm.body['user_name'])
+
+        M1.stop()
+
+        node.close()
+
+if __name__ == '__main__':
+    unittest.main(main_module())


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


[2/2] qpid-dispatch git commit: DISPATCH-200 - Minor cleanup from Ganesh's pull request.

Posted by tr...@apache.org.
DISPATCH-200 - Minor cleanup from Ganesh's pull request.


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

Branch: refs/heads/master
Commit: 122eeec3494a4e33d1fdbe7bb3e7ff2d298cffb5
Parents: 56e56ce
Author: Ted Ross <tr...@redhat.com>
Authored: Wed Mar 30 08:23:23 2016 -0400
Committer: Ted Ross <tr...@redhat.com>
Committed: Wed Mar 30 08:23:23 2016 -0400

----------------------------------------------------------------------
 include/qpid/dispatch/server.h | 11 +++++++++++
 src/container.c                |  1 -
 src/server_private.h           |  8 --------
 tests/management/qdrouter.py   | 15 +++++++++++++--
 4 files changed, 24 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/122eeec3/include/qpid/dispatch/server.h
----------------------------------------------------------------------
diff --git a/include/qpid/dispatch/server.h b/include/qpid/dispatch/server.h
index 134dc30..46f50b5 100644
--- a/include/qpid/dispatch/server.h
+++ b/include/qpid/dispatch/server.h
@@ -500,6 +500,17 @@ void *qd_connection_get_link_context(qd_connection_t *conn);
 
 
 /**
+ * Sets the user id on the connection.
+ * If the sasl mech is EXTERNAL, set the user_id on the connection as the concatenated
+ * list of fields specified in the uidFormat field of qdrouter.json
+ * If no uidFormat is specified, the user is set to the pn_transport_user
+ *
+ * @param conn Connection object
+ */
+void qd_connection_set_user(qd_connection_t *conn);
+
+
+/**
  * Activate a connection for output.
  *
  * This function is used to request that the server activate the indicated

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/122eeec3/src/container.c
----------------------------------------------------------------------
diff --git a/src/container.c b/src/container.c
index 0d789b0..ddd85ae 100644
--- a/src/container.c
+++ b/src/container.c
@@ -21,7 +21,6 @@
 #include <string.h>
 #include "dispatch_private.h"
 #include "connection_manager_private.h"
-#include "server_private.h"
 #include <qpid/dispatch/container.h>
 #include <qpid/dispatch/server.h>
 #include <qpid/dispatch/message.h>

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/122eeec3/src/server_private.h
----------------------------------------------------------------------
diff --git a/src/server_private.h b/src/server_private.h
index 930f271..7a0d1db 100644
--- a/src/server_private.h
+++ b/src/server_private.h
@@ -173,12 +173,4 @@ ALLOC_DECLARE(qd_connector_t);
 ALLOC_DECLARE(qd_connection_t);
 ALLOC_DECLARE(qd_user_fd_t);
 
-/**
- * Sets the user id on the connection.
- * If the sasl mech is EXTERNAL, set the user_id on the connection as the concatenated list of fields specified in the uidFormat field of qdrouter.json
- * If no uidFormat is specified, the user is set to the pn_transport_user
- * @param conn Connection object
- */
-void qd_connection_set_user(qd_connection_t *conn);
-
 #endif

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/122eeec3/tests/management/qdrouter.py
----------------------------------------------------------------------
diff --git a/tests/management/qdrouter.py b/tests/management/qdrouter.py
index 1be6510..595ea17 100644
--- a/tests/management/qdrouter.py
+++ b/tests/management/qdrouter.py
@@ -81,11 +81,22 @@ class QdrouterTest(unittest.TestCase):
         conf = Config()
         content = conf._parse(text.split("\n"))
         self.maxDiff = None
-        expect = [[u'router', {u'mode': u'standalone'}], [u'sslProfile', {u'password': u'secret', u'name': u'test-profile'}], [u'listener', {u'sslProfile': u'test-profile', u'name': u'l0', u'saslMechanisms': u'ANONYMOUS'}], [u'listener', {u'saslMechanisms': u'ANONYMOUS', u'identity': u'l1', u'port': u'1234'}], [u'listener', {u'saslMechanisms': u'ANONYMOUS', u'port': u'4567'}]]
+        expect = [
+            [u'router', {u'mode': u'standalone'}],
+            [u'sslProfile', {u'password': u'secret', u'name': u'test-profile'}],
+            [u'listener', {u'sslProfile': u'test-profile', u'name': u'l0', u'saslMechanisms': u'ANONYMOUS'}],
+            [u'listener', {u'saslMechanisms': u'ANONYMOUS', u'identity': u'l1', u'port': u'1234'}],
+            [u'listener', {u'saslMechanisms': u'ANONYMOUS', u'port': u'4567'}]
+        ]
         self.assertEqual(content, expect)
 
         content = conf._expand(content)
-        expect = [[u'router', {u'mode': u'standalone'}], [u'listener', {u'password': u'secret', u'name': u'l0', u'sslProfileName': u'test-profile', u'saslMechanisms': u'ANONYMOUS'}], [u'listener', {u'port': u'1234', u'identity': u'l1', u'saslMechanisms': u'ANONYMOUS'}], [u'listener', {u'port': u'4567', u'saslMechanisms': u'ANONYMOUS'}]]
+        expect = [
+            [u'router', {u'mode': u'standalone'}],
+            [u'listener', {u'password': u'secret', u'name': u'l0', u'sslProfileName': u'test-profile', u'saslMechanisms': u'ANONYMOUS'}],
+            [u'listener', {u'port': u'1234', u'identity': u'l1', u'saslMechanisms': u'ANONYMOUS'}],
+            [u'listener', {u'port': u'4567', u'saslMechanisms': u'ANONYMOUS'}]
+        ]
         self.assertEqual(content, expect)
 
         conf.load(text.split(u"\n"))


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