Hello community, here is the log from the commit of package python-PyJWT for openSUSE:Factory checked in at 2016-09-28 11:30:56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-PyJWT (Old) and /work/SRC/openSUSE:Factory/.python-PyJWT.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-PyJWT" Changes: -------- --- /work/SRC/openSUSE:Factory/python-PyJWT/python-PyJWT.changes 2016-01-12 16:12:13.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.python-PyJWT.new/python-PyJWT.changes 2016-09-28 11:30:58.000000000 +0200 @@ -1,0 +2,19 @@ +Thu Sep 15 13:52:58 UTC 2016 - [email protected] + +- Include in SLES 12 (FATE#321371, bsc#998103) + +------------------------------------------------------------------- +Thu Sep 1 12:36:06 UTC 2016 - [email protected] + +- Use https for Source url + +------------------------------------------------------------------- +Thu Sep 1 05:41:26 UTC 2016 - [email protected] + +- update to 1.4.2: + - A PEM-formatted key encoded as bytes could cause a `TypeError` to be raised [#213][213] + - Newer versions of Pytest could not detect warnings properly [#182][182] + - Non-string 'kid' value now raises `InvalidTokenError` [#174][174] + - `jwt.decode(None)` now gracefully fails with `InvalidTokenError` [#183][183] + +------------------------------------------------------------------- Old: ---- PyJWT-1.4.0.tar.gz New: ---- PyJWT-1.4.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-PyJWT.spec ++++++ --- /var/tmp/diff_new_pack.E0pg0T/_old 2016-09-28 11:30:59.000000000 +0200 +++ /var/tmp/diff_new_pack.E0pg0T/_new 2016-09-28 11:30:59.000000000 +0200 @@ -17,13 +17,13 @@ Name: python-PyJWT -Version: 1.4.0 +Version: 1.4.2 Release: 0 Url: https://github.com/progrium/pyjwt Summary: JSON Web Token implementation in Python License: MIT Group: Development/Languages/Python -Source: http://pypi.python.org/packages/source/P/PyJWT/PyJWT-%{version}.tar.gz +Source: https://pypi.io/packages/source/P/PyJWT/PyJWT-%{version}.tar.gz # PATCH-FIX-CENTOS PyJWT-1.1.0.diff -- without this, the centos build %%check will try to download stuff from pypi --seife Patch1: PyJWT-1.1.0.diff BuildRoot: %{_tmppath}/%{name}-%{version}-build ++++++ PyJWT-1.4.0.tar.gz -> PyJWT-1.4.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyJWT-1.4.0/CHANGELOG.md new/PyJWT-1.4.2/CHANGELOG.md --- old/PyJWT-1.4.0/CHANGELOG.md 2015-07-17 03:29:04.000000000 +0200 +++ new/PyJWT-1.4.2/CHANGELOG.md 2016-08-08 22:06:37.000000000 +0200 @@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +[v1.4.2][1.4.2] +------------------------------------------------------------------------- +### Fixed +- A PEM-formatted key encoded as bytes could cause a `TypeError` to be raised [#213][213] + +[v1.4.1][1.4.1] +------------------------------------------------------------------------- +### Fixed +- Newer versions of Pytest could not detect warnings properly [#182][182] +- Non-string 'kid' value now raises `InvalidTokenError` [#174][174] +- `jwt.decode(None)` now gracefully fails with `InvalidTokenError` [#183][183] + [v1.4][1.4.0] ------------------------------------------------------------------------- ### Fixed @@ -86,6 +98,9 @@ [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 +[1.4.1]: https://github.com/jpadilla/pyjwt/compare/1.4.0...1.4.1 +[1.4.2]: https://github.com/jpadilla/pyjwt/compare/1.4.1...1.4.2 + [109]: https://github.com/jpadilla/pyjwt/pull/109 @@ -102,3 +117,7 @@ [141]: https://github.com/jpadilla/pyjwt/pull/141 [158]: https://github.com/jpadilla/pyjwt/pull/158 [163]: https://github.com/jpadilla/pyjwt/pull/163 +[174]: https://github.com/jpadilla/pyjwt/pull/174 +[182]: https://github.com/jpadilla/pyjwt/pull/182 +[183]: https://github.com/jpadilla/pyjwt/pull/183 +[213]: https://github.com/jpadilla/pyjwt/pull/214 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyJWT-1.4.0/PKG-INFO new/PyJWT-1.4.2/PKG-INFO --- old/PyJWT-1.4.0/PKG-INFO 2015-07-17 03:30:17.000000000 +0200 +++ new/PyJWT-1.4.2/PKG-INFO 2016-08-08 22:07:50.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: PyJWT -Version: 1.4.0 +Version: 1.4.2 Summary: JSON Web Token implementation in Python Home-page: http://github.com/jpadilla/pyjwt Author: José Padilla @@ -12,8 +12,9 @@ [![appveyor-status-image]][appveyor] [![pypi-version-image]][pypi] [![coveralls-status-image]][coveralls] + [![docs-status-image]][docs] - A Python implementation of [JSON Web Token draft 32][jwt-spec]. + A Python implementation of [RFC 7519][jwt-spec]. Original implementation was written by [@progrium][progrium]. ## Installing @@ -22,114 +23,15 @@ $ pip install PyJWT ``` - **A Note on Dependencies**: - - RSA and ECDSA signatures depend on the recommended `cryptography` package (0.8+). If you plan on - using any of those algorithms, you'll need to install it as well. - - ``` - $ pip install cryptography - ``` - - 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 ```python >>> import jwt >>> encoded = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256') 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg' - ``` - Additional headers may also be specified. - - ```python - >>> jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256', headers={'kid': '230498151c214b788dd97f22b85410a5'}) - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjIzMDQ5ODE1MWMyMTRiNzg4ZGQ5N2YyMmI4NTQxMGE1In0.eyJzb21lIjoicGF5bG9hZCJ9.DogbDGmMHgA_bU05TAB-R6geQ2nMU2BRM-LnYEtefwg' - ``` - - Note the resulting JWT will not be encrypted, but verifiable with a secret key. - - ```python >>> jwt.decode(encoded, 'secret', algorithms=['HS256']) - {u'some': u'payload'} - ``` - - If the secret is wrong, it will raise a `jwt.DecodeError` telling you as such. - You can still get the payload by setting the `verify` argument to `False`. - - ```python - >>> jwt.decode(encoded, verify=False) - {u'some': u'payload'} - ``` - - ## 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: - payload = jwt.decode(encoded) - except jwt.InvalidTokenError: - pass # do something sensible here, e.g. return HTTP 403 status code - ``` - - ### Skipping Claim Verification - You may also override claim verification via the `options` dictionary. The - default options are: - - ```python - options = { - 'verify_signature': True, - 'verify_exp': True, - 'verify_nbf': True, - 'verify_iat': True, - 'verify_aud': True - 'require_exp': False, - 'require_iat': False, - 'require_nbf': False - } - ``` - - 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': 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.* - - ### 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 + {'some': 'payload'} ``` ## Tests @@ -140,244 +42,6 @@ $ python setup.py test ``` - ## Algorithms - - The JWT spec supports several algorithms for cryptographic signing. This library - currently supports: - - * HS256 - HMAC using SHA-256 hash algorithm (default) - * HS384 - HMAC using SHA-384 hash algorithm - * HS512 - HMAC using SHA-512 hash algorithm - * ES256 - ECDSA signature algorithm using SHA-256 hash algorithm - * ES384 - ECDSA signature algorithm using SHA-384 hash algorithm - * ES512 - ECDSA signature algorithm using SHA-512 hash algorithm - * RS256 - RSASSA-PKCS1-v1_5 signature algorithm using SHA-256 hash algorithm - * RS384 - RSASSA-PKCS1-v1_5 signature algorithm using SHA-384 hash algorithm - * RS512 - RSASSA-PKCS1-v1_5 signature algorithm using SHA-512 hash algorithm - * PS256 - RSASSA-PSS signature using SHA-256 and MGF1 padding with SHA-256 - * PS384 - RSASSA-PSS signature using SHA-384 and MGF1 padding with SHA-384 - * PS512 - RSASSA-PSS signature using SHA-512 and MGF1 padding with SHA-512 - - ### Encoding - You can specify which algorithm you would like to use to sign the JWT - by using the `algorithm` parameter: - - ```python - >>> encoded = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS512') - 'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.WTzLzFO079PduJiFIyzrOah54YaM8qoxH9fLMQoQhKtw3_fMGjImIOokijDkXVbyfBqhMo2GCNu4w9v7UXvnpA' - ``` - - ### Decoding - When decoding, you can specify which algorithms you would like to permit - when validating the JWT by using the `algorithms` parameter which takes a list - of allowed algorithms: - - ```python - >>> jwt.decode(encoded, 'secret', algorithms=['HS512', 'HS256']) - {u'some': u'payload'} - ``` - - In the above case, if the JWT has any value for its alg header other than - HS512 or HS256, the claim will be rejected with an `InvalidAlgorithmError`. - - ### Asymmetric (Public-key) Algorithms - Usage of RSA (RS\*) and EC (EC\*) algorithms require a basic understanding - of how public-key cryptography is used with regards to digital signatures. - If you are unfamiliar, you may want to read - [this article](http://en.wikipedia.org/wiki/Public-key_cryptography). - - When using the RSASSA-PKCS1-v1_5 algorithms, the `key` argument in both - `jwt.encode()` and `jwt.decode()` (`"secret"` in the examples) is expected to - be either an RSA public or private key in PEM or SSH format. The type of key - (private or public) depends on whether you are signing or verifying. - - When using the ECDSA algorithms, the `key` argument is expected to - be an Elliptic Curve public or private key in PEM format. The type of key - (private or public) depends on whether you are signing or verifying. - - - ## Support of registered claim names - - JSON Web Token defines some registered claim names and defines how they should - be used. PyJWT supports these registered claim names: - - - "exp" (Expiration Time) Claim - - "nbf" (Not Before Time) Claim - - "iss" (Issuer) Claim - - "aud" (Audience) Claim - - "iat" (Issued At) Claim - - ### Expiration Time Claim - - From [the JWT spec][jwt-spec-reg-claims]: - - > The "exp" (expiration time) claim identifies the expiration time on - > or after which the JWT MUST NOT be accepted for processing. The - > processing of the "exp" claim requires that the current date/time - > MUST be before the expiration date/time listed in the "exp" claim. - > Implementers MAY provide for some small leeway, usually no more than - > a few minutes, to account for clock skew. Its value MUST be a number - > containing a NumericDate value. Use of this claim is OPTIONAL. - - You can pass the expiration time as a UTC UNIX timestamp (an int) or as a - datetime, which will be converted into an int. For example: - - ```python - jwt.encode({'exp': 1371720939}, 'secret') - - jwt.encode({'exp': datetime.utcnow()}, 'secret') - ``` - - Expiration time is automatically verified in `jwt.decode()` and raises - `jwt.ExpiredSignatureError` if the expiration time is in the past: - - ```python - import jwt - - try: - jwt.decode('JWT_STRING', 'secret') - except jwt.ExpiredSignatureError: - # Signature has expired - ``` - - Expiration time will be compared to the current UTC time (as given by - `timegm(datetime.utcnow().utctimetuple())`), so be sure to use a UTC timestamp - or datetime in encoding. - - You can turn off expiration time verification with the `verify_exp` parameter in the options argument. - - PyJWT also supports the leeway part of the expiration time definition, which - means you can validate a expiration time which is in the past but not very far. - For example, if you have a JWT payload with a expiration time set to 30 seconds - after creation but you know that sometimes you will process it after 30 seconds, - you can set a leeway of 10 seconds in order to have some margin: - - ```python - import datetime - import time - import jwt - - jwt_payload = jwt.encode({ - 'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=30) - }, 'secret') - - time.sleep(32) - - # JWT payload is now expired - # But with some leeway, it will still validate - jwt.decode(jwt_payload, 'secret', leeway=10) - ``` - - Instead of specifying the leeway as a number of seconds, a `datetime.timedelta` - instance can be used. The last line in the example above is equivalent to: - - ```python - jwt.decode(jwt_payload, 'secret', leeway=datetime.timedelta(seconds=10)) - ``` - - - ### Not Before Time Claim - - > The "nbf" (not before) claim identifies the time before which the JWT - > MUST NOT be accepted for processing. The processing of the "nbf" - > claim requires that the current date/time MUST be after or equal to - > the not-before date/time listed in the "nbf" claim. Implementers MAY - > provide for some small leeway, usually no more than a few minutes, to - > account for clock skew. Its value MUST be a number containing a - > NumericDate value. Use of this claim is OPTIONAL. - - The `nbf` claim works similarly to the `exp` claim above. - - ```python - jwt.encode({'nbf': 1371720939}, 'secret') - - jwt.encode({'nbf': datetime.utcnow()}, 'secret') - ``` - - ### Issuer Claim - - > The "iss" (issuer) claim identifies the principal that issued the - > JWT. The processing of this claim is generally application specific. - > The "iss" value is a case-sensitive string containing a StringOrURI - > value. Use of this claim is OPTIONAL. - - ```python - import jwt - - - payload = { - 'some': 'payload', - 'iss': 'urn:foo' - } - - token = jwt.encode(payload, 'secret') - decoded = jwt.decode(token, 'secret', issuer='urn:foo') - ``` - - If the issuer claim is incorrect, `jwt.InvalidIssuerError` will be raised. - - - ### Audience Claim - - > The "aud" (audience) claim identifies the recipients that the JWT is - > intended for. Each principal intended to process the JWT MUST - > identify itself with a value in the audience claim. If the principal - > processing the claim does not identify itself with a value in the - > "aud" claim when this claim is present, then the JWT MUST be - > rejected. In the general case, the "aud" value is an array of case- - > sensitive strings, each containing a StringOrURI value. In the - > special case when the JWT has one audience, the "aud" value MAY be a - > single case-sensitive string containing a StringOrURI value. The - > interpretation of audience values is generally application specific. - > Use of this claim is OPTIONAL. - - ```python - import jwt - - - payload = { - 'some': 'payload', - 'aud': 'urn:foo' - } - - token = jwt.encode(payload, 'secret') - decoded = jwt.decode(token, 'secret', audience='urn:foo') - ``` - - If the audience claim is incorrect, `jwt.InvalidAudienceError` will be raised. - - ### Issued At Claim - - > The iat (issued at) claim identifies the time at which the JWT was issued. - > This claim can be used to determine the age of the JWT. Its value MUST be a - > number containing a NumericDate value. Use of this claim is OPTIONAL. - - If the `iat` claim is in the future, an `jwt.InvalidIssuedAtError` exception - will be raised. - - ```python - jwt.encode({'iat': 1371720939}, 'secret') - - jwt.encode({'iat': datetime.utcnow()}, 'secret') - ``` - - ## Frequently Asked Questions - - **How can I extract a public / private key from a x509 certificate?** - - The `load_pem_x509_certificate()` function from `cryptography` can be used to - extract the public or private keys from a x509 certificate in PEM format. - - ```python - from cryptography.x509 import load_pem_x509_certificate - from cryptography.hazmat.backends import default_backend - - cert_str = "-----BEGIN CERTIFICATE-----MIIDETCCAfm..." - cert_obj = load_pem_x509_certificate(cert_str, default_backend()) - public_key = cert_obj.public_key() - private_key = cert_obj.private_key() - ``` - [travis-status-image]: https://secure.travis-ci.org/jpadilla/pyjwt.svg?branch=master [travis]: http://travis-ci.org/jpadilla/pyjwt?branch=master [appveyor-status-image]: https://ci.appveyor.com/api/projects/status/h8nt70aqtwhht39t?svg=true @@ -386,8 +50,9 @@ [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 - [jwt-spec]: https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32 - [jwt-spec-reg-claims]: http://self-issued.info/docs/draft-jones-json-web-token-01.html#ReservedClaimName + [docs-status-image]: https://readthedocs.org/projects/pyjwt/badge/?version=latest + [docs]: http://pyjwt.readthedocs.org + [jwt-spec]: https://tools.ietf.org/html/rfc7519 [progrium]: https://github.com/progrium Keywords: jwt json web token security signing @@ -401,4 +66,5 @@ Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 Classifier: Topic :: Utilities diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyJWT-1.4.0/PyJWT.egg-info/PKG-INFO new/PyJWT-1.4.2/PyJWT.egg-info/PKG-INFO --- old/PyJWT-1.4.0/PyJWT.egg-info/PKG-INFO 2015-07-17 03:30:17.000000000 +0200 +++ new/PyJWT-1.4.2/PyJWT.egg-info/PKG-INFO 2016-08-08 22:07:50.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: PyJWT -Version: 1.4.0 +Version: 1.4.2 Summary: JSON Web Token implementation in Python Home-page: http://github.com/jpadilla/pyjwt Author: José Padilla @@ -12,8 +12,9 @@ [![appveyor-status-image]][appveyor] [![pypi-version-image]][pypi] [![coveralls-status-image]][coveralls] + [![docs-status-image]][docs] - A Python implementation of [JSON Web Token draft 32][jwt-spec]. + A Python implementation of [RFC 7519][jwt-spec]. Original implementation was written by [@progrium][progrium]. ## Installing @@ -22,114 +23,15 @@ $ pip install PyJWT ``` - **A Note on Dependencies**: - - RSA and ECDSA signatures depend on the recommended `cryptography` package (0.8+). If you plan on - using any of those algorithms, you'll need to install it as well. - - ``` - $ pip install cryptography - ``` - - 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 ```python >>> import jwt >>> encoded = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256') 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg' - ``` - Additional headers may also be specified. - - ```python - >>> jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256', headers={'kid': '230498151c214b788dd97f22b85410a5'}) - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjIzMDQ5ODE1MWMyMTRiNzg4ZGQ5N2YyMmI4NTQxMGE1In0.eyJzb21lIjoicGF5bG9hZCJ9.DogbDGmMHgA_bU05TAB-R6geQ2nMU2BRM-LnYEtefwg' - ``` - - Note the resulting JWT will not be encrypted, but verifiable with a secret key. - - ```python >>> jwt.decode(encoded, 'secret', algorithms=['HS256']) - {u'some': u'payload'} - ``` - - If the secret is wrong, it will raise a `jwt.DecodeError` telling you as such. - You can still get the payload by setting the `verify` argument to `False`. - - ```python - >>> jwt.decode(encoded, verify=False) - {u'some': u'payload'} - ``` - - ## 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: - payload = jwt.decode(encoded) - except jwt.InvalidTokenError: - pass # do something sensible here, e.g. return HTTP 403 status code - ``` - - ### Skipping Claim Verification - You may also override claim verification via the `options` dictionary. The - default options are: - - ```python - options = { - 'verify_signature': True, - 'verify_exp': True, - 'verify_nbf': True, - 'verify_iat': True, - 'verify_aud': True - 'require_exp': False, - 'require_iat': False, - 'require_nbf': False - } - ``` - - 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': 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.* - - ### 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 + {'some': 'payload'} ``` ## Tests @@ -140,244 +42,6 @@ $ python setup.py test ``` - ## Algorithms - - The JWT spec supports several algorithms for cryptographic signing. This library - currently supports: - - * HS256 - HMAC using SHA-256 hash algorithm (default) - * HS384 - HMAC using SHA-384 hash algorithm - * HS512 - HMAC using SHA-512 hash algorithm - * ES256 - ECDSA signature algorithm using SHA-256 hash algorithm - * ES384 - ECDSA signature algorithm using SHA-384 hash algorithm - * ES512 - ECDSA signature algorithm using SHA-512 hash algorithm - * RS256 - RSASSA-PKCS1-v1_5 signature algorithm using SHA-256 hash algorithm - * RS384 - RSASSA-PKCS1-v1_5 signature algorithm using SHA-384 hash algorithm - * RS512 - RSASSA-PKCS1-v1_5 signature algorithm using SHA-512 hash algorithm - * PS256 - RSASSA-PSS signature using SHA-256 and MGF1 padding with SHA-256 - * PS384 - RSASSA-PSS signature using SHA-384 and MGF1 padding with SHA-384 - * PS512 - RSASSA-PSS signature using SHA-512 and MGF1 padding with SHA-512 - - ### Encoding - You can specify which algorithm you would like to use to sign the JWT - by using the `algorithm` parameter: - - ```python - >>> encoded = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS512') - 'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.WTzLzFO079PduJiFIyzrOah54YaM8qoxH9fLMQoQhKtw3_fMGjImIOokijDkXVbyfBqhMo2GCNu4w9v7UXvnpA' - ``` - - ### Decoding - When decoding, you can specify which algorithms you would like to permit - when validating the JWT by using the `algorithms` parameter which takes a list - of allowed algorithms: - - ```python - >>> jwt.decode(encoded, 'secret', algorithms=['HS512', 'HS256']) - {u'some': u'payload'} - ``` - - In the above case, if the JWT has any value for its alg header other than - HS512 or HS256, the claim will be rejected with an `InvalidAlgorithmError`. - - ### Asymmetric (Public-key) Algorithms - Usage of RSA (RS\*) and EC (EC\*) algorithms require a basic understanding - of how public-key cryptography is used with regards to digital signatures. - If you are unfamiliar, you may want to read - [this article](http://en.wikipedia.org/wiki/Public-key_cryptography). - - When using the RSASSA-PKCS1-v1_5 algorithms, the `key` argument in both - `jwt.encode()` and `jwt.decode()` (`"secret"` in the examples) is expected to - be either an RSA public or private key in PEM or SSH format. The type of key - (private or public) depends on whether you are signing or verifying. - - When using the ECDSA algorithms, the `key` argument is expected to - be an Elliptic Curve public or private key in PEM format. The type of key - (private or public) depends on whether you are signing or verifying. - - - ## Support of registered claim names - - JSON Web Token defines some registered claim names and defines how they should - be used. PyJWT supports these registered claim names: - - - "exp" (Expiration Time) Claim - - "nbf" (Not Before Time) Claim - - "iss" (Issuer) Claim - - "aud" (Audience) Claim - - "iat" (Issued At) Claim - - ### Expiration Time Claim - - From [the JWT spec][jwt-spec-reg-claims]: - - > The "exp" (expiration time) claim identifies the expiration time on - > or after which the JWT MUST NOT be accepted for processing. The - > processing of the "exp" claim requires that the current date/time - > MUST be before the expiration date/time listed in the "exp" claim. - > Implementers MAY provide for some small leeway, usually no more than - > a few minutes, to account for clock skew. Its value MUST be a number - > containing a NumericDate value. Use of this claim is OPTIONAL. - - You can pass the expiration time as a UTC UNIX timestamp (an int) or as a - datetime, which will be converted into an int. For example: - - ```python - jwt.encode({'exp': 1371720939}, 'secret') - - jwt.encode({'exp': datetime.utcnow()}, 'secret') - ``` - - Expiration time is automatically verified in `jwt.decode()` and raises - `jwt.ExpiredSignatureError` if the expiration time is in the past: - - ```python - import jwt - - try: - jwt.decode('JWT_STRING', 'secret') - except jwt.ExpiredSignatureError: - # Signature has expired - ``` - - Expiration time will be compared to the current UTC time (as given by - `timegm(datetime.utcnow().utctimetuple())`), so be sure to use a UTC timestamp - or datetime in encoding. - - You can turn off expiration time verification with the `verify_exp` parameter in the options argument. - - PyJWT also supports the leeway part of the expiration time definition, which - means you can validate a expiration time which is in the past but not very far. - For example, if you have a JWT payload with a expiration time set to 30 seconds - after creation but you know that sometimes you will process it after 30 seconds, - you can set a leeway of 10 seconds in order to have some margin: - - ```python - import datetime - import time - import jwt - - jwt_payload = jwt.encode({ - 'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=30) - }, 'secret') - - time.sleep(32) - - # JWT payload is now expired - # But with some leeway, it will still validate - jwt.decode(jwt_payload, 'secret', leeway=10) - ``` - - Instead of specifying the leeway as a number of seconds, a `datetime.timedelta` - instance can be used. The last line in the example above is equivalent to: - - ```python - jwt.decode(jwt_payload, 'secret', leeway=datetime.timedelta(seconds=10)) - ``` - - - ### Not Before Time Claim - - > The "nbf" (not before) claim identifies the time before which the JWT - > MUST NOT be accepted for processing. The processing of the "nbf" - > claim requires that the current date/time MUST be after or equal to - > the not-before date/time listed in the "nbf" claim. Implementers MAY - > provide for some small leeway, usually no more than a few minutes, to - > account for clock skew. Its value MUST be a number containing a - > NumericDate value. Use of this claim is OPTIONAL. - - The `nbf` claim works similarly to the `exp` claim above. - - ```python - jwt.encode({'nbf': 1371720939}, 'secret') - - jwt.encode({'nbf': datetime.utcnow()}, 'secret') - ``` - - ### Issuer Claim - - > The "iss" (issuer) claim identifies the principal that issued the - > JWT. The processing of this claim is generally application specific. - > The "iss" value is a case-sensitive string containing a StringOrURI - > value. Use of this claim is OPTIONAL. - - ```python - import jwt - - - payload = { - 'some': 'payload', - 'iss': 'urn:foo' - } - - token = jwt.encode(payload, 'secret') - decoded = jwt.decode(token, 'secret', issuer='urn:foo') - ``` - - If the issuer claim is incorrect, `jwt.InvalidIssuerError` will be raised. - - - ### Audience Claim - - > The "aud" (audience) claim identifies the recipients that the JWT is - > intended for. Each principal intended to process the JWT MUST - > identify itself with a value in the audience claim. If the principal - > processing the claim does not identify itself with a value in the - > "aud" claim when this claim is present, then the JWT MUST be - > rejected. In the general case, the "aud" value is an array of case- - > sensitive strings, each containing a StringOrURI value. In the - > special case when the JWT has one audience, the "aud" value MAY be a - > single case-sensitive string containing a StringOrURI value. The - > interpretation of audience values is generally application specific. - > Use of this claim is OPTIONAL. - - ```python - import jwt - - - payload = { - 'some': 'payload', - 'aud': 'urn:foo' - } - - token = jwt.encode(payload, 'secret') - decoded = jwt.decode(token, 'secret', audience='urn:foo') - ``` - - If the audience claim is incorrect, `jwt.InvalidAudienceError` will be raised. - - ### Issued At Claim - - > The iat (issued at) claim identifies the time at which the JWT was issued. - > This claim can be used to determine the age of the JWT. Its value MUST be a - > number containing a NumericDate value. Use of this claim is OPTIONAL. - - If the `iat` claim is in the future, an `jwt.InvalidIssuedAtError` exception - will be raised. - - ```python - jwt.encode({'iat': 1371720939}, 'secret') - - jwt.encode({'iat': datetime.utcnow()}, 'secret') - ``` - - ## Frequently Asked Questions - - **How can I extract a public / private key from a x509 certificate?** - - The `load_pem_x509_certificate()` function from `cryptography` can be used to - extract the public or private keys from a x509 certificate in PEM format. - - ```python - from cryptography.x509 import load_pem_x509_certificate - from cryptography.hazmat.backends import default_backend - - cert_str = "-----BEGIN CERTIFICATE-----MIIDETCCAfm..." - cert_obj = load_pem_x509_certificate(cert_str, default_backend()) - public_key = cert_obj.public_key() - private_key = cert_obj.private_key() - ``` - [travis-status-image]: https://secure.travis-ci.org/jpadilla/pyjwt.svg?branch=master [travis]: http://travis-ci.org/jpadilla/pyjwt?branch=master [appveyor-status-image]: https://ci.appveyor.com/api/projects/status/h8nt70aqtwhht39t?svg=true @@ -386,8 +50,9 @@ [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 - [jwt-spec]: https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32 - [jwt-spec-reg-claims]: http://self-issued.info/docs/draft-jones-json-web-token-01.html#ReservedClaimName + [docs-status-image]: https://readthedocs.org/projects/pyjwt/badge/?version=latest + [docs]: http://pyjwt.readthedocs.org + [jwt-spec]: https://tools.ietf.org/html/rfc7519 [progrium]: https://github.com/progrium Keywords: jwt json web token security signing @@ -401,4 +66,5 @@ Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 Classifier: Topic :: Utilities diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyJWT-1.4.0/PyJWT.egg-info/requires.txt new/PyJWT-1.4.2/PyJWT.egg-info/requires.txt --- old/PyJWT-1.4.0/PyJWT.egg-info/requires.txt 2015-07-17 03:30:17.000000000 +0200 +++ new/PyJWT-1.4.2/PyJWT.egg-info/requires.txt 2016-08-08 22:07:50.000000000 +0200 @@ -8,6 +8,6 @@ pep8-naming [test] -pytest +pytest==2.7.3 pytest-cov pytest-runner diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyJWT-1.4.0/README.md new/PyJWT-1.4.2/README.md --- old/PyJWT-1.4.0/README.md 2015-07-17 03:17:27.000000000 +0200 +++ new/PyJWT-1.4.2/README.md 2015-11-11 16:01:54.000000000 +0100 @@ -4,8 +4,9 @@ [![appveyor-status-image]][appveyor] [![pypi-version-image]][pypi] [![coveralls-status-image]][coveralls] +[![docs-status-image]][docs] -A Python implementation of [JSON Web Token draft 32][jwt-spec]. +A Python implementation of [RFC 7519][jwt-spec]. Original implementation was written by [@progrium][progrium]. ## Installing @@ -14,114 +15,15 @@ $ pip install PyJWT ``` -**A Note on Dependencies**: - -RSA and ECDSA signatures depend on the recommended `cryptography` package (0.8+). If you plan on -using any of those algorithms, you'll need to install it as well. - -``` -$ pip install cryptography -``` - -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 ```python >>> import jwt >>> encoded = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256') 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg' -``` - -Additional headers may also be specified. -```python ->>> jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256', headers={'kid': '230498151c214b788dd97f22b85410a5'}) -'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjIzMDQ5ODE1MWMyMTRiNzg4ZGQ5N2YyMmI4NTQxMGE1In0.eyJzb21lIjoicGF5bG9hZCJ9.DogbDGmMHgA_bU05TAB-R6geQ2nMU2BRM-LnYEtefwg' -``` - -Note the resulting JWT will not be encrypted, but verifiable with a secret key. - -```python >>> jwt.decode(encoded, 'secret', algorithms=['HS256']) -{u'some': u'payload'} -``` - -If the secret is wrong, it will raise a `jwt.DecodeError` telling you as such. -You can still get the payload by setting the `verify` argument to `False`. - -```python ->>> jwt.decode(encoded, verify=False) -{u'some': u'payload'} -``` - -## 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: - payload = jwt.decode(encoded) -except jwt.InvalidTokenError: - pass # do something sensible here, e.g. return HTTP 403 status code -``` - -### Skipping Claim Verification -You may also override claim verification via the `options` dictionary. The -default options are: - -```python -options = { - 'verify_signature': True, - 'verify_exp': True, - 'verify_nbf': True, - 'verify_iat': True, - 'verify_aud': True - 'require_exp': False, - 'require_iat': False, - 'require_nbf': False -} -``` - -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': 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.* - -### 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 +{'some': 'payload'} ``` ## Tests @@ -132,244 +34,6 @@ $ python setup.py test ``` -## Algorithms - -The JWT spec supports several algorithms for cryptographic signing. This library -currently supports: - -* HS256 - HMAC using SHA-256 hash algorithm (default) -* HS384 - HMAC using SHA-384 hash algorithm -* HS512 - HMAC using SHA-512 hash algorithm -* ES256 - ECDSA signature algorithm using SHA-256 hash algorithm -* ES384 - ECDSA signature algorithm using SHA-384 hash algorithm -* ES512 - ECDSA signature algorithm using SHA-512 hash algorithm -* RS256 - RSASSA-PKCS1-v1_5 signature algorithm using SHA-256 hash algorithm -* RS384 - RSASSA-PKCS1-v1_5 signature algorithm using SHA-384 hash algorithm -* RS512 - RSASSA-PKCS1-v1_5 signature algorithm using SHA-512 hash algorithm -* PS256 - RSASSA-PSS signature using SHA-256 and MGF1 padding with SHA-256 -* PS384 - RSASSA-PSS signature using SHA-384 and MGF1 padding with SHA-384 -* PS512 - RSASSA-PSS signature using SHA-512 and MGF1 padding with SHA-512 - -### Encoding -You can specify which algorithm you would like to use to sign the JWT -by using the `algorithm` parameter: - -```python ->>> encoded = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS512') -'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.WTzLzFO079PduJiFIyzrOah54YaM8qoxH9fLMQoQhKtw3_fMGjImIOokijDkXVbyfBqhMo2GCNu4w9v7UXvnpA' -``` - -### Decoding -When decoding, you can specify which algorithms you would like to permit -when validating the JWT by using the `algorithms` parameter which takes a list -of allowed algorithms: - -```python ->>> jwt.decode(encoded, 'secret', algorithms=['HS512', 'HS256']) -{u'some': u'payload'} -``` - -In the above case, if the JWT has any value for its alg header other than -HS512 or HS256, the claim will be rejected with an `InvalidAlgorithmError`. - -### Asymmetric (Public-key) Algorithms -Usage of RSA (RS\*) and EC (EC\*) algorithms require a basic understanding -of how public-key cryptography is used with regards to digital signatures. -If you are unfamiliar, you may want to read -[this article](http://en.wikipedia.org/wiki/Public-key_cryptography). - -When using the RSASSA-PKCS1-v1_5 algorithms, the `key` argument in both -`jwt.encode()` and `jwt.decode()` (`"secret"` in the examples) is expected to -be either an RSA public or private key in PEM or SSH format. The type of key -(private or public) depends on whether you are signing or verifying. - -When using the ECDSA algorithms, the `key` argument is expected to -be an Elliptic Curve public or private key in PEM format. The type of key -(private or public) depends on whether you are signing or verifying. - - -## Support of registered claim names - -JSON Web Token defines some registered claim names and defines how they should -be used. PyJWT supports these registered claim names: - - - "exp" (Expiration Time) Claim - - "nbf" (Not Before Time) Claim - - "iss" (Issuer) Claim - - "aud" (Audience) Claim - - "iat" (Issued At) Claim - -### Expiration Time Claim - -From [the JWT spec][jwt-spec-reg-claims]: - -> The "exp" (expiration time) claim identifies the expiration time on -> or after which the JWT MUST NOT be accepted for processing. The -> processing of the "exp" claim requires that the current date/time -> MUST be before the expiration date/time listed in the "exp" claim. -> Implementers MAY provide for some small leeway, usually no more than -> a few minutes, to account for clock skew. Its value MUST be a number -> containing a NumericDate value. Use of this claim is OPTIONAL. - -You can pass the expiration time as a UTC UNIX timestamp (an int) or as a -datetime, which will be converted into an int. For example: - -```python -jwt.encode({'exp': 1371720939}, 'secret') - -jwt.encode({'exp': datetime.utcnow()}, 'secret') -``` - -Expiration time is automatically verified in `jwt.decode()` and raises -`jwt.ExpiredSignatureError` if the expiration time is in the past: - -```python -import jwt - -try: - jwt.decode('JWT_STRING', 'secret') -except jwt.ExpiredSignatureError: - # Signature has expired -``` - -Expiration time will be compared to the current UTC time (as given by -`timegm(datetime.utcnow().utctimetuple())`), so be sure to use a UTC timestamp -or datetime in encoding. - -You can turn off expiration time verification with the `verify_exp` parameter in the options argument. - -PyJWT also supports the leeway part of the expiration time definition, which -means you can validate a expiration time which is in the past but not very far. -For example, if you have a JWT payload with a expiration time set to 30 seconds -after creation but you know that sometimes you will process it after 30 seconds, -you can set a leeway of 10 seconds in order to have some margin: - -```python -import datetime -import time -import jwt - -jwt_payload = jwt.encode({ - 'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=30) -}, 'secret') - -time.sleep(32) - -# JWT payload is now expired -# But with some leeway, it will still validate -jwt.decode(jwt_payload, 'secret', leeway=10) -``` - -Instead of specifying the leeway as a number of seconds, a `datetime.timedelta` -instance can be used. The last line in the example above is equivalent to: - -```python -jwt.decode(jwt_payload, 'secret', leeway=datetime.timedelta(seconds=10)) -``` - - -### Not Before Time Claim - -> The "nbf" (not before) claim identifies the time before which the JWT -> MUST NOT be accepted for processing. The processing of the "nbf" -> claim requires that the current date/time MUST be after or equal to -> the not-before date/time listed in the "nbf" claim. Implementers MAY -> provide for some small leeway, usually no more than a few minutes, to -> account for clock skew. Its value MUST be a number containing a -> NumericDate value. Use of this claim is OPTIONAL. - -The `nbf` claim works similarly to the `exp` claim above. - -```python -jwt.encode({'nbf': 1371720939}, 'secret') - -jwt.encode({'nbf': datetime.utcnow()}, 'secret') -``` - -### Issuer Claim - -> The "iss" (issuer) claim identifies the principal that issued the -> JWT. The processing of this claim is generally application specific. -> The "iss" value is a case-sensitive string containing a StringOrURI -> value. Use of this claim is OPTIONAL. - -```python -import jwt - - -payload = { - 'some': 'payload', - 'iss': 'urn:foo' -} - -token = jwt.encode(payload, 'secret') -decoded = jwt.decode(token, 'secret', issuer='urn:foo') -``` - -If the issuer claim is incorrect, `jwt.InvalidIssuerError` will be raised. - - -### Audience Claim - -> The "aud" (audience) claim identifies the recipients that the JWT is -> intended for. Each principal intended to process the JWT MUST -> identify itself with a value in the audience claim. If the principal -> processing the claim does not identify itself with a value in the -> "aud" claim when this claim is present, then the JWT MUST be -> rejected. In the general case, the "aud" value is an array of case- -> sensitive strings, each containing a StringOrURI value. In the -> special case when the JWT has one audience, the "aud" value MAY be a -> single case-sensitive string containing a StringOrURI value. The -> interpretation of audience values is generally application specific. -> Use of this claim is OPTIONAL. - -```python -import jwt - - -payload = { - 'some': 'payload', - 'aud': 'urn:foo' -} - -token = jwt.encode(payload, 'secret') -decoded = jwt.decode(token, 'secret', audience='urn:foo') -``` - -If the audience claim is incorrect, `jwt.InvalidAudienceError` will be raised. - -### Issued At Claim - -> The iat (issued at) claim identifies the time at which the JWT was issued. -> This claim can be used to determine the age of the JWT. Its value MUST be a -> number containing a NumericDate value. Use of this claim is OPTIONAL. - -If the `iat` claim is in the future, an `jwt.InvalidIssuedAtError` exception -will be raised. - -```python -jwt.encode({'iat': 1371720939}, 'secret') - -jwt.encode({'iat': datetime.utcnow()}, 'secret') -``` - -## Frequently Asked Questions - -**How can I extract a public / private key from a x509 certificate?** - -The `load_pem_x509_certificate()` function from `cryptography` can be used to -extract the public or private keys from a x509 certificate in PEM format. - -```python -from cryptography.x509 import load_pem_x509_certificate -from cryptography.hazmat.backends import default_backend - -cert_str = "-----BEGIN CERTIFICATE-----MIIDETCCAfm..." -cert_obj = load_pem_x509_certificate(cert_str, default_backend()) -public_key = cert_obj.public_key() -private_key = cert_obj.private_key() -``` - [travis-status-image]: https://secure.travis-ci.org/jpadilla/pyjwt.svg?branch=master [travis]: http://travis-ci.org/jpadilla/pyjwt?branch=master [appveyor-status-image]: https://ci.appveyor.com/api/projects/status/h8nt70aqtwhht39t?svg=true @@ -378,6 +42,7 @@ [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 -[jwt-spec]: https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32 -[jwt-spec-reg-claims]: http://self-issued.info/docs/draft-jones-json-web-token-01.html#ReservedClaimName +[docs-status-image]: https://readthedocs.org/projects/pyjwt/badge/?version=latest +[docs]: http://pyjwt.readthedocs.org +[jwt-spec]: https://tools.ietf.org/html/rfc7519 [progrium]: https://github.com/progrium diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyJWT-1.4.0/jwt/__init__.py new/PyJWT-1.4.2/jwt/__init__.py --- old/PyJWT-1.4.0/jwt/__init__.py 2015-07-17 03:24:52.000000000 +0200 +++ new/PyJWT-1.4.2/jwt/__init__.py 2016-08-08 22:06:37.000000000 +0200 @@ -10,7 +10,7 @@ __title__ = 'pyjwt' -__version__ = '1.4.0' +__version__ = '1.4.2' __author__ = 'José Padilla' __license__ = 'MIT' __copyright__ = 'Copyright 2015 José Padilla' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyJWT-1.4.0/jwt/__main__.py new/PyJWT-1.4.2/jwt/__main__.py --- old/PyJWT-1.4.0/jwt/__main__.py 2015-05-30 16:21:11.000000000 +0200 +++ new/PyJWT-1.4.2/jwt/__main__.py 2016-06-30 06:07:44.000000000 +0200 @@ -40,7 +40,7 @@ action='store_false', dest='verify', default=True, - help='ignore signature verification on decode' + help='ignore signature and claims verification on decode' ) p.add_option( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyJWT-1.4.0/jwt/algorithms.py new/PyJWT-1.4.2/jwt/algorithms.py --- old/PyJWT-1.4.0/jwt/algorithms.py 2015-05-30 16:21:11.000000000 +0200 +++ new/PyJWT-1.4.2/jwt/algorithms.py 2016-08-08 22:06:37.000000000 +0200 @@ -1,7 +1,7 @@ import hashlib import hmac -from .compat import constant_time_compare, string_types, text_type +from .compat import binary_type, constant_time_compare, is_string_type from .exceptions import InvalidKeyError from .utils import der_to_raw_signature, raw_to_der_signature @@ -112,10 +112,10 @@ self.hash_alg = hash_alg def prepare_key(self, key): - if not isinstance(key, string_types) and not isinstance(key, bytes): + if not is_string_type(key): raise TypeError('Expecting a string- or bytes-formatted key.') - if isinstance(key, text_type): + if not isinstance(key, binary_type): key = key.encode('utf-8') invalid_strings = [ @@ -156,8 +156,8 @@ isinstance(key, RSAPublicKey): return key - if isinstance(key, string_types): - if isinstance(key, text_type): + if is_string_type(key): + if not isinstance(key, binary_type): key = key.encode('utf-8') try: @@ -213,8 +213,8 @@ isinstance(key, EllipticCurvePublicKey): return key - if isinstance(key, string_types): - if isinstance(key, text_type): + if is_string_type(key): + if not isinstance(key, binary_type): key = key.encode('utf-8') # Attempt to load key. We don't know if it's diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyJWT-1.4.0/jwt/api_jws.py new/PyJWT-1.4.2/jwt/api_jws.py --- old/PyJWT-1.4.0/jwt/api_jws.py 2015-07-17 03:17:27.000000000 +0200 +++ new/PyJWT-1.4.2/jwt/api_jws.py 2015-11-11 16:01:54.000000000 +0100 @@ -5,8 +5,8 @@ from collections import Mapping from .algorithms import Algorithm, get_default_algorithms # NOQA -from .compat import text_type -from .exceptions import DecodeError, InvalidAlgorithmError +from .compat import binary_type, string_types, text_type +from .exceptions import DecodeError, InvalidAlgorithmError, InvalidTokenError from .utils import base64url_decode, base64url_encode, merge_dict @@ -79,6 +79,7 @@ header = {'typ': self.header_typ, 'alg': algorithm} if headers: + self._validate_headers(headers) header.update(headers) json_header = json.dumps( @@ -125,12 +126,19 @@ Note: The signature is not verified so the header parameters should not be fully trusted until signature verification is complete """ - return self._load(jwt)[2] + headers = self._load(jwt)[2] + self._validate_headers(headers) + + return headers def _load(self, jwt): if isinstance(jwt, text_type): jwt = jwt.encode('utf-8') + if not issubclass(type(jwt), binary_type): + raise DecodeError("Invalid token type. Token must be a {0}".format( + binary_type)) + try: signing_input, crypto_segment = jwt.rsplit(b'.', 1) header_segment, payload_segment = signing_input.split(b'.', 1) @@ -180,6 +188,13 @@ except KeyError: raise InvalidAlgorithmError('Algorithm not supported') + def _validate_headers(self, headers): + if 'kid' in headers: + self._validate_kid(headers['kid']) + + def _validate_kid(self, kid): + if not isinstance(kid, string_types): + raise InvalidTokenError('Key ID header parameter must be a string') _jws_global_obj = PyJWS() encode = _jws_global_obj.encode diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyJWT-1.4.0/jwt/compat.py new/PyJWT-1.4.2/jwt/compat.py --- old/PyJWT-1.4.0/jwt/compat.py 2015-05-30 16:21:11.000000000 +0200 +++ new/PyJWT-1.4.2/jwt/compat.py 2016-08-08 22:06:37.000000000 +0200 @@ -11,11 +11,17 @@ if PY3: - string_types = str, text_type = str + binary_type = bytes else: - string_types = basestring, text_type = unicode + binary_type = str + +string_types = (text_type, binary_type) + + +def is_string_type(val): + return any([isinstance(val, typ) for typ in string_types]) def timedelta_total_seconds(delta): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyJWT-1.4.0/setup.cfg new/PyJWT-1.4.2/setup.cfg --- old/PyJWT-1.4.0/setup.cfg 2015-07-17 03:30:17.000000000 +0200 +++ new/PyJWT-1.4.2/setup.cfg 2016-08-08 22:07:50.000000000 +0200 @@ -1,5 +1,8 @@ [flake8] max-line-length = 119 +exclude = + docs/, + .tox/ [wheel] universal = 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyJWT-1.4.0/setup.py new/PyJWT-1.4.2/setup.py --- old/PyJWT-1.4.0/setup.py 2015-05-30 16:21:11.000000000 +0200 +++ new/PyJWT-1.4.2/setup.py 2016-06-30 06:07:44.000000000 +0200 @@ -30,11 +30,14 @@ sys.exit() tests_require = [ - 'pytest', + 'pytest==2.7.3', 'pytest-cov', 'pytest-runner', ] +needs_pytest = set(('pytest', 'test', 'ptr')).intersection(sys.argv) +pytest_runner = ['pytest-runner'] if needs_pytest else [] + setup( name='PyJWT', version=version, @@ -58,10 +61,11 @@ 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', 'Topic :: Utilities', ], test_suite='tests', - setup_requires=['pytest-runner'], + setup_requires=pytest_runner, tests_require=tests_require, extras_require=dict( test=tests_require, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyJWT-1.4.0/tests/test_algorithms.py new/PyJWT-1.4.2/tests/test_algorithms.py --- old/PyJWT-1.4.0/tests/test_algorithms.py 2015-05-30 16:21:11.000000000 +0200 +++ new/PyJWT-1.4.2/tests/test_algorithms.py 2016-08-08 22:06:37.000000000 +0200 @@ -56,7 +56,6 @@ algo.prepare_key(ensure_unicode('awesome')) - @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_hmac_should_throw_exception_if_key_is_pem_public_key(self): algo = HMACAlgorithm(HMACAlgorithm.SHA256) @@ -64,7 +63,6 @@ with open(key_path('testkey2_rsa.pub.pem'), 'r') as keyfile: algo.prepare_key(keyfile.read()) - @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_hmac_should_throw_exception_if_key_is_x509_certificate(self): algo = HMACAlgorithm(HMACAlgorithm.SHA256) @@ -72,7 +70,6 @@ with open(key_path('testkey_rsa.cer'), 'r') as keyfile: algo.prepare_key(keyfile.read()) - @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_hmac_should_throw_exception_if_key_is_ssh_public_key(self): algo = HMACAlgorithm(HMACAlgorithm.SHA256) @@ -80,7 +77,6 @@ with open(key_path('testkey_rsa.pub'), 'r') as keyfile: algo.prepare_key(keyfile.read()) - @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_hmac_should_throw_exception_if_key_is_x509_cert(self): algo = HMACAlgorithm(HMACAlgorithm.SHA256) @@ -96,6 +92,13 @@ algo.prepare_key(pem_key.read()) @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') + def test_rsa_should_accept_pem_private_key_bytes(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) + + with open(key_path('testkey_rsa'), 'rb') as pem_key: + algo.prepare_key(pem_key.read()) + + @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_rsa_should_accept_unicode_key(self): algo = RSAAlgorithm(RSAAlgorithm.SHA256) @@ -146,6 +149,13 @@ algo.prepare_key(ensure_unicode(ec_key.read())) @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') + def test_ec_should_accept_pem_private_key_bytes(self): + algo = ECAlgorithm(ECAlgorithm.SHA256) + + with open(key_path('testkey_ec'), 'rb') as ec_key: + algo.prepare_key(ec_key.read()) + + @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_ec_verify_should_return_false_if_signature_invalid(self): algo = ECAlgorithm(ECAlgorithm.SHA256) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyJWT-1.4.0/tests/test_api_jws.py new/PyJWT-1.4.2/tests/test_api_jws.py --- old/PyJWT-1.4.0/tests/test_api_jws.py 2015-07-17 03:17:27.000000000 +0200 +++ new/PyJWT-1.4.2/tests/test_api_jws.py 2015-11-11 16:01:54.000000000 +0100 @@ -6,7 +6,7 @@ from jwt.algorithms import Algorithm from jwt.api_jws import PyJWS from jwt.exceptions import ( - DecodeError, InvalidAlgorithmError + DecodeError, InvalidAlgorithmError, InvalidTokenError ) from jwt.utils import base64url_decode @@ -122,6 +122,26 @@ exception = context.value assert str(exception) == 'Not enough segments' + def test_decode_invalid_token_type_is_none(self, jws): + example_jws = None + example_secret = 'secret' + + with pytest.raises(DecodeError) as context: + jws.decode(example_jws, example_secret) + + exception = context.value + assert 'Invalid token type' in str(exception) + + def test_decode_invalid_token_type_is_int(self, jws): + example_jws = 123 + example_secret = 'secret' + + with pytest.raises(DecodeError) as context: + jws.decode(example_jws, example_secret) + + exception = context.value + assert 'Invalid token type' in str(exception) + def test_decode_with_non_mapping_header_throws_exception(self, jws): secret = 'secret' example_jws = ('MQ' # == 1 @@ -367,12 +387,24 @@ def test_get_unverified_header_returns_header_values(self, jws, payload): jws_message = jws.encode(payload, key='secret', algorithm='HS256', - headers={'kid': 123}) + headers={'kid': 'toomanysecrets'}) header = jws.get_unverified_header(jws_message) assert 'kid' in header - assert header['kid'] == 123 + assert header['kid'] == 'toomanysecrets' + + def test_get_unverified_header_fails_on_bad_header_types(self, jws, payload): + # Contains a bad kid value (int 123 instead of string) + example_jws = ( + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6MTIzfQ' + '.eyJzdWIiOiIxMjM0NTY3ODkwIn0' + '.vs2WY54jfpKP3JGC73Vq5YlMsqM5oTZ1ZydT77SiZSk') + + with pytest.raises(InvalidTokenError) as exc: + jws.get_unverified_header(example_jws) + + assert 'Key ID header parameter must be a string' == str(exc.value) @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_encode_decode_with_rsa_sha256(self, jws, payload): @@ -597,3 +629,14 @@ assert 'testheader' in header_obj assert header_obj['testheader'] == headers['testheader'] + + def test_encode_fails_on_invalid_kid_types(self, jws, payload): + with pytest.raises(InvalidTokenError) as exc: + jws.encode(payload, 'secret', headers={'kid': 123}) + + assert 'Key ID header parameter must be a string' == str(exc.value) + + with pytest.raises(InvalidTokenError) as exc: + jws.encode(payload, 'secret', headers={'kid': None}) + + assert 'Key ID header parameter must be a string' == str(exc.value) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/PyJWT-1.4.0/tox.ini new/PyJWT-1.4.2/tox.ini --- old/PyJWT-1.4.0/tox.ini 2015-05-30 16:21:11.000000000 +0200 +++ new/PyJWT-1.4.2/tox.ini 2016-06-30 06:07:44.000000000 +0200 @@ -1,14 +1,11 @@ [tox] -envlist = py{26,27,33,34}-crypto, py{27,34}-contrib_crypto, py{27,34}-nocrypto, flake8 +envlist = py{26,27,33,34,35}-crypto, py{27,35}-contrib_crypto, py{27,35}-nocrypto, flake8 [testenv] commands = python setup.py pytest deps = crypto: cryptography - pytest - pytest-cov - pytest-runner contrib_crypto: pycrypto contrib_crypto: ecdsa
