Michael Merickel
2014-11-17 e07af13b19b8fb00a393bb91b950b516cfca1cb6
Merge branch 'master' into feature.security-docs-enhancements
5 files modified
102 ■■■■ changed files
.travis.yml 22 ●●●● patch | view | raw | blame | history
CHANGES.txt 5 ●●●●● patch | view | raw | blame | history
pyramid/tests/test_util.py 43 ●●●●● patch | view | raw | blame | history
pyramid/util.py 30 ●●●● patch | view | raw | blame | history
tox.ini 2 ●●● patch | view | raw | blame | history
.travis.yml
@@ -1,18 +1,20 @@
# Wire up travis
language: python
python:
  - 2.6
  - 2.7
  - pypy
  - 3.2
  - 3.3
  - 3.4
  - pypy3
env:
  - TOXENV=py26
  - TOXENV=py27
  - TOXENV=py32
  - TOXENV=py33
  - TOXENV=py34
  - TOXENV=pypy
  - TOXENV=cover
install: python setup.py dev
install:
  - travis_retry pip install tox
script: python setup.py test -q
script:
  - travis_retry tox
notifications:
  email:
CHANGES.txt
@@ -33,6 +33,11 @@
- Greatly improve the readability of the ``pcreate`` shell script output.
  See https://github.com/Pylons/pyramid/pull/1453
- Improve robustness to timing attacks in the ``AuthTktCookieHelper`` and
  the ``SignedCookieSessionFactory`` classes by using the stdlib's
  ``hmac.compare_digest`` if it is available (such as Python 2.7.7+ and 3.3+).
  See https://github.com/Pylons/pyramid/pull/1457
Bug Fixes
---------
pyramid/tests/test_util.py
@@ -217,6 +217,49 @@
        self.assertEqual(list(wos), [])
        self.assertEqual(wos.last, None)
class Test_strings_differ(unittest.TestCase):
    def _callFUT(self, *args, **kw):
        from pyramid.util import strings_differ
        return strings_differ(*args, **kw)
    def test_it(self):
        self.assertFalse(self._callFUT(b'foo', b'foo'))
        self.assertTrue(self._callFUT(b'123', b'345'))
        self.assertTrue(self._callFUT(b'1234', b'123'))
        self.assertTrue(self._callFUT(b'123', b'1234'))
    def test_it_with_internal_comparator(self):
        result = self._callFUT(b'foo', b'foo', compare_digest=None)
        self.assertFalse(result)
        result = self._callFUT(b'123', b'abc', compare_digest=None)
        self.assertTrue(result)
    def test_it_with_external_comparator(self):
        class DummyComparator(object):
            called = False
            def __init__(self, ret_val):
                self.ret_val = ret_val
            def __call__(self, a, b):
                self.called = True
                return self.ret_val
        dummy_compare = DummyComparator(True)
        result = self._callFUT(b'foo', b'foo', compare_digest=dummy_compare)
        self.assertTrue(dummy_compare.called)
        self.assertFalse(result)
        dummy_compare = DummyComparator(False)
        result = self._callFUT(b'123', b'345', compare_digest=dummy_compare)
        self.assertTrue(dummy_compare.called)
        self.assertTrue(result)
        dummy_compare = DummyComparator(False)
        result = self._callFUT(b'abc', b'abc', compare_digest=dummy_compare)
        self.assertTrue(dummy_compare.called)
        self.assertTrue(result)
class Test_object_description(unittest.TestCase):
    def _callFUT(self, object):
        from pyramid.util import object_description
pyramid/util.py
@@ -1,4 +1,9 @@
import functools
try:
    # py2.7.7+ and py3.3+ have native comparison support
    from hmac import compare_digest
except ImportError: # pragma: nocover
    compare_digest = None
import inspect
import traceback
import weakref
@@ -227,7 +232,7 @@
            oid = self._order[-1]
            return self._items[oid]()
def strings_differ(string1, string2):
def strings_differ(string1, string2, compare_digest=compare_digest):
    """Check whether two strings differ while avoiding timing attacks.
    This function returns True if the given strings differ and False
@@ -237,14 +242,25 @@
        http://seb.dbzteam.org/crypto/python-oauth-timing-hmac.pdf
    .. versionchanged:: 1.6
       Support :func:`hmac.compare_digest` if it is available (Python 2.7.7+
       and Python 3.3+).
    """
    if len(string1) != len(string2):
        return True
    len_eq = len(string1) == len(string2)
    if len_eq:
        invalid_bits = 0
        left = string1
    else:
        invalid_bits = 1
        left = string2
    right = string2
    invalid_bits = 0
    for a, b in zip(string1, string2):
        invalid_bits += a != b
    if compare_digest is not None:
        invalid_bits += not compare_digest(left, right)
    else:
        for a, b in zip(left, right):
            invalid_bits += a != b
    return invalid_bits != 0
def object_description(object):
tox.ini
@@ -12,7 +12,7 @@
    python2.6
commands = 
    python setup.py dev
    python setup.py nosetests --with-xunit --with-xcoverage
    python setup.py nosetests --with-xunit --with-xcoverage --cover-min-percentage=100
deps =
    nosexcover