8000 Fix flaky base jwt tests · raghav7997/twilio-python@087dd2e · GitHub
[go: up one dir, main page]

Skip to content

Commit 087dd2e

Browse files
committed
Fix flaky base jwt tests
1 parent a4111d5 commit 087dd2e

File tree

4 files changed

+102
-76
lines changed
  • twilio/jwt
  • 4 files changed

    +102
    -76
    lines changed

    Makefile

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -17,7 +17,7 @@ analysis:
    1717
    . venv/bin/activate; flake8 --ignore=E123,E126,E128,E501,W391,W291,W293,F401 tests
    1818
    . venv/bin/activate; flake8 --ignore=F401,W391,W291,W293 twilio --max-line-length=300
    1919

    20-
    test: analysis
    20+
    test:
    2121
    . venv/bin/activate; \
    2222
    find tests -type d | xargs nosetests
    2323

    setup.py

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -13,7 +13,7 @@
    1313
    #
    1414
    # You need to have the setuptools module installed. Try reading the setuptools
    1515
    # documentation: http://pypi.python.org/pypi/setuptools
    16-
    REQUIRES = ["httplib2 >= 0.7", "six", "pytz"]
    16+
    REQUIRES = ["httplib2 >= 0.7", "six", "pytz", "PyJWT == 1.4.2"]
    1717

    1818
    if sys.version_info < (2, 6):
    1919
    REQUIRES.append('simplejson')

    tests/unit/jwt/test_jwt.py

    Lines changed: 99 additions & 71 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,6 +1,6 @@
    11
    import unittest
    22
    import jwt as jwt_lib
    3-
    import time
    3+
    import time as real_time
    44

    55
    from nose.tools import assert_true
    66
    from mock import patch
    @@ -37,153 +37,164 @@ def assertIn(self, foo, bar, msg=None):
    3737
    return assert_true(foo in bar, msg=(msg or "%s not found in %s" % (foo, bar)))
    3838

    3939
    def now(self):
    40-
    return int(time.time())
    40+
    return int(real_time.time())
    41+
    42+
    def assertJwtsEqual(self, jwt, key, expected_payload=None, expected_headers=None):
    43+
    expected_headers = expected_headers or {}
    44+
    expected_payload = expected_payload or {}
    45+
    46+
    decoded_payload = jwt_lib.decode(jwt, key, verify=False)
    47+
    decoded_headers = jwt_lib.get_unverified_header(jwt)
    48+
    49+
    self.assertEqual(expected_headers, decoded_headers)
    50+
    self.assertEqual(expected_payload, decoded_payload)
    4151

    4252
    @patch('time.time')
    4353
    def test_basic_encode(self, time_mock):
    4454
    time_mock.return_value = 0.0
    4555

    4656
    jwt = DummyJwt('secret_key', 'issuer', headers={}, payload={})
    47-
    expected_jwt = jwt_lib.encode(
    48-
    {'iss': 'issuer', 'exp': 3600, 'nbf': 0},
    49-
    'secret_key',
    50-
    algorithm='HS256'
    51-
    )
    5257

    53-
    self.assertEqual(expected_jwt, jwt.to_jwt())
    58+
    self.assertJwtsEqual(
    59+
    jwt.to_jwt(), 'secret_key',
    60+
    expected_headers={'typ': 'JWT', 'alg': 'HS256'},
    61+
    expected_payload={'iss': 'issuer', 'exp': 3600, 'nbf': 0},
    62+
    )
    5463

    5564
    @patch('time.time')
    5665
    def test_encode_with_subject(self, time_mock):
    5766
    time_mock.return_value = 0.0
    5867

    5968
    jwt = DummyJwt('secret_key', 'issuer', subject='subject', headers={}, payload={})
    60-
    expected_jwt = jwt_lib.encode(
    61-
    {'iss': 'issuer', 'exp': 3600, 'nbf': 0, 'sub': 'subject'},
    62-
    'secret_key',
    63-
    algorithm='HS256'
    64-
    )
    6569

    66-
    self.assertEqual(expected_jwt, jwt.to_jwt())
    70+
    self.assertJwtsEqual(
    71+
    jwt.to_jwt(), 'secret_key',
    72+
    expected_headers={'typ': 'JWT', 'alg': 'HS256'},
    73+
    expected_payload={'iss': 'issuer', 'exp': 3600, 'nbf': 0, 'sub': 'subject'},
    74+
    )
    6775

    6876
    @patch('time.time')
    6977
    def test_encode_custom_ttl(self, time_mock):
    7078
    time_mock.return_value = 0.0
    7179

    7280
    jwt = DummyJwt('secret_key', 'issuer', ttl=10, headers={}, payload={})
    73-
    expected_jwt = jwt_lib.encode(
    74-
    {'iss': 'issuer', 'exp': 10, 'nbf': 0},
    75-
    'secret_key',
    76-
    algorithm='HS256'
    77-
    )
    7881

    79-
    self.assertEqual(expected_jwt, jwt.to_jwt())
    82+
    self.assertJwtsEqual(
    83+
    jwt.to_jwt(), 'secret_key',
    84+
    expected_headers={'typ': 'JWT', 'alg': 'HS256'},
    85+
    expected_payload={'iss': 'issuer', 'exp': 10, 'nbf': 0},
    86+
    )
    8087

    8188
    @patch('time.time')
    8289
    def test_encode_ttl_added_to_current_time(self, time_mock):
    8390
    time_mock.return_value = 50.0
    8491

    8592
    jwt = DummyJwt('secret_key', 'issuer', ttl=10, headers={}, payload={})
    86-
    expected_jwt = jwt_lib.encode(
    87-
    {'iss': 'issuer', 'exp': 60, 'nbf': 50},
    88-
    'secret_key',
    89-
    algorithm='HS256'
    90-
    )
    9193

    92-
    self.assertEqual(expected_jwt, jwt.to_jwt())
    94+
    self.assertJwtsEqual(
    95+
    jwt.to_jwt(), 'secret_key',
    96+
    expected_headers={'typ': 'JWT', 'alg': 'HS256'},
    97+
    expected_payload={'iss': 'issuer', 'exp': 60, 'nbf': 50},
    98+
    )
    9399

    94100
    @patch('time.time')
    95101
    def test_encode_override_ttl(self, time_mock):
    96102
    time_mock.return_value = 0.0
    97103

    98104
    jwt = DummyJwt('secret_key', 'issuer', ttl=10, headers={}, payload={})
    99-
    expected_jwt = jwt_lib.encode(
    100-
    {'iss': 'issuer', 'exp': 20, 'nbf': 0},
    105+
    106+
    self.assertJwtsEqual(
    107+
    jwt.to_jwt(ttl=20),
    101108
    'secret_key',
    102-
    algorithm='HS256'
    109+
    expected_headers={'typ': 'JWT', 'alg': 'HS256'},
    110+
    expected_payload={'iss': 'issuer', 'exp': 20, 'nbf': 0},
    103111
    )
    104112

    105-
    self.assertEqual(expected_jwt, jwt.to_jwt(ttl=20))
    106-
    107113
    @patch('time.time')
    108114
    def test_encode_valid_until_overrides_ttl(self, time_mock):
    109115
    time_mock.return_value = 0.0
    110116

    111117
    jwt = DummyJwt('secret_key', 'issuer', ttl=10, valid_until=70, headers={}, payload={})
    112-
    expected_jwt = jwt_lib.encode(
    113-
    {'iss': 'issuer', 'exp': 70, 'nbf': 0},
    114-
    'secret_key',
    115-
    algorithm='HS256'
    116-
    )
    117118

    118-
    self.assertEqual(expected_jwt, jwt.to_jwt())
    119+
    self.assertJwtsEqual(
    120+
    jwt.to_jwt(), 'secret_key',
    121+
    expected_headers={'typ': 'JWT', 'alg': 'HS256'},
    122+
    expected_payload={'iss': 'issuer', 'exp': 70, 'nbf': 0},
    123+
    )
    119124

    120125
    @patch('time.time')
    121126
    def test_encode_custom_nbf(self, time_mock):
    122127
    time_mock.return_value = 0.0
    123128

    124129
    jwt = DummyJwt('secret_key', 'issuer', ttl=10, nbf=5, headers={}, payload={})
    125-
    expected_jwt = jwt_lib.encode(
    126-
    {'iss': 'issuer', 'exp': 10, 'nbf': 5},
    127-
    'secret_key',
    128-
    algorithm='HS256'
    129-
    )
    130130

    131-
    self.assertEqual(expected_jwt, jwt.to_jwt())
    131+
    self.assertJwtsEqual(
    132+
    jwt.to_jwt(), 'secret_key',
    133+
    expected_headers={'typ': 'JWT', 'alg': 'HS256'},
    134+
    expected_payload={'iss': 'issuer', 'exp': 10, 'nbf': 5},
    135+
    )
    132136

    133137
    @patch('time.time')
    134138
    def test_encode_custom_algorithm(self, time_mock):
    135139
    time_mock.return_value = 0.0
    136140

    137141
    jwt = DummyJwt('secret_key', 'issuer', algorithm='HS512', headers={}, payload={})
    138-
    expected_jwt = jwt_lib.encode(
    139-
    {'iss': 'issuer', 'exp': 3600, 'nbf': 0},
    140-
    'secret_key',
    141-
    algorithm='HS512'
    142-
    )
    143142

    144-
    self.assertEqual(expected_jwt, jwt.to_jwt())
    143+
    self.assertJwtsEqual(
    144+
    jwt.to_jwt(), 'secret_key',
    145+
    expected_headers={'typ': 'JWT', 'alg': 'HS512'},
    146+
    expected_payload={'iss': 'issuer', 'exp': 3600, 'nbf': 0},
    147+
    )
    145148

    146149
    @patch('time.time')
    147-
    def test_encode_with_headers(self, time_mock):
    150+
    def test_encode_override_algorithm(self, time_mock):
    148151
    time_mock.return_value = 0.0
    149-
    headers = {'sooper': 'secret'}
    150152

    151-
    jwt = DummyJwt('secret_key', 'issuer', algorithm='HS512', headers=headers, payload={})
    152-
    expected_jwt = jwt_lib.encode(
    153-
    {'iss': 'issuer', 'exp': 3600, 'nbf': 0},
    153+
    jwt = DummyJwt('secret_key', 'issuer', algorithm='HS256', headers={}, payload={})
    154+
    155+
    self.assertJwtsEqual(
    156+
    jwt.to_jwt(algorithm='HS512'),
    154157
    'secret_key',
    155-
    algorithm='HS512',
    156-
    headers=headers
    158+
    expected_headers={'typ': 'JWT', 'alg': 'HS512'},
    159+
    expected_payload={'iss': 'issuer', 'exp': 3600, 'nbf': 0},
    157160
    )
    158161

    159-
    self.assertEqual(expected_jwt, jwt.to_jwt())
    162+
    @patch('time.time')
    163+
    def test_encode_with_headers(self, time_mock):
    164+
    time_mock.return_value = 0.0
    165+
    166+
    jwt = DummyJwt('secret_key', 'issuer', algorithm='HS256', headers={'sooper': 'secret'},
    167+
    payload={})
    168+
    169+
    self.assertJwtsEqual(
    170+
    jwt.to_jwt(), 'secret_key',
    171+
    expected_headers={'typ': 'JWT', 'alg': 'HS256', 'sooper': 'secret'},
    172+
    expected_payload={'iss': 'issuer', 'exp': 3600, 'nbf': 0},
    173+
    )
    160174

    161175
    @patch('time.time')
    162176
    def test_encode_with_payload(self, time_mock):
    163177
    time_mock.return_value = 0.0
    164178

    165-
    jwt = DummyJwt('secret_key', 'issuer', algorithm='HS512', payload={'root': 'true'})
    166-
    expected_jwt = jwt_lib.encode(
    167-
    {'iss': 'issuer', 'exp': 3600, 'nbf': 0, 'root': 'true'},
    168-
    'secret_key',
    169-
    algorithm='HS512'
    170-
    )
    179+
    jwt = DummyJwt('secret_key', 'issuer', algorithm='HS256', payload={'root': 'true'})
    171180

    172-
    self.assertEqual(expected_jwt, jwt.to_jwt())
    181+
    self.assertJwtsEqual(
    182+
    jwt.to_jwt(), 'secret_key',
    183+
    expected_headers={'typ': 'JWT', 'alg': 'HS256'},
    184+
    expected_payload={'iss': 'issuer', 'exp': 3600, 'nbf': 0, 'root': 'true'},
    185+
    )
    173186

    174187
    @patch('time.time')
    175188
    def test_encode_with_payload_and_headers(self, time_mock):
    176189
    time_mock.return_value = 0.0
    177190

    178191
    jwt = DummyJwt('secret_key', 'issuer', headers={'yes': 'oui'}, payload={'pay': 'me'})
    179-
    expected_jwt = jwt_lib.encode(
    180-
    {'iss': 'issuer', 'exp': 3600, 'nbf': 0, 'pay': 'me'},
    181-
    'secret_key',
    182-
    algorithm='HS256',
    183-
    headers={'yes': 'oui'}
    184-
    )
    185192

    186-
    self.assertEqual(expected_jwt, jwt.to_jwt())
    193+
    self.assertJwtsEqual(
    194+
    jwt.to_jwt(), 'secret_key',
    195+
    expected_headers={'typ': 'JWT', 'alg': 'HS256', 'yes': 'oui'},
    196+
    expected_payload={'iss': 'issuer', 'exp': 3600, 'nbf': 0, 'pay': 'me'},
    197+
    )
    187198

    188199
    def test_encode_invalid_crypto_alg_fails(self):
    189200
    jwt = DummyJwt('secret_key', 'issuer', algorithm='PlzDontTouchAlgorithm')
    @@ -217,6 +228,23 @@ def test_decode_bad_secret(self):
    217228
    jwt = DummyJwt('secret_key', 'issuer')
    218229
    self.assertRaises(JwtDecodeError, Jwt.from_jwt, jwt.to_jwt(), 'letmeinplz')
    219230

    231+
    def test_decode_modified_jwt_fails(self):
    232+
    jwt = DummyJwt('secret_key', 'issuer')
    233+
    example_jwt = jwt.to_jwt().decode('utf-8')
    234+
    example_jwt = 'ABC' + example_jwt[3:]
    235+
    example_jwt = example_jwt.encode('utf-8')
    236+
    237+
    self.assertRaises(JwtDecodeError, Jwt.from_jwt, example_jwt, 'secret_key')
    238+
    239+
    def test_decode_validates_expiration(self):
    240+
    expired_jwt = DummyJwt('secret_key', 'issuer', valid_until=self.now())
    241+
    real_time.sleep(1)
    242+
    self.assertRaises(JwtDecodeError, Jwt.from_jwt, expired_jwt.to_jwt(), 'secret_key')
    243+
    244+
    def test_decode_validates_nbf(self):
    245+
    expired_jwt = DummyJwt('secret_key', 'issuer', nbf=self.now() + 3600) # valid 1hr from now
    246+
    self.assertRaises(JwtDecodeError, Jwt.from_jwt, expired_jwt.to_jwt(), 'secret_key')
    247+
    220248
    def test_decodes_valid_jwt(self):
    221249
    expiry_time = self.now() + 1000
    222250
    example_jwt = jwt_lib.encode(

    twilio/jwt/__init__.py

    Lines changed: 1 addition & 3 deletions
    Original file line numberDiff line numberDiff line change
    @@ -6,8 +6,6 @@
    66
    import simplejson as json
    77

    88
    import time
    9-
    import hashlib
    10-
    import hmac
    119
    import base64
    1210
    from six import b
    1311

    @@ -149,7 +147,7 @@ def from_jwt(cls, jwt, key=''):
    149147
    })
    150148
    headers = jwt_lib.get_unverified_header(jwt)
    151149
    except Exception as e:
    152-
    raise JwtDecodeError(e.message)
    150+
    raise JwtDecodeError(getattr(e, 'message', str(e)))
    153151

    154152
    return cls._from_jwt(headers, payload, key)
    155153

    0 commit comments

    Comments
     (0)
    0