Fix signature validation failure when using qpid message queue

When using qpid message queue, the metering message will get
signature validation failure because of extra unicode encoding
given by json loads. This change peels off unicode of the message
so that this issue can be avoided.

Change-Id: Ia23af789460ad8597867902f713b8a78f4a09e06
Closes-Bug: 1373356
This commit is contained in:
Feng Xi Yan
2014-09-24 18:37:02 +08:00
parent aee04936af
commit 4166da70b3
2 changed files with 26 additions and 24 deletions

View File

@@ -72,7 +72,7 @@ class TestUtils(base.BaseTestCase):
big = 1 << 64 big = 1 << 64
expected = [('a', 'A'), expected = [('a', 'A'),
('b', 'B'), ('b', 'B'),
('nested:list', ['{%d: 99, %d: 42}' % (small, big)])] ('nested:list', [{small: 99, big: 42}])]
data = {'a': 'A', data = {'a': 'A',
'b': 'B', 'b': 'B',
'nested': {'list': [{small: 99, big: 42}]}} 'nested': {'list': [{small: 99, big: 42}]}}
@@ -82,14 +82,8 @@ class TestUtils(base.BaseTestCase):
# the keys 1 and 1<<64 cause a hash collision on 64bit platforms # the keys 1 and 1<<64 cause a hash collision on 64bit platforms
if k == 'nested:list': if k == 'nested:list':
self.assertIn(v, self.assertIn(v,
[[('{%d: 99, %d: 42}' [[{small: 99, big: 42}],
% (small, big)).encode('ascii')], [{big: 42, small: 99}]])
[('{%d: 99, %dL: 42}'
% (small, big)).encode('ascii')],
[('{%d: 42, %d: 99}'
% (big, small)).encode('ascii')],
[('{%dL: 42, %d: 99}'
% (big, small)).encode('ascii')]])
else: else:
self.assertIn((k, v), expected) self.assertIn((k, v), expected)

View File

@@ -33,7 +33,6 @@ from oslo.utils import timeutils
from oslo.utils import units from oslo.utils import units
import six import six
rootwrap_conf = cfg.StrOpt('rootwrap_config', rootwrap_conf = cfg.StrOpt('rootwrap_config',
default="/etc/ceilometer/rootwrap.conf", default="/etc/ceilometer/rootwrap.conf",
help='Path to the rootwrap configuration file to' help='Path to the rootwrap configuration file to'
@@ -53,6 +52,28 @@ def execute(*cmd, **kwargs):
return processutils.execute(*cmd, **kwargs) return processutils.execute(*cmd, **kwargs)
def decode_unicode(input):
"""Decode the unicode of the message, and encode it into utf-8."""
if isinstance(input, dict):
temp = {}
# If the input data is a dict, create an equivalent dict with a
# predictable insertion order to avoid inconsistencies in the
# message signature computation for equivalent payloads modulo
# ordering
for key, value in sorted(six.iteritems(input)):
temp[decode_unicode(key)] = decode_unicode(value)
return temp
elif isinstance(input, (tuple, list)):
# When doing a pair of JSON encode/decode operations to the tuple,
# the tuple would become list. So we have to generate the value as
# list here.
return [decode_unicode(element) for element in input]
elif isinstance(input, six.text_type):
return input.encode('utf-8')
else:
return input
def recursive_keypairs(d, separator=':'): def recursive_keypairs(d, separator=':'):
"""Generator that produces sequence of keypairs for nested dictionaries.""" """Generator that produces sequence of keypairs for nested dictionaries."""
for name, value in sorted(six.iteritems(d)): for name, value in sorted(six.iteritems(d)):
@@ -60,20 +81,7 @@ def recursive_keypairs(d, separator=':'):
for subname, subvalue in recursive_keypairs(value, separator): for subname, subvalue in recursive_keypairs(value, separator):
yield ('%s%s%s' % (name, separator, subname), subvalue) yield ('%s%s%s' % (name, separator, subname), subvalue)
elif isinstance(value, (tuple, list)): elif isinstance(value, (tuple, list)):
# When doing a pair of JSON encode/decode operations to the tuple, yield name, decode_unicode(value)
# the tuple would become list. So we have to generate the value as
# list here.
# in the special case of the list item itself being a dict,
# create an equivalent dict with a predictable insertion order
# to avoid inconsistencies in the message signature computation
# for equivalent payloads modulo ordering
first = lambda i: i[0]
m = map(lambda x: six.text_type(dict(sorted(x.items(), key=first))
if isinstance(x, dict)
else x).encode('utf-8'),
value)
yield name, list(m)
else: else:
yield name, value yield name, value