You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2015/03/11 17:12:23 UTC
svn commit: r1665924 - in /qpid/dispatch/trunk: src/server.c
tests/system_tests_qdstat.py
Author: aconway
Date: Wed Mar 11 16:12:23 2015
New Revision: 1665924
URL: http://svn.apache.org/r1665924
Log:
DISPATCH-124: Error handling when SSL is not available.
Fix tests and error handling.
Modified:
qpid/dispatch/trunk/src/server.c
qpid/dispatch/trunk/tests/system_tests_qdstat.py
Modified: qpid/dispatch/trunk/src/server.c
URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/server.c?rev=1665924&r1=1665923&r2=1665924&view=diff
==============================================================================
--- qpid/dispatch/trunk/src/server.c (original)
+++ qpid/dispatch/trunk/src/server.c Wed Mar 11 16:12:23 2015
@@ -101,7 +101,66 @@ qd_error_t qd_entity_refresh_connection(
return qd_error_code();
}
+static qd_error_t listener_setup_ssl(const qd_server_config_t *config, pn_transport_t *tport) {
+ pn_ssl_domain_t *domain = pn_ssl_domain(PN_SSL_MODE_SERVER);
+ if (!domain) return qd_error(QD_ERROR_RUNTIME, "No SSL support");
+
+ // setup my identifying cert:
+ if (pn_ssl_domain_set_credentials(domain,
+ config->ssl_certificate_file,
+ config->ssl_private_key_file,
+ config->ssl_password)) {
+ pn_ssl_domain_free(domain);
+ return qd_error(QD_ERROR_RUNTIME, "Cannot set SSL credentials");
+ }
+ if (config->ssl_allow_unsecured_client) {
+ if (pn_ssl_domain_allow_unsecured_client(domain)) {
+ pn_ssl_domain_free(domain);
+ return qd_error(QD_ERROR_RUNTIME, "Cannot allow unsecured client");
+ }
+ }
+
+ // for peer authentication:
+ if (config->ssl_trusted_certificate_db) {
+ if (pn_ssl_domain_set_trusted_ca_db(domain, config->ssl_trusted_certificate_db)) {
+ pn_ssl_domain_free(domain);
+ return qd_error(QD_ERROR_RUNTIME, "Cannot set truested SSL CA" );
+ }
+ }
+
+ const char *trusted = config->ssl_trusted_certificate_db;
+ if (config->ssl_trusted_certificates)
+ trusted = config->ssl_trusted_certificates;
+
+ // do we force the peer to send a cert?
+ if (config->ssl_require_peer_authentication) {
+ if (!trusted || pn_ssl_domain_set_peer_authentication(domain, PN_SSL_VERIFY_PEER, trusted)) {
+ pn_ssl_domain_free(domain);
+ return qd_error(QD_ERROR_RUNTIME, "Cannot set peer authentication");
+ }
+ }
+
+ pn_ssl_t *ssl = pn_ssl(tport);
+ if (!ssl || pn_ssl_init(ssl, domain, 0)) {
+ pn_ssl_domain_free(domain);
+ return qd_error(QD_ERROR_RUNTIME, "Cannot initialize SSL");
+ }
+
+ return QD_ERROR_NONE;
+}
+
+// Format the identity of an incoming connection to buf for logging
+static const char *log_incoming(char *buf, size_t size, qdpn_connector_t *cxtr)
+{
+ qd_listener_t *qd_listener = qdpn_listener_context(qdpn_connector_listener(cxtr));
+ assert(qd_listener);
+ const char *cname = qdpn_connector_name(cxtr);
+ const char *host = qd_listener->config->host;
+ const char *port = qd_listener->config->port;
+ snprintf(buf, size, "incoming connection from %s to %s:%s", cname, host, port);
+ return buf;
+}
static void thread_process_listeners(qd_server_t *qd_server)
{
@@ -115,17 +174,10 @@ static void thread_process_listeners(qd_
if (!cxtr)
continue;
- // Information for error messages
- qd_listener_t *qd_listener = qdpn_listener_context(listener);
- assert(qd_listener);
- const char *cname = qdpn_connector_name(cxtr);
- const char *host = qd_listener->config->host;
- const char *port = qd_listener->config->port;
- assert(cname && host && port);
-
-#define FROM_TO " connection from %s to %s:%s", cname, host, port
+ char logbuf[qd_log_max_len()];
- qd_log(qd_server->log_source, QD_LOG_DEBUG, "Accepting" FROM_TO);
+ qd_log(qd_server->log_source, QD_LOG_DEBUG, "Accepting %s",
+ log_incoming(logbuf, sizeof(logbuf), cxtr));
ctx = new_qd_connection_t();
DEQ_ITEM_INIT(ctx);
ctx->state = CONN_STATE_OPENING;
@@ -133,7 +185,7 @@ static void thread_process_listeners(qd_
ctx->enqueued = 0;
ctx->pn_cxtr = cxtr;
ctx->collector = 0;
- ctx->listener = qd_listener;
+ ctx->listener = qdpn_listener_context(listener);
ctx->connector = 0;
ctx->context = ctx->listener->context;
ctx->user_context = 0;
@@ -151,6 +203,7 @@ static void thread_process_listeners(qd_
qdpn_connector_set_connection(cxtr, conn);
pn_connection_set_context(conn, ctx);
ctx->pn_conn = conn;
+ qdpn_connector_set_context(cxtr, ctx);
// qd_server->lock is already locked
DEQ_INSERT_TAIL(qd_server->connections, ctx);
@@ -168,60 +221,15 @@ static void thread_process_listeners(qd_
pn_transport_set_server(tport);
pn_transport_set_max_frame(tport, config->max_frame_size);
- //
- // Set up SSL if appropriate
- //
+ // Set up SSL if configured
if (config->ssl_enabled) {
-
- pn_ssl_domain_t *domain = pn_ssl_domain(PN_SSL_MODE_SERVER);
- if (!domain) {
- qd_log(qd_server->log_source, QD_LOG_ERROR, "SSL setup failed on" FROM_TO);
- continue;
- }
-
-#define ERROR(MSG) do { \
- qd_log(qd_server->log_source, QD_LOG_ERROR, MSG FROM_TO); \
- goto ssl_error; \
- } while(0)
-
- // setup my identifying cert:
- if (pn_ssl_domain_set_credentials(domain,
- config->ssl_certificate_file,
- config->ssl_private_key_file,
- config->ssl_password)) {
- ERROR("SSL credentials failed on");
- }
- if (config->ssl_allow_unsecured_client) {
- if (pn_ssl_domain_allow_unsecured_client(domain)) {
- ERROR("SSL cannot allow unsecured client on");
- }
+ qd_log(qd_server->log_source, QD_LOG_TRACE, "Configuring SSL on %s",
+ log_incoming(logbuf, sizeof(logbuf), cxtr));
+ if (listener_setup_ssl(config, tport) != QD_ERROR_NONE) {
+ qd_log(qd_server->log_source, QD_LOG_ERROR, "%s on %s",
+ qd_error_message(), log_incoming(logbuf, sizeof(logbuf), cxtr));
+ qdpn_connector_close(cxtr);
}
-
- // for peer authentication:
- if (config->ssl_trusted_certificate_db) {
- if (pn_ssl_domain_set_trusted_ca_db(domain, config->ssl_trusted_certificate_db)) {
- ERROR("SSL CA configuration failed on" );
- }
- }
-
- const char *trusted = config->ssl_trusted_certificate_db;
- if (config->ssl_trusted_certificates)
- trusted = config->ssl_trusted_certificates;
-
- // do we force the peer to send a cert?
- if (config->ssl_require_peer_authentication) {
- if (pn_ssl_domain_set_peer_authentication(domain, PN_SSL_VERIFY_PEER, trusted)) {
- ERROR("SSL Authentication configuration failed on");
- }
- }
- pn_ssl_t *ssl = pn_ssl(tport);
- if (!ssl || pn_ssl_init(ssl, domain, 0)) {
- ERROR("SSL setup failed");
- }
- qd_log(qd_server->log_source, QD_LOG_TRACE, "Configured SSL on" FROM_TO);
-
- ssl_error:
- pn_ssl_domain_free(domain);
}
//
@@ -233,7 +241,6 @@ static void thread_process_listeners(qd_
pn_sasl_allow_skip(sasl, config->allow_no_sasl);
pn_sasl_done(sasl, PN_SASL_OK); // TODO - This needs to go away
- qdpn_connector_set_context(cxtr, ctx);
ctx->owner_thread = CONTEXT_NO_OWNER;
}
}
Modified: qpid/dispatch/trunk/tests/system_tests_qdstat.py
URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/system_tests_qdstat.py?rev=1665924&r1=1665923&r2=1665924&view=diff
==============================================================================
--- qpid/dispatch/trunk/tests/system_tests_qdstat.py (original)
+++ qpid/dispatch/trunk/tests/system_tests_qdstat.py Wed Mar 11 16:12:23 2015
@@ -22,44 +22,15 @@ import re
import system_test
import unittest
from subprocess import PIPE
-from proton import Url
+from proton import Url, SSLDomain, SSLUnavailable
class QdstatTest(system_test.TestCase):
"""Test qdstat tool output"""
-
- @staticmethod
- def ssl_file(name):
- return os.path.join(os.path.dirname(__file__), 'ssl_certs', name)
-
@classmethod
def setUpClass(cls):
super(QdstatTest, cls).setUpClass()
config = system_test.Qdrouterd.Config([
- ('ssl-profile', {'name': 'server-ssl-strict',
- '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',
- 'allow-unsecured': False,
- 'require-peer-auth': False}),
- ('ssl-profile', {'name': 'server-ssl-unsecured',
- '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',
- 'allow-unsecured': True,
- 'require-peer-auth': False}),
- ('ssl-profile', {'name': 'server-ssl-auth',
- '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',
- 'allow-unsecured': False,
- 'require-peer-auth': True}),
('listener', {'port': cls.tester.get_port()}),
- ('listener', {'port': cls.tester.get_port(), 'ssl-profile': 'server-ssl-strict'}),
- ('listener', {'port': cls.tester.get_port(), 'ssl-profile': 'server-ssl-unsecured'}),
- ('listener', {'port': cls.tester.get_port(), 'ssl-profile': 'server-ssl-auth'})
])
cls.router = cls.tester.qdrouterd('test-router', config)
@@ -97,98 +68,154 @@ class QdstatTest(system_test.TestCase):
def test_log(self):
self.run_qdstat(['--log', '--limit=5'], r'AGENT \(trace\).*GET-LOG')
- def ssl_test(self, url_name, arg_names):
- """Run simple SSL connection test with supplied parameters.
- See test_ssl_* below.
- """
- args = dict(
- trustfile = ['--ssl-trustfile', self.ssl_file('ca-certificate.pem')],
- bad_trustfile = ['--ssl-trustfile', self.ssl_file('bad-ca-certificate.pem')],
- client_cert = ['--ssl-certificate', self.ssl_file('client-certificate.pem')],
- client_key = ['--ssl-key', self.ssl_file('client-private-key.pem')],
- client_pass = ['--ssl-password', 'client-password'])
- args['client_cert_all'] = args['client_cert'] + args['client_key'] + args['client_pass']
-
- addrs = [self.router.addresses[i] for i in xrange(4)];
- urls = dict(zip(['none', 'strict', 'unsecured', 'auth'], addrs) +
- zip(['none_s', 'strict_s', 'unsecured_s', 'auth_s'],
- (Url(a, scheme="amqps") for a in addrs)))
-
- self.run_qdstat(['--general'] + sum([args[n] for n in arg_names], []),
- regexp=r'(?s)Router Statistics.*Mode\s*Standalone',
- address=str(urls[url_name]))
-
- def ssl_test_bad(self, url_name, arg_names):
- self.assertRaises(AssertionError, self.ssl_test, url_name, arg_names)
-
- # Non-SSL enabled listener should fail SSL connections.
- def test_ssl_none(self):
- self.ssl_test('none', [])
-
- def test_ssl_scheme_to_none(self):
- self.ssl_test_bad('none_s', [])
-
- def test_ssl_cert_to_none(self):
- self.ssl_test_bad('none', ['client_cert'])
-
- # Strict SSL listener, SSL only
- def test_ssl_none_to_strict(self):
- self.ssl_test_bad('strict', [])
-
- def test_ssl_schema_to_strict(self):
- self.ssl_test('strict_s', [])
-
- def test_ssl_cert_to_strict(self):
- self.ssl_test('strict_s', ['client_cert_all'])
-
- def test_ssl_trustfile_to_strict(self):
- self.ssl_test('strict_s', ['trustfile'])
-
- def test_ssl_trustfile_cert_to_strict(self):
- self.ssl_test('strict_s', ['trustfile', 'client_cert_all'])
-
- def test_ssl_bad_trustfile_to_strict(self):
- self.ssl_test_bad('strict_s', ['bad_trustfile'])
-
-
- # Require-auth SSL listener
- def test_ssl_none_to_auth(self):
- self.ssl_test_bad('auth', [])
-
- def test_ssl_schema_to_auth(self):
- self.ssl_test_bad('auth_s', [])
-
- def test_ssl_trustfile_to_auth(self):
- self.ssl_test_bad('auth_s', ['trustfile'])
-
- def test_ssl_cert_to_auth(self):
- self.ssl_test('auth_s', ['client_cert_all'])
-
- def test_ssl_trustfile_cert_to_auth(self):
- self.ssl_test('auth_s', ['trustfile', 'client_cert_all'])
-
- def test_ssl_bad_trustfile_to_auth(self):
- self.ssl_test_bad('auth_s', ['bad_trustfile', 'client_cert_all'])
-
-
- # Unsecured SSL listener, allows non-SSL
- def test_ssl_none_to_unsecured(self):
- self.ssl_test('unsecured', [])
-
- def test_ssl_schema_to_unsecured(self):
- self.ssl_test('unsecured_s', [])
-
- def test_ssl_cert_to_unsecured(self):
- self.ssl_test('unsecured_s', ['client_cert_all'])
-
- def test_ssl_trustfile_to_unsecured(self):
- self.ssl_test('unsecured_s', ['trustfile'])
-
- def test_ssl_trustfile_cert_to_unsecured(self):
- self.ssl_test('unsecured_s', ['trustfile', 'client_cert_all'])
-
- def test_ssl_bad_trustfile_to_unsecured(self):
- self.ssl_test_bad('unsecured_s', ['bad_trustfile'])
+try:
+ SSLDomain(SSLDomain.MODE_CLIENT)
+ class QdstatSslTest(system_test.TestCase):
+ """Test qdstat tool output"""
+
+ @staticmethod
+ def ssl_file(name):
+ return os.path.join(os.path.dirname(__file__), 'ssl_certs', name)
+
+ @classmethod
+ def setUpClass(cls):
+ super(QdstatSslTest, cls).setUpClass()
+ config = system_test.Qdrouterd.Config([
+ ('ssl-profile', {'name': 'server-ssl-strict',
+ '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',
+ 'allow-unsecured': False,
+ 'require-peer-auth': False}),
+ ('ssl-profile', {'name': 'server-ssl-unsecured',
+ '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',
+ 'allow-unsecured': True,
+ 'require-peer-auth': False}),
+ ('ssl-profile', {'name': 'server-ssl-auth',
+ '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',
+ 'allow-unsecured': False,
+ 'require-peer-auth': True}),
+ ('listener', {'port': cls.tester.get_port()}),
+ ('listener', {'port': cls.tester.get_port(), 'ssl-profile': 'server-ssl-strict'}),
+ ('listener', {'port': cls.tester.get_port(), 'ssl-profile': 'server-ssl-unsecured'}),
+ ('listener', {'port': cls.tester.get_port(), 'ssl-profile': 'server-ssl-auth'})
+ ])
+ cls.router = cls.tester.qdrouterd('test-router', config)
+
+ def run_qdstat(self, args, regexp=None, address=None):
+ p = self.popen(
+ ['qdstat', '--bus', str(address or self.router.addresses[0]), '--timeout', str(system_test.TIMEOUT) ] + args,
+ 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)
+ if regexp: assert re.search(regexp, out, re.I), "Can't find '%s' in '%s'" % (regexp, out)
+ return out
+
+ def ssl_test(self, url_name, arg_names):
+ """Run simple SSL connection test with supplied parameters.
+ See test_ssl_* below.
+ """
+ args = dict(
+ trustfile = ['--ssl-trustfile', self.ssl_file('ca-certificate.pem')],
+ bad_trustfile = ['--ssl-trustfile', self.ssl_file('bad-ca-certificate.pem')],
+ client_cert = ['--ssl-certificate', self.ssl_file('client-certificate.pem')],
+ client_key = ['--ssl-key', self.ssl_file('client-private-key.pem')],
+ client_pass = ['--ssl-password', 'client-password'])
+ args['client_cert_all'] = args['client_cert'] + args['client_key'] + args['client_pass']
+
+ addrs = [self.router.addresses[i] for i in xrange(4)];
+ urls = dict(zip(['none', 'strict', 'unsecured', 'auth'], addrs) +
+ zip(['none_s', 'strict_s', 'unsecured_s', 'auth_s'],
+ (Url(a, scheme="amqps") for a in addrs)))
+
+ self.run_qdstat(['--general'] + sum([args[n] for n in arg_names], []),
+ regexp=r'(?s)Router Statistics.*Mode\s*Standalone',
+ address=str(urls[url_name]))
+
+ def ssl_test_bad(self, url_name, arg_names):
+ self.assertRaises(AssertionError, self.ssl_test, url_name, arg_names)
+
+ # Non-SSL enabled listener should fail SSL connections.
+ def test_ssl_none(self):
+ self.ssl_test('none', [])
+
+ def test_ssl_scheme_to_none(self):
+ self.ssl_test_bad('none_s', [])
+
+ def test_ssl_cert_to_none(self):
+ self.ssl_test_bad('none', ['client_cert'])
+
+ # Strict SSL listener, SSL only
+ def test_ssl_none_to_strict(self):
+ self.ssl_test_bad('strict', [])
+
+ def test_ssl_schema_to_strict(self):
+ self.ssl_test('strict_s', [])
+
+ def test_ssl_cert_to_strict(self):
+ self.ssl_test('strict_s', ['client_cert_all'])
+
+ def test_ssl_trustfile_to_strict(self):
+ self.ssl_test('strict_s', ['trustfile'])
+
+ def test_ssl_trustfile_cert_to_strict(self):
+ self.ssl_test('strict_s', ['trustfile', 'client_cert_all'])
+
+ def test_ssl_bad_trustfile_to_strict(self):
+ self.ssl_test_bad('strict_s', ['bad_trustfile'])
+
+
+ # Require-auth SSL listener
+ def test_ssl_none_to_auth(self):
+ self.ssl_test_bad('auth', [])
+
+ def test_ssl_schema_to_auth(self):
+ self.ssl_test_bad('auth_s', [])
+
+ def test_ssl_trustfile_to_auth(self):
+ self.ssl_test_bad('auth_s', ['trustfile'])
+
+ def test_ssl_cert_to_auth(self):
+ self.ssl_test('auth_s', ['client_cert_all'])
+
+ def test_ssl_trustfile_cert_to_auth(self):
+ self.ssl_test('auth_s', ['trustfile', 'client_cert_all'])
+
+ def test_ssl_bad_trustfile_to_auth(self):
+ self.ssl_test_bad('auth_s', ['bad_trustfile', 'client_cert_all'])
+
+
+ # Unsecured SSL listener, allows non-SSL
+ def test_ssl_none_to_unsecured(self):
+ self.ssl_test('unsecured', [])
+
+ def test_ssl_schema_to_unsecured(self):
+ self.ssl_test('unsecured_s', [])
+
+ def test_ssl_cert_to_unsecured(self):
+ self.ssl_test('unsecured_s', ['client_cert_all'])
+
+ def test_ssl_trustfile_to_unsecured(self):
+ self.ssl_test('unsecured_s', ['trustfile'])
+
+ def test_ssl_trustfile_cert_to_unsecured(self):
+ self.ssl_test('unsecured_s', ['trustfile', 'client_cert_all'])
+
+ def test_ssl_bad_trustfile_to_unsecured(self):
+ self.ssl_test_bad('unsecured_s', ['bad_trustfile'])
+
+except SSLUnavailable:
+ class QdstatSslTest(system_test.TestCase):
+ def test_skip(self):
+ self.skipTest("Proton SSL support unavailable.")
if __name__ == '__main__':
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org