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 2015/10/22 21:34:21 UTC

qpid-dispatch git commit: DISPATCH-163 - Added username and password for authentication of connectors. Added system test to verify SASL PLAIN authentication

Repository: qpid-dispatch
Updated Branches:
  refs/heads/master 8353ac674 -> 2991015c7


DISPATCH-163 - Added username and password for authentication of connectors. Added system test to verify SASL PLAIN authentication


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

Branch: refs/heads/master
Commit: 2991015c7f2426814e7a1687997ebda4847ba6e5
Parents: 8353ac6
Author: ganeshmurthy <gm...@redhat.com>
Authored: Fri Oct 16 14:18:45 2015 -0400
Committer: ganeshmurthy <gm...@redhat.com>
Committed: Wed Oct 21 10:19:03 2015 -0400

----------------------------------------------------------------------
 python/qpid_dispatch/management/qdrouter.json |  14 ++-
 src/connection_manager.c                      |   2 +
 src/server.c                                  |  10 +-
 tests/CMakeLists.txt                          |  62 ++++++++----
 tests/sasl_configs/qdrouterd.sasldb           | Bin 0 -> 12288 bytes
 tests/sasl_configs/tests-mech-PLAIN.conf.in   |  79 +++++++++++++++
 tests/system_tests_sasl_plain.py.in           | 106 +++++++++++++++++++++
 7 files changed, 253 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/2991015c/python/qpid_dispatch/management/qdrouter.json
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch/management/qdrouter.json b/python/qpid_dispatch/management/qdrouter.json
index 6c8dae8..ca6685e 100644
--- a/python/qpid_dispatch/management/qdrouter.json
+++ b/python/qpid_dispatch/management/qdrouter.json
@@ -678,7 +678,19 @@
                     "default": "both",
                     "description": "['in', 'out', 'both', 'no'] in: Strip the dispatch router specific annotations only on ingress; out: Strip the dispatch router specific annotations only on egress; both: Strip the dispatch router specific annotations on both ingress and egress; no - do not strip dispatch router specific annotations",
                     "create": true
-                }
+                },
+                "saslUsername": {
+                    "type": "string",
+                    "required": false,
+                    "description": "The user name that the connector is using to connect to a peer.",
+                    "create": true
+                },
+                "saslPassword": {
+                    "type": "string",
+                    "required": false,
+                    "description": "The password that the connector is using to connect to a peer.",
+                    "create": true
+                }                                
             }
         },
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/2991015c/src/connection_manager.c
----------------------------------------------------------------------
diff --git a/src/connection_manager.c b/src/connection_manager.c
index c9dc81c..c90db75 100644
--- a/src/connection_manager.c
+++ b/src/connection_manager.c
@@ -144,6 +144,8 @@ static qd_error_t load_server_config(qd_dispatch_t *qd, qd_server_config_t *conf
     config->role            = qd_entity_get_string(entity, "role"); CHECK();
     config->max_frame_size  = qd_entity_get_long(entity, "maxFrameSize"); CHECK();
     config->idle_timeout_seconds = qd_entity_get_long(entity, "idleTimeoutSeconds"); CHECK();
+    config->sasl_username = qd_entity_opt_string(entity, "saslUsername", 0); CHECK();
+    config->sasl_password = qd_entity_opt_string(entity, "saslPassword", 0); CHECK();
     config->sasl_mechanisms = qd_entity_opt_string(entity, "saslMechanisms", 0); CHECK();
     config->ssl_enabled = has_attrs(entity, ssl_attributes, ssl_attributes_count);
 

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/2991015c/src/server.c
----------------------------------------------------------------------
diff --git a/src/server.c b/src/server.c
index 623a587..d53b64e 100644
--- a/src/server.c
+++ b/src/server.c
@@ -830,6 +830,8 @@ static void cxtr_try_open(void *context)
     }
     sys_mutex_unlock(ct->server->lock);
 
+    const qd_server_config_t *config = ct->config;
+
     if (ctx->pn_cxtr == 0) {
         sys_mutex_free(ctx->deferred_call_lock);
         free_qd_connection_t(ctx);
@@ -838,6 +840,13 @@ static void cxtr_try_open(void *context)
         return;
     }
 
