You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by gs...@apache.org on 2018/01/15 19:43:50 UTC
[1/2] qpid-dispatch git commit: DISPATCH-901: authorization from
remote auth service
Repository: qpid-dispatch
Updated Branches:
refs/heads/master e9f8502ea -> eed8bb654
DISPATCH-901: authorization from remote auth service
If the client specifies its desire for the ADDRESS-AUTHZ capacbility, the authorization service, if it supports this, will return a
set of permissions in the properties of the open frame. The properties will have an address-authz key, whose value is a map of address (or wildcard pattern) to an array of permissions.
The only permissions recognised at present by this patch are 'send' and 'recv'.
Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/eed8bb65
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/eed8bb65
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/eed8bb65
Branch: refs/heads/master
Commit: eed8bb65497b23e512072f5ea9fefd8ed73921ef
Parents: f8a1c9c
Author: Gordon Sim <gs...@redhat.com>
Authored: Fri Dec 15 10:29:21 2017 +0000
Committer: Gordon Sim <gs...@redhat.com>
Committed: Mon Jan 15 19:43:23 2018 +0000
----------------------------------------------------------------------
src/policy.c | 12 +-
src/remote_sasl.c | 234 +++++++++++++++++++++++-
tests/CMakeLists.txt | 2 +
tests/authservice.py | 81 ++++++++
tests/system_tests_authz_service_plugin.py | 147 +++++++++++++++
5 files changed, 469 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eed8bb65/src/policy.c
----------------------------------------------------------------------
diff --git a/src/policy.c b/src/policy.c
index 22cc79f..a712f35 100644
--- a/src/policy.c
+++ b/src/policy.c
@@ -321,8 +321,10 @@ bool qd_policy_open_lookup_user(
settings->allowAnonymousSender = qd_entity_opt_bool((qd_entity_t*)upolicy, "allowAnonymousSender", false);
settings->allowDynamicSource = qd_entity_opt_bool((qd_entity_t*)upolicy, "allowDynamicSource", false);
settings->allowUserIdProxy = qd_entity_opt_bool((qd_entity_t*)upolicy, "allowUserIdProxy", false);
- settings->sources = qd_entity_get_string((qd_entity_t*)upolicy, "sources");
- settings->targets = qd_entity_get_string((qd_entity_t*)upolicy, "targets");
+ if (settings->sources == 0)
+ settings->sources = qd_entity_get_string((qd_entity_t*)upolicy, "sources");
+ if (settings->targets == 0)
+ settings->targets = qd_entity_get_string((qd_entity_t*)upolicy, "targets");
settings->denialCounts = (qd_policy_denial_counts_t*)
qd_entity_get_long((qd_entity_t*)upolicy, "denialCounts");
Py_XDECREF(result2);
@@ -689,8 +691,10 @@ void qd_policy_amqp_open(qd_connection_t *qd_conn) {
#define SETTINGS_NAME_SIZE 256
char settings_name[SETTINGS_NAME_SIZE];
uint32_t conn_id = qd_conn->connection_id;
- qd_conn->policy_settings = NEW(qd_policy_settings_t); // TODO: memory pool for settings
- memset(qd_conn->policy_settings, 0, sizeof(qd_policy_settings_t));
+ if (!qd_conn->policy_settings) {
+ qd_conn->policy_settings = NEW(qd_policy_settings_t); // TODO: memory pool for settings
+ memset(qd_conn->policy_settings, 0, sizeof(qd_policy_settings_t));
+ }
if (qd_policy_open_lookup_user(policy, qd_conn->user_id, hostip, vhost, conn_name,
settings_name, SETTINGS_NAME_SIZE, conn_id,
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eed8bb65/src/remote_sasl.c
----------------------------------------------------------------------
diff --git a/src/remote_sasl.c b/src/remote_sasl.c
index e3c969b..93e6129 100644
--- a/src/remote_sasl.c
+++ b/src/remote_sasl.c
@@ -20,6 +20,7 @@
*/
#include "remote_sasl.h"
+#include "server_private.h"
#include <stdio.h>
#include <stdlib.h>
@@ -29,6 +30,7 @@
#include <proton/sasl.h>
#include <proton/sasl-plugin.h>
#include <qpid/dispatch/log.h>
+#include <qpid/dispatch/ctools.h>
static qd_log_source_t* auth_service_log;
@@ -45,6 +47,45 @@ const int8_t DOWNSTREAM_CHALLENGE_RECEIVED = 4;
const int8_t DOWNSTREAM_OUTCOME_RECEIVED = 5;
const int8_t DOWNSTREAM_CLOSED = 6;
+typedef struct {
+ size_t used;
+ size_t capacity;
+ char *start;
+} buffer_t;
+
+
+static void allocate_buffer(buffer_t* buffer)
+{
+ buffer->start = malloc(buffer->capacity);
+ memset(buffer->start, 0, buffer->capacity);
+}
+
+static void free_buffer(buffer_t* buffer)
+{
+ free(buffer->start);
+ buffer->start = 0;
+ buffer->capacity = 0;
+ buffer->used = 0;
+}
+
+typedef struct {
+ buffer_t sources;
+ buffer_t targets;
+} permissions_t;
+
+static void init_buffer(buffer_t* buffer)
+{
+ buffer->used = 0;
+ buffer->capacity = 0;
+ buffer->start = 0;
+}
+
+static void init_permissions(permissions_t* permissions)
+{
+ init_buffer(&permissions->sources);
+ init_buffer(&permissions->targets);
+}
+
typedef struct
{
char* authentication_service_address;
@@ -65,6 +106,7 @@ typedef struct
bool complete;
char* username;
+ permissions_t permissions;
pn_sasl_outcome_t outcome;
} qdr_sasl_relay_t;
@@ -101,6 +143,7 @@ static qdr_sasl_relay_t* new_qdr_sasl_relay_t(const char* address, const char* s
instance->upstream = 0;
instance->downstream = 0;
instance->username = 0;
+ init_permissions(&instance->permissions);
return instance;
}
@@ -113,6 +156,8 @@ static void delete_qdr_sasl_relay_t(qdr_sasl_relay_t* instance)
if (instance->response.start) free(instance->response.start);
if (instance->challenge.start) free(instance->challenge.start);
if (instance->username) free(instance->username);
+ free_buffer(&(instance->permissions.targets));
+ free_buffer(&(instance->permissions.sources));
free(instance);
}
@@ -160,8 +205,13 @@ static bool remote_sasl_init_server(pn_transport_t* transport)
if (!proactor) return false;
impl->downstream = pn_connection();
pn_connection_set_hostname(impl->downstream, pn_connection_get_hostname(upstream));
- pn_connection_set_user(impl->downstream, "dummy");//force sasl
set_sasl_relay_context(impl->downstream, impl);
+ //request permissions in response if supported by peer:
+ pn_data_t* data = pn_connection_desired_capabilities(impl->downstream);
+ pn_data_put_array(data, false, PN_SYMBOL);
+ pn_data_enter(data);
+ pn_data_put_symbol(data, pn_bytes(13, "ADDRESS-AUTHZ"));
+ pn_data_exit(data);
pn_proactor_connect(proactor, impl->downstream, impl->authentication_service_address);
return true;
@@ -207,6 +257,25 @@ static void remote_sasl_free(pn_transport_t *transport)
}
}
+static void set_policy_settings(pn_connection_t* conn, permissions_t* permissions)
+{
+ if (permissions->targets.start || permissions->sources.start) {
+ qd_connection_t *qd_conn = (qd_connection_t*) pn_connection_get_context(conn);
+ qd_conn->policy_settings = NEW(qd_policy_settings_t);
+ ZERO(qd_conn->policy_settings);
+
+ qd_conn->policy_settings->denialCounts = NEW(qd_policy_denial_counts_t);
+ ZERO(qd_conn->policy_settings->denialCounts);
+
+ if (permissions->targets.start && permissions->targets.capacity) {
+ qd_conn->policy_settings->targets = strdup(permissions->targets.start);
+ }
+ if (permissions->sources.start && permissions->sources.capacity) {
+ qd_conn->policy_settings->sources = strdup(permissions->sources.start);
+ }
+ }
+}
+
static void remote_sasl_prepare(pn_transport_t *transport)
{
qdr_sasl_relay_t* impl = (qdr_sasl_relay_t*) pnx_sasl_get_context(transport);
@@ -231,6 +300,7 @@ static void remote_sasl_prepare(pn_transport_t *transport)
} else if (impl->upstream_state == DOWNSTREAM_OUTCOME_RECEIVED) {
switch (impl->outcome) {
case PN_SASL_OK:
+ set_policy_settings(impl->upstream, &impl->permissions);
pnx_sasl_succeed_authentication(transport, impl->username);
break;
default:
@@ -304,9 +374,9 @@ static void remote_sasl_process_outcome(pn_transport_t *transport)
pn_sasl_t* sasl = pn_sasl(transport);
if (sasl) {
impl->outcome = pn_sasl_outcome(sasl);
- impl->username = strdup(pn_sasl_get_user(sasl));
impl->complete = true;
- if (!notify_upstream(impl, DOWNSTREAM_OUTCOME_RECEIVED)) {
+ //only consider complete if failed; if successful wait for the open frame
+ if (impl->outcome != PN_SASL_OK && !notify_upstream(impl, DOWNSTREAM_OUTCOME_RECEIVED)) {
pnx_sasl_set_desired_state(transport, SASL_ERROR);
}
}
@@ -398,11 +468,142 @@ void qdr_use_remote_authentication_service(pn_transport_t *transport, const char
set_remote_impl(transport, context);
}
+static bool append(buffer_t* buffer, pn_bytes_t data)
+{
+ if (buffer->capacity > data.size + buffer->used) {
+ if (buffer->used > 0) buffer->start[buffer->used++] = ',';
+ strncpy(buffer->start + buffer->used, data.start, data.size);
+ buffer->used += data.size;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static size_t min(size_t a, size_t b)
+{
+ if (a > b) return b;
+ else return a;
+}
+
+typedef void* (*permission_handler)(pn_bytes_t, bool, bool, void*);
+
+static void* compute_required_size(pn_bytes_t address, bool send, bool recv, void* context)
+{
+ permissions_t* permissions = (permissions_t*) context;
+ if (send) permissions->targets.capacity += address.size + 1;
+ if (recv) permissions->sources.capacity += address.size + 1;
+ return context;
+}
+
+static void* collect_permissions(pn_bytes_t address, bool send, bool recv, void* context)
+{
+ permissions_t* permissions = (permissions_t*) context;
+ if (send) append(&(permissions->targets), address);
+ if (recv) append(&(permissions->sources), address);
+ return context;
+}
+
+static void* parse_permissions(pn_data_t* data, permission_handler handler, void* initial_context)
+{
+ void* context = initial_context;
+ size_t count = pn_data_get_map(data);
+ pn_data_enter(data);
+ for (size_t i = 0; i < count/2; i++) {
+ if (pn_data_next(data)) {
+ if (pn_data_type(data) == PN_STRING) {
+ pn_bytes_t address = pn_data_get_string(data);
+ if (pn_data_next(data)) {
+ if (pn_data_type(data) == PN_ARRAY && pn_data_get_array_type(data) == PN_STRING) {
+ size_t length = pn_data_get_array(data);
+ pn_data_enter(data);
+ for (size_t j = 0; j < length; j++) {
+ if (pn_data_next(data)) {
+ pn_bytes_t permission = pn_data_get_string(data);
+ //printf("in permissions map %i of %i is %.*s for %.*s\n", (int) (j+1), (int) length, (int) permission.size, permission.start, (int) address.size, address.start);
+ bool send = strncmp(permission.start, "send", min(permission.size, 4)) == 0;
+ bool recv = strncmp(permission.start, "recv", min(permission.size, 4)) == 0;
+
+ if (send || recv) {
+ context = handler(address, send, recv, context);
+ }
+ }
+ }
+ pn_data_exit(data);
+ }
+ }
+ } else {
+ //key is not string, consume value to move onto next pair
+ pn_data_next(data);
+ }
+ }
+ }
+ pn_data_exit(data);
+ return context;
+}
+
+static void* parse_properties(pn_data_t* data, permission_handler handler, void* initial_context)
+{
+ void* context = 0;
+ size_t count = pn_data_get_map(data);
+ pn_data_enter(data);
+ for (size_t i = 0; !context && i < count/2; i++) {
+ if (pn_data_next(data)) {
+ if (pn_data_type(data) == PN_SYMBOL) {
+ pn_bytes_t key = pn_data_get_symbol(data);
+ if (key.size && key.start && strncmp(key.start, "address-authz", min(key.size, 13)) == 0) {
+ pn_data_next(data);
+ context = parse_permissions(data, handler, initial_context);
+ } else {
+ //key didn't match, move to next pair
+ pn_data_next(data);
+ }
+ } else {
+ //key was not symbol, move to next pair
+ pn_data_next(data);
+ }
+ }
+ }
+ pn_data_exit(data);
+ pn_data_rewind(data);
+ pn_data_next(data);
+ return context;
+}
+
+static pn_bytes_t extract_authenticated_identity(pn_data_t* data)
+{
+ pn_bytes_t result = pn_bytes_null;
+ size_t count = pn_data_get_map(data);
+ pn_data_enter(data);
+ for (size_t i = 0; !result.size && i < count/2; i++) {
+ if (pn_data_next(data)) {
+ if (pn_data_type(data) == PN_SYMBOL) {
+ pn_bytes_t key = pn_data_get_symbol(data);
+ if (key.size && key.start && strncmp(key.start, "authenticated-identity", min(key.size, 22)) == 0) {
+ pn_data_next(data);
+ result = pn_data_get_string(data);
+ } else {
+ //key didn't match, move to next pair
+ pn_data_next(data);
+ }
+ } else {
+ //key was not symbol, move to next pair
+ pn_data_next(data);
+ }
+ }
+ }
+ pn_data_exit(data);
+ pn_data_rewind(data);
+ pn_data_next(data);
+ return result;
+}
+
void qdr_handle_authentication_service_connection_event(pn_event_t *e)
{
pn_connection_t *conn = pn_event_connection(e);
pn_transport_t *transport = pn_event_transport(e);
if (pn_event_type(e) == PN_CONNECTION_BOUND) {
+ pn_sasl(transport);
qd_log(auth_service_log, QD_LOG_DEBUG, "Handling connection bound event for authentication service connection");
qdr_sasl_relay_t* context = get_sasl_relay_context(conn);
if (context->ssl_domain) {
@@ -416,6 +617,33 @@ void qdr_handle_authentication_service_connection_event(pn_event_t *e)
set_remote_impl(pn_event_transport(e), context);
} else if (pn_event_type(e) == PN_CONNECTION_REMOTE_OPEN) {
qd_log(auth_service_log, QD_LOG_DEBUG, "authentication against service complete; closing connection");
+
+ qdr_sasl_relay_t* context = get_sasl_relay_context(conn);
+ //extract permissions as two comma separated lists (allowed sources and targets)
+ pn_data_t* properties = pn_connection_remote_properties(conn);
+ if (parse_properties(properties, compute_required_size, (void*) &(context->permissions))) {
+ if (!context->permissions.sources.capacity) {
+ context->permissions.sources.capacity = 1;
+ }
+ if (!context->permissions.targets.capacity) {
+ context->permissions.targets.capacity = 1;
+ }
+ allocate_buffer(&(context->permissions.targets));
+ allocate_buffer(&(context->permissions.sources));
+ parse_properties(properties, collect_permissions, (void*) &(context->permissions));
+ printf("allowed sources %s\n", context->permissions.sources.start);
+ printf("allowed targets %s\n", context->permissions.targets.start);
+ }
+ const pn_bytes_t authid = extract_authenticated_identity(properties);
+ if (authid.start && authid.size) {
+ context->username = strndup(authid.start, authid.size);
+ } else {
+ context->username = strdup("");
+ }
+ //notify upstream connection of successful authentication
+ notify_upstream(context, DOWNSTREAM_OUTCOME_RECEIVED);
+
+ //close downstream connection
pn_connection_close(conn);
} else if (pn_event_type(e) == PN_CONNECTION_REMOTE_CLOSE) {
qd_log(auth_service_log, QD_LOG_DEBUG, "authentication service closed connection");
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eed8bb65/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index a8aedd2..0105c29 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -100,6 +100,7 @@ foreach(py_test_module
system_tests_failover_list
system_tests_denied_unsettled_multicast
system_tests_auth_service_plugin
+ system_tests_authz_service_plugin
system_tests_delivery_abort
system_tests_topology
${SYSTEM_TESTS_HTTP}
@@ -131,6 +132,7 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/policy-1/policy-safari.json DESTINATI
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/policy-2/policy-photoserver-sasl.sasldb DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/policy-2)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/policy-3/test-sender-receiver-limits.json DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/policy-3)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/policy-4/management-access.json DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/policy-4/)
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/authservice.py 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/eed8bb65/tests/authservice.py
----------------------------------------------------------------------
diff --git a/tests/authservice.py b/tests/authservice.py
new file mode 100755
index 0000000..c46a9ae
--- /dev/null
+++ b/tests/authservice.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+from __future__ import print_function, unicode_literals
+import signal, optparse
+from proton.handlers import MessagingHandler
+from proton.reactor import Container
+from proton import Array, Data, symbol, UNDESCRIBED
+from cproton import pn_sasl_config_path
+
+class AuthService(MessagingHandler):
+ def __init__(self, address):
+ super(AuthService, self).__init__()
+ self.address = address
+ self.permissions = {}
+ self.allow('admin', '*', ['send', 'recv'])
+ self.allow('guest', 'foo', ['send', 'recv'])
+ self.listener = None
+
+ def allow(self, user, address, permissions):
+ if not self.permissions.get(user):
+ self.permissions[user] = {}
+ self.permissions[user][address] = Array(UNDESCRIBED, Data.STRING, *permissions)
+
+ def on_start(self, event):
+ self.listener = event.container.listen(self.address)
+
+ def stop(self):
+ if self.listener:
+ self.listener.close()
+
+ def on_connection_opening(self, event):
+ if self.permissions.get(event.transport.user):
+ event.connection.properties = {
+ symbol('authenticated-identity'): "%s" % event.transport.user,
+ symbol('address-authz'): self.permissions[event.transport.user]
+ }
+ else:
+ event.connection.properties = {
+ symbol('authenticated-identity'): "%s" % event.transport.user,
+ symbol('address-authz'): {}
+ }
+
+parser = optparse.OptionParser(usage="usage: %prog [options]",
+ description="test authentication and authorization service")
+parser.add_option("-a", "--address", default="localhost:55671",
+ help="address to listen on (default %default)")
+parser.add_option("-c", "--config", help="sasl config path")
+opts, args = parser.parse_args()
+
+print('starting')
+if opts.config:
+ pn_sasl_config_path(None, opts.config)
+ print('set sasl config path to %s' % opts.config)
+
+handler = AuthService(opts.address)
+def sigterm_handler(_signo, _stack_frame):
+ #sys.exit(0)
+ handler.stop()
+
+signal.signal(signal.SIGTERM, sigterm_handler)
+
+Container(handler).run()
+
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/eed8bb65/tests/system_tests_authz_service_plugin.py
----------------------------------------------------------------------
diff --git a/tests/system_tests_authz_service_plugin.py b/tests/system_tests_authz_service_plugin.py
new file mode 100644
index 0000000..af84bc0
--- /dev/null
+++ b/tests/system_tests_authz_service_plugin.py
@@ -0,0 +1,147 @@
+#
+# 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 unittest2 as unitest
+import os, json
+from subprocess import PIPE, Popen, STDOUT
+from system_test import TestCase, Qdrouterd, main_module, DIR, TIMEOUT, Process
+from proton import Array, Data, Message, SASL, symbol, UNDESCRIBED
+from proton.handlers import MessagingHandler
+from proton.reactor import Container
+
+class AuthServicePluginAuthzTest(TestCase):
+ @classmethod
+ def addUser(cls, user, password):
+ # Create a sasl database.
+ p = Popen(['saslpasswd2', '-c', '-p', '-f', 'users.sasldb', user],
+ stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ result = p.communicate(password)
+ assert p.returncode == 0, "saslpasswd2 exit status %s, output:\n%s" % (p.returncode, result)
+
+ @classmethod
+ def createSaslFiles(cls):
+ cls.addUser('guest', 'guest')
+ cls.addUser('admin', 'admin')
+ # Create a SASL configuration file.
+ with open('tests-mech-SCRAM.conf', 'w') as sasl_conf:
+ sasl_conf.write("""
+mech_list: SCRAM-SHA-1
+""")
+ with open('proton-server.conf', 'w') as sasl_conf:
+ sasl_conf.write("""
+pwcheck_method: auxprop
+auxprop_plugin: sasldb
+sasldb_path: users.sasldb
+mech_list: SCRAM-SHA-1
+""")
+
+
+ @classmethod
+ def setUpClass(cls):
+ """
+ Tests the delegation of sasl auth to an external auth service.
+ """
+ super(AuthServicePluginAuthzTest, cls).setUpClass()
+
+ if not SASL.extended():
+ return
+
+ cls.createSaslFiles()
+
+ cls.auth_service_port = cls.tester.get_port()
+ cls.tester.popen(['/usr/bin/env', 'python', os.path.join(os.path.dirname(os.path.abspath(__file__)), 'authservice.py'), '-a', '127.0.0.1:%d' % cls.auth_service_port, '-c', os.getcwd()], expect=Process.RUNNING)
+
+ cls.router_port = cls.tester.get_port()
+ cls.tester.qdrouterd('router', Qdrouterd.Config([
+ ('authServicePlugin', {'name':'myauth', 'authService': '127.0.0.1:%d' % cls.auth_service_port}),
+ ('listener', {'host': '0.0.0.0', 'port': cls.router_port, 'role': 'normal', 'saslPlugin':'myauth', 'saslMechanisms':'SCRAM-SHA-1'}),
+ ('router', {'mode': 'standalone', 'id': 'router',
+ 'saslConfigName': 'tests-mech-SCRAM',
+ 'saslConfigPath': os.getcwd()})
+ ])).wait_ready()
+
+ def test_authorized(self):
+ if not SASL.extended():
+ self.skipTest("Cyrus library not available. skipping test")
+
+ container = Container()
+ client = ConnectionHandler('foo', 1)
+ container.connect("guest:guest@127.0.0.1:%d" % self.router_port, handler=client)
+ container.run()
+ self.assertEqual(1, client.sent)
+ self.assertEqual(1, client.received)
+ self.assertEqual(0, len(client.errors))
+
+ def test_unauthorized(self):
+ if not SASL.extended():
+ self.skipTest("Cyrus library not available. skipping test")
+
+ container = Container()
+ client = ConnectionHandler('bar', 1)
+ container.connect("guest:guest@127.0.0.1:%d" % self.router_port, handler=client)
+ container.run()
+ self.assertEqual(0, client.sent)
+ self.assertEqual(0, client.received)
+ self.assertEqual(2, len(client.errors))
+ self.assertEqual('amqp:unauthorized-access', client.errors[0])
+ self.assertEqual('amqp:unauthorized-access', client.errors[1])
+
+ def test_wildcard(self):
+ if not SASL.extended():
+ self.skipTest("Cyrus library not available. skipping test")
+
+ container = Container()
+ client = ConnectionHandler('whatever', 1)
+ container.connect("admin:admin@127.0.0.1:%d" % self.router_port, handler=client)
+ container.run()
+ self.assertEqual(1, client.sent)
+ self.assertEqual(1, client.received)
+ self.assertEqual(0, len(client.errors))
+
+
+class ConnectionHandler(MessagingHandler):
+ def __init__(self, address, count):
+ super(ConnectionHandler, self).__init__()
+ self.address = address
+ self.count = count
+ self.received = 0
+ self.sent = 0
+ self.errors = []
+
+ def on_message(self, event):
+ self.received += 1
+ if self.received == self.count:
+ event.connection.close()
+
+ def on_sendable(self, event):
+ if self.sent < self.count:
+ self.sent += 1
+ event.sender.send(Message(body='msg-%s' %self.sent))
+
+ def on_link_error(self, event):
+ self.errors.append(event.link.remote_condition.name)
+ event.connection.close()
+
+ def on_connection_opened(self, event):
+ event.container.create_receiver(event.connection, self.address)
+ event.container.create_sender(event.connection, self.address)
+
+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-912: move setting rhost from
connection-bound to remote-open event to ensure proton has retrieved the
necessary info
Posted by gs...@apache.org.
DISPATCH-912: move setting rhost from connection-bound to remote-open event to ensure proton has retrieved the necessary info
Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/f8a1c9c9
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/f8a1c9c9
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/f8a1c9c9
Branch: refs/heads/master
Commit: f8a1c9c975f3f8d859a4d57ce0d705fe4bd12e68
Parents: e9f8502
Author: Gordon Sim <gs...@redhat.com>
Authored: Mon Jan 15 15:47:23 2018 +0000
Committer: Gordon Sim <gs...@redhat.com>
Committed: Mon Jan 15 19:43:23 2018 +0000
----------------------------------------------------------------------
src/server.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/f8a1c9c9/src/server.c
----------------------------------------------------------------------
diff --git a/src/server.c b/src/server.c
index 5cf967e..5005cb3 100644
--- a/src/server.c
+++ b/src/server.c
@@ -577,7 +577,9 @@ void connect_fail(qd_connection_t *ctx, const char *name, const char *descriptio
/* Get the host IP address for the remote end */
-static void set_rhost_port(qd_connection_t *ctx) {
+static void set_rhost_port(pn_event_t *e) {
+ pn_connection_t *pn_conn = pn_event_connection(e);
+ qd_connection_t *ctx = pn_connection_get_context(pn_conn);
pn_transport_t *tport = pn_connection_transport(ctx->pn_conn);
const struct sockaddr* sa = pn_netaddr_sockaddr(pn_netaddr_remote(tport));
size_t salen = pn_netaddr_socklen(pn_netaddr_remote(tport));
@@ -592,7 +594,6 @@ static void set_rhost_port(qd_connection_t *ctx) {
}
}
-
/* Configure the transport once it is bound to the connection */
static void on_connection_bound(qd_server_t *server, pn_event_t *e) {
pn_connection_t *pn_conn = pn_event_connection(e);
@@ -614,7 +615,6 @@ static void on_connection_bound(qd_server_t *server, pn_event_t *e) {
config = &ctx->listener->config;
const char *name = config->host_port;
pn_transport_set_server(tport);
- set_rhost_port(ctx);
sys_mutex_lock(server->lock); /* Policy check is not thread safe */
ctx->policy_counted = qd_policy_socket_accept(server->qd->policy, ctx->rhost);
@@ -874,6 +874,7 @@ static bool handle(qd_server_t *qd_server, pn_event_t *e) {
break;
case PN_CONNECTION_REMOTE_OPEN:
+ set_rhost_port(e);
// If we are transitioning to the open state, notify the client via callback.
if (ctx && ctx->timer) {
qd_timer_free(ctx->timer);
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org