[Python-modules-commits] [pyjwt] 02/08: Import pyjwt_1.4.0.orig.tar.gz

Daniele Tricoli eriol-guest at moszumanska.debian.org
Sat May 7 22:28:04 UTC 2016


This is an automated email from the git hooks/post-receive script.

eriol-guest pushed a commit to branch master
in repository pyjwt.

commit 77fff08f75254712fc0b64f3094cbfbbc7ae8386
Author: Daniele Tricoli <eriol at mornie.org>
Date:   Fri Feb 12 05:09:49 2016 +0100

    Import pyjwt_1.4.0.orig.tar.gz
---
 CHANGELOG.md                                       |  14 +++++
 MANIFEST.in                                        |   2 +
 PKG-INFO                                           |  63 +++++++++++++++-----
 PyJWT.egg-info/PKG-INFO                            |  63 +++++++++++++++-----
 PyJWT.egg-info/SOURCES.txt                         |  12 +---
 README.md                                          |  61 ++++++++++++++-----
 jwt/__init__.py                                    |   5 +-
 jwt/api_jws.py                                     |   2 +-
 jwt/api_jwt.py                                     |  23 ++++++--
 jwt/exceptions.py                                  |   8 +++
 tests/__init__.pyc                                 | Bin 144 -> 0 bytes
 .../test_algorithms.cpython-27-PYTEST.pyc          | Bin 14156 -> 0 bytes
 .../__pycache__/test_api_jws.cpython-27-PYTEST.pyc | Bin 41476 -> 0 bytes
 .../__pycache__/test_api_jwt.cpython-27-PYTEST.pyc | Bin 25197 -> 0 bytes
 .../__pycache__/test_compat.cpython-27-PYTEST.pyc  | Bin 3447 -> 0 bytes
 tests/__pycache__/test_jwt.cpython-27-PYTEST.pyc   | Bin 1593 -> 0 bytes
 tests/compat.pyc                                   | Bin 338 -> 0 bytes
 tests/contrib/__init__.pyc                         | Bin 152 -> 0 bytes
 .../test_algorithms.cpython-27-PYTEST.pyc          | Bin 10845 -> 0 bytes
 tests/test_api_jws.py                              |  10 ++++
 tests/test_api_jwt.py                              |  65 +++++++++++++++++----
 tests/test_exceptions.py                           |   7 +++
 tests/test_jwt.pyc                                 | Bin 28933 -> 0 bytes
 tests/utils.pyc                                    | Bin 1264 -> 0 bytes
 24 files changed, 258 insertions(+), 77 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8330390..573eabd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,19 @@ Change Log
 All notable changes to this project will be documented in this file.
 This project adheres to [Semantic Versioning](http://semver.org/).
 
+[v1.4][1.4.0]
+-------------------------------------------------------------------------
+### Fixed
+- Exclude Python cache files from PyPI releases.
+
+### Added
+- Added new options to require certain claims
+  (require_nbf, require_iat, require_exp) and raise `MissingRequiredClaimError`
+  if they are not present.
+- If `audience=` or `issuer=` is specified but the claim is not present,
+  `MissingRequiredClaimError` is now raised instead of `InvalidAudienceError`
+  and `InvalidIssuerError`
+
 [v1.3][1.3.0]
 -------------------------------------------------------------------------
 ### Fixed
@@ -72,6 +85,7 @@ rarely used. Users affected by this should upgrade to 3.3+.
 [1.1.0]: https://github.com/jpadilla/pyjwt/compare/1.0.1...1.1.0
 [1.2.0]: https://github.com/jpadilla/pyjwt/compare/1.1.0...1.2.0
 [1.3.0]: https://github.com/jpadilla/pyjwt/compare/1.2.0...1.3.0
+[1.4.0]: https://github.com/jpadilla/pyjwt/compare/1.3.0...1.4.0
 
 
 [109]: https://github.com/jpadilla/pyjwt/pull/109
diff --git a/MANIFEST.in b/MANIFEST.in
index 1321c3a..38dbbef 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -3,4 +3,6 @@ include CHANGELOG.md
 include LICENSE
 include AUTHORS
 include tox.ini
+recursive-exclude * __pycache__
+recursive-exclude * *.py[co]
 graft tests
diff --git a/PKG-INFO b/PKG-INFO
index 760e74c..a2eeee7 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: PyJWT
-Version: 1.3.0
+Version: 1.4.0
 Summary: JSON Web Token implementation in Python
 Home-page: http://github.com/jpadilla/pyjwt
 Author: José Padilla
@@ -9,6 +9,7 @@ License: MIT
 Description: # PyJWT
         
         [![travis-status-image]][travis]
+        [![appveyor-status-image]][appveyor]
         [![pypi-version-image]][pypi]
         [![coveralls-status-image]][coveralls]
         
@@ -30,7 +31,7 @@ Description: # PyJWT
         $ pip install cryptography
         ```
         
-        If you're system doesn't allow installing `cryptography` like on Google App Engine, you can install `PyCrypto` for RSA signatures and `ecdsa` for ECDSA signatures.
+        If your system doesn't allow installing `cryptography` like on Google App Engine, you can install `PyCrypto` for RSA signatures and `ecdsa` for ECDSA signatures.
         
         ## Usage
         
@@ -62,10 +63,12 @@ Description: # PyJWT
         {u'some': u'payload'}
         ```
         
-        The `decode()` function can raise other exceptions, e.g. for invalid issuer or
-        audience (see below). All exceptions that signify that the token is invalid
-        extend from the base `InvalidTokenError` exception class, so applications can
-        use this approach to catch any issues relating to invalid tokens:
+        ## Validation
+        Exceptions can be raised during `decode()` for other errors besides an
+        invalid signature (e.g. for invalid issuer or audience (see below). All
+        exceptions that signify that the token is invalid extend from the base
+        `InvalidTokenError` exception class, so applications can use this approach to
+        catch any issues relating to invalid tokens:
         
         ```python
         try:
@@ -74,8 +77,9 @@ Description: # PyJWT
              pass  # do something sensible here, e.g. return HTTP 403 status code
         ```
         
-        You may also override exception checking via an `options` dictionary.  The default
-        options are as follows:
+        ### Skipping Claim Verification
+        You may also override claim verification via the `options` dictionary.  The
+        default options are:
         
         ```python
         options = {
@@ -84,24 +88,49 @@ Description: # PyJWT
            'verify_nbf': True,
            'verify_iat': True,
            'verify_aud': True
+           'require_exp': False,
+           'require_iat': False,
+           'require_nbf': False
         }
         ```
         
-        You can skip individual checks by passing an `options` dictionary with certain keys set to `False`.
-        For example, if you want to verify the signature of a JWT that has already expired.
+        You can skip validation of individual claims by passing an `options` dictionary
+        with the "verify_<claim_name>" key set to `False` when you call `jwt.decode()`.
+        For example, if you want to verify the signature of a JWT that has already
+        expired, you could do so by setting `verify_exp` to `False`.
         
         ```python
         >>> options = {
-        >>>    'verify_exp': True,
+        >>>    'verify_exp': False,
         >>> }
         
+        >>> encoded = '...' # JWT with an expired exp claim
         >>> jwt.decode(encoded, 'secret', options=options)
         {u'some': u'payload'}
         ```
         
-        **NOTE**: *Changing the default behavior is done at your own risk, and almost certainly will make your
-        application less secure.  Doing so should only be done with a very clear understanding of what you
-        are doing.*
+        **NOTE**: *Changing the default behavior is done at your own risk, and almost
+        certainly will make your application less secure.  Doing so should only be done
+        with a very clear understanding of what you are doing.*
+        
+        ### Requiring Optional Claims
+        In addition to skipping certain validations, you may also specify that certain
+        optional claims are required by setting the appropriate `require_<claim_name>`
+        option to True. If the claim is not present, PyJWT will raise a
+        `jwt.exceptions.MissingRequiredClaimError`.
+        
+        For instance, the following code would require that the token has a 'exp'
+        claim and raise an error if it is not present:
+        
+        ```python
+        >>> options = {
+        >>>     'require_exp': True
+        >>> }
+        
+        >>> encoded =  '...' # JWT without an exp claim
+        >>> jwt.decode(encoded, 'secret', options=options)
+        jwt.exceptions.MissingRequiredClaimError: Token is missing the "exp" claim
+        ```
         
         ## Tests
         
@@ -349,9 +378,11 @@ Description: # PyJWT
         private_key = cert_obj.private_key()
         ```
         
-        [travis-status-image]: https://secure.travis-ci.org/jpadilla/pyjwt.png?branch=master
+        [travis-status-image]: https://secure.travis-ci.org/jpadilla/pyjwt.svg?branch=master
         [travis]: http://travis-ci.org/jpadilla/pyjwt?branch=master
-        [pypi-version-image]: https://pypip.in/version/pyjwt/badge.svg
+        [appveyor-status-image]: https://ci.appveyor.com/api/projects/status/h8nt70aqtwhht39t?svg=true
+        [appveyor]: https://ci.appveyor.com/project/jpadilla/pyjwt
+        [pypi-version-image]: https://img.shields.io/pypi/v/pyjwt.svg
         [pypi]: https://pypi.python.org/pypi/pyjwt
         [coveralls-status-image]: https://coveralls.io/repos/jpadilla/pyjwt/badge.svg?branch=master
         [coveralls]: https://coveralls.io/r/jpadilla/pyjwt?branch=master
diff --git a/PyJWT.egg-info/PKG-INFO b/PyJWT.egg-info/PKG-INFO
index 760e74c..a2eeee7 100644
--- a/PyJWT.egg-info/PKG-INFO
+++ b/PyJWT.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: PyJWT
-Version: 1.3.0
+Version: 1.4.0
 Summary: JSON Web Token implementation in Python
 Home-page: http://github.com/jpadilla/pyjwt
 Author: José Padilla
@@ -9,6 +9,7 @@ License: MIT
 Description: # PyJWT
         
         [![travis-status-image]][travis]
+        [![appveyor-status-image]][appveyor]
         [![pypi-version-image]][pypi]
         [![coveralls-status-image]][coveralls]
         
@@ -30,7 +31,7 @@ Description: # PyJWT
         $ pip install cryptography
         ```
         
-        If you're system doesn't allow installing `cryptography` like on Google App Engine, you can install `PyCrypto` for RSA signatures and `ecdsa` for ECDSA signatures.
+        If your system doesn't allow installing `cryptography` like on Google App Engine, you can install `PyCrypto` for RSA signatures and `ecdsa` for ECDSA signatures.
         
         ## Usage
         
@@ -62,10 +63,12 @@ Description: # PyJWT
         {u'some': u'payload'}
         ```
         
-        The `decode()` function can raise other exceptions, e.g. for invalid issuer or
-        audience (see below). All exceptions that signify that the token is invalid
-        extend from the base `InvalidTokenError` exception class, so applications can
-        use this approach to catch any issues relating to invalid tokens:
+        ## Validation
+        Exceptions can be raised during `decode()` for other errors besides an
+        invalid signature (e.g. for invalid issuer or audience (see below). All
+        exceptions that signify that the token is invalid extend from the base
+        `InvalidTokenError` exception class, so applications can use this approach to
+        catch any issues relating to invalid tokens:
         
         ```python
         try:
@@ -74,8 +77,9 @@ Description: # PyJWT
              pass  # do something sensible here, e.g. return HTTP 403 status code
         ```
         
-        You may also override exception checking via an `options` dictionary.  The default
-        options are as follows:
+        ### Skipping Claim Verification
+        You may also override claim verification via the `options` dictionary.  The
+        default options are:
         
         ```python
         options = {
@@ -84,24 +88,49 @@ Description: # PyJWT
            'verify_nbf': True,
            'verify_iat': True,
            'verify_aud': True
+           'require_exp': False,
+           'require_iat': False,
+           'require_nbf': False
         }
         ```
         
-        You can skip individual checks by passing an `options` dictionary with certain keys set to `False`.
-        For example, if you want to verify the signature of a JWT that has already expired.
+        You can skip validation of individual claims by passing an `options` dictionary
+        with the "verify_<claim_name>" key set to `False` when you call `jwt.decode()`.
+        For example, if you want to verify the signature of a JWT that has already
+        expired, you could do so by setting `verify_exp` to `False`.
         
         ```python
         >>> options = {
-        >>>    'verify_exp': True,
+        >>>    'verify_exp': False,
         >>> }
         
+        >>> encoded = '...' # JWT with an expired exp claim
         >>> jwt.decode(encoded, 'secret', options=options)
         {u'some': u'payload'}
         ```
         
-        **NOTE**: *Changing the default behavior is done at your own risk, and almost certainly will make your
-        application less secure.  Doing so should only be done with a very clear understanding of what you
-        are doing.*
+        **NOTE**: *Changing the default behavior is done at your own risk, and almost
+        certainly will make your application less secure.  Doing so should only be done
+        with a very clear understanding of what you are doing.*
+        
+        ### Requiring Optional Claims
+        In addition to skipping certain validations, you may also specify that certain
+        optional claims are required by setting the appropriate `require_<claim_name>`
+        option to True. If the claim is not present, PyJWT will raise a
+        `jwt.exceptions.MissingRequiredClaimError`.
+        
+        For instance, the following code would require that the token has a 'exp'
+        claim and raise an error if it is not present:
+        
+        ```python
+        >>> options = {
+        >>>     'require_exp': True
+        >>> }
+        
+        >>> encoded =  '...' # JWT without an exp claim
+        >>> jwt.decode(encoded, 'secret', options=options)
+        jwt.exceptions.MissingRequiredClaimError: Token is missing the "exp" claim
+        ```
         
         ## Tests
         
@@ -349,9 +378,11 @@ Description: # PyJWT
         private_key = cert_obj.private_key()
         ```
         
-        [travis-status-image]: https://secure.travis-ci.org/jpadilla/pyjwt.png?branch=master
+        [travis-status-image]: https://secure.travis-ci.org/jpadilla/pyjwt.svg?branch=master
         [travis]: http://travis-ci.org/jpadilla/pyjwt?branch=master
-        [pypi-version-image]: https://pypip.in/version/pyjwt/badge.svg
+        [appveyor-status-image]: https://ci.appveyor.com/api/projects/status/h8nt70aqtwhht39t?svg=true
+        [appveyor]: https://ci.appveyor.com/project/jpadilla/pyjwt
+        [pypi-version-image]: https://img.shields.io/pypi/v/pyjwt.svg
         [pypi]: https://pypi.python.org/pypi/pyjwt
         [coveralls-status-image]: https://coveralls.io/repos/jpadilla/pyjwt/badge.svg?branch=master
         [coveralls]: https://coveralls.io/r/jpadilla/pyjwt?branch=master
diff --git a/PyJWT.egg-info/SOURCES.txt b/PyJWT.egg-info/SOURCES.txt
index 4537ce6..972fb0f 100644
--- a/PyJWT.egg-info/SOURCES.txt
+++ b/PyJWT.egg-info/SOURCES.txt
@@ -25,26 +25,16 @@ jwt/contrib/algorithms/__init__.py
 jwt/contrib/algorithms/py_ecdsa.py
 jwt/contrib/algorithms/pycrypto.py
 tests/__init__.py
-tests/__init__.pyc
 tests/compat.py
-tests/compat.pyc
 tests/test_algorithms.py
 tests/test_api_jws.py
 tests/test_api_jwt.py
 tests/test_compat.py
+tests/test_exceptions.py
 tests/test_jwt.py
-tests/test_jwt.pyc
 tests/utils.py
-tests/utils.pyc
-tests/__pycache__/test_algorithms.cpython-27-PYTEST.pyc
-tests/__pycache__/test_api_jws.cpython-27-PYTEST.pyc
-tests/__pycache__/test_api_jwt.cpython-27-PYTEST.pyc
-tests/__pycache__/test_compat.cpython-27-PYTEST.pyc
-tests/__pycache__/test_jwt.cpython-27-PYTEST.pyc
 tests/contrib/__init__.py
-tests/contrib/__init__.pyc
 tests/contrib/test_algorithms.py
-tests/contrib/__pycache__/test_algorithms.cpython-27-PYTEST.pyc
 tests/keys/__init__.py
 tests/keys/jwk_ec_key.json
 tests/keys/jwk_ec_pub.json
diff --git a/README.md b/README.md
index 5e3d529..0dbe758 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
 # PyJWT
 
 [![travis-status-image]][travis]
+[![appveyor-status-image]][appveyor]
 [![pypi-version-image]][pypi]
 [![coveralls-status-image]][coveralls]
 
@@ -22,7 +23,7 @@ using any of those algorithms, you'll need to install it as well.
 $ pip install cryptography
 ```
 
-If you're system doesn't allow installing `cryptography` like on Google App Engine, you can install `PyCrypto` for RSA signatures and `ecdsa` for ECDSA signatures.
+If your system doesn't allow installing `cryptography` like on Google App Engine, you can install `PyCrypto` for RSA signatures and `ecdsa` for ECDSA signatures.
 
 ## Usage
 
@@ -54,10 +55,12 @@ You can still get the payload by setting the `verify` argument to `False`.
 {u'some': u'payload'}
 ```
 
-The `decode()` function can raise other exceptions, e.g. for invalid issuer or
-audience (see below). All exceptions that signify that the token is invalid
-extend from the base `InvalidTokenError` exception class, so applications can
-use this approach to catch any issues relating to invalid tokens:
+## Validation
+Exceptions can be raised during `decode()` for other errors besides an
+invalid signature (e.g. for invalid issuer or audience (see below). All
+exceptions that signify that the token is invalid extend from the base
+`InvalidTokenError` exception class, so applications can use this approach to
+catch any issues relating to invalid tokens:
 
 ```python
 try:
@@ -66,8 +69,9 @@ except jwt.InvalidTokenError:
      pass  # do something sensible here, e.g. return HTTP 403 status code
 ```
 
-You may also override exception checking via an `options` dictionary.  The default
-options are as follows:
+### Skipping Claim Verification
+You may also override claim verification via the `options` dictionary.  The
+default options are:
 
 ```python
 options = {
@@ -76,24 +80,49 @@ options = {
    'verify_nbf': True,
    'verify_iat': True,
    'verify_aud': True
+   'require_exp': False,
+   'require_iat': False,
+   'require_nbf': False
 }
 ```
 
-You can skip individual checks by passing an `options` dictionary with certain keys set to `False`.
-For example, if you want to verify the signature of a JWT that has already expired.
+You can skip validation of individual claims by passing an `options` dictionary
+with the "verify_<claim_name>" key set to `False` when you call `jwt.decode()`.
+For example, if you want to verify the signature of a JWT that has already
+expired, you could do so by setting `verify_exp` to `False`.
 
 ```python
 >>> options = {
->>>    'verify_exp': True,
+>>>    'verify_exp': False,
 >>> }
 
+>>> encoded = '...' # JWT with an expired exp claim
 >>> jwt.decode(encoded, 'secret', options=options)
 {u'some': u'payload'}
 ```
 
-**NOTE**: *Changing the default behavior is done at your own risk, and almost certainly will make your
-application less secure.  Doing so should only be done with a very clear understanding of what you
-are doing.*
+**NOTE**: *Changing the default behavior is done at your own risk, and almost
+certainly will make your application less secure.  Doing so should only be done
+with a very clear understanding of what you are doing.*
+
+### Requiring Optional Claims
+In addition to skipping certain validations, you may also specify that certain
+optional claims are required by setting the appropriate `require_<claim_name>`
+option to True. If the claim is not present, PyJWT will raise a
+`jwt.exceptions.MissingRequiredClaimError`.
+
+For instance, the following code would require that the token has a 'exp'
+claim and raise an error if it is not present:
+
+```python
+>>> options = {
+>>>     'require_exp': True
+>>> }
+
+>>> encoded =  '...' # JWT without an exp claim
+>>> jwt.decode(encoded, 'secret', options=options)
+jwt.exceptions.MissingRequiredClaimError: Token is missing the "exp" claim
+```
 
 ## Tests
 
@@ -341,9 +370,11 @@ public_key = cert_obj.public_key()
 private_key = cert_obj.private_key()
 ```
 
-[travis-status-image]: https://secure.travis-ci.org/jpadilla/pyjwt.png?branch=master
+[travis-status-image]: https://secure.travis-ci.org/jpadilla/pyjwt.svg?branch=master
 [travis]: http://travis-ci.org/jpadilla/pyjwt?branch=master
-[pypi-version-image]: https://pypip.in/version/pyjwt/badge.svg
+[appveyor-status-image]: https://ci.appveyor.com/api/projects/status/h8nt70aqtwhht39t?svg=true
+[appveyor]: https://ci.appveyor.com/project/jpadilla/pyjwt
+[pypi-version-image]: https://img.shields.io/pypi/v/pyjwt.svg
 [pypi]: https://pypi.python.org/pypi/pyjwt
 [coveralls-status-image]: https://coveralls.io/repos/jpadilla/pyjwt/badge.svg?branch=master
 [coveralls]: https://coveralls.io/r/jpadilla/pyjwt?branch=master
diff --git a/jwt/__init__.py b/jwt/__init__.py
index 63b4a53..2840c04 100644
--- a/jwt/__init__.py
+++ b/jwt/__init__.py
@@ -10,7 +10,7 @@ http://self-issued.info/docs/draft-jones-json-web-token-01.html
 
 
 __title__ = 'pyjwt'
-__version__ = '1.3.0'
+__version__ = '1.4.0'
 __author__ = 'José Padilla'
 __license__ = 'MIT'
 __copyright__ = 'Copyright 2015 José Padilla'
@@ -24,5 +24,6 @@ from .api_jws import PyJWS
 from .exceptions import (
     InvalidTokenError, DecodeError, InvalidAudienceError,
     ExpiredSignatureError, ImmatureSignatureError, InvalidIssuedAtError,
-    InvalidIssuerError, ExpiredSignature, InvalidAudience, InvalidIssuer
+    InvalidIssuerError, ExpiredSignature, InvalidAudience, InvalidIssuer,
+    MissingRequiredClaimError
 )
diff --git a/jwt/api_jws.py b/jwt/api_jws.py
index 13b6214..0c61c7d 100644
--- a/jwt/api_jws.py
+++ b/jwt/api_jws.py
@@ -165,7 +165,7 @@ class PyJWS(object):
     def _verify_signature(self, payload, signing_input, header, signature,
                           key='', algorithms=None):
 
-        alg = header['alg']
+        alg = header.get('alg')
 
         if algorithms is not None and alg not in algorithms:
             raise InvalidAlgorithmError('The specified alg value is not allowed')
diff --git a/jwt/api_jwt.py b/jwt/api_jwt.py
index 09290e1..9703b8d 100644
--- a/jwt/api_jwt.py
+++ b/jwt/api_jwt.py
@@ -11,7 +11,7 @@ from .compat import string_types, timedelta_total_seconds
 from .exceptions import (
     DecodeError, ExpiredSignatureError, ImmatureSignatureError,
     InvalidAudienceError, InvalidIssuedAtError,
-    InvalidIssuerError
+    InvalidIssuerError, MissingRequiredClaimError
 )
 from .utils import merge_dict
 
@@ -27,7 +27,10 @@ class PyJWT(PyJWS):
             'verify_nbf': True,
             'verify_iat': True,
             'verify_aud': True,
-            'verify_iss': True
+            'verify_iss': True,
+            'require_exp': False,
+            'require_iat': False,
+            'require_nbf': False
         }
 
     def encode(self, payload, key, algorithm='HS256', headers=None,
@@ -87,6 +90,8 @@ class PyJWT(PyJWS):
         if not isinstance(audience, (string_types, type(None))):
             raise TypeError('audience must be a string or None')
 
+        self._validate_required_claims(payload, options)
+
         now = timegm(datetime.utcnow().utctimetuple())
 
         if 'iat' in payload and options.get('verify_iat'):
@@ -104,6 +109,16 @@ class PyJWT(PyJWS):
         if options.get('verify_aud'):
             self._validate_aud(payload, audience)
 
+    def _validate_required_claims(self, payload, options):
+        if options.get('require_exp') and payload.get('exp') is None:
+            raise MissingRequiredClaimError('exp')
+
+        if options.get('require_iat') and payload.get('iat') is None:
+            raise MissingRequiredClaimError('iat')
+
+        if options.get('require_nbf') and payload.get('nbf') is None:
+            raise MissingRequiredClaimError('nbf')
+
     def _validate_iat(self, payload, now, leeway):
         try:
             iat = int(payload['iat'])
@@ -140,7 +155,7 @@ class PyJWT(PyJWS):
         if audience is not None and 'aud' not in payload:
             # Application specified an audience, but it could not be
             # verified since the token does not contain a claim.
-            raise InvalidAudienceError('No audience claim in token')
+            raise MissingRequiredClaimError('aud')
 
         audience_claims = payload['aud']
 
@@ -158,7 +173,7 @@ class PyJWT(PyJWS):
             return
 
         if 'iss' not in payload:
-            raise InvalidIssuerError('Token does not contain an iss claim')
+            raise MissingRequiredClaimError('iss')
 
         if payload['iss'] != issuer:
             raise InvalidIssuerError('Invalid issuer')
diff --git a/jwt/exceptions.py b/jwt/exceptions.py
index 0e82e6f..31177a0 100644
--- a/jwt/exceptions.py
+++ b/jwt/exceptions.py
@@ -34,6 +34,14 @@ class InvalidAlgorithmError(InvalidTokenError):
     pass
 
 
+class MissingRequiredClaimError(InvalidTokenError):
+    def __init__(self, claim):
+        self.claim = claim
+
+    def __str__(self):
+        return 'Token is missing the "%s" claim' % self.claim
+
+
 # Compatibility aliases (deprecated)
 ExpiredSignature = ExpiredSignatureError
 InvalidAudience = InvalidAudienceError
diff --git a/tests/__init__.pyc b/tests/__init__.pyc
deleted file mode 100644
index 45386bc..0000000
Binary files a/tests/__init__.pyc and /dev/null differ
diff --git a/tests/__pycache__/test_algorithms.cpython-27-PYTEST.pyc b/tests/__pycache__/test_algorithms.cpython-27-PYTEST.pyc
deleted file mode 100644
index 9ee2f3a..0000000
Binary files a/tests/__pycache__/test_algorithms.cpython-27-PYTEST.pyc and /dev/null differ
diff --git a/tests/__pycache__/test_api_jws.cpython-27-PYTEST.pyc b/tests/__pycache__/test_api_jws.cpython-27-PYTEST.pyc
deleted file mode 100644
index ddaf543..0000000
Binary files a/tests/__pycache__/test_api_jws.cpython-27-PYTEST.pyc and /dev/null differ
diff --git a/tests/__pycache__/test_api_jwt.cpython-27-PYTEST.pyc b/tests/__pycache__/test_api_jwt.cpython-27-PYTEST.pyc
deleted file mode 100644
index 30387ef..0000000
Binary files a/tests/__pycache__/test_api_jwt.cpython-27-PYTEST.pyc and /dev/null differ
diff --git a/tests/__pycache__/test_compat.cpython-27-PYTEST.pyc b/tests/__pycache__/test_compat.cpython-27-PYTEST.pyc
deleted file mode 100644
index edca733..0000000
Binary files a/tests/__pycache__/test_compat.cpython-27-PYTEST.pyc and /dev/null differ
diff --git a/tests/__pycache__/test_jwt.cpython-27-PYTEST.pyc b/tests/__pycache__/test_jwt.cpython-27-PYTEST.pyc
deleted file mode 100644
index 8c532b4..0000000
Binary files a/tests/__pycache__/test_jwt.cpython-27-PYTEST.pyc and /dev/null differ
diff --git a/tests/compat.pyc b/tests/compat.pyc
deleted file mode 100644
index c4a9435..0000000
Binary files a/tests/compat.pyc and /dev/null differ
diff --git a/tests/contrib/__init__.pyc b/tests/contrib/__init__.pyc
deleted file mode 100644
index 330b7cd..0000000
Binary files a/tests/contrib/__init__.pyc and /dev/null differ
diff --git a/tests/contrib/__pycache__/test_algorithms.cpython-27-PYTEST.pyc b/tests/contrib/__pycache__/test_algorithms.cpython-27-PYTEST.pyc
deleted file mode 100644
index 43c6dcb..0000000
Binary files a/tests/contrib/__pycache__/test_algorithms.cpython-27-PYTEST.pyc and /dev/null differ
diff --git a/tests/test_api_jws.py b/tests/test_api_jws.py
index 9395ae8..9aa8b85 100644
--- a/tests/test_api_jws.py
+++ b/tests/test_api_jws.py
@@ -270,6 +270,16 @@ class TestJWS:
 
         assert 'Signature verification' in str(exc.value)
 
+    def test_verify_signature_with_no_algo_header_throws_exception(self, jws, payload):
+        example_jws = (
+            b'e30'
+            b'.eyJhIjo1fQ'
+            b'.KEh186CjVw_Q8FadjJcaVnE7hO5Z9nHBbU8TgbhHcBY'
+        )
+
+        with pytest.raises(InvalidAlgorithmError):
+            jws.decode(example_jws, 'secret')
+
     def test_invalid_crypto_alg(self, jws, payload):
         with pytest.raises(NotImplementedError):
             jws.encode(payload, 'secret', algorithm='HS1024')
diff --git a/tests/test_api_jwt.py b/tests/test_api_jwt.py
index 7d33a9e..211f0df 100644
--- a/tests/test_api_jwt.py
+++ b/tests/test_api_jwt.py
@@ -9,7 +9,8 @@ from decimal import Decimal
 from jwt.api_jwt import PyJWT
 from jwt.exceptions import (
     DecodeError, ExpiredSignatureError, ImmatureSignatureError,
-    InvalidAudienceError, InvalidIssuedAtError, InvalidIssuerError
+    InvalidAudienceError, InvalidIssuedAtError, InvalidIssuerError,
+    MissingRequiredClaimError
 )
 
 import pytest
@@ -317,15 +318,31 @@ class TestJWT:
         with pytest.raises(InvalidAudienceError):
             jwt.decode(token, 'secret', audience='urn:me')
 
+    def test_raise_exception_token_without_issuer(self, jwt):
+        issuer = 'urn:wrong'
+
+        payload = {
+            'some': 'payload'
+        }
+
+        token = jwt.encode(payload, 'secret')
+
+        with pytest.raises(MissingRequiredClaimError) as exc:
+            jwt.decode(token, 'secret', issuer=issuer)
+
+        assert exc.value.claim == 'iss'
+
     def test_raise_exception_token_without_audience(self, jwt):
         payload = {
             'some': 'payload',
         }
         token = jwt.encode(payload, 'secret')
 
-        with pytest.raises(InvalidAudienceError):
+        with pytest.raises(MissingRequiredClaimError) as exc:
             jwt.decode(token, 'secret', audience='urn:me')
 
+        assert exc.value.claim == 'aud'
+
     def test_check_issuer_when_valid(self, jwt):
         issuer = 'urn:foo'
         payload = {
@@ -348,33 +365,57 @@ class TestJWT:
         with pytest.raises(InvalidIssuerError):
             jwt.decode(token, 'secret', issuer=issuer)
 
-    def test_raise_exception_token_without_issuer(self, jwt):
-        issuer = 'urn:wrong'
+    def test_skip_check_audience(self, jwt):
+        payload = {
+            'some': 'payload',
+            'aud': 'urn:me',
+        }
+        token = jwt.encode(payload, 'secret')
+        jwt.decode(token, 'secret', options={'verify_aud': False})
 
+    def test_skip_check_exp(self, jwt):
         payload = {
             'some': 'payload',
+            'exp': datetime.utcnow() - timedelta(days=1)
         }
+        token = jwt.encode(payload, 'secret')
+        jwt.decode(token, 'secret', options={'verify_exp': False})
 
+    def test_decode_should_raise_error_if_exp_required_but_not_present(self, jwt):
+        payload = {
+            'some': 'payload',
+            # exp not present
+        }
         token = jwt.encode(payload, 'secret')
 
-        with pytest.raises(InvalidIssuerError):
-            jwt.decode(token, 'secret', issuer=issuer)
+        with pytest.raises(MissingRequiredClaimError) as exc:
+            jwt.decode(token, 'secret', options={'require_exp': True})
 
-    def test_skip_check_audience(self, jwt):
+        assert exc.value.claim == 'exp'
+
+    def test_decode_should_raise_error_if_iat_required_but_not_present(self, jwt):
         payload = {
             'some': 'payload',
-            'aud': 'urn:me',
+            # iat not present
         }
         token = jwt.encode(payload, 'secret')
-        jwt.decode(token, 'secret', options={'verify_aud': False})
 
-    def test_skip_check_exp(self, jwt):
+        with pytest.raises(MissingRequiredClaimError) as exc:
+            jwt.decode(token, 'secret', options={'require_iat': True})
+
+        assert exc.value.claim == 'iat'
+
+    def test_decode_should_raise_error_if_nbf_required_but_not_present(self, jwt):
         payload = {
             'some': 'payload',
-            'exp': datetime.utcnow() - timedelta(days=1)
+            # nbf not present
         }
         token = jwt.encode(payload, 'secret')
-        jwt.decode(token, 'secret', options={'verify_exp': False})
+
+        with pytest.raises(MissingRequiredClaimError) as exc:
+            jwt.decode(token, 'secret', options={'require_nbf': True})
+
+        assert exc.value.claim == 'nbf'
 
     def test_skip_check_signature(self, jwt):
         token = ("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py
new file mode 100644
index 0000000..9e7f91e
--- /dev/null
+++ b/tests/test_exceptions.py
@@ -0,0 +1,7 @@
+from jwt.exceptions import MissingRequiredClaimError
+
+
+def test_missing_required_claim_error_has_proper_str():
+    exc = MissingRequiredClaimError('abc')
+
+    assert str(exc) == 'Token is missing the "abc" claim'
diff --git a/tests/test_jwt.pyc b/tests/test_jwt.pyc
deleted file mode 100644
index fa82e3f..0000000
Binary files a/tests/test_jwt.pyc and /dev/null differ
diff --git a/tests/utils.pyc b/tests/utils.pyc
deleted file mode 100644
index e1d4c0b..0000000
Binary files a/tests/utils.pyc and /dev/null differ

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/pyjwt.git



More information about the Python-modules-commits mailing list