+    // Set the sasl user name and password on the proton connection object. This has to be done before the call to qdpn_connector_transport() which
+    // binds the transport to the connection
+    if(config->sasl_username)
+        pn_connection_set_user(ctx->pn_conn, config->sasl_username);
+    if (config->sasl_password)
+        pn_connection_set_password(ctx->pn_conn, config->sasl_password);
+
     qdpn_connector_set_connection(ctx->pn_cxtr, ctx->pn_conn);
     pn_connection_set_context(ctx->pn_conn, ctx);
 
@@ -850,7 +859,6 @@ static void cxtr_try_open(void *context)
     // Set up the transport, SASL, and SSL for the connection.
     //
     pn_transport_t           *tport  = qdpn_connector_transport(ctx->pn_cxtr);
-    const qd_server_config_t *config = ct->config;
 
     //
     // Configure the transport

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/2991015c/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index e2b79e3..b31f642 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -50,6 +50,21 @@ set(unit_test_size_SOURCES
 add_executable(unit_tests_size ${unit_test_size_SOURCES})
 target_link_libraries(unit_tests_size qpid-dispatch)
 
+# Move all the python system tests from the src/tests dir to the build/tests dir and execute the tests from there.
+# While moving the files make sure that configure_file() is called on any .py.in files resulting in .py file
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/system_tests_sasl_plain.py.in ${CMAKE_CURRENT_BINARY_DIR}/system_tests_sasl_plain.py)
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/router_engine_test.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/system_tests_broker.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/system_tests_management.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/system_tests_one_router.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/system_tests_qdmanage.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/system_tests_qdstat.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/system_tests_two_routers.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/system_tests_link_routes.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/run_system_tests.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/system_test.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+
+
 set(TEST_WRAP ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/run.py)
 
 add_test(unit_tests_size_10000 ${TEST_WRAP} --vg unit_tests_size 10000)
@@ -61,34 +76,45 @@ add_test(unit_tests_size_3     ${TEST_WRAP} --vg unit_tests_size 3)
 add_test(unit_tests_size_2     ${TEST_WRAP} --vg unit_tests_size 2)
 add_test(unit_tests_size_1     ${TEST_WRAP} --vg unit_tests_size 1)
 add_test(unit_tests            ${TEST_WRAP} --vg unit_tests ${CMAKE_CURRENT_SOURCE_DIR}/threads4.conf)
-add_test(router_tests          ${TEST_WRAP} -s ${CMAKE_CURRENT_SOURCE_DIR}/router_engine_test.py -v)
-add_test(management_tests      ${TEST_WRAP} -m unittest -v management)
-
-macro(add_system_test test)
-  add_test(${test} ${TEST_WRAP} -m ${test} -v)
-endmacro(add_system_test)
 
-add_system_test(system_tests_broker)
-add_system_test(system_tests_management)
-add_system_test(system_tests_one_router)
-add_system_test(system_tests_qdmanage)
-add_system_test(system_tests_qdstat)
-add_system_test(system_tests_two_routers)
-add_system_test(system_tests_link_routes)
+# Add all sytem_tests* using add_test
+add_test(router_tests             ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/router_engine_test.py -v)
+add_test(system_tests_broker      ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_broker.py -v)
+add_test(system_tests_management  ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_management.py -v)
+add_test(system_tests_one_router  ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_one_router.py -v)
+add_test(system_tests_qdmanage    ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_qdmanage.py -v)
+add_test(system_tests_qdstat      ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_qdstat.py -v)
+add_test(system_tests_two_routers ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_two_routers.py -v)
+add_test(system_tests_link_routes ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_link_routes.py -v)
+add_test(system_tests_sasl_plain  ${TEST_WRAP} -s ${CMAKE_CURRENT_BINARY_DIR}/system_tests_sasl_plain.py -v)
+add_test(management_tests         ${TEST_WRAP} -m unittest -v management)
+
+#macro(add_system_test test)
+#  add_test(${test} ${TEST_WRAP} -m ${test} -v)
+#endmacro(add_system_test)
 
 # NOTE: Don't install run.py. A system test of a dispatch installation should pick everything
 # up from standard install locations.
 #
 set(SYSTEM_TEST_FILES
-  run_system_tests.py system_test.py
-  system_tests_one_router.py system_tests_two_routers.py
-  system_tests_broker.py system_tests_management.py
-  system_tests_qdstat.py system_tests_qdmanage.py
-  system_tests_link_routes.py)
+  ${CMAKE_CURRENT_BINARY_DIR}/router_engine_test.py
+  ${CMAKE_CURRENT_BINARY_DIR}/run_system_tests.py
+  ${CMAKE_CURRENT_BINARY_DIR}/system_test.py
+  ${CMAKE_CURRENT_BINARY_DIR}/system_tests_one_router.py
+  ${CMAKE_CURRENT_BINARY_DIR}/system_tests_two_routers.py
+  ${CMAKE_CURRENT_BINARY_DIR}/system_tests_broker.py
+  ${CMAKE_CURRENT_BINARY_DIR}/system_tests_management.py
+  ${CMAKE_CURRENT_BINARY_DIR}/system_tests_qdstat.py
+  ${CMAKE_CURRENT_BINARY_DIR}/system_tests_qdmanage.py
+  ${CMAKE_CURRENT_BINARY_DIR}/system_tests_link_routes.py
+  ${CMAKE_CURRENT_BINARY_DIR}/system_tests_sasl_plain.py)
 
 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}/sasl_configs/qdrouterd.sasldb DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/sasl_configs)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sasl_configs/tests-mech-PLAIN.conf.in ${CMAKE_CURRENT_BINARY_DIR}/sasl_configs/tests-mech-PLAIN.conf)
 
