Package: release.debian.org Severity: normal User: [email protected] Usertags: unblock
Dear release team, Moritz Mühlenhoff (aka jmm) made me aware of CVE-2014-7231, which has been fixed in the release 0.2.0 of python-oslo.utils. This version has never been uploaded to Sid (I uploaded it to Experimental instead), as I didn't want to risk changing anything in OpenStack Icehouse in Jessie. But since it fixes CVE-2014-7231, I'd like now to have version 0.2.0 replacing version 0.1.1 in Jessie. Indeed, the patch available here: https://review.openstack.org/gitweb?p=openstack%2Foslo.utils.git;a=commitdiff;h=e0425691d90bce0bbe847a9ff49468ce0fab5486 which fixes the issue, cannot be applied on top of version 0.1.1. I don't want to risk doing a backport by myself, and would very much prefer to use what's been done by upstream, which is "gated" (eg: tested by a CI / CD system). Note that upstream currently declares that any version of python-oslo.utils lower than version 1.0.0 can work with OpenStack Icehouse currently in Jessie, as per the "global-requirements.txt" maintained for OpenStack Icehouse: https://github.com/openstack/requirements/blob/stable/icehouse/global-requirements.txt#L53 So even version 0.3.0 would work, and may even be preferred, since that's what the OpenStack gate uses right now to test Icehouse. I have attached the debdiff between 0.1.1-1, and 0.2.0-1 (as per the package I uploaded in Experimental, available in snapshot.d.o). Will the release team accept such an unblock? Do I have your go-ahead to upload version 0.2.0-1 to Sid? Cheers, Thomas Goirand (zigo)
diff -Nru python-oslo.utils-0.1.1/debian/changelog python-oslo.utils-0.2.0/debian/changelog --- python-oslo.utils-0.1.1/debian/changelog 2014-08-07 10:19:33.000000000 +0200 +++ python-oslo.utils-0.2.0/debian/changelog 2014-09-05 10:07:10.000000000 +0200 @@ -1,3 +1,10 @@ +python-oslo.utils (0.2.0-1) experimental; urgency=medium + + * New upstream release. + * Uploading to experimental before Jessie's freeze. + + -- Thomas Goirand <[email protected]> Fri, 05 Sep 2014 15:50:43 +0800 + python-oslo.utils (0.1.1-1) unstable; urgency=medium * Initial release. (Closes: #757325) diff -Nru python-oslo.utils-0.1.1/debian/gbp.conf python-oslo.utils-0.2.0/debian/gbp.conf --- python-oslo.utils-0.1.1/debian/gbp.conf 2014-08-07 10:19:33.000000000 +0200 +++ python-oslo.utils-0.2.0/debian/gbp.conf 2014-09-05 10:07:10.000000000 +0200 @@ -1,6 +1,6 @@ [DEFAULT] upstream-branch = master -debian-branch = debian/unstable +debian-branch = debian/experimental upstream-tag = %(version)s compression = xz diff -Nru python-oslo.utils-0.1.1/debian/rules python-oslo.utils-0.2.0/debian/rules --- python-oslo.utils-0.1.1/debian/rules 2014-08-07 10:19:33.000000000 +0200 +++ python-oslo.utils-0.2.0/debian/rules 2014-09-05 10:07:10.000000000 +0200 @@ -24,18 +24,18 @@ override_dh_auto_test: ifeq (,$(findstring nocheck, $(DEB_BUILD_OPTIONS))) - @echo "===> Running tests" - set -e && set -x && for i in 2.7 $(PYTHON3S) ; do \ - PYMAJOR=`echo $$i | cut -d'.' -f1` ; \ - echo "===> Testing with python$$i (python$$PYMAJOR)" ; \ - rm -rf .testrepository ; \ - testr-python$$PYMAJOR init ; \ - TEMP_REZ=`mktemp -t` && \ - PYTHONPATH=$(CURDIR) PYTHON=python$$i testr-python$$PYMAJOR run --subunit | tee $$TEMP_REZ | subunit2pyunit ; \ - cat $$TEMP_REZ | subunit-filter -s --no-passthrough | subunit-stats ; \ - rm -f $$TEMP_REZ ; \ - testr-python$$PYMAJOR slowest ; \ - done + @echo "===> Running tests" + set -e ; set -x ; for i in 2.7 ; do \ + PYMAJOR=`echo $$i | cut -d'.' -f1` ; \ + echo "===> Testing with python$$i (python$$PYMAJOR)" ; \ + rm -rf .testrepository ; \ + testr-python$$PYMAJOR init ; \ + TEMP_REZ=`mktemp -t` ; \ + PYTHONPATH=$(CURDIR) PYTHON=python$$i testr-python$$PYMAJOR run --subunit | tee $$TEMP_REZ | subunit2pyunit ; \ + cat $$TEMP_REZ | subunit-filter -s --no-passthrough | subunit-stats ; \ + rm -f $$TEMP_REZ ; \ + testr-python$$PYMAJOR slowest ; \ + done endif override_dh_clean: diff -Nru python-oslo.utils-0.1.1/oslo/utils/strutils.py python-oslo.utils-0.2.0/oslo/utils/strutils.py --- python-oslo.utils-0.1.1/oslo/utils/strutils.py 2014-07-28 19:20:33.000000000 +0200 +++ python-oslo.utils-0.2.0/oslo/utils/strutils.py 2014-08-15 19:53:57.000000000 +0200 @@ -50,6 +50,39 @@ SLUGIFY_HYPHENATE_RE = re.compile(r"[-\s]+") +# NOTE(flaper87): The following globals are used by `mask_password` +_SANITIZE_KEYS = ['adminPass', 'admin_pass', 'password', 'admin_password'] + +# NOTE(ldbragst): Let's build a list of regex objects using the list of +# _SANITIZE_KEYS we already have. This way, we only have to add the new key +# to the list of _SANITIZE_KEYS and we can generate regular expressions +# for XML and JSON automatically. +_SANITIZE_PATTERNS_2 = [] +_SANITIZE_PATTERNS_1 = [] + +# NOTE(amrith): Some regular expressions have only one parameter, some +# have two parameters. Use different lists of patterns here. +_FORMAT_PATTERNS_1 = [r'(%(key)s\s*[=]\s*)[^\s^\'^\"]+'] +_FORMAT_PATTERNS_2 = [r'(%(key)s\s*[=]\s*[\"\']).*?([\"\'])', + r'(%(key)s\s+[\"\']).*?([\"\'])', + r'([-]{2}%(key)s\s+)[^\'^\"^=^\s]+([\s]*)', + r'(<%(key)s>).*?(</%(key)s>)', + r'([\"\']%(key)s[\"\']\s*:\s*[\"\']).*?([\"\'])', + r'([\'"].*?%(key)s[\'"]\s*:\s*u?[\'"]).*?([\'"])', + r'([\'"].*?%(key)s[\'"]\s*,\s*\'--?[A-z]+\'\s*,\s*u?' + '[\'"]).*?([\'"])', + r'(%(key)s\s*--?[A-z]+\s*)\S+(\s*)'] + +for key in _SANITIZE_KEYS: + for pattern in _FORMAT_PATTERNS_2: + reg_ex = re.compile(pattern % {'key': key}, re.DOTALL) + _SANITIZE_PATTERNS_2.append(reg_ex) + + for pattern in _FORMAT_PATTERNS_1: + reg_ex = re.compile(pattern % {'key': key}, re.DOTALL) + _SANITIZE_PATTERNS_1.append(reg_ex) + + def int_from_bool_as_string(subject): """Interpret a string as a boolean and return either 1 or 0. @@ -166,3 +199,42 @@ "ascii", "ignore").decode("ascii") value = SLUGIFY_STRIP_RE.sub("", value).strip().lower() return SLUGIFY_HYPHENATE_RE.sub("-", value) + + +def mask_password(message, secret="***"): + """Replace password with 'secret' in message. + + :param message: The string which includes security information. + :param secret: value with which to replace passwords. + :returns: The unicode value of message with the password fields masked. + + For example: + + >>> mask_password("'adminPass' : 'aaaaa'") + "'adminPass' : '***'" + >>> mask_password("'admin_pass' : 'aaaaa'") + "'admin_pass' : '***'" + >>> mask_password('"password" : "aaaaa"') + '"password" : "***"' + >>> mask_password("'original_password' : 'aaaaa'") + "'original_password' : '***'" + >>> mask_password("u'original_password' : u'aaaaa'") + "u'original_password' : u'***'" + """ + message = six.text_type(message) + + # NOTE(ldbragst): Check to see if anything in message contains any key + # specified in _SANITIZE_KEYS, if not then just return the message since + # we don't have to mask any passwords. + if not any(key in message for key in _SANITIZE_KEYS): + return message + + substitute = r'\g<1>' + secret + r'\g<2>' + for pattern in _SANITIZE_PATTERNS_2: + message = re.sub(pattern, substitute, message) + + substitute = r'\g<1>' + secret + for pattern in _SANITIZE_PATTERNS_1: + message = re.sub(pattern, substitute, message) + + return message diff -Nru python-oslo.utils-0.1.1/oslo.utils/locale/oslo.utils-log-critical.pot python-oslo.utils-0.2.0/oslo.utils/locale/oslo.utils-log-critical.pot --- python-oslo.utils-0.1.1/oslo.utils/locale/oslo.utils-log-critical.pot 1970-01-01 01:00:00.000000000 +0100 +++ python-oslo.utils-0.2.0/oslo.utils/locale/oslo.utils-log-critical.pot 2014-08-15 19:53:57.000000000 +0200 @@ -0,0 +1,19 @@ +# Translations template for oslo.utils. +# Copyright (C) 2014 ORGANIZATION +# This file is distributed under the same license as the oslo.utils project. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2014. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: oslo.utils 0.1.1\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2014-08-11 06:10+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" + diff -Nru python-oslo.utils-0.1.1/oslo.utils/locale/oslo.utils-log-error.pot python-oslo.utils-0.2.0/oslo.utils/locale/oslo.utils-log-error.pot --- python-oslo.utils-0.1.1/oslo.utils/locale/oslo.utils-log-error.pot 1970-01-01 01:00:00.000000000 +0100 +++ python-oslo.utils-0.2.0/oslo.utils/locale/oslo.utils-log-error.pot 2014-08-15 19:53:57.000000000 +0200 @@ -0,0 +1,29 @@ +# Translations template for oslo.utils. +# Copyright (C) 2014 ORGANIZATION +# This file is distributed under the same license as the oslo.utils project. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2014. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: oslo.utils 0.1.1\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2014-08-11 06:10+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" + +#: oslo/utils/excutils.py:76 +#, python-format +msgid "Original exception being dropped: %s" +msgstr "" + +#: oslo/utils/excutils.py:105 +#, python-format +msgid "Unexpected exception occurred %d time(s)... retrying." +msgstr "" + diff -Nru python-oslo.utils-0.1.1/oslo.utils/locale/oslo.utils-log-info.pot python-oslo.utils-0.2.0/oslo.utils/locale/oslo.utils-log-info.pot --- python-oslo.utils-0.1.1/oslo.utils/locale/oslo.utils-log-info.pot 1970-01-01 01:00:00.000000000 +0100 +++ python-oslo.utils-0.2.0/oslo.utils/locale/oslo.utils-log-info.pot 2014-08-15 19:53:57.000000000 +0200 @@ -0,0 +1,19 @@ +# Translations template for oslo.utils. +# Copyright (C) 2014 ORGANIZATION +# This file is distributed under the same license as the oslo.utils project. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2014. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: oslo.utils 0.1.1\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2014-08-11 06:10+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" + diff -Nru python-oslo.utils-0.1.1/oslo.utils/locale/oslo.utils-log-warning.pot python-oslo.utils-0.2.0/oslo.utils/locale/oslo.utils-log-warning.pot --- python-oslo.utils-0.1.1/oslo.utils/locale/oslo.utils-log-warning.pot 1970-01-01 01:00:00.000000000 +0100 +++ python-oslo.utils-0.2.0/oslo.utils/locale/oslo.utils-log-warning.pot 2014-08-15 19:53:57.000000000 +0200 @@ -0,0 +1,31 @@ +# Translations template for oslo.utils. +# Copyright (C) 2014 ORGANIZATION +# This file is distributed under the same license as the oslo.utils project. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2014. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: oslo.utils 0.1.1\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2014-08-11 06:10+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <[email protected]>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" + +#: oslo/utils/netutils.py:151 +msgid "tcp_keepidle not available on your system" +msgstr "" + +#: oslo/utils/netutils.py:158 +msgid "tcp_keepintvl not available on your system" +msgstr "" + +#: oslo/utils/netutils.py:165 +msgid "tcp_keepcnt not available on your system" +msgstr "" + diff -Nru python-oslo.utils-0.1.1/oslo.utils/locale/oslo.utils.pot python-oslo.utils-0.2.0/oslo.utils/locale/oslo.utils.pot --- python-oslo.utils-0.1.1/oslo.utils/locale/oslo.utils.pot 2014-07-28 19:20:33.000000000 +0200 +++ python-oslo.utils-0.2.0/oslo.utils/locale/oslo.utils.pot 2014-08-15 19:53:57.000000000 +0200 @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: oslo.utils 5621114\n" +"Project-Id-Version: oslo.utils 0.1.1\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2014-07-11 13:25+0200\n" +"POT-Creation-Date: 2014-08-11 06:10+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <[email protected]>\n" @@ -17,48 +17,18 @@ "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 1.3\n" -#: oslo/utils/strutils.py:92 oslo/utils/openstack/common/strutils.py:92 +#: oslo/utils/strutils.py:92 #, python-format msgid "Unrecognized value '%(val)s', acceptable values are: %(acceptable)s" msgstr "" -#: oslo/utils/strutils.py:197 oslo/utils/openstack/common/strutils.py:197 +#: oslo/utils/strutils.py:126 #, python-format msgid "Invalid unit system: \"%s\"" msgstr "" -#: oslo/utils/strutils.py:206 oslo/utils/openstack/common/strutils.py:206 +#: oslo/utils/strutils.py:135 #, python-format msgid "Invalid string format: %s" msgstr "" -#: oslo/utils/openstack/common/gettextutils.py:320 -msgid "Message objects do not support addition." -msgstr "" - -#: oslo/utils/openstack/common/gettextutils.py:330 -msgid "" -"Message objects do not support str() because they may contain non-ascii " -"characters. Please use unicode() or translate() instead." -msgstr "" - -#: oslo/utils/openstack/common/log.py:327 -#, python-format -msgid "Deprecated: %s" -msgstr "" - -#: oslo/utils/openstack/common/log.py:436 -#, python-format -msgid "Error loading logging config %(log_config)s: %(err_msg)s" -msgstr "" - -#: oslo/utils/openstack/common/log.py:487 -#, python-format -msgid "syslog facility must be one of: %s" -msgstr "" - -#: oslo/utils/openstack/common/log.py:725 -#, python-format -msgid "Fatal call to deprecated config: %(msg)s" -msgstr "" - diff -Nru python-oslo.utils-0.1.1/tests/test_strutils.py python-oslo.utils-0.2.0/tests/test_strutils.py --- python-oslo.utils-0.1.1/tests/test_strutils.py 2014-07-28 19:20:33.000000000 +0200 +++ python-oslo.utils-0.2.0/tests/test_strutils.py 2014-08-15 19:53:57.000000000 +0200 @@ -259,3 +259,290 @@ self.assertAlmostEqual(actual, expected) StringToBytesTest.generate_scenarios() + + +class MaskPasswordTestCase(test_base.BaseTestCase): + + def test_json(self): + # Test 'adminPass' w/o spaces + payload = """{'adminPass':'mypassword'}""" + expected = """{'adminPass':'***'}""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'adminPass' with spaces + payload = """{ 'adminPass' : 'mypassword' }""" + expected = """{ 'adminPass' : '***' }""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'admin_pass' w/o spaces + payload = """{'admin_pass':'mypassword'}""" + expected = """{'admin_pass':'***'}""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'admin_pass' with spaces + payload = """{ 'admin_pass' : 'mypassword' }""" + expected = """{ 'admin_pass' : '***' }""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'admin_password' w/o spaces + payload = """{'admin_password':'mypassword'}""" + expected = """{'admin_password':'***'}""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'admin_password' with spaces + payload = """{ 'admin_password' : 'mypassword' }""" + expected = """{ 'admin_password' : '***' }""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'password' w/o spaces + payload = """{'password':'mypassword'}""" + expected = """{'password':'***'}""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'password' with spaces + payload = """{ 'password' : 'mypassword' }""" + expected = """{ 'password' : '***' }""" + self.assertEqual(expected, strutils.mask_password(payload)) + + def test_xml(self): + # Test 'adminPass' w/o spaces + payload = """<adminPass>mypassword</adminPass>""" + expected = """<adminPass>***</adminPass>""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'adminPass' with spaces + payload = """<adminPass> + mypassword + </adminPass>""" + expected = """<adminPass>***</adminPass>""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'admin_pass' w/o spaces + payload = """<admin_pass>mypassword</admin_pass>""" + expected = """<admin_pass>***</admin_pass>""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'admin_pass' with spaces + payload = """<admin_pass> + mypassword + </admin_pass>""" + expected = """<admin_pass>***</admin_pass>""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'admin_password' w/o spaces + payload = """<admin_password>mypassword</admin_password>""" + expected = """<admin_password>***</admin_password>""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'admin_password' with spaces + payload = """<admin_password> + mypassword + </admin_password>""" + expected = """<admin_password>***</admin_password>""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'password' w/o spaces + payload = """<password>mypassword</password>""" + expected = """<password>***</password>""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'password' with spaces + payload = """<password> + mypassword + </password>""" + expected = """<password>***</password>""" + self.assertEqual(expected, strutils.mask_password(payload)) + + def test_xml_attribute(self): + # Test 'adminPass' w/o spaces + payload = """adminPass='mypassword'""" + expected = """adminPass='***'""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'adminPass' with spaces + payload = """adminPass = 'mypassword'""" + expected = """adminPass = '***'""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'adminPass' with double quotes + payload = """adminPass = "mypassword\"""" + expected = """adminPass = "***\"""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'admin_pass' w/o spaces + payload = """admin_pass='mypassword'""" + expected = """admin_pass='***'""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'admin_pass' with spaces + payload = """admin_pass = 'mypassword'""" + expected = """admin_pass = '***'""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'admin_pass' with double quotes + payload = """admin_pass = "mypassword\"""" + expected = """admin_pass = "***\"""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'admin_password' w/o spaces + payload = """admin_password='mypassword'""" + expected = """admin_password='***'""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'admin_password' with spaces + payload = """admin_password = 'mypassword'""" + expected = """admin_password = '***'""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'admin_password' with double quotes + payload = """admin_password = "mypassword\"""" + expected = """admin_password = "***\"""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'password' w/o spaces + payload = """password='mypassword'""" + expected = """password='***'""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'password' with spaces + payload = """password = 'mypassword'""" + expected = """password = '***'""" + self.assertEqual(expected, strutils.mask_password(payload)) + # Test 'password' with double quotes + payload = """password = "mypassword\"""" + expected = """password = "***\"""" + self.assertEqual(expected, strutils.mask_password(payload)) + + def test_json_message(self): + payload = """body: {"changePassword": {"adminPass": "1234567"}}""" + expected = """body: {"changePassword": {"adminPass": "***"}}""" + self.assertEqual(expected, strutils.mask_password(payload)) + payload = """body: {"rescue": {"admin_pass": "1234567"}}""" + expected = """body: {"rescue": {"admin_pass": "***"}}""" + self.assertEqual(expected, strutils.mask_password(payload)) + payload = """body: {"rescue": {"admin_password": "1234567"}}""" + expected = """body: {"rescue": {"admin_password": "***"}}""" + self.assertEqual(expected, strutils.mask_password(payload)) + payload = """body: {"rescue": {"password": "1234567"}}""" + expected = """body: {"rescue": {"password": "***"}}""" + self.assertEqual(expected, strutils.mask_password(payload)) + + def test_xml_message(self): + payload = """<?xml version="1.0" encoding="UTF-8"?> +<rebuild + xmlns="http://docs.openstack.org/compute/api/v1.1" + name="foobar" + imageRef="http://openstack.example.com/v1.1/32278/images/70a599e0-31e7" + accessIPv4="1.2.3.4" + accessIPv6="fe80::100" + adminPass="seekr3t"> + <metadata> + <meta key="My Server Name">Apache1</meta> + </metadata> +</rebuild>""" + expected = """<?xml version="1.0" encoding="UTF-8"?> +<rebuild + xmlns="http://docs.openstack.org/compute/api/v1.1" + name="foobar" + imageRef="http://openstack.example.com/v1.1/32278/images/70a599e0-31e7" + accessIPv4="1.2.3.4" + accessIPv6="fe80::100" + adminPass="***"> + <metadata> + <meta key="My Server Name">Apache1</meta> + </metadata> +</rebuild>""" + self.assertEqual(expected, strutils.mask_password(payload)) + payload = """<?xml version="1.0" encoding="UTF-8"?> +<rescue xmlns="http://docs.openstack.org/compute/api/v1.1" + admin_pass="MySecretPass"/>""" + expected = """<?xml version="1.0" encoding="UTF-8"?> +<rescue xmlns="http://docs.openstack.org/compute/api/v1.1" + admin_pass="***"/>""" + self.assertEqual(expected, strutils.mask_password(payload)) + payload = """<?xml version="1.0" encoding="UTF-8"?> +<rescue xmlns="http://docs.openstack.org/compute/api/v1.1" + admin_password="MySecretPass"/>""" + expected = """<?xml version="1.0" encoding="UTF-8"?> +<rescue xmlns="http://docs.openstack.org/compute/api/v1.1" + admin_password="***"/>""" + self.assertEqual(expected, strutils.mask_password(payload)) + payload = """<?xml version="1.0" encoding="UTF-8"?> +<rescue xmlns="http://docs.openstack.org/compute/api/v1.1" + password="MySecretPass"/>""" + expected = """<?xml version="1.0" encoding="UTF-8"?> +<rescue xmlns="http://docs.openstack.org/compute/api/v1.1" + password="***"/>""" + self.assertEqual(expected, strutils.mask_password(payload)) + + def test_mask_password(self): + payload = "test = 'password' : 'aaaaaa'" + expected = "test = 'password' : '111'" + self.assertEqual(expected, + strutils.mask_password(payload, secret='111')) + + payload = 'mysqld --password "aaaaaa"' + expected = 'mysqld --password "****"' + self.assertEqual(expected, + strutils.mask_password(payload, secret='****')) + + payload = 'mysqld --password aaaaaa' + expected = 'mysqld --password ???' + self.assertEqual(expected, + strutils.mask_password(payload, secret='???')) + + payload = 'mysqld --password = "aaaaaa"' + expected = 'mysqld --password = "****"' + self.assertEqual(expected, + strutils.mask_password(payload, secret='****')) + + payload = "mysqld --password = 'aaaaaa'" + expected = "mysqld --password = '****'" + self.assertEqual(expected, + strutils.mask_password(payload, secret='****')) + + payload = "mysqld --password = aaaaaa" + expected = "mysqld --password = ****" + self.assertEqual(expected, + strutils.mask_password(payload, secret='****')) + + payload = "test = password = aaaaaa" + expected = "test = password = 111" + self.assertEqual(expected, + strutils.mask_password(payload, secret='111')) + + payload = "test = password= aaaaaa" + expected = "test = password= 111" + self.assertEqual(expected, + strutils.mask_password(payload, secret='111')) + + payload = "test = password =aaaaaa" + expected = "test = password =111" + self.assertEqual(expected, + strutils.mask_password(payload, secret='111')) + + payload = "test = password=aaaaaa" + expected = "test = password=111" + self.assertEqual(expected, + strutils.mask_password(payload, secret='111')) + + payload = 'test = "original_password" : "aaaaaaaaa"' + expected = 'test = "original_password" : "***"' + self.assertEqual(expected, strutils.mask_password(payload)) + + payload = 'test = "param1" : "value"' + expected = 'test = "param1" : "value"' + self.assertEqual(expected, strutils.mask_password(payload)) + + payload = """{'adminPass':'mypassword'}""" + payload = six.text_type(payload) + expected = """{'adminPass':'***'}""" + self.assertEqual(expected, strutils.mask_password(payload)) + + payload = ("test = 'node.session.auth.password','-v','mypassword'," + "'nomask'") + expected = ("test = 'node.session.auth.password','-v','***'," + "'nomask'") + self.assertEqual(expected, strutils.mask_password(payload)) + + payload = ("test = 'node.session.auth.password', '--password', " + "'mypassword', 'nomask'") + expected = ("test = 'node.session.auth.password', '--password', " + "'***', 'nomask'") + self.assertEqual(expected, strutils.mask_password(payload)) + + payload = ("test = 'node.session.auth.password', '--password', " + "'mypassword'") + expected = ("test = 'node.session.auth.password', '--password', " + "'***'") + self.assertEqual(expected, strutils.mask_password(payload)) + + payload = "test = node.session.auth.password -v mypassword nomask" + expected = "test = node.session.auth.password -v *** nomask" + self.assertEqual(expected, strutils.mask_password(payload)) + + payload = ("test = node.session.auth.password --password mypassword " + "nomask") + expected = ("test = node.session.auth.password --password *** " + "nomask") + self.assertEqual(expected, strutils.mask_password(payload)) + + payload = ("test = node.session.auth.password --password mypassword") + expected = ("test = node.session.auth.password --password ***") + self.assertEqual(expected, strutils.mask_password(payload))

