summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Giusti <kgiusti@gmail.com>2017-04-13 13:46:11 -0400
committerKenneth Giusti <kgiusti@gmail.com>2017-04-13 13:46:11 -0400
commit3b53605bad8b0bf57816f55f37c2bcc491135108 (patch)
tree7537caec82188a69228b9f714ee08b1150b2d28a
parent094f5076f237ca029d79dbed0e90a920e45e9ed2 (diff)
downloadoslo-messaging-3b53605bad8b0bf57816f55f37c2bcc491135108.tar.gz
[AMQP 1.0] Add default SASL realm setting
Change-Id: I2ac680bb9b594f0493dfb6d52c3f40bf5282dec7 Closes-Bug: 1681927
-rw-r--r--oslo_messaging/_drivers/amqp1_driver/controller.py16
-rw-r--r--oslo_messaging/_drivers/amqp1_driver/opts.py4
-rw-r--r--oslo_messaging/tests/drivers/test_amqp_driver.py96
3 files changed, 62 insertions, 54 deletions
diff --git a/oslo_messaging/_drivers/amqp1_driver/controller.py b/oslo_messaging/_drivers/amqp1_driver/controller.py
index f0d073b..1bd3777 100644
--- a/oslo_messaging/_drivers/amqp1_driver/controller.py
+++ b/oslo_messaging/_drivers/amqp1_driver/controller.py
@@ -763,13 +763,14 @@ class NotificationServer(Server):
class Hosts(object):
- """An order list of TransportHost addresses. Connection failover
- progresses from one host to the next. username and password come from the
- configuration and are used only if no username/password was given in the
- URL.
+ """An order list of TransportHost addresses. Connection failover progresses
+ from one host to the next. username, password , and realm come from the
+ configuration and are used only if no username/password/realm is present in
+ the URL.
"""
def __init__(self, entries=None, default_username=None,
- default_password=None):
+ default_password=None,
+ default_realm=None):
if entries:
self._entries = entries[:]
else:
@@ -779,6 +780,8 @@ class Hosts(object):
entry.port = entry.port or 5672
entry.username = entry.username or default_username
entry.password = entry.password or default_password
+ if default_realm and entry.username and '@' not in entry.username:
+ entry.username = entry.username + '@' + default_realm
self._current = random.randint(0, len(self._entries) - 1)
@property
@@ -840,7 +843,8 @@ class Controller(pyngus.ConnectionEventHandler):
self.sasl_config_dir = config.oslo_messaging_amqp.sasl_config_dir
self.sasl_config_name = config.oslo_messaging_amqp.sasl_config_name
self.hosts = Hosts(hosts, config.oslo_messaging_amqp.username,
- config.oslo_messaging_amqp.password)
+ config.oslo_messaging_amqp.password,
+ config.oslo_messaging_amqp.sasl_default_realm)
self.conn_retry_interval = \
config.oslo_messaging_amqp.connection_retry_interval
self.conn_retry_backoff = \
diff --git a/oslo_messaging/_drivers/amqp1_driver/opts.py b/oslo_messaging/_drivers/amqp1_driver/opts.py
index ad53f49..2086030 100644
--- a/oslo_messaging/_drivers/amqp1_driver/opts.py
+++ b/oslo_messaging/_drivers/amqp1_driver/opts.py
@@ -83,6 +83,10 @@ amqp1_opts = [
deprecated_group='amqp1',
help='Name of configuration file (without .conf suffix)'),
+ cfg.StrOpt('sasl_default_realm',
+ default='',
+ help='SASL realm to use if no realm present in username'),
+
cfg.StrOpt('username',
default='',
deprecated_group='amqp1',
diff --git a/oslo_messaging/tests/drivers/test_amqp_driver.py b/oslo_messaging/tests/drivers/test_amqp_driver.py
index 51b67a1..9f7b2a5 100644
--- a/oslo_messaging/tests/drivers/test_amqp_driver.py
+++ b/oslo_messaging/tests/drivers/test_amqp_driver.py
@@ -711,7 +711,7 @@ class TestCyrusAuthentication(test_utils.BaseTestCase):
# the temp dir after the first test is run
os.makedirs(cls._conf_dir)
db = os.path.join(cls._conf_dir, 'openstack.sasldb')
- _t = "echo secret | saslpasswd2 -c -p -f ${db} joe"
+ _t = "echo secret | saslpasswd2 -c -p -f ${db} -u myrealm joe"
cmd = Template(_t).substitute(db=db)
try:
subprocess.check_call(args=cmd, shell=True)
@@ -744,7 +744,7 @@ mech_list: ${mechs}
_dir = TestCyrusAuthentication._conf_dir
self._broker = FakeBroker(self.conf.oslo_messaging_amqp,
sasl_mechanisms=_mechs,
- user_credentials=["\0joe\0secret"],
+ user_credentials=["\0joe@myrealm\0secret"],
sasl_config_dir=_dir,
sasl_config_name="openstack")
self._broker.start()
@@ -757,45 +757,44 @@ mech_list: ${mechs}
self._broker = None
super(TestCyrusAuthentication, self).tearDown()
- def test_authentication_ok(self):
- """Verify that username and password given in TransportHost are
- accepted by the broker.
- """
- addr = "amqp://joe:secret@%s:%d" % (self._broker.host,
- self._broker.port)
+ def _authentication_test(self, addr, retry=None):
url = oslo_messaging.TransportURL.parse(self.conf, addr)
driver = amqp_driver.ProtonDriver(self.conf, url)
target = oslo_messaging.Target(topic="test-topic")
listener = _ListenerThread(
driver.listen(target, None, None)._poll_style_listener, 1)
- rc = driver.send(target, {"context": True},
- {"method": "echo"}, wait_for_reply=True)
- self.assertIsNotNone(rc)
- listener.join(timeout=30)
- self.assertFalse(listener.isAlive())
- driver.cleanup()
+ try:
+ rc = driver.send(target, {"context": True},
+ {"method": "echo"}, wait_for_reply=True,
+ retry=retry)
+ self.assertIsNotNone(rc)
+ listener.join(timeout=30)
+ self.assertFalse(listener.isAlive())
+ finally:
+ driver.cleanup()
+
+ def test_authentication_ok(self):
+ """Verify that username and password given in TransportHost are
+ accepted by the broker.
+ """
+ addr = "amqp://joe@myrealm:secret@%s:%d" % (self._broker.host,
+ self._broker.port)
+ self._authentication_test(addr)
def test_authentication_failure(self):
"""Verify that a bad password given in TransportHost is
rejected by the broker.
"""
- addr = "amqp://joe:badpass@%s:%d" % (self._broker.host,
- self._broker.port)
- url = oslo_messaging.TransportURL.parse(self.conf, addr)
- driver = amqp_driver.ProtonDriver(self.conf, url)
- target = oslo_messaging.Target(topic="test-topic")
- _ListenerThread(
- driver.listen(target, None, None)._poll_style_listener, 1)
+ addr = "amqp://joe@myrealm:badpass@%s:%d" % (self._broker.host,
+ self._broker.port)
try:
- driver.send(target, {"context": True}, {"method": "echo"},
- wait_for_reply=True, retry=2)
+ self._authentication_test(addr, retry=2)
except oslo_messaging.MessageDeliveryFailure as e:
# verify the exception indicates the failure was an authentication
# error
self.assertTrue('amqp:unauthorized-access' in str(e))
else:
self.assertIsNone("Expected authentication failure")
- driver.cleanup()
def test_authentication_bad_mechs(self):
"""Verify that the connection fails if the client's SASL mechanisms do
@@ -803,40 +802,41 @@ mech_list: ${mechs}
"""
self.config(sasl_mechanisms="EXTERNAL ANONYMOUS",
group="oslo_messaging_amqp")
- addr = "amqp://joe:secret@%s:%d" % (self._broker.host,
- self._broker.port)
- url = oslo_messaging.TransportURL.parse(self.conf, addr)
- driver = amqp_driver.ProtonDriver(self.conf, url)
- target = oslo_messaging.Target(topic="test-topic")
- _ListenerThread(
- driver.listen(target, None, None)._poll_style_listener, 1)
+ addr = "amqp://joe@myrealm:secret@%s:%d" % (self._broker.host,
+ self._broker.port)
self.assertRaises(oslo_messaging.MessageDeliveryFailure,
- driver.send,
- target, {"context": True},
- {"method": "echo"},
- wait_for_reply=True,
+ self._authentication_test,
+ addr,
retry=0)
- driver.cleanup()
def test_authentication_default_username(self):
"""Verify that a configured username/password is used if none appears
in the URL.
+ Deprecated: username password deprecated in favor of transport_url
"""
addr = "amqp://%s:%d" % (self._broker.host, self._broker.port)
- self.config(username="joe",
+ self.config(username="joe@myrealm",
password="secret",
group="oslo_messaging_amqp")
- url = oslo_messaging.TransportURL.parse(self.conf, addr)
- driver = amqp_driver.ProtonDriver(self.conf, url)
- target = oslo_messaging.Target(topic="test-topic")
- listener = _ListenerThread(
- driver.listen(target, None, None)._poll_style_listener, 1)
- rc = driver.send(target, {"context": True},
- {"method": "echo"}, wait_for_reply=True)
- self.assertIsNotNone(rc)
- listener.join(timeout=30)
- self.assertFalse(listener.isAlive())
- driver.cleanup()
+ self._authentication_test(addr)
+
+ def test_authentication_default_realm(self):
+ """Verify that default realm is used if none present in username"""
+ addr = "amqp://joe:secret@%s:%d" % (self._broker.host,
+ self._broker.port)
+ self.config(sasl_default_realm="myrealm",
+ group="oslo_messaging_amqp")
+ self._authentication_test(addr)
+
+ def test_authentication_ignore_default_realm(self):
+ """Verify that default realm is not used if realm present in
+ username
+ """
+ addr = "amqp://joe@myrealm:secret@%s:%d" % (self._broker.host,
+ self._broker.port)
+ self.config(sasl_default_realm="bad-realm",
+ group="oslo_messaging_amqp")
+ self._authentication_test(addr)
@testtools.skipUnless(pyngus, "proton modules not present")