+# following install() functions will be called only if you do a make "install"
 install(FILES ${SYSTEM_TEST_FILES}
         DESTINATION ${QPID_DISPATCH_HOME_INSTALLED}/tests
         )

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/2991015c/tests/sasl_configs/qdrouterd.sasldb
----------------------------------------------------------------------
diff --git a/tests/sasl_configs/qdrouterd.sasldb b/tests/sasl_configs/qdrouterd.sasldb
new file mode 100644
index 0000000..d73e603
Binary files /dev/null and b/tests/sasl_configs/qdrouterd.sasldb differ

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/2991015c/tests/sasl_configs/tests-mech-PLAIN.conf.in
----------------------------------------------------------------------
diff --git a/tests/sasl_configs/tests-mech-PLAIN.conf.in b/tests/sasl_configs/tests-mech-PLAIN.conf.in
new file mode 100644
index 0000000..4e04097
--- /dev/null
+++ b/tests/sasl_configs/tests-mech-PLAIN.conf.in
@@ -0,0 +1,79 @@
+#
+# 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.
+#
+#
+#---------------------------------
+# SASL Mechanisms and Users
+#---------------------------------
+#
+# This default mech list allows for PLAIN, but that
+# mechanism sends credentials in the clear, and is normally 
+# only used along with SSL transport-layer security.
+#
+# This default also permits DIGEST-MD5, but you must have
+# a user and password defined in your sasldb file to use
+# this mechanism.    ( See notes below. )
+#
+#                              PLEASE NOTE 
+#  For production messaging systems, a high-security mechanism such as
+#  DIGEST-MD5 or PLAIN+SSL should be used.
+#
+#
+
+pwcheck_method: auxprop
+auxprop_plugin: sasldb
+sasldb_path: ${CMAKE_CURRENT_BINARY_DIR}/sasl_configs/qdrouterd.sasldb
+mech_list: ANONYMOUS DIGEST-MD5 EXTERNAL PLAIN
+
+#---------------------------------
+# Please Note
+#---------------------------------
+#
+# 1. If you use a nonstandard location for your sasl_config directory,
+#    you can point qdrouterd to it by using the container->saslConfigPath
+#    configuration attribute.
+#
+#    If your nonstandard sasl directory is $MY_SASL_DIR, put a copy
+#    of this file at $MY_SASL_DIR/qdrouterd.conf, alter the mech list as 
+#    appropriate for your installation, and then use the saslpasswd2 
+#    command to add new user+passwd pairs:
+#      echo $PASSWD | saslpasswd2 -c -p -f $MY_SASL_DIR/qdrouterd.sasldb -u qdrouterd $USERNAME
+#    
+#
+# 2. The standard location for the qdrouterd sasldb file is 
+#       /var/lib/qdrouterd/qdrouterd.sasldb
+#
+# 3. You can see what usernames have been stored in the sasldb, with the
+#    command "sasldblistusers2 -f /var/lib/qdrouterd/qdrouterd.sasldb"
+#
+# 4. The sasldb file must be readable by the user running the qdrouterd
+#    daemon, ( the user name is qdrouterd ) and should be readable only 
+#    by that user.
+#
+# 5. The EXTERNAL mechanism allows you to use SSL transport layer 
+#    security.  In that case, you can also set the broker option
+#    --ssl-require-client-authentication .
+
+
+
+# The following line stops spurious 'sql_select option missing' errors when
+# cyrus-sql-sasl plugin is installed
+sql_select: dummy select
+
+
+

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/2991015c/tests/system_tests_sasl_plain.py.in
----------------------------------------------------------------------
diff --git a/tests/system_tests_sasl_plain.py.in b/tests/system_tests_sasl_plain.py.in
new file mode 100644
index 0000000..5e03efd
--- /dev/null
+++ b/tests/system_tests_sasl_plain.py.in
@@ -0,0 +1,106 @@
+#
+# 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 unittest, os
+from subprocess import PIPE
+import system_test
+from system_test import TestCase, Qdrouterd, main_module
+
+class RouterTestPlainSasl(TestCase):
+
+    @classmethod
+    def createSasldb(cls):
+        pass
+
+
+    @classmethod
+    def setUpClass(cls):
+        """
+        Tests the sasl_username, sasl_password property of the dispatch router.
+
+        Creates two routers (QDR.X and QDR.Y) and sets up PLAIN authentication on QDR.X.
+        QDR.Y connects to QDR.X by providing a sasl_username and a sasl_password.
+
+        """
+        super(RouterTestPlainSasl, cls).setUpClass()
+
+        def router(name, connection):
+
+            config = [
+                ('router', {'mode': 'interior', 'routerId': 'QDR.%s'%name}),
+                ('fixedAddress', {'prefix': '/closest/', 'fanout': 'single', 'bias': 'closest'}),
+                ('fixedAddress', {'prefix': '/spread/', 'fanout': 'single', 'bias': 'spread'}),
+                ('fixedAddress', {'prefix': '/multicast/', 'fanout': 'multiple'}),
+                ('fixedAddress', {'prefix': '/', 'fanout': 'multiple'}),
+
+            ] + connection
+
+            config = Qdrouterd.Config(config)
+            cls.routers.append(cls.tester.qdrouterd(name, config, wait=False))
+
+        cls.routers = []
+
+        x_listener_port = cls.tester.get_port()
+        y_listener_port = cls.tester.get_port()
+
+        # Look at the tests/CMakeLists.txt to find out how CMAKE replaces ${CMAKE_CURRENT_BINARY_DIR} with the correct path
+        # CMAKE also renames this file to system_tests_sasl_plain.py and copies it to the build/tests folder before executing it.
+        sasl_config_path = '${CMAKE_CURRENT_BINARY_DIR}' + '/sasl_configs'
+
+        router('X', [
+                     ('listener', {'addr': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port,
+                                   'saslMechanisms':'PLAIN DIGEST-MD5', 'authenticatePeer': 'yes'}),
+                     # This unauthenticated listener is for qdstat to connect to it.
+                     ('listener', {'addr': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port(),
+                                   'authenticatePeer': 'no'}),
+                     ('container', {'workerThreads': 4, 'containerName': 'Qpid.Dispatch.Router.X',
+                                    'saslConfigName': 'tests-mech-PLAIN',
+                                    'saslConfigPath': sasl_config_path}),
+        ])
+
+        router('Y', [
+                     ('connector', {'addr': '0.0.0.0', 'role': 'inter-router', 'port': x_listener_port,
+                                    # Provide a sasl user name and password to connect to QDR.X
+                                   'saslMechanisms': 'PLAIN DIGEST-MD5', 'saslUsername': 'test@domain.com', 'saslPassword': 'password'}),
+                     ('container', {'workerThreads': 4, 'containerName': 'Qpid.Dispatch.Router.Y'}),
+                     ('listener', {'addr': '0.0.0.0', 'role': 'normal', 'port': y_listener_port}),
+        ])
+
+        cls.routers[1].wait_router_connected('QDR.X')
+
+    def test_inter_router_plain_exists(self):
+        """
+        The setUpClass sets up two routers with SASL PLAIN enabled.
+        This test makes executes a qdstat -c via an unauthenticated listener to QDR.X and makes sure that the output
+        has an "inter-router" connection to QDR.Y whose authentication is PLAIN. This ensures that QDR.Y did not
+        somehow use SASL ANONYMOUS to connect to QDR.X
+        """
+        p = self.popen(
+            ['qdstat', '-b', str(self.routers[0].addresses[1]), '-c'],
+            name='qdstat-'+self.id(), stdout=PIPE, expect=None)
+        out = p.communicate()[0]
+        assert p.returncode == 0, \
+            "qdstat exit status %s, output:\n%s" % (p.returncode, out)
+
+        assert "inter-router" in out
+        assert "test@domain.com(PLAIN)" in out
+
+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