PyJWT-1.3.0/0000755000076500000240000000000012527650161013400 5ustar jpadillastaff00000000000000PyJWT-1.3.0/AUTHORS0000644000076500000240000000100512517223733014444 0ustar jpadillastaff00000000000000PyJWT lead developer --------------------- - jpadilla Original author ------------------ - progrium Patches and Suggestions ----------------------- - Boris Feld - Åsmund Ødegård Adding support for RSA-SHA256 privat/public signature. - Mark Adams - Wouter Bolsterlee - Michael Davis PyJWT-1.3.0/CHANGELOG.md0000644000076500000240000000746212527650137015225 0ustar jpadillastaff00000000000000Change Log ========================================================================= All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). [v1.3][1.3.0] ------------------------------------------------------------------------- ### Fixed - ECDSA (ES256, ES384, ES512) signatures are now being properly serialized [#158][158] - RSA-PSS (PS256, PS384, PS512) signatures now use the proper salt length for PSS padding. [#163][163] ### Added - Added a new `jwt.get_unverified_header()` to parse and return the header portion of a token prior to signature verification. ### Removed - Python 3.2 is no longer a supported platform. This version of Python is rarely used. Users affected by this should upgrade to 3.3+. [v1.2.0][1.2.0] ------------------------------------------------------------------------- ### Fixed - Added back `verify_expiration=` argument to `jwt.decode()` that was erroneously removed in [v1.1.0][1.1.0]. ### Changed - Refactored JWS-specific logic out of PyJWT and into PyJWS superclass. [#141][141] ### Deprecated - `verify_expiration=` argument to `jwt.decode()` is now deprecated and will be removed in a future version. Use the `option=` argument instead. [v1.1.0][1.1.0] ------------------------------------------------------------------------- ### Added - Added support for PS256, PS384, and PS512 algorithms. [#132][132] - Added flexible and complete verification options during decode. [#131][131] - Added this CHANGELOG.md file. ### Deprecated - Deprecated usage of the .decode(..., verify=False) parameter. ### Fixed - Fixed command line encoding. [#128][128] [v1.0.1][1.0.1] ------------------------------------------------------------------------- ### Fixed - Include jwt/contrib' and jwt/contrib/algorithms` in setup.py so that they will actually be included when installing. [882524d][882524d] - Fix bin/jwt after removing jwt.header(). [bd57b02][bd57b02] [v1.0.0][1.0.0] ------------------------------------------------------------------------- ### Changed - Moved `jwt.api.header` out of the public API. [#85][85] - Added README details how to extract public / private keys from an x509 certificate. [#100][100] - Refactor api.py functions into an object (`PyJWT`). [#101][101] - Added support for PyCrypto and ecdsa when cryptography isn't available. [#101][103] ### Fixed - Fixed a security vulnerability where `alg=None` header could bypass signature verification. [#109][109] - Fixed a security vulnerability by adding support for a whitelist of allowed `alg` values `jwt.decode(algorithms=[])`. [#110][110] [unreleased]: https://github.com/jpadilla/pyjwt/compare/1.3.0...HEAD [1.0.0]: https://github.com/jpadilla/pyjwt/compare/0.4.3...1.0.0 [1.0.1]: https://github.com/jpadilla/pyjwt/compare/1.0.0...1.0.1 [1.0.1]: https://github.com/jpadilla/pyjwt/compare/1.0.0...1.0.1 [1.0.1]: https://github.com/jpadilla/pyjwt/compare/1.0.0...1.0.1 [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 [109]: https://github.com/jpadilla/pyjwt/pull/109 [110]: https://github.com/jpadilla/pyjwt/pull/110 [100]: https://github.com/jpadilla/pyjwt/pull/100 [101]: https://github.com/jpadilla/pyjwt/pull/101 [103]: https://github.com/jpadilla/pyjwt/pull/103 [85]: https://github.com/jpadilla/pyjwt/pull/85 [882524d]: https://github.com/jpadilla/pyjwt/commit/882524d [bd57b02]: https://github.com/jpadilla/pyjwt/commit/bd57b02 [131]: https://github.com/jpadilla/pyjwt/pull/131 [132]: https://github.com/jpadilla/pyjwt/pull/132 [128]: https://github.com/jpadilla/pyjwt/pull/128 [141]: https://github.com/jpadilla/pyjwt/pull/141 [158]: https://github.com/jpadilla/pyjwt/pull/158 [163]: https://github.com/jpadilla/pyjwt/pull/163 PyJWT-1.3.0/jwt/0000755000076500000240000000000012527650161014204 5ustar jpadillastaff00000000000000PyJWT-1.3.0/jwt/__init__.py0000644000076500000240000000130312527650137016315 0ustar jpadillastaff00000000000000# -*- coding: utf-8 -*- # flake8: noqa """ JSON Web Token implementation Minimum implementation based on this spec: http://self-issued.info/docs/draft-jones-json-web-token-01.html """ __title__ = 'pyjwt' __version__ = '1.3.0' __author__ = 'José Padilla' __license__ = 'MIT' __copyright__ = 'Copyright 2015 José Padilla' from .api_jwt import ( encode, decode, register_algorithm, unregister_algorithm, get_unverified_header, PyJWT ) from .api_jws import PyJWS from .exceptions import ( InvalidTokenError, DecodeError, InvalidAudienceError, ExpiredSignatureError, ImmatureSignatureError, InvalidIssuedAtError, InvalidIssuerError, ExpiredSignature, InvalidAudience, InvalidIssuer ) PyJWT-1.3.0/jwt/__main__.py0000644000076500000240000000677012527650137016313 0ustar jpadillastaff00000000000000#!/usr/bin/env python from __future__ import absolute_import, print_function import json import optparse import sys import time from . import DecodeError, __package__, __version__, decode, encode def main(): usage = '''Encodes or decodes JSON Web Tokens based on input. %prog [options] input Decoding examples: %prog --key=secret json.web.token %prog --no-verify json.web.token Encoding requires the key option and takes space separated key/value pairs separated by equals (=) as input. Examples: %prog --key=secret iss=me exp=1302049071 %prog --key=secret foo=bar exp=+10 The exp key is special and can take an offset to current Unix time.\ ''' p = optparse.OptionParser( usage=usage, prog=__package__, version='%s %s' % (__package__, __version__), ) p.add_option( '-n', '--no-verify', action='store_false', dest='verify', default=True, help='ignore signature verification on decode' ) p.add_option( '--key', dest='key', metavar='KEY', default=None, help='set the secret key to sign with' ) p.add_option( '--alg', dest='algorithm', metavar='ALG', default='HS256', help='set crypto algorithm to sign with. default=HS256' ) options, arguments = p.parse_args() if len(arguments) > 0 or not sys.stdin.isatty(): if len(arguments) == 1 and (not options.verify or options.key): # Try to decode try: if not sys.stdin.isatty(): token = sys.stdin.read() else: token = arguments[0] token = token.encode('utf-8') data = decode(token, key=options.key, verify=options.verify) print(json.dumps(data)) sys.exit(0) except DecodeError as e: print(e) sys.exit(1) # Try to encode if options.key is None: print('Key is required when encoding. See --help for usage.') sys.exit(1) # Build payload object to encode payload = {} for arg in arguments: try: k, v = arg.split('=', 1) # exp +offset special case? if k == 'exp' and v[0] == '+' and len(v) > 1: v = str(int(time.time()+int(v[1:]))) # Cast to integer? if v.isdigit(): v = int(v) else: # Cast to float? try: v = float(v) except ValueError: pass # Cast to true, false, or null? constants = {'true': True, 'false': False, 'null': None} if v in constants: v = constants[v] payload[k] = v except ValueError: print('Invalid encoding input at {}'.format(arg)) sys.exit(1) try: token = encode( payload, key=options.key, algorithm=options.algorithm ) print(token) sys.exit(0) except Exception as e: print(e) sys.exit(1) else: p.print_help() if __name__ == '__main__': main() PyJWT-1.3.0/jwt/algorithms.py0000644000076500000240000002101412527650137016730 0ustar jpadillastaff00000000000000import hashlib import hmac from .compat import constant_time_compare, string_types, text_type from .exceptions import InvalidKeyError from .utils import der_to_raw_signature, raw_to_der_signature try: from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.serialization import ( load_pem_private_key, load_pem_public_key, load_ssh_public_key ) from cryptography.hazmat.primitives.asymmetric.rsa import ( RSAPrivateKey, RSAPublicKey ) from cryptography.hazmat.primitives.asymmetric.ec import ( EllipticCurvePrivateKey, EllipticCurvePublicKey ) from cryptography.hazmat.primitives.asymmetric import ec, padding from cryptography.hazmat.backends import default_backend from cryptography.exceptions import InvalidSignature has_crypto = True except ImportError: has_crypto = False def get_default_algorithms(): """ Returns the algorithms that are implemented by the library. """ default_algorithms = { 'none': NoneAlgorithm(), 'HS256': HMACAlgorithm(HMACAlgorithm.SHA256), 'HS384': HMACAlgorithm(HMACAlgorithm.SHA384), 'HS512': HMACAlgorithm(HMACAlgorithm.SHA512) } if has_crypto: default_algorithms.update({ 'RS256': RSAAlgorithm(RSAAlgorithm.SHA256), 'RS384': RSAAlgorithm(RSAAlgorithm.SHA384), 'RS512': RSAAlgorithm(RSAAlgorithm.SHA512), 'ES256': ECAlgorithm(ECAlgorithm.SHA256), 'ES384': ECAlgorithm(ECAlgorithm.SHA384), 'ES512': ECAlgorithm(ECAlgorithm.SHA512), 'PS256': RSAPSSAlgorithm(RSAPSSAlgorithm.SHA256), 'PS384': RSAPSSAlgorithm(RSAPSSAlgorithm.SHA384), 'PS512': RSAPSSAlgorithm(RSAPSSAlgorithm.SHA512) }) return default_algorithms class Algorithm(object): """ The interface for an algorithm used to sign and verify tokens. """ def prepare_key(self, key): """ Performs necessary validation and conversions on the key and returns the key value in the proper format for sign() and verify(). """ raise NotImplementedError def sign(self, msg, key): """ Returns a digital signature for the specified message using the specified key value. """ raise NotImplementedError def verify(self, msg, key, sig): """ Verifies that the specified digital signature is valid for the specified message and key values. """ raise NotImplementedError class NoneAlgorithm(Algorithm): """ Placeholder for use when no signing or verification operations are required. """ def prepare_key(self, key): if key == '': key = None if key is not None: raise InvalidKeyError('When alg = "none", key value must be None.') return key def sign(self, msg, key): return b'' def verify(self, msg, key, sig): return False class HMACAlgorithm(Algorithm): """ Performs signing and verification operations using HMAC and the specified hash function. """ SHA256 = hashlib.sha256 SHA384 = hashlib.sha384 SHA512 = hashlib.sha512 def __init__(self, hash_alg): self.hash_alg = hash_alg def prepare_key(self, key): if not isinstance(key, string_types) and not isinstance(key, bytes): raise TypeError('Expecting a string- or bytes-formatted key.') if isinstance(key, text_type): key = key.encode('utf-8') invalid_strings = [ b'-----BEGIN PUBLIC KEY-----', b'-----BEGIN CERTIFICATE-----', b'ssh-rsa' ] if any([string_value in key for string_value in invalid_strings]): raise InvalidKeyError( 'The specified key is an asymmetric key or x509 certificate and' ' should not be used as an HMAC secret.') return key def sign(self, msg, key): return hmac.new(key, msg, self.hash_alg).digest() def verify(self, msg, key, sig): return constant_time_compare(sig, self.sign(msg, key)) if has_crypto: class RSAAlgorithm(Algorithm): """ Performs signing and verification operations using RSASSA-PKCS-v1_5 and the specified hash function. """ SHA256 = hashes.SHA256 SHA384 = hashes.SHA384 SHA512 = hashes.SHA512 def __init__(self, hash_alg): self.hash_alg = hash_alg def prepare_key(self, key): if isinstance(key, RSAPrivateKey) or \ isinstance(key, RSAPublicKey): return key if isinstance(key, string_types): if isinstance(key, text_type): key = key.encode('utf-8') try: if key.startswith(b'ssh-rsa'): key = load_ssh_public_key(key, backend=default_backend()) else: key = load_pem_private_key(key, password=None, backend=default_backend()) except ValueError: key = load_pem_public_key(key, backend=default_backend()) else: raise TypeError('Expecting a PEM-formatted key.') return key def sign(self, msg, key): signer = key.signer( padding.PKCS1v15(), self.hash_alg() ) signer.update(msg) return signer.finalize() def verify(self, msg, key, sig): verifier = key.verifier( sig, padding.PKCS1v15(), self.hash_alg() ) verifier.update(msg) try: verifier.verify() return True except InvalidSignature: return False class ECAlgorithm(Algorithm): """ Performs signing and verification operations using ECDSA and the specified hash function """ SHA256 = hashes.SHA256 SHA384 = hashes.SHA384 SHA512 = hashes.SHA512 def __init__(self, hash_alg): self.hash_alg = hash_alg def prepare_key(self, key): if isinstance(key, EllipticCurvePrivateKey) or \ isinstance(key, EllipticCurvePublicKey): return key if isinstance(key, string_types): if isinstance(key, text_type): key = key.encode('utf-8') # Attempt to load key. We don't know if it's # a Signing Key or a Verifying Key, so we try # the Verifying Key first. try: key = load_pem_public_key(key, backend=default_backend()) except ValueError: key = load_pem_private_key(key, password=None, backend=default_backend()) else: raise TypeError('Expecting a PEM-formatted key.') return key def sign(self, msg, key): signer = key.signer(ec.ECDSA(self.hash_alg())) signer.update(msg) der_sig = signer.finalize() return der_to_raw_signature(der_sig, key.curve) def verify(self, msg, key, sig): try: der_sig = raw_to_der_signature(sig, key.curve) except ValueError: return False verifier = key.verifier(der_sig, ec.ECDSA(self.hash_alg())) verifier.update(msg) try: verifier.verify() return True except InvalidSignature: return False class RSAPSSAlgorithm(RSAAlgorithm): """ Performs a signature using RSASSA-PSS with MGF1 """ def sign(self, msg, key): signer = key.signer( padding.PSS( mgf=padding.MGF1(self.hash_alg()), salt_length=self.hash_alg.digest_size ), self.hash_alg() ) signer.update(msg) return signer.finalize() def verify(self, msg, key, sig): verifier = key.verifier( sig, padding.PSS( mgf=padding.MGF1(self.hash_alg()), salt_length=self.hash_alg.digest_size ), self.hash_alg() ) verifier.update(msg) try: verifier.verify() return True except InvalidSignature: return False PyJWT-1.3.0/jwt/api_jws.py0000644000076500000240000001401612527650137016217 0ustar jpadillastaff00000000000000import binascii import json import warnings from collections import Mapping from .algorithms import Algorithm, get_default_algorithms # NOQA from .compat import text_type from .exceptions import DecodeError, InvalidAlgorithmError from .utils import base64url_decode, base64url_encode, merge_dict class PyJWS(object): header_typ = 'JWT' def __init__(self, algorithms=None, options=None): self._algorithms = get_default_algorithms() self._valid_algs = (set(algorithms) if algorithms is not None else set(self._algorithms)) # Remove algorithms that aren't on the whitelist for key in list(self._algorithms.keys()): if key not in self._valid_algs: del self._algorithms[key] if not options: options = {} self.options = merge_dict(self._get_default_options(), options) @staticmethod def _get_default_options(): return { 'verify_signature': True } def register_algorithm(self, alg_id, alg_obj): """ Registers a new Algorithm for use when creating and verifying tokens. """ if alg_id in self._algorithms: raise ValueError('Algorithm already has a handler.') if not isinstance(alg_obj, Algorithm): raise TypeError('Object is not of type `Algorithm`') self._algorithms[alg_id] = alg_obj self._valid_algs.add(alg_id) def unregister_algorithm(self, alg_id): """ Unregisters an Algorithm for use when creating and verifying tokens Throws KeyError if algorithm is not registered. """ if alg_id not in self._algorithms: raise KeyError('The specified algorithm could not be removed' ' because it is not registered.') del self._algorithms[alg_id] self._valid_algs.remove(alg_id) def get_algorithms(self): """ Returns a list of supported values for the 'alg' parameter. """ return list(self._valid_algs) def encode(self, payload, key, algorithm='HS256', headers=None, json_encoder=None): segments = [] if algorithm is None: algorithm = 'none' if algorithm not in self._valid_algs: pass # Header header = {'typ': self.header_typ, 'alg': algorithm} if headers: header.update(headers) json_header = json.dumps( header, separators=(',', ':'), cls=json_encoder ).encode('utf-8') segments.append(base64url_encode(json_header)) segments.append(base64url_encode(payload)) # Segments signing_input = b'.'.join(segments) try: alg_obj = self._algorithms[algorithm] key = alg_obj.prepare_key(key) signature = alg_obj.sign(signing_input, key) except KeyError: raise NotImplementedError('Algorithm not supported') segments.append(base64url_encode(signature)) return b'.'.join(segments) def decode(self, jws, key='', verify=True, algorithms=None, options=None, **kwargs): payload, signing_input, header, signature = self._load(jws) if verify: merged_options = merge_dict(self.options, options) if merged_options.get('verify_signature'): self._verify_signature(payload, signing_input, header, signature, key, algorithms) else: warnings.warn('The verify parameter is deprecated. ' 'Please use options instead.', DeprecationWarning) return payload def get_unverified_header(self, jwt): """Returns back the JWT header parameters as a dict() 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] def _load(self, jwt): if isinstance(jwt, text_type): jwt = jwt.encode('utf-8') try: signing_input, crypto_segment = jwt.rsplit(b'.', 1) header_segment, payload_segment = signing_input.split(b'.', 1) except ValueError: raise DecodeError('Not enough segments') try: header_data = base64url_decode(header_segment) except (TypeError, binascii.Error): raise DecodeError('Invalid header padding') try: header = json.loads(header_data.decode('utf-8')) except ValueError as e: raise DecodeError('Invalid header string: %s' % e) if not isinstance(header, Mapping): raise DecodeError('Invalid header string: must be a json object') try: payload = base64url_decode(payload_segment) except (TypeError, binascii.Error): raise DecodeError('Invalid payload padding') try: signature = base64url_decode(crypto_segment) except (TypeError, binascii.Error): raise DecodeError('Invalid crypto padding') return (payload, signing_input, header, signature) def _verify_signature(self, payload, signing_input, header, signature, key='', algorithms=None): alg = header['alg'] if algorithms is not None and alg not in algorithms: raise InvalidAlgorithmError('The specified alg value is not allowed') try: alg_obj = self._algorithms[alg] key = alg_obj.prepare_key(key) if not alg_obj.verify(signing_input, key, signature): raise DecodeError('Signature verification failed') except KeyError: raise InvalidAlgorithmError('Algorithm not supported') _jws_global_obj = PyJWS() encode = _jws_global_obj.encode decode = _jws_global_obj.decode register_algorithm = _jws_global_obj.register_algorithm unregister_algorithm = _jws_global_obj.unregister_algorithm get_unverified_header = _jws_global_obj.get_unverified_header PyJWT-1.3.0/jwt/api_jwt.py0000644000076500000240000001377412527650137016232 0ustar jpadillastaff00000000000000import json import warnings from calendar import timegm from collections import Mapping from datetime import datetime, timedelta from .api_jws import PyJWS from .algorithms import Algorithm, get_default_algorithms # NOQA from .compat import string_types, timedelta_total_seconds from .exceptions import ( DecodeError, ExpiredSignatureError, ImmatureSignatureError, InvalidAudienceError, InvalidIssuedAtError, InvalidIssuerError ) from .utils import merge_dict class PyJWT(PyJWS): header_type = 'JWT' @staticmethod def _get_default_options(): return { 'verify_signature': True, 'verify_exp': True, 'verify_nbf': True, 'verify_iat': True, 'verify_aud': True, 'verify_iss': True } def encode(self, payload, key, algorithm='HS256', headers=None, json_encoder=None): # Check that we get a mapping if not isinstance(payload, Mapping): raise TypeError('Expecting a mapping object, as JWT only supports ' 'JSON objects as payloads.') # Payload for time_claim in ['exp', 'iat', 'nbf']: # Convert datetime to a intDate value in known time-format claims if isinstance(payload.get(time_claim), datetime): payload[time_claim] = timegm(payload[time_claim].utctimetuple()) json_payload = json.dumps( payload, separators=(',', ':'), cls=json_encoder ).encode('utf-8') return super(PyJWT, self).encode( json_payload, key, algorithm, headers, json_encoder ) def decode(self, jwt, key='', verify=True, algorithms=None, options=None, **kwargs): payload, signing_input, header, signature = self._load(jwt) decoded = super(PyJWT, self).decode(jwt, key, verify, algorithms, options, **kwargs) try: payload = json.loads(decoded.decode('utf-8')) except ValueError as e: raise DecodeError('Invalid payload string: %s' % e) if not isinstance(payload, Mapping): raise DecodeError('Invalid payload string: must be a json object') if verify: merged_options = merge_dict(self.options, options) self._validate_claims(payload, merged_options, **kwargs) return payload def _validate_claims(self, payload, options, audience=None, issuer=None, leeway=0, **kwargs): if 'verify_expiration' in kwargs: options['verify_exp'] = kwargs.get('verify_expiration', True) warnings.warn('The verify_expiration parameter is deprecated. ' 'Please use options instead.', DeprecationWarning) if isinstance(leeway, timedelta): leeway = timedelta_total_seconds(leeway) if not isinstance(audience, (string_types, type(None))): raise TypeError('audience must be a string or None') now = timegm(datetime.utcnow().utctimetuple()) if 'iat' in payload and options.get('verify_iat'): self._validate_iat(payload, now, leeway) if 'nbf' in payload and options.get('verify_nbf'): self._validate_nbf(payload, now, leeway) if 'exp' in payload and options.get('verify_exp'): self._validate_exp(payload, now, leeway) if options.get('verify_iss'): self._validate_iss(payload, issuer) if options.get('verify_aud'): self._validate_aud(payload, audience) def _validate_iat(self, payload, now, leeway): try: iat = int(payload['iat']) except ValueError: raise DecodeError('Issued At claim (iat) must be an integer.') if iat > (now + leeway): raise InvalidIssuedAtError('Issued At claim (iat) cannot be in' ' the future.') def _validate_nbf(self, payload, now, leeway): try: nbf = int(payload['nbf']) except ValueError: raise DecodeError('Not Before claim (nbf) must be an integer.') if nbf > (now + leeway): raise ImmatureSignatureError('The token is not yet valid (nbf)') def _validate_exp(self, payload, now, leeway): try: exp = int(payload['exp']) except ValueError: raise DecodeError('Expiration Time claim (exp) must be an' ' integer.') if exp < (now - leeway): raise ExpiredSignatureError('Signature has expired') def _validate_aud(self, payload, audience): if audience is None and 'aud' not in payload: return 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') audience_claims = payload['aud'] if isinstance(audience_claims, string_types): audience_claims = [audience_claims] if not isinstance(audience_claims, list): raise InvalidAudienceError('Invalid claim format in token') if any(not isinstance(c, string_types) for c in audience_claims): raise InvalidAudienceError('Invalid claim format in token') if audience not in audience_claims: raise InvalidAudienceError('Invalid audience') def _validate_iss(self, payload, issuer): if issuer is None: return if 'iss' not in payload: raise InvalidIssuerError('Token does not contain an iss claim') if payload['iss'] != issuer: raise InvalidIssuerError('Invalid issuer') _jwt_global_obj = PyJWT() encode = _jwt_global_obj.encode decode = _jwt_global_obj.decode register_algorithm = _jwt_global_obj.register_algorithm unregister_algorithm = _jwt_global_obj.unregister_algorithm get_unverified_header = _jwt_global_obj.get_unverified_header PyJWT-1.3.0/jwt/compat.py0000644000076500000240000000225312527650137016046 0ustar jpadillastaff00000000000000""" The `compat` module provides support for backwards compatibility with older versions of python, and compatibility wrappers around optional packages. """ # flake8: noqa import sys import hmac PY3 = sys.version_info[0] == 3 if PY3: string_types = str, text_type = str else: string_types = basestring, text_type = unicode def timedelta_total_seconds(delta): try: delta.total_seconds except AttributeError: # On Python 2.6, timedelta instances do not have # a .total_seconds() method. total_seconds = delta.days * 24 * 60 * 60 + delta.seconds else: total_seconds = delta.total_seconds() return total_seconds try: constant_time_compare = hmac.compare_digest except AttributeError: # Fallback for Python < 2.7 def constant_time_compare(val1, val2): """ Returns True if the two strings are equal, False otherwise. The time taken is independent of the number of characters that match. """ if len(val1) != len(val2): return False result = 0 for x, y in zip(val1, val2): result |= ord(x) ^ ord(y) return result == 0 PyJWT-1.3.0/jwt/contrib/0000755000076500000240000000000012527650161015644 5ustar jpadillastaff00000000000000PyJWT-1.3.0/jwt/contrib/__init__.py0000644000076500000240000000000012517223733017743 0ustar jpadillastaff00000000000000PyJWT-1.3.0/jwt/contrib/algorithms/0000755000076500000240000000000012527650161020015 5ustar jpadillastaff00000000000000PyJWT-1.3.0/jwt/contrib/algorithms/__init__.py0000644000076500000240000000000012517223733022114 0ustar jpadillastaff00000000000000PyJWT-1.3.0/jwt/contrib/algorithms/py_ecdsa.py0000644000076500000240000000335312527650137022165 0ustar jpadillastaff00000000000000# Note: This file is named py_ecdsa.py because import behavior in Python 2 # would cause ecdsa.py to squash the ecdsa library that it depends upon. import hashlib import ecdsa from jwt.algorithms import Algorithm from jwt.compat import string_types, text_type class ECAlgorithm(Algorithm): """ Performs signing and verification operations using ECDSA and the specified hash function This class requires the ecdsa package to be installed. This is based off of the implementation in PyJWT 0.3.2 """ SHA256 = hashlib.sha256 SHA384 = hashlib.sha384 SHA512 = hashlib.sha512 def __init__(self, hash_alg): self.hash_alg = hash_alg def prepare_key(self, key): if isinstance(key, ecdsa.SigningKey) or \ isinstance(key, ecdsa.VerifyingKey): return key if isinstance(key, string_types): if isinstance(key, text_type): key = key.encode('utf-8') # Attempt to load key. We don't know if it's # a Signing Key or a Verifying Key, so we try # the Verifying Key first. try: key = ecdsa.VerifyingKey.from_pem(key) except ecdsa.der.UnexpectedDER: key = ecdsa.SigningKey.from_pem(key) else: raise TypeError('Expecting a PEM-formatted key.') return key def sign(self, msg, key): return key.sign(msg, hashfunc=self.hash_alg, sigencode=ecdsa.util.sigencode_string) def verify(self, msg, key, sig): try: return key.verify(sig, msg, hashfunc=self.hash_alg, sigdecode=ecdsa.util.sigdecode_string) except AssertionError: return False PyJWT-1.3.0/jwt/contrib/algorithms/pycrypto.py0000644000076500000240000000234212517223733022261 0ustar jpadillastaff00000000000000import Crypto.Hash.SHA256 import Crypto.Hash.SHA384 import Crypto.Hash.SHA512 from Crypto.PublicKey import RSA from Crypto.Signature import PKCS1_v1_5 from jwt.algorithms import Algorithm from jwt.compat import string_types, text_type class RSAAlgorithm(Algorithm): """ Performs signing and verification operations using RSASSA-PKCS-v1_5 and the specified hash function. This class requires PyCrypto package to be installed. This is based off of the implementation in PyJWT 0.3.2 """ SHA256 = Crypto.Hash.SHA256 SHA384 = Crypto.Hash.SHA384 SHA512 = Crypto.Hash.SHA512 def __init__(self, hash_alg): self.hash_alg = hash_alg def prepare_key(self, key): if isinstance(key, RSA._RSAobj): return key if isinstance(key, string_types): if isinstance(key, text_type): key = key.encode('utf-8') key = RSA.importKey(key) else: raise TypeError('Expecting a PEM- or RSA-formatted key.') return key def sign(self, msg, key): return PKCS1_v1_5.new(key).sign(self.hash_alg.new(msg)) def verify(self, msg, key, sig): return PKCS1_v1_5.new(key).verify(self.hash_alg.new(msg), sig) PyJWT-1.3.0/jwt/exceptions.py0000644000076500000240000000120312517223733016733 0ustar jpadillastaff00000000000000class InvalidTokenError(Exception): pass class DecodeError(InvalidTokenError): pass class ExpiredSignatureError(InvalidTokenError): pass class InvalidAudienceError(InvalidTokenError): pass class InvalidIssuerError(InvalidTokenError): pass class InvalidIssuedAtError(InvalidTokenError): pass class ImmatureSignatureError(InvalidTokenError): pass class InvalidKeyError(Exception): pass class InvalidAlgorithmError(InvalidTokenError): pass # Compatibility aliases (deprecated) ExpiredSignature = ExpiredSignatureError InvalidAudience = InvalidAudienceError InvalidIssuer = InvalidIssuerError PyJWT-1.3.0/jwt/utils.py0000644000076500000240000000303612527650137015723 0ustar jpadillastaff00000000000000import base64 import binascii try: from cryptography.hazmat.primitives.asymmetric.utils import ( decode_rfc6979_signature, encode_rfc6979_signature ) except ImportError: pass def base64url_decode(input): rem = len(input) % 4 if rem > 0: input += b'=' * (4 - rem) return base64.urlsafe_b64decode(input) def base64url_encode(input): return base64.urlsafe_b64encode(input).replace(b'=', b'') def merge_dict(original, updates): if not updates: return original try: merged_options = original.copy() merged_options.update(updates) except (AttributeError, ValueError) as e: raise TypeError('original and updates must be a dictionary: %s' % e) return merged_options def number_to_bytes(num, num_bytes): padded_hex = '%0*x' % (2 * num_bytes, num) big_endian = binascii.a2b_hex(padded_hex.encode('ascii')) return big_endian def bytes_to_number(string): return int(binascii.b2a_hex(string), 16) def der_to_raw_signature(der_sig, curve): num_bits = curve.key_size num_bytes = (num_bits + 7) // 8 r, s = decode_rfc6979_signature(der_sig) return number_to_bytes(r, num_bytes) + number_to_bytes(s, num_bytes) def raw_to_der_signature(raw_sig, curve): num_bits = curve.key_size num_bytes = (num_bits + 7) // 8 if len(raw_sig) != 2 * num_bytes: raise ValueError('Invalid signature') r = bytes_to_number(raw_sig[:num_bytes]) s = bytes_to_number(raw_sig[num_bytes:]) return encode_rfc6979_signature(r, s) PyJWT-1.3.0/LICENSE0000644000076500000240000000207012457167006014407 0ustar jpadillastaff00000000000000The MIT License (MIT) Copyright (c) 2015 José Padilla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PyJWT-1.3.0/MANIFEST.in0000644000076500000240000000014312517223733015134 0ustar jpadillastaff00000000000000include README.md include CHANGELOG.md include LICENSE include AUTHORS include tox.ini graft tests PyJWT-1.3.0/PKG-INFO0000644000076500000240000003627212527650161014507 0ustar jpadillastaff00000000000000Metadata-Version: 1.1 Name: PyJWT Version: 1.3.0 Summary: JSON Web Token implementation in Python Home-page: http://github.com/jpadilla/pyjwt Author: José Padilla Author-email: hello@jpadilla.com License: MIT Description: # PyJWT [![travis-status-image]][travis] [![pypi-version-image]][pypi] [![coveralls-status-image]][coveralls] A Python implementation of [JSON Web Token draft 32][jwt-spec]. Original implementation was written by [@progrium][progrium]. ## Installing ``` $ 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 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. ## 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'} ``` 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: ```python try: payload = jwt.decode(encoded) 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: ```python options = { 'verify_signature': True, 'verify_exp': True, 'verify_nbf': True, 'verify_iat': True, 'verify_aud': True } ``` 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. ```python >>> options = { >>> 'verify_exp': True, >>> } >>> 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.* ## Tests You can run tests from the project root after cloning with: ``` $ 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.png?branch=master [travis]: http://travis-ci.org/jpadilla/pyjwt?branch=master [pypi-version-image]: https://pypip.in/version/pyjwt/badge.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 [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 [progrium]: https://github.com/progrium Keywords: jwt json web token security signing Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Natural Language :: English Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Topic :: Utilities PyJWT-1.3.0/PyJWT.egg-info/0000755000076500000240000000000012527650161016047 5ustar jpadillastaff00000000000000PyJWT-1.3.0/PyJWT.egg-info/dependency_links.txt0000644000076500000240000000000112527650161022115 0ustar jpadillastaff00000000000000 PyJWT-1.3.0/PyJWT.egg-info/entry_points.txt0000644000076500000240000000005312527650161021343 0ustar jpadillastaff00000000000000[console_scripts] jwt = jwt.__main__:main PyJWT-1.3.0/PyJWT.egg-info/PKG-INFO0000644000076500000240000003627212527650161017156 0ustar jpadillastaff00000000000000Metadata-Version: 1.1 Name: PyJWT Version: 1.3.0 Summary: JSON Web Token implementation in Python Home-page: http://github.com/jpadilla/pyjwt Author: José Padilla Author-email: hello@jpadilla.com License: MIT Description: # PyJWT [![travis-status-image]][travis] [![pypi-version-image]][pypi] [![coveralls-status-image]][coveralls] A Python implementation of [JSON Web Token draft 32][jwt-spec]. Original implementation was written by [@progrium][progrium]. ## Installing ``` $ 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 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. ## 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'} ``` 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: ```python try: payload = jwt.decode(encoded) 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: ```python options = { 'verify_signature': True, 'verify_exp': True, 'verify_nbf': True, 'verify_iat': True, 'verify_aud': True } ``` 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. ```python >>> options = { >>> 'verify_exp': True, >>> } >>> 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.* ## Tests You can run tests from the project root after cloning with: ``` $ 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.png?branch=master [travis]: http://travis-ci.org/jpadilla/pyjwt?branch=master [pypi-version-image]: https://pypip.in/version/pyjwt/badge.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 [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 [progrium]: https://github.com/progrium Keywords: jwt json web token security signing Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Natural Language :: English Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Topic :: Utilities PyJWT-1.3.0/PyJWT.egg-info/requires.txt0000644000076500000240000000016012527650161020444 0ustar jpadillastaff00000000000000 [crypto] cryptography [flake8] flake8 flake8-import-order pep8-naming [test] pytest pytest-cov pytest-runner PyJWT-1.3.0/PyJWT.egg-info/SOURCES.txt0000644000076500000240000000266712527650161017746 0ustar jpadillastaff00000000000000AUTHORS CHANGELOG.md LICENSE MANIFEST.in README.md setup.cfg setup.py tox.ini PyJWT.egg-info/PKG-INFO PyJWT.egg-info/SOURCES.txt PyJWT.egg-info/dependency_links.txt PyJWT.egg-info/entry_points.txt PyJWT.egg-info/requires.txt PyJWT.egg-info/top_level.txt jwt/__init__.py jwt/__main__.py jwt/algorithms.py jwt/api_jws.py jwt/api_jwt.py jwt/compat.py jwt/exceptions.py jwt/utils.py jwt/contrib/__init__.py 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_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 tests/keys/jwk_hmac.json tests/keys/jwk_rsa_key.json tests/keys/jwk_rsa_pub.json tests/keys/testkey2_rsa.pub.pem tests/keys/testkey_ec tests/keys/testkey_ec.pub tests/keys/testkey_rsa tests/keys/testkey_rsa.cer tests/keys/testkey_rsa.pubPyJWT-1.3.0/PyJWT.egg-info/top_level.txt0000644000076500000240000000000412527650161020573 0ustar jpadillastaff00000000000000jwt PyJWT-1.3.0/README.md0000644000076500000240000002731112517716076014672 0ustar jpadillastaff00000000000000# PyJWT [![travis-status-image]][travis] [![pypi-version-image]][pypi] [![coveralls-status-image]][coveralls] A Python implementation of [JSON Web Token draft 32][jwt-spec]. Original implementation was written by [@progrium][progrium]. ## Installing ``` $ 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 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. ## 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'} ``` 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: ```python try: payload = jwt.decode(encoded) 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: ```python options = { 'verify_signature': True, 'verify_exp': True, 'verify_nbf': True, 'verify_iat': True, 'verify_aud': True } ``` 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. ```python >>> options = { >>> 'verify_exp': True, >>> } >>> 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.* ## Tests You can run tests from the project root after cloning with: ``` $ 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.png?branch=master [travis]: http://travis-ci.org/jpadilla/pyjwt?branch=master [pypi-version-image]: https://pypip.in/version/pyjwt/badge.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 [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 [progrium]: https://github.com/progrium PyJWT-1.3.0/setup.cfg0000644000076500000240000000033212527650161015217 0ustar jpadillastaff00000000000000[flake8] max-line-length = 119 [wheel] universal = 1 [pytest] addopts = --cov-report term-missing --cov-config=.coveragerc --cov . [aliases] test = pytest [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 PyJWT-1.3.0/setup.py0000755000076500000240000000430412527650137015121 0ustar jpadillastaff00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import os import re import sys from setuptools import find_packages, setup def get_version(package): """ Return package version as listed in `__version__` in `init.py`. """ with open(os.path.join(package, '__init__.py'), 'rb') as init_py: src = init_py.read().decode('utf-8') return re.search("__version__ = ['\"]([^'\"]+)['\"]", src).group(1) version = get_version('jwt') with open(os.path.join(os.path.dirname(__file__), 'README.md')) as readme: long_description = readme.read() if sys.argv[-1] == 'publish': os.system('python setup.py sdist upload') os.system('python setup.py bdist_wheel upload') print('You probably want to also tag the version now:') print(" git tag -a {0} -m 'version {0}'".format(version)) print(' git push --tags') sys.exit() tests_require = [ 'pytest', 'pytest-cov', 'pytest-runner', ] setup( name='PyJWT', version=version, author='José Padilla', author_email='hello@jpadilla.com', description='JSON Web Token implementation in Python', license='MIT', keywords='jwt json web token security signing', url='http://github.com/jpadilla/pyjwt', packages=find_packages( exclude=["*.tests", "*.tests.*", "tests.*", "tests"] ), long_description=long_description, classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Natural Language :: English', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Topic :: Utilities', ], test_suite='tests', setup_requires=['pytest-runner'], tests_require=tests_require, extras_require=dict( test=tests_require, crypto=['cryptography'], flake8=[ 'flake8', 'flake8-import-order', 'pep8-naming' ] ), entry_points={ 'console_scripts': [ 'jwt = jwt.__main__:main' ] } ) PyJWT-1.3.0/tests/0000755000076500000240000000000012527650161014542 5ustar jpadillastaff00000000000000PyJWT-1.3.0/tests/__init__.py0000644000076500000240000000000012457167006016644 0ustar jpadillastaff00000000000000PyJWT-1.3.0/tests/__init__.pyc0000644000076500000240000000022012457345251017013 0ustar jpadillastaff00000000000000 Tc@sdS(N((((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/__init__.pytsPyJWT-1.3.0/tests/__pycache__/0000755000076500000240000000000012527650161016752 5ustar jpadillastaff00000000000000PyJWT-1.3.0/tests/__pycache__/test_algorithms.cpython-27-PYTEST.pyc0000644000076500000240000003351412517227064025645 0ustar jpadillastaff00000000000000 '=U*c@sddlZddljjZddlZddlmZm Z m Z ddl m Z ddl Z ddlmZmZmZy&ddlmZmZmZeZWnek reZnXdd dYZdS( iN(t Algorithmt HMACAlgorithmt NoneAlgorithm(tInvalidKeyErrori(t ensure_bytestensure_unicodetkey_path(t RSAAlgorithmt ECAlgorithmtRSAPSSAlgorithmtTestAlgorithmscBs^eZdZdZdZdZdZdZej j e dddZ ej j e ddd Z ej j e ddd Zej j e ddd Zej j e ddd Zej j e ddd Zej j e dddZej j e dddZej j e dddZej j e dddZej j e dddZej j e dddZej j e dddZej j e dddZej j e dddZej j e dddZRS(cCs0t}tjt|jdWdQXdS(Nttest(RtpytesttraisestNotImplementedErrort prepare_key(tselftalgo((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt=test_algorithm_should_throw_exception_if_prepare_key_not_impls cCs3t}tjt|jddWdQXdS(Ntmessagetkey(RR R Rtsign(RR((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt6test_algorithm_should_throw_exception_if_sign_not_impls cCs6t}tjt|jdddWdQXdS(NRRt signature(RR R Rtverify(RR((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt8test_algorithm_should_throw_exception_if_verify_not_impls cCs0t}tjt|jdWdQXdS(Nt123(RR R RR(RR((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt=test_none_algorithm_should_throw_exception_if_key_is_not_none%s c CsRttj}tjt}|jtWdQX|j}t|}d}||k}|s@t j d |fd||fidt j kst j trt jtndd6dt j kst j |rt j|ndd6t j|d6t j|d 6}di|d 6}tt j|nd}}}dS(Ns+Expecting a string- or bytes-formatted key.s==s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)ststrtpy0t exceptiontpy1tpy3tpy6tsassert %(py8)stpy8(s==(s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)ssassert %(py8)s(RtSHA256R R t TypeErrorRtobjecttvalueRt @pytest_art_call_reprcomparet @py_builtinstlocalst_should_repr_global_namet _safereprtAssertionErrort_format_explanationtNone( RRtcontextRt @py_assert2t @py_assert5t @py_assert4t @py_format7t @py_format9((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt%test_hmac_should_reject_nonstring_key+s   cCs&ttj}|jtddS(Ntawesome(RR$RR(RR((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt#test_hmac_should_accept_unicode_key4streasons*Not supported without cryptography libraryc CsZttj}tjt6ttdd}|j|jWdQXWdQXdS(Nstestkey2_rsa.pub.pemtr( RR$R R RtopenRRtread(RRtkeyfile((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt9test_hmac_should_throw_exception_if_key_is_pem_public_key9sc CsZttj}tjt6ttdd}|j|jWdQXWdQXdS(Nstestkey_rsa.cerR;( RR$R R RR<RRR=(RRR>((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt;test_hmac_should_throw_exception_if_key_is_x509_certificateAsc CsZttj}tjt6ttdd}|j|jWdQXWdQXdS(Nstestkey_rsa.pubR;( RR$R R RR<RRR=(RRR>((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt9test_hmac_should_throw_exception_if_key_is_ssh_public_keyIsc CsZttj}tjt6ttdd}|j|jWdQXWdQXdS(Nstestkey2_rsa.pub.pemR;( RR$R R RR<RRR=(RRR>((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt4test_hmac_should_throw_exception_if_key_is_x509_certQscCsDttj}ttdd}|j|jWdQXdS(Nstestkey2_rsa.pub.pemR;(RR$R<RRR=(RRtpem_key((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt$test_rsa_should_parse_pem_public_keyYscCsJttj}ttdd }|jt|jWdQXdS(Nt testkey_rsaR;(RR$R<RRRR=(RRtrsa_key((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt"test_rsa_should_accept_unicode_key`scCs6ttj}tjt|jdWdQXdS(N(RR$R R R%RR0(RR((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt%test_rsa_should_reject_non_string_keygsc Csttj}td}tjtd}|td7}ttdd}|j|j}WdQX|j |||}| }|sd idt j kst j |rt j|ndd 6}tt j|nd}dS( Ns Hello World!sXyS6zk9DBkuGTtcBzLUzSpo9gGJxJFOGvUqN01iLhWHrzBQ9ZEz3+Ae38AXp10RWwscp42ySC85Z6zoN67yGkLNWnfmCZSEv+xqELGEvBJvciOKsrhiObUl2mveSc1oeO/2ujkGDkkkJ2epn0YliacVjZF5+/uDmImUfAAj8lzjnHlzYixsn5jGz1H07jYYbi9diixN8IUhXeTafwFg02IcONhum29V40Wu6O5tAKWlJXfHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCAAPCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA==Rstestkey_rsa.pubR;R"sassert not %(py0)stresultRsassert not %(py0)s(RR$Rtbase64t b64decodeR<RRR=RR*R+R(R,R-R.R/R0( RRRtsigR>tpub_keyRIt @py_assert1t @py_format2((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt8test_rsa_verify_should_return_false_if_signature_invalidns   AcCsttj}td}tjtd}ttdd}|j|j}WdQX|j |||}|sd idt j kst j |rt j|ndd6}tt j|ndS( Ns Hello World!sXyS6zk9DBkuGTtcBzLUzSpo9gGJxJFOGvUqN01iLhWHrzBQ9ZEz3+Ae38AXp10RWwscp42ySC85Z6zoN67yGkLNWnfmCZSEv+xqELGEvBJvciOKsrhiObUl2mveSc1oeO/2ujkGDkkkJ2epn0YliacVjZF5+/uDmImUfAAj8lzjnHlzYixsn5jGz1H07jYYbi9diixN8IUhXeTafwFg02IcONhum29V40Wu6O5tAKWlJXfHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCAAPCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA==stestkey_rsa.pubR;R"sassert %(py0)sRIRsassert %(py0)s(RR$RRJRKR<RRR=RR*R+R(R,R-R.R/(RRRRLR>RMRIt @py_format1((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt5test_rsa_verify_should_return_true_if_signature_valids   AcCs6ttj}tjt|jdWdQXdS(N(RR$R R R%RR0(RR((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt$test_ec_should_reject_non_string_keyscCsJttj}ttdd }|jt|jWdQXdS(Nt testkey_ecR;(RR$R<RRRR=(RRtec_key((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt!test_ec_should_accept_unicode_keysc Csttj}td}tjtdjdd}ttdd}|j|j }WdQX|j |||}| }|sd idt j kst j|rt j|ndd 6}tt j|nd}dS( Ns Hello World!sMIGIAkIB9vYz+inBL8aOTA4auYz/zVuig7TT1bQgKROIQX9YpViHkFa4DT55FuFKn9XzVlk90p6ldEj42DC9YecXHbC2t+cCQgCicY+8f3f/KCNtWK7cif6vdsVwm6Lrjs0Ag6ZqCf+olN11hVt1qKBC4lXppqB1gNWEmNQaiz1z2QRyczJ8hSJmbw==R;tsstestkey_ec.pubR"sassert not %(py0)sRIRsassert not %(py0)s(RR$RRJRKtreplaceR<RRR=RR*R+R(R,R-R.R/R0( RRRRLR>RMRIRNRO((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt7test_ec_verify_should_return_false_if_signature_invalids  AcCsttj}td}tjtd}ttdd}|j|j}WdQX|j |||}|sd idt j kst j |rt j|ndd6}tt j|ndS( Ns Hello World!sMIGIAkIB9vYz+inBL8aOTA4auYz/zVuig7TT1bQgKROIQX9YpViHkFa4DT55FuFKn9XzVlk90p6ldEj42DC9YecXHbC2t+cCQgCicY+8f3f/KCNtWK7cif6vdsVwm6Lrjs0Ag6ZqCf+olN11hVt1qKBC4lXppqB1gNWEmNQaiz1z2QRyczJ8hSJmbw==stestkey_ec.pubR;R"sassert %(py0)sRIRsassert %(py0)s(RR$RRJRKR<RRR=RR*R+R(R,R-R.R/(RRRRLR>RMRIRQ((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt4test_ec_verify_should_return_true_if_signature_valids   Ac Cs ttj}td}ttdd.}|j|j}|j||}WdQXttdd}|j|j}WdQX|j|||}|sd idt j kst j |rt j |ndd6}tt j|ndS( Ns Hello World!RER;stestkey_rsa.pubR"sassert %(py0)sRIRsassert %(py0)s(R R$RR<RRR=RRR*R+R(R,R-R.R/( RRRR>tpriv_keyRLRMRIRQ((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt0test_rsa_pss_sign_then_verify_should_return_trues Ac Csttj}td}tjtd}|td7}ttdd}|j|j}WdQX|j |||}| }|sd idt j kst j |rt j|ndd 6}tt j|nd}dS( Ns Hello World!sXywKAUGRIDC//6X+tjvZA96yEtMqpOrSppCNfYI7NKyon3P7doud5v65oWNuvQsz0fzPGfF7mQFGo9Cm9Vn0nljm4G6PtqZRbz5fXNQBH9k10gq34AtM02c/cveqACQ8gF3zxWh6qr9jVqIpeMEaEBIkvqG954E0HT9s9ybHShgHX9mlWk186/LopP4xe5c/hxOQjwhv6yDlTiwJFiqjNCvj0GyBKsc4iECLGIIO+4mC4daOCWqbpZDuLb1imKpmm8Nsm56kAxijMLZnpCcnPgyb7CqG+B93W9GHglA5drUeR1gRtO7vqbZMsCAQ4bpjXxwbYyjQlEVuMl73UL6sOWg==Rstestkey_rsa.pubR;R"sassert not %(py0)sRIRsassert not %(py0)s(R R$RRJRKR<RRR=RR*R+R(R,R-R.R/R0( RRt jwt_messagetjwt_sigR>t jwt_pub_keyRIRNRO((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt<test_rsa_pss_verify_should_return_false_if_signature_invalids   AcCsttj}td}tjtd}ttdd}|j|j}WdQX|j |||}|sd idt j kst j |rt j|ndd6}tt j|ndS( Ns Hello World!sXywKAUGRIDC//6X+tjvZA96yEtMqpOrSppCNfYI7NKyon3P7doud5v65oWNuvQsz0fzPGfF7mQFGo9Cm9Vn0nljm4G6PtqZRbz5fXNQBH9k10gq34AtM02c/cveqACQ8gF3zxWh6qr9jVqIpeMEaEBIkvqG954E0HT9s9ybHShgHX9mlWk186/LopP4xe5c/hxOQjwhv6yDlTiwJFiqjNCvj0GyBKsc4iECLGIIO+4mC4daOCWqbpZDuLb1imKpmm8Nsm56kAxijMLZnpCcnPgyb7CqG+B93W9GHglA5drUeR1gRtO7vqbZMsCAQ4bpjXxwbYyjQlEVuMl73UL6sOWg==stestkey_rsa.pubR;R"sassert %(py0)sRIRsassert %(py0)s(R R$RRJRKR<RRR=RR*R+R(R,R-R.R/(RRR]R^R>R_RIRQ((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyt9test_rsa_pss_verify_should_return_true_if_signature_valids   A(t__name__t __module__RRRRR7R9R tmarktskipift has_cryptoR?R@RARBRDRGRHRPRRRSRVRYRZR\R`Ra(((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyR s,     """""""""""""""((t __builtin__R*t_pytest.assertion.rewritet assertiontrewriteR(RJtjwt.algorithmsRRRtjwt.exceptionsRR tutilsRRRRRR tTrueRft ImportErrortFalseR (((s@/Users/jpadilla/Projects/Personal/pyjwt/tests/test_algorithms.pyts      PyJWT-1.3.0/tests/__pycache__/test_api_jws.cpython-27-PYTEST.pyc0000644000076500000240000012100412517227064025120 0ustar jpadillastaff00000000000000 '=UYc@sCddlZddljjZddlZddlmZddl m Z ddl m Z ddl mZmZddlmZddlZddlmZmZdd lmZmZy6dd lmZdd lmZmZmZeZ Wne!k re"Z nXej#d Z$ej#d Z%dddYZ&dS(iN(tDecimal(t Algorithm(tPyJWS(t DecodeErrortInvalidAlgorithmError(tbase64url_decodei(t string_typest text_type(t ensure_bytestensure_unicode(tdefault_backend(tload_pem_private_keytload_pem_public_keytload_ssh_public_keycCstS(N(R(((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pytjwsscCs tdS(sA Creates a sample jws claimset for use as a payload during tests s hello world(R(((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pytpayload"stTestJWScBsweZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZdZejje dddZejje dddZdZdZdZdZdZdZdZdZ dZ!dZ"dZ#d Z$d!Z%d"Z&d#Z'd$Z(ejje dd%d&Z)ejje dd%d'Z*ejje dd%d(Z+d)Z,ejje ddd*Z-ejje ddd+Z.ejje ddd,Z/d-Z0d.Z1d/Z2d0Z3d1Z4RS(2cCs@|jdttjt|jdtWdQXdS(NtAAA(tregister_algorithmRtpytesttraisest ValueError(tselfR((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt8test_register_algo_does_not_allow_duplicate_registration)scCs*tjt|jdiWdQXdS(NtAAA123(RRt TypeErrorR(RR((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt,test_register_algo_rejects_non_algorithm_obj/scCsN|j}d}||k}|stjd |fd||fitj|d6dtjksvtj|rtj|ndd6}di|d 6}ttj|nd}}d }||k}|sptjd|fd||fitj|d6dtjks-tj|r<tj|ndd6}di|d 6}ttj|nd}}|j d |j}d }||k}|s@tjd|fd||fitj|d6dtjkstj|r tj|ndd6}di|d 6}ttj|nd}}dS(Ntnonetins%(py1)s in %(py3)stpy1t supportedtpy3tsassert %(py5)stpy5tHS256snot ins%(py1)s not in %(py3)s(R(s%(py1)s in %(py3)ssassert %(py5)s(R(s%(py1)s in %(py3)ssassert %(py5)s(snot in(s%(py1)s not in %(py3)ssassert %(py5)s( tget_algorithmst @pytest_art_call_reprcomparet _safereprt @py_builtinstlocalst_should_repr_global_nametAssertionErrort_format_explanationtNonetunregister_algorithm(RRRt @py_assert0t @py_assert2t @py_format4t @py_format6((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt&test_unregister_algo_removes_algorithm3s0  l  l    lcCs'tjt|jdWdQXdS(NR(RRtKeyErrorR-(RR((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt3test_unregister_algo_throws_error_if_not_registered=scCsd}|j}|}||k}|stjd|fd||fitj|d6dtjks|tj|rtj|ndd6tj|d6tj|d6}di|d 6}ttj|nd}}}}d }|j}|}||k}|stjd|fd||fitj|d6dtjksmtj|r|tj|ndd6tj|d6tj|d6}di|d 6}ttj|nd}}}}t d d g}d}|j}|}||k}|stjd|fd||fitj|d6dtjksptj|rtj|ndd6tj|d6tj|d6}di|d 6}ttj|nd}}}}d }|j}|}||k}|stjd|fd||fitj|d6dtjksatj|rptj|ndd6tj|d6tj|d6}di|d 6}ttj|nd}}}}dS(NRRsM%(py1)s in %(py7)s {%(py7)s = %(py5)s {%(py5)s = %(py3)s.get_algorithms }() }RRRR!tpy7R sassert %(py9)stpy9R"t algorithmssnot insQ%(py1)s not in %(py7)s {%(py7)s = %(py5)s {%(py5)s = %(py3)s.get_algorithms }() }(R(sM%(py1)s in %(py7)s {%(py7)s = %(py5)s {%(py5)s = %(py3)s.get_algorithms }() }sassert %(py9)s(R(sM%(py1)s in %(py7)s {%(py7)s = %(py5)s {%(py5)s = %(py3)s.get_algorithms }() }sassert %(py9)s(snot in(sQ%(py1)s not in %(py7)s {%(py7)s = %(py5)s {%(py5)s = %(py3)s.get_algorithms }() }sassert %(py9)s(R(sM%(py1)s in %(py7)s {%(py7)s = %(py5)s {%(py5)s = %(py3)s.get_algorithms }() }sassert %(py9)s( R#R$R%R&R'R(R)R*R+R,R(RRR.t @py_assert4t @py_assert6R/t @py_format8t @py_format10((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt4test_algo_parameter_removes_alg_from_algorithms_listAsJ    cCsptditd6}|jd}| }|sbditj|d6}ttj|nd}}dS(Ntoptionstverify_signatureR sassert not %(py1)sRsassert not %(py1)s(RtFalseR=R$R&R*R+R,(RRR.R/t @py_format3((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_override_optionsIs cCs~|j|d}|j|dditd6|jd}|stditj|d6}ttj|nd}dS(NtsecretR=R>R sassert %(py1)sRsassert %(py1)s( tencodetdecodeR?R=R$R&R*R+R,(RRRttokenR.t @py_format2((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt$test_non_object_options_dont_persistNs cCs3tjttdttjttdddS(NR=t something(RRRRtobject(RR((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_options_must_be_dictUsc Csd}|j||}|j||}||k}|stjd |fd ||fidtjks~tj|rtj|ndd6dtjkstj|rtj|ndd6}d i|d 6}ttj |nd}dS(NRBs==s%(py0)s == %(py2)stdecoded_payloadtpy0Rtpy2R sassert %(py4)stpy4(s==(s%(py0)s == %(py2)ssassert %(py4)s( RCRDR$R%R'R(R)R&R*R+R,( RRRRBt jws_messageRKt @py_assert1R@t @py_format5((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_encode_decodeYs c Csad}|j||dd}|j||tjt|j||ddgWdQXdS(NRBt algorithmR"R7tHS384(RCRDRRR(RRRRBt jws_token((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt<test_decode_fails_when_alg_is_not_on_method_algorithms_param`s cCs&d}td}|j||dS(NRBsmeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8(RRD(RRRBt unicode_jws((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt$test_decode_works_with_unicode_tokenhs c CsOd}d}tjt}|j||WdQX|j}t|}d}||k}|s=tjd|fd||fidtj kstj trtj tndd6dtj kstj |rtj |ndd 6tj |d 6tj |d 6} di| d6} t tj | nd}}}dS(NRBsAeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9sNot enough segmentss==s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)ststrRLt exceptionRRtpy6R sassert %(py8)stpy8(s==(s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)ssassert %(py8)s(RRRRDtvalueRYR$R%R'R(R)R&R*R+R,( RRRBt example_jwstcontextRZR/t @py_assert5R8t @py_format7t @py_format9((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt-test_decode_missing_segments_throws_exceptionqs   c CsOd}d}tjt}|j||WdQX|j}t|}d}||k}|s=tjd|fd||fidtj kstj trtj tndd6dtj kstj |rtj |ndd 6tj |d 6tj |d 6} di| d6} t tj | nd}}}dS(NRBsGMQ.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8s,Invalid header string: must be a json objects==s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)sRYRLRZRRR[R sassert %(py8)sR\(s==(s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)ssassert %(py8)s(RRRRDR]RYR$R%R'R(R)R&R*R+R,( RRRBR^R_RZR/R`R8RaRb((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt4test_decode_with_non_mapping_header_throws_exception}s   c Cs_|j|dddtjt}|j|dddWdQX|j}t|}d}||k}|sMtjd|fd||fidt j kstj trtj tndd 6d t j kstj |rtj |nd d 6tj |d 6tj |d 6}di|d6} t tj| nd}}}dS(NRBRSR"ths256sAlgorithm not supporteds==s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)sRYRLRZRRR[R sassert %(py8)sR\(s==(s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)ssassert %(py8)s(RCRRtNotImplementedErrorR,R]RYR$R%R'R(R)R&R*R+( RRRR_RZR/R`R8RaRb((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt4test_encode_algorithm_param_should_be_case_sensitives   c CsId}tjt}|j|dWdQX|j}t|}d}||k}|s7tjd|fd||fidtj kstj trtj tndd6dtj kstj |rtj |ndd 6tj |d 6tj |d 6}di|d6} t tj | nd}}}dS(NsheyJhbGciOiJoczI1NiIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6IndvcmxkIn0.5R_FEPE7SW2dT9GgIxPgZATjFGXfUDOSwo7TtO_Kd_gRBsAlgorithm not supporteds==s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)sRYRLRZRRR[R sassert %(py8)sR\(s==(s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)ssassert %(py8)s(RRRRDR]RYR$R%R'R(R)R&R*R+R,( RRR^R_RZR/R`R8RaRb((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt4test_decode_algorithm_param_should_be_case_sensitives   cCsHd}d}|j||}tjt|j||WdQXdS(Ntfootbar(RCRRRRD(RRRt right_secrett bad_secretRO((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_bad_secrets c Csd}d}|j||}||k}|stjd |fd ||fidtjksrtj|rtj|ndd6dtjkstj|rtj|ndd6}di|d 6}ttj|nd}dS(NRBs`eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.aGVsbG8gd29ybGQ.gEW0pdU4kxPthjtehYdhxB9mMOGajt1xCKlGGXDJ8PMs==s%(py0)s == %(py2)sRKRLRRMR sassert %(py4)sRN(s==(s%(py0)s == %(py2)ssassert %(py4)s( RDR$R%R'R(R)R&R*R+R,( RRRtexample_secretR^RKRPR@RQ((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_decodes_valid_jwss treasons&Can't run without cryptography libraryc Cs6idd6}tdd}|j}WdQXd}|j||}tjt|}||k}|s,tjd|fd||fidtj kstj |rtj |ndd 6d tj kstj |rtj |nd d 6} di| d6} t tj | nd}dS(Ntworldthellostests/keys/testkey_ec.pubtrseyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6IndvcmxkIn0.MIGHAkEdh2kR7IRu5w0tGuY6Xz3Vqa7PHHY2DgXWeeeLXotEqpn9udp2NfVL-XFG0TDoCakzXbIGAWg42S69GFlKZzxhXAJCAPLPuJoKyAixFnXPBkvkti-UzSIj4s6DePeuTu7102G_QIXiijY5bx6mdmZa3xUuKeu-zobOIOqR8ZwFqGjBLZums==s%(py0)s == %(py2)st json_payloadRLtexample_payloadRMR sassert %(py4)sRN(s==(s%(py0)s == %(py2)ssassert %(py4)s(topentreadRDtjsontloadsR R$R%R'R(R)R&R*R+R,( RRRutfptexample_pubkeyR^RKRtRPR@RQ((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_decodes_valid_es384_jwss  c Cs6idd6}tdd}|j}WdQXd}|j||}tjt|}||k}|s,tjd|fd||fidtj kstj |rtj |ndd 6d tj kstj |rtj |nd d 6} di| d6} t tj | nd}dS(NRqRrstests/keys/testkey_rsa.pubRsseyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6IndvcmxkIn0.yNQ3nI9vEDs7lEh-Cp81McPuiQ4ZRv6FL4evTYYAh1XlRTTR3Cz8pPA9Stgso8Ra9xGB4X3rlra1c8Jz10nTUjuO06OMm7oXdrnxp1KIiAJDerWHkQ7l3dlizIk1bmMA457W2fNzNfHViuED5ISM081dgf_a71qBwJ_yShMMrSOfxDxmX9c4DjRogRJG8SM5PvpLqI_Cm9iQPGMvmYK7gzcq2cJurHRJDJHTqIdpLWXkY7zVikeen6FhuGyn060Dz9gYq9tuwmrtSWCBUjiN8sqJ00CDgycxKqHfUndZbEAOjcCAhBrqWW3mSVivUfubsYbwUdUG3fSRPjaUPcpe8As==s%(py0)s == %(py2)sRtRLRuRMR sassert %(py4)sRN(s==(s%(py0)s == %(py2)ssassert %(py4)s(RvRwRDRxRyR R$R%R'R(R)R&R*R+R,( RRRuRzR{R^RKRtRPR@RQ((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_decodes_valid_rs384_jwss   c Csd}d}|j|d|}||k}|stjd |fd||fidtjksutj|rtj|ndd6dtjkstj|rtj|ndd 6}di|d 6}ttj|nd}dS(NRBs`eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.aGVsbG8gd29ybGQ.SIr03zM64awWRdPrAM_61QWsZchAtgDV3pphfHPPWkItkeys==s%(py0)s == %(py2)sRKRLRRMR sassert %(py4)sRN(s==(s%(py0)s == %(py2)ssassert %(py4)s( RDR$R%R'R(R)R&R*R+R,( RRRRnR^RKRPR@RQ((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_load_verify_valid_jwss c Csd}|j||}|j|dt}||k}|stjd |fd ||fidtjkstj|rtj|ndd6dtjkstj|rtj|ndd6}di|d 6}t tj |nd}dS(NRitverifys==s%(py0)s == %(py2)sRKRLRRMR sassert %(py4)sRN(s==(s%(py0)s == %(py2)ssassert %(py4)s( RCRDR?R$R%R'R(R)R&R*R+R,( RRRRkRORKRPR@RQ((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_allow_skip_verifications cCs#d}tj|j|dtdS(NsmeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8R(Rtdeprecated_callRDR?(RRtrecwarnR^((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_verify_false_deprecatedsc Cs d}|j||}|j|dddt}||k}|stjd |fd||fidtjkstj|rtj |ndd6dtjkstj|rtj |ndd 6}di|d 6}t tj |nd}dS(NRiR~Rs==s%(py0)s == %(py2)sRKRLRRMR sassert %(py4)sRN(s==(s%(py0)s == %(py2)ssassert %(py4)s( RCRDR,R?R$R%R'R(R)R&R*R+( RRRRkRORKRPR@RQ((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_load_no_verifications cCs?d}|j||}tjt|j|WdQXdS(NRi(RCRRRRD(RRRRkRO((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_no_secretsc Csld}|j||}tjt}|j|WdQXd}|j}t|}||k} | sVtjd| fd||fitj |d6tj |d6dt j kstj trtj tndd6d t j kstj |rtj |nd d 6tj |d 6} di| d6} t tj| nd}} }}dS(NRisSignature verificationRsK%(py1)s in %(py8)s {%(py8)s = %(py3)s(%(py6)s {%(py6)s = %(py4)s.value }) }R\RRYRtexcRNR[R sassert %(py10)stpy10(R(sK%(py1)s in %(py8)s {%(py8)s = %(py3)s(%(py6)s {%(py6)s = %(py4)s.value }) }sassert %(py10)s(RCRRRRDR]RYR$R%R&R'R(R)R*R+R,( RRRRkRORR.R`t @py_assert7R/Rbt @py_format11((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt$test_verify_signature_with_no_secret s c Cs0tjt|j|dddWdQXdS(NRBRStHS1024(RRRfRC(RRR((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_invalid_crypto_algsc Csd}|j||}|j||}||k}|stjd |fd ||fidtjks~tj|rtj|ndd6dtjkstj|rtj|ndd6}d i|d 6}ttj |nd}dS(Nss==s%(py0)s == %(py2)sRKRLRRMR sassert %(py4)sRN(s==(s%(py0)s == %(py2)ssassert %(py4)s( RCRDR$R%R'R(R)R&R*R+R,( RRRRBRORKRPR@RQ((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_unicode_secrets c Csd}|j||}|j||}||k}|stjd |fd ||fidtjks~tj|rtj|ndd6dtjkstj|rtj|ndd6}d i|d 6}ttj |nd}dS(Nss==s%(py0)s == %(py2)sRKRLRRMR sassert %(py4)sRN(s==(s%(py0)s == %(py2)ssassert %(py4)s( RCRDR$R%R'R(R)R&R*R+R,( RRRRBRORKRPR@RQ((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_nonascii_secrets c Csd}|j||}|j||}||k}|stjd |fd ||fidtjks~tj|rtj|ndd6dtjkstj|rtj|ndd6}d i|d 6}ttj |nd}dS(Nss==s%(py0)s == %(py2)sRKRLRRMR sassert %(py4)sRN(s==(s%(py0)s == %(py2)ssassert %(py4)s( RCRDR$R%R'R(R)R&R*R+R,( RRRRBRORKRPR@RQ((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_bytes_secret%s c Cscd}d}tjt}|j||WdQXd}|j}t|}||k}|sMtjd|fd||fitj|d6tj|d6dt j kstj trtjtndd 6d t j kstj |r tj|nd d 6tj|d 6} di| d6} t tj | nd}}}}dS(NsnaeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8RBsheader paddingRsK%(py1)s in %(py8)s {%(py8)s = %(py3)s(%(py6)s {%(py6)s = %(py4)s.value }) }R\RRYRRRNR[R sassert %(py10)sR(R(sK%(py1)s in %(py8)s {%(py8)s = %(py3)s(%(py6)s {%(py6)s = %(py4)s.value }) }sassert %(py10)s(RRRRDR]RYR$R%R&R'R(R)R*R+R,( RRR^RnRR.R`RR/RbR((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt"test_decode_invalid_header_padding-s c Cscd}d}tjt}|j||WdQXd}|j}t|}||k}|sMtjd|fd||fitj|d6tj|d6dt j kstj trtjtndd 6d t j kstj |r tj|nd d 6tj|d 6} di| d6} t tj | nd}}}}dS(NsqeyJhbGciOiAiSFMyNTbpIiwgInR5cCI6ICJKV1QifQ==.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8RBsInvalid headerRsK%(py1)s in %(py8)s {%(py8)s = %(py3)s(%(py6)s {%(py6)s = %(py4)s.value }) }R\RRYRRRNR[R sassert %(py10)sR(R(sK%(py1)s in %(py8)s {%(py8)s = %(py3)s(%(py6)s {%(py6)s = %(py4)s.value }) }sassert %(py10)s(RRRRDR]RYR$R%R&R'R(R)R*R+R,( RRR^RnRR.R`RR/RbR((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt!test_decode_invalid_header_string9s c Cscd}d}tjt}|j||WdQXd}|j}t|}||k}|sMtjd|fd||fitj|d6tj|d6dt j kstj trtjtndd 6d t j kstj |r tj|nd d 6tj|d 6} di| d6} t tj | nd}}}}dS(NsneyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.aeyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8RBsInvalid payload paddingRsK%(py1)s in %(py8)s {%(py8)s = %(py3)s(%(py6)s {%(py6)s = %(py4)s.value }) }R\RRYRRRNR[R sassert %(py10)sR(R(sK%(py1)s in %(py8)s {%(py8)s = %(py3)s(%(py6)s {%(py6)s = %(py4)s.value }) }sassert %(py10)s(RRRRDR]RYR$R%R&R'R(R)R*R+R,( RRR^RnRR.R`RR/RbR((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt#test_decode_invalid_payload_paddingEs c Cscd}d}tjt}|j||WdQXd}|j}t|}||k}|sMtjd|fd||fitj|d6tj|d6dt j kstj trtjtndd 6d t j kstj |r tj|nd d 6tj|d 6} di| d6} t tj | nd}}}}dS(NsoeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.aatvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8RBsInvalid crypto paddingRsK%(py1)s in %(py8)s {%(py8)s = %(py3)s(%(py6)s {%(py6)s = %(py4)s.value }) }R\RRYRRRNR[R sassert %(py10)sR(R(sK%(py1)s in %(py8)s {%(py8)s = %(py3)s(%(py6)s {%(py6)s = %(py4)s.value }) }sassert %(py10)s(RRRRDR]RYR$R%R&R'R(R)R*R+R,( RRR^RnRR.R`RR/RbR((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt"test_decode_invalid_crypto_paddingQs cCsB|j|dddd}tjt|j|WdQXdS(NR~RS(RCR,RRRRD(RRRRO((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt&test_decode_with_algo_none_should_fail]scCs2|j|dddd}|j|dtdS(NR~RSR(RCR,RDR?(RRRRO((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt7test_decode_with_algo_none_and_verify_false_should_passcss*Not supported without cryptography libraryc CstddF}tt|jdddt}|j||dd}WdQXtdd8}tt|jdt}|j||WdQXtdd+}|j}|j||dd}WdQXtdd#}|j}|j||WdQXdS(Nstests/keys/testkey_rsaRstpasswordtbackendRStRS256stests/keys/testkey_rsa.pub( RvR RRwR,R RCR RD(RRRt rsa_priv_filet priv_rsakeyROt rsa_pub_filet pub_rsakey((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt"test_encode_decode_with_rsa_sha256gs   c CstddF}tt|jdddt}|j||dd}WdQXtdd8}tt|jdt}|j||WdQXtdd+}|j}|j||dd}WdQXtdd#}|j}|j||WdQXdS(Nstests/keys/testkey_rsaRsRRRStRS384stests/keys/testkey_rsa.pub( RvR RRwR,R RCR RD(RRRRRRORR((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt"test_encode_decode_with_rsa_sha384~s   c CstddF}tt|jdddt}|j||dd}WdQXtdd8}tt|jdt}|j||WdQXtdd+}|j}|j||dd}WdQXtdd#}|j}|j||WdQXdS(Nstests/keys/testkey_rsaRsRRRStRS512stests/keys/testkey_rsa.pub( RvR RRwR,R RCR RD(RRRRRRORR((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt"test_encode_decode_with_rsa_sha512s   cCst}|j}trhd}||k}|stjd|fd||fitj|d6dtjkstj|rtj|ndd6}di|d 6}t tj |nd}}d }||k}|stjd|fd||fitj|d6dtjks<tj|rKtj|ndd6}di|d 6}t tj |nd}}d }||k}|s6tjd|fd||fitj|d6dtjkstj|rtj|ndd6}di|d 6}t tj |nd}}d }||k}|stjd|fd||fitj|d6dtjkstj|rtj|ndd6}di|d 6}t tj |nd}}d }||k}|stjd|fd||fitj|d6dtjksatj|rptj|ndd6}di|d 6}t tj |nd}}d}||k}|s[tjd |fd!||fitj|d6dtjkstj|r'tj|ndd6}d"i|d 6}t tj |nd}}nJd}||k}|stjd#|fd$||fitj|d6dtjkstj|rtj|ndd6}d%i|d 6}t tj |nd}}d }||k}|stjd&|fd'||fitj|d6dtjkstj|rtj|ndd6}d(i|d 6}t tj |nd}}d }||k}|stjd)|fd*||fitj|d6dtjks@tj|rOtj|ndd6}d+i|d 6}t tj |nd}}d }||k}|s:tjd,|fd-||fitj|d6dtjkstj|rtj|ndd6}d.i|d 6}t tj |nd}}d }||k}|stjd/|fd0||fitj|d6dtjkstj|rtj|ndd6}d1i|d 6}t tj |nd}}d}||k}|stjd2|fd3||fitj|d6dtjksetj|rttj|ndd6}d4i|d 6}t tj |nd}}dS(5NRRs%(py1)s in %(py3)sRtjws_algorithmsRR sassert %(py5)sR!RRtPS256tPS384tPS512snot ins%(py1)s not in %(py3)s(R(s%(py1)s in %(py3)ssassert %(py5)s(R(s%(py1)s in %(py3)ssassert %(py5)s(R(s%(py1)s in %(py3)ssassert %(py5)s(R(s%(py1)s in %(py3)ssassert %(py5)s(R(s%(py1)s in %(py3)ssassert %(py5)s(R(s%(py1)s in %(py3)ssassert %(py5)s(snot in(s%(py1)s not in %(py3)ssassert %(py5)s(snot in(s%(py1)s not in %(py3)ssassert %(py5)s(snot in(s%(py1)s not in %(py3)ssassert %(py5)s(snot in(s%(py1)s not in %(py3)ssassert %(py5)s(snot in(s%(py1)s not in %(py3)ssassert %(py5)s(snot in(s%(py1)s not in %(py3)ssassert %(py5)s( RR#t has_cryptoR$R%R&R'R(R)R*R+R,(RRRR.R/R0R1((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_rsa_related_algorithmss   l  l  l  l  l  l  l  l  l  l  l  lc CstddF}tt|jdddt}|j||dd}WdQXtdd8}tt|jdt}|j||WdQXtdd+}|j}|j||dd}WdQXtdd#}|j}|j||WdQXdS(Nstests/keys/testkey_ecRsRRRStES256stests/keys/testkey_ec.pub( RvR RRwR,R RCR RD(RRRt ec_priv_filet priv_eckeyROt ec_pub_filet pub_eckey((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt$test_encode_decode_with_ecdsa_sha256s   c CstddF}tt|jdddt}|j||dd}WdQXtdd8}tt|jdt}|j||WdQXtdd+}|j}|j||dd}WdQXtdd#}|j}|j||WdQXdS(Nstests/keys/testkey_ecRsRRRStES384stests/keys/testkey_ec.pub( RvR RRwR,R RCR RD(RRRRRRORR((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt$test_encode_decode_with_ecdsa_sha384s   c CstddF}tt|jdddt}|j||dd}WdQXtdd8}tt|jdt}|j||WdQXtdd+}|j}|j||dd}WdQXtdd#}|j}|j||WdQXdS(Nstests/keys/testkey_ecRsRRRStES512stests/keys/testkey_ec.pub( RvR RRwR,R RCR RD(RRRRRRORR((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt$test_encode_decode_with_ecdsa_sha512s!  cCslt}|j}trCd}||k}|stjd|fd||fitj|d6dtjkstj|rtj|ndd6}di|d 6}t tj |nd}}d }||k}|stjd|fd||fitj|d6dtjks<tj|rKtj|ndd6}di|d 6}t tj |nd}}d }||k}|s6tjd|fd||fitj|d6dtjkstj|rtj|ndd6}di|d 6}t tj |nd}}n%d}||k}|stjd|fd||fitj|d6dtjkstj|rtj|ndd6}di|d 6}t tj |nd}}d }||k}|stjd|fd||fitj|d6dtjksdtj|rstj|ndd6}di|d 6}t tj |nd}}d }||k}|s^tjd|fd||fitj|d6dtjkstj|r*tj|ndd6}di|d 6}t tj |nd}}dS( NRRs%(py1)s in %(py3)sRRRR sassert %(py5)sR!RRsnot ins%(py1)s not in %(py3)s(R(s%(py1)s in %(py3)ssassert %(py5)s(R(s%(py1)s in %(py3)ssassert %(py5)s(R(s%(py1)s in %(py3)ssassert %(py5)s(snot in(s%(py1)s not in %(py3)ssassert %(py5)s(snot in(s%(py1)s not in %(py3)ssassert %(py5)s(snot in(s%(py1)s not in %(py3)ssassert %(py5)s( RR#RR$R%R&R'R(R)R*R+R,(RRRR.R/R0R1((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_ecdsa_related_algorithmssZ   l  l  l  l  l  lcCs'd}|j|dditd6dS(NsieyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZARBR=R>(RDR?(RRRE((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_skip_check_signature sc Csq|j|d}tjt|j|ddtWdQXtjt|j|dddWdQXdS(NRBR=RH(RCRRRRDRI(RRRRE((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt test_decode_options_must_be_dicts c sdtjffdYitdd6}tjt|j|dd|WdQX|j|dd|d}tt|j dd }tj tt |}d}||k}|sct j d|fd||fit j|d 6d tjks t j|r/t j|nd d6}di|d6} tt j| nd}}|d}d} || k}|st j d|fd|| fit j|d 6t j| d6} di| d6} tt j| nd}}} dS(NtCustomJSONEncodercseZfdZRS(cs)t|trdSt|j|S(Ns it worked(t isinstanceRtsupertdefault(Rto(R(s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyR s(t__name__t __module__R((R(s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyRss2.2t some_decimalRBtheaderst json_encodert.iRs%(py1)s in %(py3)sRtheaderRR sassert %(py5)sR!s it workeds==s%(py1)s == %(py4)sRNsassert %(py6)sR[(R(s%(py1)s in %(py3)ssassert %(py5)s(s==(s%(py1)s == %(py4)ssassert %(py6)s(Rxt JSONEncoderRRRRRCRR tsplitRyRR$R%R&R'R(R)R*R+R,( RRRtdataRERR.R/R0R1t @py_assert3RQRa((Rs=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyttest_custom_json_encoders0  l   EcCsitd6}|j|dd|}t|tsC|j}n|d|jd!j}t|}t|ts|j}ntj |}d}||k}|sEt j d|fd||fit j |d6d t jkst j|rt j |nd d 6} di| d 6} tt j| nd}}|d}|d} || k}|st j d|fd|| fit j |d6t j | d6} di| d6} tt j| nd}}} dS(Nt testheaderRBRiRRs%(py1)s in %(py3)sRt header_objRR sassert %(py5)sR!s==s%(py1)s == %(py4)sRNsassert %(py6)sR[(R(s%(py1)s in %(py3)ssassert %(py5)s(s==(s%(py1)s == %(py4)ssassert %(py6)s(tTrueRCRRRDtindexRRRxRyR$R%R&R'R(R)R*R+R,(RRRRRERRR.R/R0R1RRQRa((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyt*test_encode_headers_parameter_adds_headers5s0   l  E(5RRRRR2R4R<RARGRJRRRVRXRcRdRgRhRmRoRtmarktskipifRR|R}RRRRRRRRRRRRRRRRRRRRRRRRRRRR(((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyR(s^           ""          """ """  (('t __builtin__R't_pytest.assertion.rewritet assertiontrewriteR$RxtdecimalRtjwt.algorithmsRt jwt.api_jwsRtjwt.exceptionsRRt jwt.utilsRRtcompatRRtutilsRR tcryptography.hazmat.backendsR t,cryptography.hazmat.primitives.serializationR R R RRt ImportErrorR?tfixtureRRR(((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jws.pyts&      PyJWT-1.3.0/tests/__pycache__/test_api_jwt.cpython-27-PYTEST.pyc0000644000076500000240000006115512517232464025133 0ustar jpadillastaff00000000000000 15=U<c@sddlZddljjZddlZddlZddlm Z ddl m Z m Z ddl m Z ddlmZddlmZmZmZmZmZmZddlZddlmZdd lmZejd Zejd Zd dd YZdS(iN(ttimegm(tdatetimet timedelta(tDecimal(tPyJWT(t DecodeErrortExpiredSignatureErrortImmatureSignatureErrortInvalidAudienceErrortInvalidIssuedAtErrortInvalidIssuerErrori(t has_crypto(t utc_timestampcCstS(N(R(((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pytjwtscCs idd6tdd6dd6S(sA Creates a sample JWT claimset for use as a payload during tests tjefftissitexptinsanitytclaim(R (((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pytpayloadstTestJWTcBs~eZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zejje d ddZejje d ddZdZdZdZdZdZdZdZdZdZdZdZdZ dZ!dZ"dZ#d Z$d!Z%d"Z&d#Z'd$Z(d%Z)RS(&c Csidd6}d}d}|j||}||k}|stjd|fd||fidtjkstj|rtj|ndd6d tjkstj|rtj|nd d 6}di|d 6}ttj|nd}dS(NtworldthellotsecretsmeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8s==s%(py0)s == %(py2)stdecoded_payloadtpy0texample_payloadtpy2tsassert %(py4)stpy4(s==(s%(py0)s == %(py2)ssassert %(py4)s( tdecodet @pytest_art_call_reprcomparet @py_builtinstlocalst_should_repr_global_namet _safereprtAssertionErrort_format_explanationtNone( tselfR Rtexample_secrett example_jwtRt @py_assert1t @py_format3t @py_format5((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyttest_decodes_valid_jwt%s  c Csidd6}d}d}|j|d|}||k}|stjd|fd||fidtjkstj|rtj|ndd 6d tjkstj|rtj|nd d 6}di|d6}ttj|nd}dS(NRRRsmeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8tkeys==s%(py0)s == %(py2)sRRRRRsassert %(py4)sR(s==(s%(py0)s == %(py2)ssassert %(py4)s( RRR R!R"R#R$R%R&R'( R(R RR)R*RR+R,R-((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyttest_load_verify_valid_jwt0s  c Cscd}d}tjt}|j||WdQXd}|j}t|}||k}|sMtjd|fd||fitj|d6tj|d6dt j kstj trtjtndd 6d t j kstj |r tj|nd d 6tj|d 6} di| d6} t tj | nd}}}}dS(Ns`eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.aGVsbG8gd29ybGQ.SIr03zM64awWRdPrAM_61QWsZchAtgDV3pphfHPPWkIRsInvalid payload stringtinsK%(py1)s in %(py8)s {%(py8)s = %(py3)s(%(py6)s {%(py6)s = %(py4)s.value }) }tpy8tpy1tstrtpy3texcRtpy6Rsassert %(py10)stpy10(R1(sK%(py1)s in %(py8)s {%(py8)s = %(py3)s(%(py6)s {%(py6)s = %(py4)s.value }) }sassert %(py10)s(tpytesttraisesRRtvalueR4RR R$R!R"R#R%R&R'( R(R R*R)R6t @py_assert0t @py_assert5t @py_assert7t @py_assert2t @py_format9t @py_format11((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyt"test_decode_invalid_payload_string<s c CsOd}d}tjt}|j||WdQX|j}t|}d}||k}|s=tjd|fd||fidtj kstj trtj tndd6dtj kstj |rtj |ndd 6tj |d 6tj |d 6} di| d6} t tj | nd}}}dS(NRsSeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.MQ.AbcSR3DWum91KOgfKxUHm78rLs_DrrZ1CrDgpUFFzlss-Invalid payload string: must be a json objects==s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)sR4Rt exceptionR3R5R7Rsassert %(py8)sR2(s==(s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)ssassert %(py8)s(R9R:RRR;R4RR R!R"R#R$R%R&R'( R(R RR*tcontextRCR?R=t @py_assert4t @py_format7R@((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyt5test_decode_with_non_mapping_payload_throws_exceptionHs   c CsUd}d}tjt}|j||ddWdQX|j}t|}d}||k}|sCtjd|fd||fidtj kstj trtj tndd 6d tj kstj |rtj |nd d 6tj |d 6tj |d 6} di| d6} t tj | nd}}}dS(NRsmeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8taudienceis!audience must be a string or Nones==s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)sR4RRCR3R5R7Rsassert %(py8)sR2(s==(s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)ssassert %(py8)s(R9R:t TypeErrorRR;R4RR R!R"R#R$R%R&R'( R(R RR*RDRCR?R=RERFR@((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyt8test_decode_with_invalid_audience_param_throws_exceptionTs   c CsUd}d}tjt}|j||ddWdQX|j}t|}d}||k}|sCtjd|fd||fidtj kstj trtj tndd 6d tj kstj |rtj |nd d 6tj |d 6tj |d 6} di| d6} t tj | nd}}}dS(NRsseyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjoxfQ.Rof08LBSwbm8Z_bhA2N3DFY-utZR1Gi9rbIS5ZthnncRHt my_audiencesInvalid claim format in tokens==s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)sR4RRCR3R5R7Rsassert %(py8)sR2(s==(s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)ssassert %(py8)s(R9R:RRR;R4RR R!R"R#R$R%R&R'( R(R RR*RDRCR?R=RERFR@((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyt3test_decode_with_nonlist_aud_claim_throws_exception`s   c CsUd}d}tjt}|j||ddWdQX|j}t|}d}||k}|sCtjd|fd||fidtj kstj trtj tndd 6d tj kstj |rtj |nd d 6tj |d 6tj |d 6} di| d6} t tj | nd}}}dS(NRsueyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjpbMV19.iQgKpJ8shetwNMIosNXWBPFB057c2BHs-8t1d2CCM2ARHRKsInvalid claim format in tokens==s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)sR4RRCR3R5R7Rsassert %(py8)sR2(s==(s0%(py3)s {%(py3)s = %(py0)s(%(py1)s) } == %(py6)ssassert %(py8)s(R9R:RRR;R4RR R!R"R#R$R%R&R'( R(R RR*RDRCR?R=RERFR@((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyt9test_decode_with_invalid_aud_list_member_throws_exceptionls   csOdttdtg}x*|D]"tjtfdq%WdS(Ntstringi*csjdS(NR(tencode((R tt(s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyt}s(ttupletlisttsetR9R:RI(R(R ttypes((R RPs=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyttest_encode_bad_typexs c Cs]d}tjt}|j|dWdQXd}|j}t|}||k}|sGtjd|fd||fitj|d6tj|d6dt j kstj trtjtndd 6d t j kstj |rtj|nd d 6tj|d 6}di|d6} t tj | nd}}}}dS(NsleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiJub3QtYW4taW50In0.P65iYgoHtBqB07PMtBSuKNUEIPPPfmjfJG217cEE66sRRR1sK%(py1)s in %(py8)s {%(py8)s = %(py3)s(%(py6)s {%(py6)s = %(py4)s.value }) }R2R3R4R5R6RR7Rsassert %(py10)sR8(R1(sK%(py1)s in %(py8)s {%(py8)s = %(py3)s(%(py6)s {%(py6)s = %(py4)s.value }) }sassert %(py10)s(R9R:RRR;R4RR R$R!R"R#R%R&R'( R(R R*R6R<R=R>R?R@RA((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyt.test_decode_raises_exception_if_exp_is_not_ints cCs0d}tjt|j|dWdQXdS(NsleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiJub3QtYW4taW50In0.H1GmcQgSySa5LOKYbzGm--b1OmRbHFkyk8pq811FzZMR(R9R:RR(R(R R*((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyt.test_decode_raises_exception_if_iat_is_not_intscCs0d}tjt|j|dWdQXdS(NsleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOiJub3QtYW4taW50In0.c25hldC8G2ZamC8uKpax9sYMTgdZo3cxrmzFHaAAluwR(R9R:RR(R(R R*((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyt.test_decode_raises_exception_if_nbf_is_not_intscCs_tj}|ji|tddd6dd}tjt|j|dWdQXdS(NtdaysitiatR/R(RtutcnowRORR9R:R R(R(R tnowttoken((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyt1test_decode_raises_exception_if_iat_in_the_futures )cCs?d}tj}i|d6|d6|d6}|j||}|j||dd}|d}|j}|} t| } || k} | stjd| fd|| fitj| d 6tj|d 6tj| d 6d t j kstj trtjtnd d 6dt j ks:tj |rItj|ndd6tj|d6} di| d6} t tj | nd}} }} } |d}|j}|} t| } || k} | stjd| fd|| fitj| d 6tj|d 6tj| d 6d t j ksOtj tr^tjtnd d 6dt j kstj |rtj|ndd6tj|d6} di| d6} t tj | nd}} }} } |d}|j}|} t| } || k} | s%tjd| fd|| fitj| d 6tj|d 6tj| d 6d t j kstj trtjtnd d 6dt j kstj |rtj|ndd6tj|d6} di| d6} t tj | nd}} }} } dS(NRRR[tnbftleewayis==sk%(py1)s == %(py10)s {%(py10)s = %(py3)s(%(py8)s {%(py8)s = %(py6)s {%(py6)s = %(py4)s.utctimetuple }() }) }R2R3R8RR5tcurrent_datetimeRR7Rsassert %(py12)stpy12(s==(sk%(py1)s == %(py10)s {%(py10)s = %(py3)s(%(py8)s {%(py8)s = %(py6)s {%(py6)s = %(py4)s.utctimetuple }() }) }sassert %(py12)s(s==(sk%(py1)s == %(py10)s {%(py10)s = %(py3)s(%(py8)s {%(py8)s = %(py6)s {%(py6)s = %(py4)s.utctimetuple }() }) }sassert %(py12)s(s==(sk%(py1)s == %(py10)s {%(py10)s = %(py3)s(%(py8)s {%(py8)s = %(py6)s {%(py6)s = %(py4)s.utctimetuple }() }) }sassert %(py12)s(RR\RORt utctimetupleRRR R$R!R"R#R%R&R'(R(R RRbRt jwt_messageRR<R=R>t @py_assert9R?RAt @py_format13((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyttest_encode_datetimesL     treasons&Can't run without cryptography libraryc Cs!idd6}tdd}|j}WdQXd}|j||}||k}|stjd|fd||fidtjkstj|rtj|ndd 6d tjkstj|rtj|nd d 6}di|d6} t tj | nd}dS(NRRstests/keys/testkey_ec.pubtrseyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6IndvcmxkIn0.MIGHAkEdh2kR7IRu5w0tGuY6Xz3Vqa7PHHY2DgXWeeeLXotEqpn9udp2NfVL-XFG0TDoCakzXbIGAWg42S69GFlKZzxhXAJCAPLPuJoKyAixFnXPBkvkti-UzSIj4s6DePeuTu7102G_QIXiijY5bx6mdmZa3xUuKeu-zobOIOqR8ZwFqGjBLZums==s%(py0)s == %(py2)sRRRRRsassert %(py4)sR(s==(s%(py0)s == %(py2)ssassert %(py4)s( topentreadRRR R!R"R#R$R%R&R'( R(R Rtfptexample_pubkeyR*RR+R,R-((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyttest_decodes_valid_es384_jwts  c Cs!idd6}tdd}|j}WdQXd}|j||}||k}|stjd|fd||fidtjkstj|rtj|ndd 6d tjkstj|rtj|nd d 6}di|d6} t tj | nd}dS(NRRstests/keys/testkey_rsa.pubRjseyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6IndvcmxkIn0.yNQ3nI9vEDs7lEh-Cp81McPuiQ4ZRv6FL4evTYYAh1XlRTTR3Cz8pPA9Stgso8Ra9xGB4X3rlra1c8Jz10nTUjuO06OMm7oXdrnxp1KIiAJDerWHkQ7l3dlizIk1bmMA457W2fNzNfHViuED5ISM081dgf_a71qBwJ_yShMMrSOfxDxmX9c4DjRogRJG8SM5PvpLqI_Cm9iQPGMvmYK7gzcq2cJurHRJDJHTqIdpLWXkY7zVikeen6FhuGyn060Dz9gYq9tuwmrtSWCBUjiN8sqJ00CDgycxKqHfUndZbEAOjcCAhBrqWW3mSVivUfubsYbwUdUG3fSRPjaUPcpe8As==s%(py0)s == %(py2)sRRRRRsassert %(py4)sR(s==(s%(py0)s == %(py2)ssassert %(py4)s( RkRlRRR R!R"R#R$R%R&R'( R(R RRmRnR*RR+R,R-((s=/Users/jpadilla/Projects/Personal/pyjwt/tests/test_api_jwt.pyttest_decodes_valid_rs384_jwts   cCsStd|ds   .  PyJWT-1.3.0/tests/__pycache__/test_compat.cpython-27-PYTEST.pyc0000644000076500000240000000656712517227064024767 0ustar jpadillastaff00000000000000 '=Urc@sUddlZddljjZddlmZddlm Z dddYZ dS(iN(tconstant_time_comparei(t ensure_bytest TestCompatcBs#eZdZdZdZRS(cCsod}t|}d}t|}t||}| rUdditj|d6dtjkprtjtrtjtndd6dtjkptjtrtjtndd6tj|d 6tj|d 6tj|d 6dtjkptjtr"tjtndd 6tj|d 6}ttj|nt }}}}}dS(Ntabctsuassert %(py12)s {%(py12)s = %(py0)s(%(py5)s {%(py5)s = %(py1)s(%(py3)s) }, %(py10)s {%(py10)s = %(py6)s(%(py8)s) }) }tpy8Rtpy0Rtpy1tpy10tpy3tpy5tpy6tpy12( RRt @pytest_art _safereprt @py_builtinstlocalst_should_repr_global_nametAssertionErrort_format_explanationtNone(tselft @py_assert2t @py_assert4t @py_assert7t @py_assert9t @py_assert11t @py_format13((s</Users/jpadilla/Projects/Personal/pyjwt/tests/test_compat.pyt/test_constant_time_compare_returns_true_if_sames  cCszd}t|}d}t|}t||}| }| r\dditj|d6dtjkpytjtrtjtndd6dtjkptjtrtjtndd 6tj|d 6tj|d 6tj|d 6dtjkptjtr)tjtndd 6tj|d6}ttj|nt }}}}}}dS(NRtabcdRsyassert not %(py12)s {%(py12)s = %(py0)s(%(py5)s {%(py5)s = %(py1)s(%(py3)s) }, %(py10)s {%(py10)s = %(py6)s(%(py8)s) }) }RRRRRRR R R R ( RRR RRRRRRR(RRRRRRt @py_assert13t @py_format14((s</Users/jpadilla/Projects/Personal/pyjwt/tests/test_compat.pyt8test_constant_time_compare_returns_false_if_diff_lengths s  cCszd}t|}d}t|}t||}| }| r\dditj|d6dtjkpytjtrtjtndd6dtjkptjtrtjtndd 6tj|d 6tj|d 6tj|d 6dtjkptjtr)tjtndd 6tj|d6}ttj|nt }}}}}}dS(NRtefghRsyassert not %(py12)s {%(py12)s = %(py0)s(%(py5)s {%(py5)s = %(py1)s(%(py3)s) }, %(py10)s {%(py10)s = %(py6)s(%(py8)s) }) }RRRRRRR R R R ( RRR RRRRRRR(RRRRRRRR((s</Users/jpadilla/Projects/Personal/pyjwt/tests/test_compat.pyt=test_constant_time_compare_returns_false_if_totally_differents  (t__name__t __module__RR R"(((s</Users/jpadilla/Projects/Personal/pyjwt/tests/test_compat.pyRs  (( t __builtin__Rt_pytest.assertion.rewritet assertiontrewriteR t jwt.compatRtutilsRR(((s</Users/jpadilla/Projects/Personal/pyjwt/tests/test_compat.pyts PyJWT-1.3.0/tests/__pycache__/test_jwt.cpython-27-PYTEST.pyc0000644000076500000240000000307112517227064024273 0ustar jpadillastaff00000000000000 '=Ufc@sGddlZddljjZddlZddlmZdZ dS(iNi(t utc_timestampcCs$idd6tdd6dd6}d}tj||}tj||}||k}|stjd|fd||fid tjkstj|rtj |nd d 6d tjkstj|rtj |nd d 6}di|d6}t tj |nd}dS(s This test exists primarily to ensure that calls to jwt.encode and jwt.decode don't explode. Most functionality is tested by the PyJWT class tests. This is primarily a sanity check to make sure we don't break the public global functions. tjefftissitexptinsanitytclaimtsecrets==s%(py0)s == %(py2)stdecoded_payloadtpy0tpayloadtpy2tsassert %(py4)stpy4N(s==(s%(py0)s == %(py2)ssassert %(py4)s( Rtjwttencodetdecodet @pytest_art_call_reprcomparet @py_builtinstlocalst_should_repr_global_namet _safereprtAssertionErrort_format_explanationtNone(R Rt jwt_messageRt @py_assert1t @py_format3t @py_format5((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_encode_decodes  ( t __builtin__Rt_pytest.assertion.rewritet assertiontrewriteRR tutilsRR(((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyts  PyJWT-1.3.0/tests/compat.py0000644000076500000240000000025512517223733016401 0ustar jpadillastaff00000000000000# flake8: noqa import sys PY3 = sys.version_info[0] == 3 if PY3: string_types = str, text_type = str else: string_types = basestring, text_type = unicode PyJWT-1.3.0/tests/compat.pyc0000644000076500000240000000052212517227064016542 0ustar jpadillastaff00000000000000 '=Uc@sJddlZejddkZer7efZeZnefZeZdS(iNii(tsyst version_infotPY3tstrt string_typest text_typet basestringtunicode(((s7/Users/jpadilla/Projects/Personal/pyjwt/tests/compat.pyts    PyJWT-1.3.0/tests/contrib/0000755000076500000240000000000012527650161016202 5ustar jpadillastaff00000000000000PyJWT-1.3.0/tests/contrib/__init__.py0000644000076500000240000000000012517223733020301 0ustar jpadillastaff00000000000000PyJWT-1.3.0/tests/contrib/__init__.pyc0000644000076500000240000000023012517227064020452 0ustar jpadillastaff00000000000000 '=Uc@sdS(N((((sA/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/__init__.pytsPyJWT-1.3.0/tests/contrib/__pycache__/0000755000076500000240000000000012527650161020412 5ustar jpadillastaff00000000000000PyJWT-1.3.0/tests/contrib/__pycache__/test_algorithms.cpython-27-PYTEST.pyc0000644000076500000240000002513512517227064027305 0ustar jpadillastaff00000000000000 '=Uc@sddlZddljjZddlZddlZddlm Z m Z m Z yddl m Z eZWnek reZnXyddlmZeZWnek reZnXejje dddd d YZejje dd d dd YZdS(iNi(t ensure_bytestensure_unicodetkey_path(t RSAAlgorithm(t ECAlgorithmtreasons&Not supported without PyCrypto librarytTestPycryptoAlgorithmscBsGeZdZdZdZdZdZdZdZRS(cCsDttj}ttdd}|j|jWdQXdS(Nstestkey2_rsa.pub.pemtr(RtSHA256topenRt prepare_keytread(tselftalgotpem_key((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyt$test_rsa_should_parse_pem_public_keyscCsJttj}ttdd }|jt|jWdQXdS(Nt testkey_rsaR(RRR RR RR (R R trsa_key((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyt"test_rsa_should_accept_unicode_keyscCs6ttj}tjt|jdWdQXdS(N(RRtpytesttraisest TypeErrorR tNone(R R ((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyt%test_rsa_should_reject_non_string_key"sc Csttj}td}tjtd}ttdd}|j|j}WdQXttdd}|j|j}WdQX|j |||j |||}|sd idt j kst j|rt j|ndd 6}tt j|ndS( Ns Hello World!sXyS6zk9DBkuGTtcBzLUzSpo9gGJxJFOGvUqN01iLhWHrzBQ9ZEz3+Ae38AXp10RWwscp42ySC85Z6zoN67yGkLNWnfmCZSEv+xqELGEvBJvciOKsrhiObUl2mveSc1oeO/2ujkGDkkkJ2epn0YliacVjZF5+/uDmImUfAAj8lzjnHlzYixsn5jGz1H07jYYbi9diixN8IUhXeTafwFg02IcONhum29V40Wu6O5tAKWlJXfHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCAAPCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA==RRstestkey_rsa.pubtsassert %(py0)stresulttpy0sassert %(py0)s(RRRtbase64t b64decodeR RR R tsigntverifyt @py_builtinstlocalst @pytest_art_should_repr_global_namet _safereprtAssertionErrort_format_explanation( R R t jwt_messaget expected_sigtkeyfiletjwt_keyt jwt_pub_keyRt @py_format1((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyt5test_rsa_sign_should_generate_correct_signature_value(s   Ac Csttj}td}tjtd}|td7}ttdd}|j|j}WdQX|j |||}| }|sd idt j kst j |rt j|ndd 6}tt j|nd}dS( Ns Hello World!sXyS6zk9DBkuGTtcBzLUzSpo9gGJxJFOGvUqN01iLhWHrzBQ9ZEz3+Ae38AXp10RWwscp42ySC85Z6zoN67yGkLNWnfmCZSEv+xqELGEvBJvciOKsrhiObUl2mveSc1oeO/2ujkGDkkkJ2epn0YliacVjZF5+/uDmImUfAAj8lzjnHlzYixsn5jGz1H07jYYbi9diixN8IUhXeTafwFg02IcONhum29V40Wu6O5tAKWlJXfHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCAAPCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA==t123stestkey_rsa.pubRRsassert not %(py0)sRRsassert not %(py0)s(RRRRRR RR R RRR R!R"R#R$R%R( R R R&tjwt_sigR(R*Rt @py_assert1t @py_format2((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyt8test_rsa_verify_should_return_false_if_signature_invalid?s   AcCsttj}td}tjtd}ttdd}|j|j}WdQX|j |||}|sd idt j kst j |rt j|ndd6}tt j|ndS( Ns Hello World!sXyS6zk9DBkuGTtcBzLUzSpo9gGJxJFOGvUqN01iLhWHrzBQ9ZEz3+Ae38AXp10RWwscp42ySC85Z6zoN67yGkLNWnfmCZSEv+xqELGEvBJvciOKsrhiObUl2mveSc1oeO/2ujkGDkkkJ2epn0YliacVjZF5+/uDmImUfAAj8lzjnHlzYixsn5jGz1H07jYYbi9diixN8IUhXeTafwFg02IcONhum29V40Wu6O5tAKWlJXfHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCAAPCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA==stestkey_rsa.pubRRsassert %(py0)sRRsassert %(py0)s(RRRRRR RR R RRR R!R"R#R$R%(R R R&R.R(R*RR+((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyt5test_rsa_verify_should_return_true_if_signature_validTs   AcCs)ttj}ttdd+}|j|j}|j|}WdQX||k}|stjd |fd ||fidtj kstj |rtj |ndd6dtj kstj |rtj |ndd6}di|d 6}t tj |nd}dS(Nstestkey_rsa.pubRs==s%(py0)s == %(py2)stjwt_pub_key_firstRtjwt_pub_key_secondtpy2Rsassert %(py4)stpy4(s==(s%(py0)s == %(py2)ssassert %(py4)s(RRR RR R R!t_call_reprcompareRR R"R#R$R%R(R R R(R3R4R/t @py_format3t @py_format5((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyt)test_rsa_prepare_key_should_be_idempotentgs ( t__name__t __module__RRRR,R1R2R:(((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyRs      s#Not supported without ecdsa librarytTestEcdsaAlgorithmscBs>eZdZdZdZdZdZdZRS(cCs6ttj}tjt|jdWdQXdS(N(RRRRRR R(R R ((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyt$test_ec_should_reject_non_string_keysscCsJttj}ttdd }|jt|jWdQXdS(Nt testkey_ecR(RRR RR RR (R R tec_key((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyt!test_ec_should_accept_unicode_keyysc Csttj}td}tjtd}ttdd}|j|j}WdQXttdd}|j|j}WdQX|j |||j |||}|sd idt j kst j|rt j|ndd 6}tt j|ndS( Ns Hello World!sMIGIAkIB9vYz+inBL8aOTA4auYz/zVuig7TT1bQgKROIQX9YpViHkFa4DT55FuFKn9XzVlk90p6ldEj42DC9YecXHbC2t+cCQgCicY+8f3f/KCNtWK7cif6vdsVwm6Lrjs0Ag6ZqCf+olN11hVt1qKBC4lXppqB1gNWEmNQaiz1z2QRyczJ8hSJmbw==R?Rstestkey_ec.pubRsassert %(py0)sRRsassert %(py0)s(RRRRRR RR R RRRR R!R"R#R$R%( R R R&R'R(R)R*RR+((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyt4test_ec_sign_should_generate_correct_signature_values   Ac Csttj}td}tjtd}|td7}ttdd}|j|j}WdQX|j |||}| }|sd idt j kst j |rt j|ndd 6}tt j|nd}dS( Ns Hello World!sMIGIAkIB9vYz+inBL8aOTA4auYz/zVuig7TT1bQgKROIQX9YpViHkFa4DT55FuFKn9XzVlk90p6ldEj42DC9YecXHbC2t+cCQgCicY+8f3f/KCNtWK7cif6vdsVwm6Lrjs0Ag6ZqCf+olN11hVt1qKBC4lXppqB1gNWEmNQaiz1z2QRyczJ8hSJmbw==R-stestkey_ec.pubRRsassert not %(py0)sRRsassert not %(py0)s(RRRRRR RR R RRR R!R"R#R$R%R( R R R&R.R(R*RR/R0((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyt7test_ec_verify_should_return_false_if_signature_invalids   AcCsttj}td}tjtd}ttdd}|j|j}WdQX|j |||}|sd idt j kst j |rt j|ndd6}tt j|ndS( Ns Hello World!sMIGIAkIB9vYz+inBL8aOTA4auYz/zVuig7TT1bQgKROIQX9YpViHkFa4DT55FuFKn9XzVlk90p6ldEj42DC9YecXHbC2t+cCQgCicY+8f3f/KCNtWK7cif6vdsVwm6Lrjs0Ag6ZqCf+olN11hVt1qKBC4lXppqB1gNWEmNQaiz1z2QRyczJ8hSJmbw==stestkey_ec.pubRRsassert %(py0)sRRsassert %(py0)s(RRRRRR RR R RRR R!R"R#R$R%(R R R&R.R(R*RR+((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyt4test_ec_verify_should_return_true_if_signature_valids   AcCs)ttj}ttdd+}|j|j}|j|}WdQX||k}|stjd |fd ||fidtj kstj |rtj |ndd6dtj kstj |rtj |ndd6}di|d 6}t tj |nd}dS(Nstestkey_ec.pubRs==s%(py0)s == %(py2)sR3RR4R5Rsassert %(py4)sR6(s==(s%(py0)s == %(py2)ssassert %(py4)s(RRR RR R R!R7RR R"R#R$R%R(R R R(R3R4R/R8R9((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyt(test_ec_prepare_key_should_be_idempotents (R;R<R>RARBRCRDRE(((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyR=qs      (((t __builtin__Rt_pytest.assertion.rewritet assertiontrewriteR!RRtutilsRRRtjwt.contrib.algorithms.pycryptoRtTruet has_pycryptot ImportErrortFalsetjwt.contrib.algorithms.py_ecdsaRt has_ecdsatmarktskipifRR=(((sH/Users/jpadilla/Projects/Personal/pyjwt/tests/contrib/test_algorithms.pyts         ,]PyJWT-1.3.0/tests/contrib/test_algorithms.py0000644000076500000240000001626312527650137021777 0ustar jpadillastaff00000000000000import base64 import pytest from ..utils import ensure_bytes, ensure_unicode, key_path try: from jwt.contrib.algorithms.pycrypto import RSAAlgorithm has_pycrypto = True except ImportError: has_pycrypto = False try: from jwt.contrib.algorithms.py_ecdsa import ECAlgorithm has_ecdsa = True except ImportError: has_ecdsa = False @pytest.mark.skipif(not has_pycrypto, reason='Not supported without PyCrypto library') class TestPycryptoAlgorithms: def test_rsa_should_parse_pem_public_key(self): algo = RSAAlgorithm(RSAAlgorithm.SHA256) with open(key_path('testkey2_rsa.pub.pem'), 'r') as pem_key: algo.prepare_key(pem_key.read()) def test_rsa_should_accept_unicode_key(self): algo = RSAAlgorithm(RSAAlgorithm.SHA256) with open(key_path('testkey_rsa'), 'r') as rsa_key: algo.prepare_key(ensure_unicode(rsa_key.read())) def test_rsa_should_reject_non_string_key(self): algo = RSAAlgorithm(RSAAlgorithm.SHA256) with pytest.raises(TypeError): algo.prepare_key(None) def test_rsa_sign_should_generate_correct_signature_value(self): algo = RSAAlgorithm(RSAAlgorithm.SHA256) jwt_message = ensure_bytes('Hello World!') expected_sig = base64.b64decode(ensure_bytes( 'yS6zk9DBkuGTtcBzLUzSpo9gGJxJFOGvUqN01iLhWHrzBQ9ZEz3+Ae38AXp' '10RWwscp42ySC85Z6zoN67yGkLNWnfmCZSEv+xqELGEvBJvciOKsrhiObUl' '2mveSc1oeO/2ujkGDkkkJ2epn0YliacVjZF5+/uDmImUfAAj8lzjnHlzYix' 'sn5jGz1H07jYYbi9diixN8IUhXeTafwFg02IcONhum29V40Wu6O5tAKWlJX' 'fHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCA' 'APCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA==')) with open(key_path('testkey_rsa'), 'r') as keyfile: jwt_key = algo.prepare_key(keyfile.read()) with open(key_path('testkey_rsa.pub'), 'r') as keyfile: jwt_pub_key = algo.prepare_key(keyfile.read()) algo.sign(jwt_message, jwt_key) result = algo.verify(jwt_message, jwt_pub_key, expected_sig) assert result def test_rsa_verify_should_return_false_if_signature_invalid(self): algo = RSAAlgorithm(RSAAlgorithm.SHA256) jwt_message = ensure_bytes('Hello World!') jwt_sig = base64.b64decode(ensure_bytes( 'yS6zk9DBkuGTtcBzLUzSpo9gGJxJFOGvUqN01iLhWHrzBQ9ZEz3+Ae38AXp' '10RWwscp42ySC85Z6zoN67yGkLNWnfmCZSEv+xqELGEvBJvciOKsrhiObUl' '2mveSc1oeO/2ujkGDkkkJ2epn0YliacVjZF5+/uDmImUfAAj8lzjnHlzYix' 'sn5jGz1H07jYYbi9diixN8IUhXeTafwFg02IcONhum29V40Wu6O5tAKWlJX' 'fHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCA' 'APCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA==')) jwt_sig += ensure_bytes('123') # Signature is now invalid with open(key_path('testkey_rsa.pub'), 'r') as keyfile: jwt_pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(jwt_message, jwt_pub_key, jwt_sig) assert not result def test_rsa_verify_should_return_true_if_signature_valid(self): algo = RSAAlgorithm(RSAAlgorithm.SHA256) jwt_message = ensure_bytes('Hello World!') jwt_sig = base64.b64decode(ensure_bytes( 'yS6zk9DBkuGTtcBzLUzSpo9gGJxJFOGvUqN01iLhWHrzBQ9ZEz3+Ae38AXp' '10RWwscp42ySC85Z6zoN67yGkLNWnfmCZSEv+xqELGEvBJvciOKsrhiObUl' '2mveSc1oeO/2ujkGDkkkJ2epn0YliacVjZF5+/uDmImUfAAj8lzjnHlzYix' 'sn5jGz1H07jYYbi9diixN8IUhXeTafwFg02IcONhum29V40Wu6O5tAKWlJX' 'fHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCA' 'APCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA==')) with open(key_path('testkey_rsa.pub'), 'r') as keyfile: jwt_pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(jwt_message, jwt_pub_key, jwt_sig) assert result def test_rsa_prepare_key_should_be_idempotent(self): algo = RSAAlgorithm(RSAAlgorithm.SHA256) with open(key_path('testkey_rsa.pub'), 'r') as keyfile: jwt_pub_key_first = algo.prepare_key(keyfile.read()) jwt_pub_key_second = algo.prepare_key(jwt_pub_key_first) assert jwt_pub_key_first == jwt_pub_key_second @pytest.mark.skipif(not has_ecdsa, reason='Not supported without ecdsa library') class TestEcdsaAlgorithms: def test_ec_should_reject_non_string_key(self): algo = ECAlgorithm(ECAlgorithm.SHA256) with pytest.raises(TypeError): algo.prepare_key(None) def test_ec_should_accept_unicode_key(self): algo = ECAlgorithm(ECAlgorithm.SHA256) with open(key_path('testkey_ec'), 'r') as ec_key: algo.prepare_key(ensure_unicode(ec_key.read())) def test_ec_sign_should_generate_correct_signature_value(self): algo = ECAlgorithm(ECAlgorithm.SHA256) jwt_message = ensure_bytes('Hello World!') expected_sig = base64.b64decode(ensure_bytes( 'AC+m4Jf/xI3guAC6w0w37t5zRpSCF6F4udEz5LiMiTIjCS4vcVe6dDOxK+M' 'mvkF8PxJuvqxP2CO3TR3okDPCl/NjATTO1jE+qBZ966CRQSSzcCM+tzcHzw' 'LZS5kbvKu0Acd/K6Ol2/W3B1NeV5F/gjvZn/jOwaLgWEUYsg0o4XVrAg65')) with open(key_path('testkey_ec'), 'r') as keyfile: jwt_key = algo.prepare_key(keyfile.read()) with open(key_path('testkey_ec.pub'), 'r') as keyfile: jwt_pub_key = algo.prepare_key(keyfile.read()) algo.sign(jwt_message, jwt_key) result = algo.verify(jwt_message, jwt_pub_key, expected_sig) assert result def test_ec_verify_should_return_false_if_signature_invalid(self): algo = ECAlgorithm(ECAlgorithm.SHA256) jwt_message = ensure_bytes('Hello World!') jwt_sig = base64.b64decode(ensure_bytes( 'AC+m4Jf/xI3guAC6w0w37t5zRpSCF6F4udEz5LiMiTIjCS4vcVe6dDOxK+M' 'mvkF8PxJuvqxP2CO3TR3okDPCl/NjATTO1jE+qBZ966CRQSSzcCM+tzcHzw' 'LZS5kbvKu0Acd/K6Ol2/W3B1NeV5F/gjvZn/jOwaLgWEUYsg0o4XVrAg65')) jwt_sig += ensure_bytes('123') # Signature is now invalid with open(key_path('testkey_ec.pub'), 'r') as keyfile: jwt_pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(jwt_message, jwt_pub_key, jwt_sig) assert not result def test_ec_verify_should_return_true_if_signature_valid(self): algo = ECAlgorithm(ECAlgorithm.SHA256) jwt_message = ensure_bytes('Hello World!') jwt_sig = base64.b64decode(ensure_bytes( 'AC+m4Jf/xI3guAC6w0w37t5zRpSCF6F4udEz5LiMiTIjCS4vcVe6dDOxK+M' 'mvkF8PxJuvqxP2CO3TR3okDPCl/NjATTO1jE+qBZ966CRQSSzcCM+tzcHzw' 'LZS5kbvKu0Acd/K6Ol2/W3B1NeV5F/gjvZn/jOwaLgWEUYsg0o4XVrAg65')) with open(key_path('testkey_ec.pub'), 'r') as keyfile: jwt_pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(jwt_message, jwt_pub_key, jwt_sig) assert result def test_ec_prepare_key_should_be_idempotent(self): algo = ECAlgorithm(ECAlgorithm.SHA256) with open(key_path('testkey_ec.pub'), 'r') as keyfile: jwt_pub_key_first = algo.prepare_key(keyfile.read()) jwt_pub_key_second = algo.prepare_key(jwt_pub_key_first) assert jwt_pub_key_first == jwt_pub_key_second PyJWT-1.3.0/tests/keys/0000755000076500000240000000000012527650161015515 5ustar jpadillastaff00000000000000PyJWT-1.3.0/tests/keys/__init__.py0000644000076500000240000000432112527650137017631 0ustar jpadillastaff00000000000000import json import os from jwt.utils import base64url_decode from tests.utils import ensure_bytes, int_from_bytes BASE_PATH = os.path.dirname(os.path.abspath(__file__)) def decode_value(val): decoded = base64url_decode(ensure_bytes(val)) return int_from_bytes(decoded, 'big') def load_hmac_key(): with open(os.path.join(BASE_PATH, 'jwk_hmac.json'), 'r') as infile: keyobj = json.load(infile) return base64url_decode(ensure_bytes(keyobj['k'])) try: from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.backends import default_backend has_crypto = True except ImportError: has_crypto = False if has_crypto: def load_rsa_key(): with open(os.path.join(BASE_PATH, 'jwk_rsa_key.json'), 'r') as infile: keyobj = json.load(infile) return rsa.RSAPrivateNumbers( p=decode_value(keyobj['p']), q=decode_value(keyobj['q']), d=decode_value(keyobj['d']), dmp1=decode_value(keyobj['dp']), dmq1=decode_value(keyobj['dq']), iqmp=decode_value(keyobj['qi']), public_numbers=load_rsa_pub_key().public_numbers() ).private_key(default_backend()) def load_rsa_pub_key(): with open(os.path.join(BASE_PATH, 'jwk_rsa_pub.json'), 'r') as infile: keyobj = json.load(infile) return rsa.RSAPublicNumbers( n=decode_value(keyobj['n']), e=decode_value(keyobj['e']) ).public_key(default_backend()) def load_ec_key(): with open(os.path.join(BASE_PATH, 'jwk_ec_key.json'), 'r') as infile: keyobj = json.load(infile) return ec.EllipticCurvePrivateNumbers( private_value=decode_value(keyobj['d']), public_numbers=load_ec_pub_key().public_numbers() ) def load_ec_pub_key(): with open(os.path.join(BASE_PATH, 'jwk_ec_pub.json'), 'r') as infile: keyobj = json.load(infile) return ec.EllipticCurvePublicNumbers( x=decode_value(keyobj['x']), y=decode_value(keyobj['y']), curve=ec.SECP521R1() ).public_key(default_backend()) PyJWT-1.3.0/tests/keys/jwk_ec_key.json0000644000076500000240000000063512527650137020531 0ustar jpadillastaff00000000000000{ "kty": "EC", "kid": "bilbo.baggins@hobbiton.example", "use": "sig", "crv": "P-521", "x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt", "y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1", "d": "AAhRON2r9cqXX1hg-RoI6R1tX5p2rUAYdmpHZoC1XNM56KtscrX6zbKipQrCW9CGZH3T4ubpnoTKLDYJ_fF3_rJt" } PyJWT-1.3.0/tests/keys/jwk_ec_pub.json0000644000076500000240000000046712527650137020532 0ustar jpadillastaff00000000000000{ "kty": "EC", "kid": "bilbo.baggins@hobbiton.example", "use": "sig", "crv": "P-521", "x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt", "y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1" } PyJWT-1.3.0/tests/keys/jwk_hmac.json0000644000076500000240000000025312527650137020176 0ustar jpadillastaff00000000000000{ "kty": "oct", "kid": "018c0ae5-4d9b-471b-bfd6-eef314bc7037", "use": "sig", "alg": "HS256", "k": "hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg" } PyJWT-1.3.0/tests/keys/jwk_rsa_key.json0000644000076500000240000000332112527650137020722 0ustar jpadillastaff00000000000000{ "kty": "RSA", "kid": "bilbo.baggins@hobbiton.example", "use": "sig", "n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw", "e": "AQAB", "d": "bWUC9B-EFRIo8kpGfh0ZuyGPvMNKvYWNtB_ikiH9k20eT-O1q_I78eiZkpXxXQ0UTEs2LsNRS-8uJbvQ-A1irkwMSMkK1J3XTGgdrhCku9gRldY7sNA_AKZGh-Q661_42rINLRCe8W-nZ34ui_qOfkLnK9QWDDqpaIsA-bMwWWSDFu2MUBYwkHTMEzLYGqOe04noqeq1hExBTHBOBdkMXiuFhUq1BU6l-DqEiWxqg82sXt2h-LMnT3046AOYJoRioz75tSUQfGCshWTBnP5uDjd18kKhyv07lhfSJdrPdM5Plyl21hsFf4L_mHCuoFau7gdsPfHPxxjVOcOpBrQzwQ", "p": "3Slxg_DwTXJcb6095RoXygQCAZ5RnAvZlno1yhHtnUex_fp7AZ_9nRaO7HX_-SFfGQeutao2TDjDAWU4Vupk8rw9JR0AzZ0N2fvuIAmr_WCsmGpeNqQnev1T7IyEsnh8UMt-n5CafhkikzhEsrmndH6LxOrvRJlsPp6Zv8bUq0k", "q": "uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc", "dp": "B8PVvXkvJrj2L-GYQ7v3y9r6Kw5g9SahXBwsWUzp19TVlgI-YV85q1NIb1rxQtD-IsXXR3-TanevuRPRt5OBOdiMGQp8pbt26gljYfKU_E9xn-RULHz0-ed9E9gXLKD4VGngpz-PfQ_q29pk5xWHoJp009Qf1HvChixRX59ehik", "dq": "CLDmDGduhylc9o7r84rEUVn7pzQ6PF83Y-iBZx5NT-TpnOZKF1pErAMVeKzFEl41DlHHqqBLSM0W1sOFbwTxYWZDm6sI6og5iTbwQGIC3gnJKbi_7k_vJgGHwHxgPaX2PnvP-zyEkDERuf-ry4c_Z11Cq9AqC2yeL6kdKT1cYF8", "qi": "3PiqvXQN0zwMeE-sBvZgi289XP9XCQF3VWqPzMKnIgQp7_Tugo6-NZBKCQsMf3HaEGBjTVJs_jcK8-TRXvaKe-7ZMaQj8VfBdYkssbu0NKDDhjJ-GtiseaDVWt7dcH0cfwxgFUHpQh7FoCrjFJ6h6ZEpMF6xmujs4qMpPz8aaI4" } PyJWT-1.3.0/tests/keys/jwk_rsa_pub.json0000644000076500000240000000071512527650137020724 0ustar jpadillastaff00000000000000{ "kty": "RSA", "kid": "bilbo.baggins@hobbiton.example", "use": "sig", "n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw", "e": "AQAB" } PyJWT-1.3.0/tests/keys/testkey2_rsa.pub.pem0000644000076500000240000000070312472132320021413 0ustar jpadillastaff00000000000000-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1tUH3/0v8fvLensHO1g2 6+U4r7jBg43DVOgqmXAWQa8ArAb4NfTrsYX8YkVhZZYwuLmKczRj0GhXUVY9iDbT sIGmgG+ySj6eiREz5VLqofFkAvRZ6y7yNv8PIGgXEhQTiDDNIkHGaFNMvn/eZ54H is70pdTjR5Ko+/y/wg71df1nb/5KwttSvy0YsTu/XpkduonPruYfAVRG3HK+3GZd xTygLcdamwe9jj+kjxtXRlrXVMQiXGFSU8U6bjafWnQiQ9XzjxvygBt0ZD0kRorr p74XGyQY5ThkN8DlpJbTTFsxOnBUAQz4zhohjobIGBRimi5yVlyLOwTlpaKGFC7O 7wIDAQAB -----END PUBLIC KEY----- PyJWT-1.3.0/tests/keys/testkey_ec0000644000076500000240000000055112472132320017567 0ustar jpadillastaff00000000000000-----BEGIN EC PRIVATE KEY----- MIHbAgEBBEG4xN/z6gk7bPkEzs1hHOsbs+Gi2lku8YH4LkS4E1q9U9jSOjvEcFNH m/CQjKi1rtpAb0/WL3p/wXsc26e7zmAA5KAHBgUrgQQAI6GBiQOBhgAEAVnCcDxA J0v5OJBYFIcTReydEkEIWRvpzYMvv5l8IUOT2SFJiHdWtU45DV4is7+g6bbQanbh 28/1dBLR/kH1stAeAYWeTJ08gxo3M9Q0KinXsXm4c6G24UiGY6WHeWlOPKPa16fz pwJ62o3XaRrCdGzX+K7TCwahWCTeizrJQAe8UwUY -----END EC PRIVATE KEY----- PyJWT-1.3.0/tests/keys/testkey_ec.pub0000644000076500000240000000041412472132320020352 0ustar jpadillastaff00000000000000-----BEGIN PUBLIC KEY----- MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBWcJwPEAnS/k4kFgUhxNF7J0SQQhZ G+nNgy+/mXwhQ5PZIUmId1a1TjkNXiKzv6DpttBqduHbz/V0EtH+QfWy0B4BhZ5M nTyDGjcz1DQqKdexebhzobbhSIZjpYd5aU48o9rXp/OnAnrajddpGsJ0bNf4rtML BqFYJN6LOslAB7xTBRg= -----END PUBLIC KEY----- PyJWT-1.3.0/tests/keys/testkey_rsa0000644000076500000240000000321712472132320017767 0ustar jpadillastaff00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEA1HgzBfJv2cOjQryCwe8NEelriOTNFWKZUivevUrRhlqcmZJd CvuCJRr+xCN+OmO8qwgJJR98feNujxVg+J9Ls3/UOA4HcF9nYH6aqVXELAE8Hk/A Lvxi96ms1DDuAvQGaYZ+lANxlvxeQFOZSbjkz/9mh8aLeGKwqJLp3p+OhUBQpwvA UAPg82+OUtgTW3nSljjeFr14B8qAneGSc/wl0ni++1SRZUXFSovzcqQOkla3W27r rLfrD6LXgj/TsDs4vD1PnIm1zcVenKT7TfYI17bsG/O/Wecwz2Nl19pL7gDosNru F3ogJWNq1Lyn/ijPQnkPLpZHyhvuiycYcI3DiQIDAQABAoIBAQCt9uzwBZ0HVGQs lGULnUu6SsC9iXlR9TVMTpdFrij4NODb7Tc5cs0QzJWkytrjvB4Se7XhK3KnMLyp cvu/Fc7J3fRJIVN98t+V5pOD6rGAxlIPD4Vv8z6lQcw8wQNgb6WAaZriXh93XJNf YBO2hSj0FU5CBZLUsxmqLQBIQ6RR/OUGAvThShouE9K4N0vKB2UPOCu5U+d5zS3W 44Q5uatxYiSHBTYIZDN4u27Nfo5WA+GTvFyeNsO6tNNWlYfRHSBtnm6SZDY/5i4J fxP2JY0waM81KRvuHTazY571lHM/TTvFDRUX5nvHIu7GToBKahfVLf26NJuTZYXR 5c09GAXBAoGBAO7a9M/dvS6eDhyESYyCjP6w61jD7UYJ1fudaYFrDeqnaQ857Pz4 BcKx3KMmLFiDvuMgnVVj8RToBGfMV0zP7sDnuFRJnWYcOeU8e2sWGbZmWGWzv0SD +AhppSZThU4mJ8aa/tgsepCHkJnfoX+3wN7S9NfGhM8GDGxTHJwBpxINAoGBAOO4 ZVtn9QEblmCX/Q5ejInl43Y9nRsfTy9lB9Lp1cyWCJ3eep6lzT60K3OZGVOuSgKQ vZ/aClMCMbqsAAG4fKBjREA6p7k4/qaMApHQum8APCh9WPsKLaavxko8ZDc41kZt hgKyUs2XOhW/BLjmzqwGryidvOfszDwhH7rNVmRtAoGBALYGdvrSaRHVsbtZtRM3 imuuOCx1Y6U0abZOx9Cw3PIukongAxLlkL5G/XX36WOrQxWkDUK930OnbXQM7ZrD +5dW/8p8L09Zw2VHKmb5eK7gYA1hZim4yJTgrdL/Y1+jBDz+cagcfWsXZMNfAZxr VLh628x0pVF/sof67pqVR9UhAoGBAMcQiLoQ9GJVhW1HMBYBnQVnCyJv1gjBo+0g emhrtVQ0y6+FrtdExVjNEzboXPWD5Hq9oKY+aswJnQM8HH1kkr16SU2EeN437pQU zKI/PtqN8AjNGp3JVgLioYp/pHOJofbLA10UGcJTMpmT9ELWsVA8P55X1a1AmYDu y9f2bFE5AoGAdjo95mB0LVYikNPa+NgyDwLotLqrueb9IviMmn6zKHCwiOXReqXD X9slB8RA15uv56bmN04O//NyVFcgJ2ef169GZHiRFIgIy0Pl8LYkMhCYKKhyqM7g xN+SqGqDTKDC22j00S7jcvCaa1qadn1qbdfukZ4NXv7E2d/LO0Y2Kkc= -----END RSA PRIVATE KEY----- PyJWT-1.3.0/tests/keys/testkey_rsa.cer0000644000076500000240000000240112517223733020542 0ustar jpadillastaff00000000000000-----BEGIN CERTIFICATE----- MIIDhTCCAm2gAwIBAgIJANE4sir3EkX8MA0GCSqGSIb3DQEBCwUAMFkxCzAJBgNV BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEPMA0GA1UEBwwGQXVzdGluMQ4wDAYDVQQK DAVQeUpXVDEZMBcGA1UECwwQVGVzdCBDZXJ0aWZpY2F0ZTAeFw0xNTAzMTgwMTE2 MTRaFw0xODAzMTcwMTE2MTRaMFkxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhh czEPMA0GA1UEBwwGQXVzdGluMQ4wDAYDVQQKDAVQeUpXVDEZMBcGA1UECwwQVGVz dCBDZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANR4 MwXyb9nDo0K8gsHvDRHpa4jkzRVimVIr3r1K0YZanJmSXQr7giUa/sQjfjpjvKsI CSUffH3jbo8VYPifS7N/1DgOB3BfZ2B+mqlVxCwBPB5PwC78YveprNQw7gL0BmmG fpQDcZb8XkBTmUm45M//ZofGi3hisKiS6d6fjoVAUKcLwFAD4PNvjlLYE1t50pY4 3ha9eAfKgJ3hknP8JdJ4vvtUkWVFxUqL83KkDpJWt1tu66y36w+i14I/07A7OLw9 T5yJtc3FXpyk+032CNe27Bvzv1nnMM9jZdfaS+4A6LDa7hd6ICVjatS8p/4oz0J5 Dy6WR8ob7osnGHCNw4kCAwEAAaNQME4wHQYDVR0OBBYEFDR6fVdFxZED6YMmD62W LlBW+qEBMB8GA1UdIwQYMBaAFDR6fVdFxZED6YMmD62WLlBW+qEBMAwGA1UdEwQF MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFwDNwm+lU/kGfWwiWM0Lv2aosXotoiG TsBSWIn2iYphq0vzlgChcNocN9zkaOz3zc9pcREP6lyqHpE0OEbNucHHDdU1L2he lLFOLOmkpP5fyPDXs9nKYhO8ygMByEonHm3K/VvCgrsSgJ3JuxMLUxnE55jQXGWV OqYQNo2J5h93Zd2HTTe19jCz+bbWnRBP5VvLAAAo5YSmk3iroWSPWAKkWOOecJ2Q /xnRyuWERsfvZiF/m9q7yDJ55LXVVm3Rufmy76SoTnJ2acap+XQNXBH/AxayeLUS OYmHWH61dUcsQtwXYHYRB8TTtMIwUCXGmthXkDJydEfrGcD0y6APIh8= -----END CERTIFICATE----- PyJWT-1.3.0/tests/keys/testkey_rsa.pub0000644000076500000240000000062112472132320020550 0ustar jpadillastaff00000000000000ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUeDMF8m/Zw6NCvILB7w0R6WuI5M0VYplSK969StGGWpyZkl0K+4IlGv7EI346Y7yrCAklH3x9426PFWD4n0uzf9Q4DgdwX2dgfpqpVcQsATweT8Au/GL3qazUMO4C9AZphn6UA3GW/F5AU5lJuOTP/2aHxot4YrCokunen46FQFCnC8BQA+Dzb45S2BNbedKWON4WvXgHyoCd4ZJz/CXSeL77VJFlRcVKi/NypA6SVrdbbuust+sPoteCP9OwOzi8PU+cibXNxV6cpPtN9gjXtuwb879Z5zDPY2XX2kvuAOiw2u4XeiAlY2rUvKf+KM9CeQ8ulkfKG+6LJxhwjcOJ aasmundo@mair.local PyJWT-1.3.0/tests/test_algorithms.py0000644000076500000240000003332612527650137020336 0ustar jpadillastaff00000000000000import base64 from jwt.algorithms import Algorithm, HMACAlgorithm, NoneAlgorithm from jwt.exceptions import InvalidKeyError from jwt.utils import base64url_decode import pytest from .keys import load_hmac_key from .utils import ensure_bytes, ensure_unicode, key_path try: from jwt.algorithms import RSAAlgorithm, ECAlgorithm, RSAPSSAlgorithm from .keys import load_rsa_pub_key, load_ec_pub_key has_crypto = True except ImportError: has_crypto = False class TestAlgorithms: def test_algorithm_should_throw_exception_if_prepare_key_not_impl(self): algo = Algorithm() with pytest.raises(NotImplementedError): algo.prepare_key('test') def test_algorithm_should_throw_exception_if_sign_not_impl(self): algo = Algorithm() with pytest.raises(NotImplementedError): algo.sign('message', 'key') def test_algorithm_should_throw_exception_if_verify_not_impl(self): algo = Algorithm() with pytest.raises(NotImplementedError): algo.verify('message', 'key', 'signature') def test_none_algorithm_should_throw_exception_if_key_is_not_none(self): algo = NoneAlgorithm() with pytest.raises(InvalidKeyError): algo.prepare_key('123') def test_hmac_should_reject_nonstring_key(self): algo = HMACAlgorithm(HMACAlgorithm.SHA256) with pytest.raises(TypeError) as context: algo.prepare_key(object()) exception = context.value assert str(exception) == 'Expecting a string- or bytes-formatted key.' def test_hmac_should_accept_unicode_key(self): algo = HMACAlgorithm(HMACAlgorithm.SHA256) 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) with pytest.raises(InvalidKeyError): 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) with pytest.raises(InvalidKeyError): 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) with pytest.raises(InvalidKeyError): 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) with pytest.raises(InvalidKeyError): 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_rsa_should_parse_pem_public_key(self): algo = RSAAlgorithm(RSAAlgorithm.SHA256) with open(key_path('testkey2_rsa.pub.pem'), 'r') 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) with open(key_path('testkey_rsa'), 'r') as rsa_key: algo.prepare_key(ensure_unicode(rsa_key.read())) @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_rsa_should_reject_non_string_key(self): algo = RSAAlgorithm(RSAAlgorithm.SHA256) with pytest.raises(TypeError): algo.prepare_key(None) @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_rsa_verify_should_return_false_if_signature_invalid(self): algo = RSAAlgorithm(RSAAlgorithm.SHA256) message = ensure_bytes('Hello World!') sig = base64.b64decode(ensure_bytes( 'yS6zk9DBkuGTtcBzLUzSpo9gGJxJFOGvUqN01iLhWHrzBQ9ZEz3+Ae38AXp' '10RWwscp42ySC85Z6zoN67yGkLNWnfmCZSEv+xqELGEvBJvciOKsrhiObUl' '2mveSc1oeO/2ujkGDkkkJ2epn0YliacVjZF5+/uDmImUfAAj8lzjnHlzYix' 'sn5jGz1H07jYYbi9diixN8IUhXeTafwFg02IcONhum29V40Wu6O5tAKWlJX' 'fHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCA' 'APCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA==')) sig += ensure_bytes('123') # Signature is now invalid with open(key_path('testkey_rsa.pub'), 'r') as keyfile: pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(message, pub_key, sig) assert not result @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_ec_should_reject_non_string_key(self): algo = ECAlgorithm(ECAlgorithm.SHA256) with pytest.raises(TypeError): algo.prepare_key(None) @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_ec_should_accept_unicode_key(self): algo = ECAlgorithm(ECAlgorithm.SHA256) with open(key_path('testkey_ec'), 'r') as ec_key: algo.prepare_key(ensure_unicode(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) message = ensure_bytes('Hello World!') # Mess up the signature by replacing a known byte sig = base64.b64decode(ensure_bytes( 'AC+m4Jf/xI3guAC6w0w37t5zRpSCF6F4udEz5LiMiTIjCS4vcVe6dDOxK+M' 'mvkF8PxJuvqxP2CO3TR3okDPCl/NjATTO1jE+qBZ966CRQSSzcCM+tzcHzw' 'LZS5kbvKu0Acd/K6Ol2/W3B1NeV5F/gjvZn/jOwaLgWEUYsg0o4XVrAg65'.replace('r', 's'))) with open(key_path('testkey_ec.pub'), 'r') as keyfile: pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(message, pub_key, sig) assert not result @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_ec_verify_should_return_false_if_signature_wrong_length(self): algo = ECAlgorithm(ECAlgorithm.SHA256) message = ensure_bytes('Hello World!') sig = base64.b64decode(ensure_bytes('AC+m4Jf/xI3guAC6w0w3')) with open(key_path('testkey_ec.pub'), 'r') as keyfile: pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(message, pub_key, sig) assert not result @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_rsa_pss_sign_then_verify_should_return_true(self): algo = RSAPSSAlgorithm(RSAPSSAlgorithm.SHA256) message = ensure_bytes('Hello World!') with open(key_path('testkey_rsa'), 'r') as keyfile: priv_key = algo.prepare_key(keyfile.read()) sig = algo.sign(message, priv_key) with open(key_path('testkey_rsa.pub'), 'r') as keyfile: pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(message, pub_key, sig) assert result @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_rsa_pss_verify_should_return_false_if_signature_invalid(self): algo = RSAPSSAlgorithm(RSAPSSAlgorithm.SHA256) jwt_message = ensure_bytes('Hello World!') jwt_sig = base64.b64decode(ensure_bytes( 'ywKAUGRIDC//6X+tjvZA96yEtMqpOrSppCNfYI7NKyon3P7doud5v65oWNu' 'vQsz0fzPGfF7mQFGo9Cm9Vn0nljm4G6PtqZRbz5fXNQBH9k10gq34AtM02c' '/cveqACQ8gF3zxWh6qr9jVqIpeMEaEBIkvqG954E0HT9s9ybHShgHX9mlWk' '186/LopP4xe5c/hxOQjwhv6yDlTiwJFiqjNCvj0GyBKsc4iECLGIIO+4mC4' 'daOCWqbpZDuLb1imKpmm8Nsm56kAxijMLZnpCcnPgyb7CqG+B93W9GHglA5' 'drUeR1gRtO7vqbZMsCAQ4bpjXxwbYyjQlEVuMl73UL6sOWg==')) jwt_sig += ensure_bytes('123') # Signature is now invalid with open(key_path('testkey_rsa.pub'), 'r') as keyfile: jwt_pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(jwt_message, jwt_pub_key, jwt_sig) assert not result class TestAlgorithmsRFC7520: """ These test vectors were taken from RFC 7520 (https://tools.ietf.org/html/rfc7520) """ def test_hmac_verify_should_return_true_for_test_vector(self): """ This test verifies that HMAC verification works with a known good signature and key. Reference: https://tools.ietf.org/html/rfc7520#section-4.4 """ signing_input = ensure_bytes( 'eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LWVlZ' 'jMxNGJjNzAzNyJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ' '29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIG' 'lmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmc' 'gd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4' ) signature = base64url_decode(ensure_bytes( 's0h6KThzkfBBBkLspW1h84VsJZFTsPPqMDA7g1Md7p0' )) algo = HMACAlgorithm(HMACAlgorithm.SHA256) key = algo.prepare_key(load_hmac_key()) result = algo.verify(signing_input, key, signature) assert result @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_rsa_verify_should_return_true_for_test_vector(self): """ This test verifies that RSA PKCS v1.5 verification works with a known good signature and key. Reference: https://tools.ietf.org/html/rfc7520#section-4.1 """ signing_input = ensure_bytes( 'eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhb' 'XBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb' '3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdS' 'Bkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmU' 'geW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4' ) signature = base64url_decode(ensure_bytes( 'MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e5CZ5NlKtainoFmKZop' 'dHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJ' 'K3lfWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4' 'QPocSadnHXFxnt8Is9UzpERV0ePPQdLuW3IS_de3xyIrDaLGdjluPxUAhb6L2aXic' '1U12podGU0KLUQSE_oI-ZnmKJ3F4uOZDnd6QZWJushZ41Axf_fcIe8u9ipH84ogor' 'ee7vjbU5y18kDquDg' )) algo = RSAAlgorithm(RSAAlgorithm.SHA256) key = algo.prepare_key(load_rsa_pub_key()) result = algo.verify(signing_input, key, signature) assert result @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_rsapss_verify_should_return_true_for_test_vector(self): """ This test verifies that RSA-PSS verification works with a known good signature and key. Reference: https://tools.ietf.org/html/rfc7520#section-4.2 """ signing_input = ensure_bytes( 'eyJhbGciOiJQUzM4NCIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhb' 'XBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb' '3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdS' 'Bkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmU' 'geW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4' ) signature = base64url_decode(ensure_bytes( 'cu22eBqkYDKgIlTpzDXGvaFfz6WGoz7fUDcfT0kkOy42miAh2qyBzk1xEsnk2IpN6' '-tPid6VrklHkqsGqDqHCdP6O8TTB5dDDItllVo6_1OLPpcbUrhiUSMxbbXUvdvWXz' 'g-UD8biiReQFlfz28zGWVsdiNAUf8ZnyPEgVFn442ZdNqiVJRmBqrYRXe8P_ijQ7p' '8Vdz0TTrxUeT3lm8d9shnr2lfJT8ImUjvAA2Xez2Mlp8cBE5awDzT0qI0n6uiP1aC' 'N_2_jLAeQTlqRHtfa64QQSUmFAAjVKPbByi7xho0uTOcbH510a6GYmJUAfmWjwZ6o' 'D4ifKo8DYM-X72Eaw' )) algo = RSAPSSAlgorithm(RSAPSSAlgorithm.SHA384) key = algo.prepare_key(load_rsa_pub_key()) result = algo.verify(signing_input, key, signature) assert result @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_ec_verify_should_return_true_for_test_vector(self): """ This test verifies that ECDSA verification works with a known good signature and key. Reference: https://tools.ietf.org/html/rfc7520#section-4.3 """ signing_input = ensure_bytes( 'eyJhbGciOiJFUzUxMiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhb' 'XBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb' '3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdS' 'Bkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmU' 'geW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4' ) signature = base64url_decode(ensure_bytes( 'AE_R_YZCChjn4791jSQCrdPZCNYqHXCTZH0-JZGYNlaAjP2kqaluUIIUnC9qvbu9P' 'lon7KRTzoNEuT4Va2cmL1eJAQy3mtPBu_u_sDDyYjnAMDxXPn7XrT0lw-kvAD890j' 'l8e2puQens_IEKBpHABlsbEPX6sFY8OcGDqoRuBomu9xQ2' )) algo = ECAlgorithm(ECAlgorithm.SHA512) key = algo.prepare_key(load_ec_pub_key()) result = algo.verify(signing_input, key, signature) assert result PyJWT-1.3.0/tests/test_api_jws.py0000644000076500000240000005512512527650137017622 0ustar jpadillastaff00000000000000 import json from decimal import Decimal from jwt.algorithms import Algorithm from jwt.api_jws import PyJWS from jwt.exceptions import ( DecodeError, InvalidAlgorithmError ) from jwt.utils import base64url_decode import pytest from .compat import string_types, text_type from .utils import ensure_bytes, ensure_unicode try: from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.serialization import ( load_pem_private_key, load_pem_public_key, load_ssh_public_key ) has_crypto = True except ImportError: has_crypto = False @pytest.fixture def jws(): return PyJWS() @pytest.fixture def payload(): """ Creates a sample jws claimset for use as a payload during tests """ return ensure_bytes('hello world') class TestJWS: def test_register_algo_does_not_allow_duplicate_registration(self, jws): jws.register_algorithm('AAA', Algorithm()) with pytest.raises(ValueError): jws.register_algorithm('AAA', Algorithm()) def test_register_algo_rejects_non_algorithm_obj(self, jws): with pytest.raises(TypeError): jws.register_algorithm('AAA123', {}) def test_unregister_algo_removes_algorithm(self, jws): supported = jws.get_algorithms() assert 'none' in supported assert 'HS256' in supported jws.unregister_algorithm('HS256') supported = jws.get_algorithms() assert 'HS256' not in supported def test_unregister_algo_throws_error_if_not_registered(self, jws): with pytest.raises(KeyError): jws.unregister_algorithm('AAA') def test_algo_parameter_removes_alg_from_algorithms_list(self, jws): assert 'none' in jws.get_algorithms() assert 'HS256' in jws.get_algorithms() jws = PyJWS(algorithms=['HS256']) assert 'none' not in jws.get_algorithms() assert 'HS256' in jws.get_algorithms() def test_override_options(self): jws = PyJWS(options={'verify_signature': False}) assert not jws.options['verify_signature'] def test_non_object_options_dont_persist(self, jws, payload): token = jws.encode(payload, 'secret') jws.decode(token, 'secret', options={'verify_signature': False}) assert jws.options['verify_signature'] def test_options_must_be_dict(self, jws): pytest.raises(TypeError, PyJWS, options=object()) pytest.raises(TypeError, PyJWS, options=('something')) def test_encode_decode(self, jws, payload): secret = 'secret' jws_message = jws.encode(payload, secret) decoded_payload = jws.decode(jws_message, secret) assert decoded_payload == payload def test_decode_fails_when_alg_is_not_on_method_algorithms_param(self, jws, payload): secret = 'secret' jws_token = jws.encode(payload, secret, algorithm='HS256') jws.decode(jws_token, secret) with pytest.raises(InvalidAlgorithmError): jws.decode(jws_token, secret, algorithms=['HS384']) def test_decode_works_with_unicode_token(self, jws): secret = 'secret' unicode_jws = text_type( 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9' '.eyJoZWxsbyI6ICJ3b3JsZCJ9' '.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8') jws.decode(unicode_jws, secret) def test_decode_missing_segments_throws_exception(self, jws): secret = 'secret' example_jws = ('eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9' '.eyJoZWxsbyI6ICJ3b3JsZCJ9' '') # Missing segment with pytest.raises(DecodeError) as context: jws.decode(example_jws, secret) exception = context.value assert str(exception) == 'Not enough segments' def test_decode_with_non_mapping_header_throws_exception(self, jws): secret = 'secret' example_jws = ('MQ' # == 1 '.eyJoZWxsbyI6ICJ3b3JsZCJ9' '.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8') with pytest.raises(DecodeError) as context: jws.decode(example_jws, secret) exception = context.value assert str(exception) == 'Invalid header string: must be a json object' def test_encode_algorithm_param_should_be_case_sensitive(self, jws, payload): jws.encode(payload, 'secret', algorithm='HS256') with pytest.raises(NotImplementedError) as context: jws.encode(payload, None, algorithm='hs256') exception = context.value assert str(exception) == 'Algorithm not supported' def test_decode_algorithm_param_should_be_case_sensitive(self, jws): example_jws = ('eyJhbGciOiJoczI1NiIsInR5cCI6IkpXVCJ9' # alg = hs256 '.eyJoZWxsbyI6IndvcmxkIn0' '.5R_FEPE7SW2dT9GgIxPgZATjFGXfUDOSwo7TtO_Kd_g') with pytest.raises(InvalidAlgorithmError) as context: jws.decode(example_jws, 'secret') exception = context.value assert str(exception) == 'Algorithm not supported' def test_bad_secret(self, jws, payload): right_secret = 'foo' bad_secret = 'bar' jws_message = jws.encode(payload, right_secret) with pytest.raises(DecodeError): jws.decode(jws_message, bad_secret) def test_decodes_valid_jws(self, jws, payload): example_secret = 'secret' example_jws = ( b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.' b'aGVsbG8gd29ybGQ.' b'gEW0pdU4kxPthjtehYdhxB9mMOGajt1xCKlGGXDJ8PM') decoded_payload = jws.decode(example_jws, example_secret) assert decoded_payload == payload # 'Control' Elliptic Curve jws created by another library. # Used to test for regressions that could affect both # encoding / decoding operations equally (causing tests # to still pass). @pytest.mark.skipif(not has_crypto, reason="Can't run without cryptography library") def test_decodes_valid_es384_jws(self, jws): example_payload = {'hello': 'world'} with open('tests/keys/testkey_ec.pub', 'r') as fp: example_pubkey = fp.read() example_jws = ( b'eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9' b'.eyJoZWxsbyI6IndvcmxkIn0' b'.AGtlemKghaIaYh1yeeekFH9fRuNY7hCaw5hUgZ5aG1N' b'2F8FIbiKLaZKr8SiFdTimXFVTEmxpBQ9sRmdsDsnrM-1' b'HAG0_zxxu0JyINOFT2iqF3URYl9HZ8kZWMeZAtXmn6Cw' b'PXRJD2f7N-f7bJ5JeL9VT5beI2XD3FlK3GgRvI-eE-2Ik') decoded_payload = jws.decode(example_jws, example_pubkey) json_payload = json.loads(ensure_unicode(decoded_payload)) assert json_payload == example_payload # 'Control' RSA jws created by another library. # Used to test for regressions that could affect both # encoding / decoding operations equally (causing tests # to still pass). @pytest.mark.skipif(not has_crypto, reason="Can't run without cryptography library") def test_decodes_valid_rs384_jws(self, jws): example_payload = {'hello': 'world'} with open('tests/keys/testkey_rsa.pub', 'r') as fp: example_pubkey = fp.read() example_jws = ( b'eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9' b'.eyJoZWxsbyI6IndvcmxkIn0' b'.yNQ3nI9vEDs7lEh-Cp81McPuiQ4ZRv6FL4evTYYAh1X' b'lRTTR3Cz8pPA9Stgso8Ra9xGB4X3rlra1c8Jz10nTUju' b'O06OMm7oXdrnxp1KIiAJDerWHkQ7l3dlizIk1bmMA457' b'W2fNzNfHViuED5ISM081dgf_a71qBwJ_yShMMrSOfxDx' b'mX9c4DjRogRJG8SM5PvpLqI_Cm9iQPGMvmYK7gzcq2cJ' b'urHRJDJHTqIdpLWXkY7zVikeen6FhuGyn060Dz9gYq9t' b'uwmrtSWCBUjiN8sqJ00CDgycxKqHfUndZbEAOjcCAhBr' b'qWW3mSVivUfubsYbwUdUG3fSRPjaUPcpe8A') decoded_payload = jws.decode(example_jws, example_pubkey) json_payload = json.loads(ensure_unicode(decoded_payload)) assert json_payload == example_payload def test_load_verify_valid_jws(self, jws, payload): example_secret = 'secret' example_jws = ( b'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.' b'aGVsbG8gd29ybGQ.' b'SIr03zM64awWRdPrAM_61QWsZchAtgDV3pphfHPPWkI' ) decoded_payload = jws.decode(example_jws, key=example_secret) assert decoded_payload == payload def test_allow_skip_verification(self, jws, payload): right_secret = 'foo' jws_message = jws.encode(payload, right_secret) decoded_payload = jws.decode(jws_message, verify=False) assert decoded_payload == payload def test_verify_false_deprecated(self, jws, recwarn): example_jws = ( b'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9' b'.eyJoZWxsbyI6ICJ3b3JsZCJ9' b'.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8') pytest.deprecated_call(jws.decode, example_jws, verify=False) def test_load_no_verification(self, jws, payload): right_secret = 'foo' jws_message = jws.encode(payload, right_secret) decoded_payload = jws.decode(jws_message, key=None, verify=False) assert decoded_payload == payload def test_no_secret(self, jws, payload): right_secret = 'foo' jws_message = jws.encode(payload, right_secret) with pytest.raises(DecodeError): jws.decode(jws_message) def test_verify_signature_with_no_secret(self, jws, payload): right_secret = 'foo' jws_message = jws.encode(payload, right_secret) with pytest.raises(DecodeError) as exc: jws.decode(jws_message) assert 'Signature verification' in str(exc.value) def test_invalid_crypto_alg(self, jws, payload): with pytest.raises(NotImplementedError): jws.encode(payload, 'secret', algorithm='HS1024') def test_unicode_secret(self, jws, payload): secret = '\xc2' jws_message = jws.encode(payload, secret) decoded_payload = jws.decode(jws_message, secret) assert decoded_payload == payload def test_nonascii_secret(self, jws, payload): secret = '\xc2' # char value that ascii codec cannot decode jws_message = jws.encode(payload, secret) decoded_payload = jws.decode(jws_message, secret) assert decoded_payload == payload def test_bytes_secret(self, jws, payload): secret = b'\xc2' # char value that ascii codec cannot decode jws_message = jws.encode(payload, secret) decoded_payload = jws.decode(jws_message, secret) assert decoded_payload == payload def test_decode_invalid_header_padding(self, jws): example_jws = ( 'aeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9' '.eyJoZWxsbyI6ICJ3b3JsZCJ9' '.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8') example_secret = 'secret' with pytest.raises(DecodeError) as exc: jws.decode(example_jws, example_secret) assert 'header padding' in str(exc.value) def test_decode_invalid_header_string(self, jws): example_jws = ( 'eyJhbGciOiAiSFMyNTbpIiwgInR5cCI6ICJKV1QifQ==' '.eyJoZWxsbyI6ICJ3b3JsZCJ9' '.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8') example_secret = 'secret' with pytest.raises(DecodeError) as exc: jws.decode(example_jws, example_secret) assert 'Invalid header' in str(exc.value) def test_decode_invalid_payload_padding(self, jws): example_jws = ( 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9' '.aeyJoZWxsbyI6ICJ3b3JsZCJ9' '.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8') example_secret = 'secret' with pytest.raises(DecodeError) as exc: jws.decode(example_jws, example_secret) assert 'Invalid payload padding' in str(exc.value) def test_decode_invalid_crypto_padding(self, jws): example_jws = ( 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9' '.eyJoZWxsbyI6ICJ3b3JsZCJ9' '.aatvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8') example_secret = 'secret' with pytest.raises(DecodeError) as exc: jws.decode(example_jws, example_secret) assert 'Invalid crypto padding' in str(exc.value) def test_decode_with_algo_none_should_fail(self, jws, payload): jws_message = jws.encode(payload, key=None, algorithm=None) with pytest.raises(DecodeError): jws.decode(jws_message) def test_decode_with_algo_none_and_verify_false_should_pass(self, jws, payload): jws_message = jws.encode(payload, key=None, algorithm=None) jws.decode(jws_message, verify=False) def test_get_unverified_header_returns_header_values(self, jws, payload): jws_message = jws.encode(payload, key='secret', algorithm='HS256', headers={'kid': 123}) header = jws.get_unverified_header(jws_message) assert 'kid' in header assert header['kid'] == 123 @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_encode_decode_with_rsa_sha256(self, jws, payload): # PEM-formatted RSA key with open('tests/keys/testkey_rsa', 'r') as rsa_priv_file: priv_rsakey = load_pem_private_key(ensure_bytes(rsa_priv_file.read()), password=None, backend=default_backend()) jws_message = jws.encode(payload, priv_rsakey, algorithm='RS256') with open('tests/keys/testkey_rsa.pub', 'r') as rsa_pub_file: pub_rsakey = load_ssh_public_key(ensure_bytes(rsa_pub_file.read()), backend=default_backend()) jws.decode(jws_message, pub_rsakey) # string-formatted key with open('tests/keys/testkey_rsa', 'r') as rsa_priv_file: priv_rsakey = rsa_priv_file.read() jws_message = jws.encode(payload, priv_rsakey, algorithm='RS256') with open('tests/keys/testkey_rsa.pub', 'r') as rsa_pub_file: pub_rsakey = rsa_pub_file.read() jws.decode(jws_message, pub_rsakey) @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_encode_decode_with_rsa_sha384(self, jws, payload): # PEM-formatted RSA key with open('tests/keys/testkey_rsa', 'r') as rsa_priv_file: priv_rsakey = load_pem_private_key(ensure_bytes(rsa_priv_file.read()), password=None, backend=default_backend()) jws_message = jws.encode(payload, priv_rsakey, algorithm='RS384') with open('tests/keys/testkey_rsa.pub', 'r') as rsa_pub_file: pub_rsakey = load_ssh_public_key(ensure_bytes(rsa_pub_file.read()), backend=default_backend()) jws.decode(jws_message, pub_rsakey) # string-formatted key with open('tests/keys/testkey_rsa', 'r') as rsa_priv_file: priv_rsakey = rsa_priv_file.read() jws_message = jws.encode(payload, priv_rsakey, algorithm='RS384') with open('tests/keys/testkey_rsa.pub', 'r') as rsa_pub_file: pub_rsakey = rsa_pub_file.read() jws.decode(jws_message, pub_rsakey) @pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library') def test_encode_decode_with_rsa_sha512(self, jws, payload): # PEM-formatted RSA key with open('tests/keys/testkey_rsa', 'r') as rsa_priv_file: priv_rsakey = load_pem_private_key(ensure_bytes(rsa_priv_file.read()), password=None, backend=default_backend()) jws_message = jws.encode(payload, priv_rsakey, algorithm='RS512') with open('tests/keys/testkey_rsa.pub', 'r') as rsa_pub_file: pub_rsakey = load_ssh_public_key(ensure_bytes(rsa_pub_file.read()), backend=default_backend()) jws.decode(jws_message, pub_rsakey) # string-formatted key with open('tests/keys/testkey_rsa', 'r') as rsa_priv_file: priv_rsakey = rsa_priv_file.read() jws_message = jws.encode(payload, priv_rsakey, algorithm='RS512') with open('tests/keys/testkey_rsa.pub', 'r') as rsa_pub_file: pub_rsakey = rsa_pub_file.read() jws.decode(jws_message, pub_rsakey) def test_rsa_related_algorithms(self, jws): jws = PyJWS() jws_algorithms = jws.get_algorithms() if has_crypto: assert 'RS256' in jws_algorithms assert 'RS384' in jws_algorithms assert 'RS512' in jws_algorithms assert 'PS256' in jws_algorithms assert 'PS384' in jws_algorithms assert 'PS512' in jws_algorithms else: assert 'RS256' not in jws_algorithms assert 'RS384' not in jws_algorithms assert 'RS512' not in jws_algorithms assert 'PS256' not in jws_algorithms assert 'PS384' not in jws_algorithms assert 'PS512' not in jws_algorithms @pytest.mark.skipif(not has_crypto, reason="Can't run without cryptography library") def test_encode_decode_with_ecdsa_sha256(self, jws, payload): # PEM-formatted EC key with open('tests/keys/testkey_ec', 'r') as ec_priv_file: priv_eckey = load_pem_private_key(ensure_bytes(ec_priv_file.read()), password=None, backend=default_backend()) jws_message = jws.encode(payload, priv_eckey, algorithm='ES256') with open('tests/keys/testkey_ec.pub', 'r') as ec_pub_file: pub_eckey = load_pem_public_key(ensure_bytes(ec_pub_file.read()), backend=default_backend()) jws.decode(jws_message, pub_eckey) # string-formatted key with open('tests/keys/testkey_ec', 'r') as ec_priv_file: priv_eckey = ec_priv_file.read() jws_message = jws.encode(payload, priv_eckey, algorithm='ES256') with open('tests/keys/testkey_ec.pub', 'r') as ec_pub_file: pub_eckey = ec_pub_file.read() jws.decode(jws_message, pub_eckey) @pytest.mark.skipif(not has_crypto, reason="Can't run without cryptography library") def test_encode_decode_with_ecdsa_sha384(self, jws, payload): # PEM-formatted EC key with open('tests/keys/testkey_ec', 'r') as ec_priv_file: priv_eckey = load_pem_private_key(ensure_bytes(ec_priv_file.read()), password=None, backend=default_backend()) jws_message = jws.encode(payload, priv_eckey, algorithm='ES384') with open('tests/keys/testkey_ec.pub', 'r') as ec_pub_file: pub_eckey = load_pem_public_key(ensure_bytes(ec_pub_file.read()), backend=default_backend()) jws.decode(jws_message, pub_eckey) # string-formatted key with open('tests/keys/testkey_ec', 'r') as ec_priv_file: priv_eckey = ec_priv_file.read() jws_message = jws.encode(payload, priv_eckey, algorithm='ES384') with open('tests/keys/testkey_ec.pub', 'r') as ec_pub_file: pub_eckey = ec_pub_file.read() jws.decode(jws_message, pub_eckey) @pytest.mark.skipif(not has_crypto, reason="Can't run without cryptography library") def test_encode_decode_with_ecdsa_sha512(self, jws, payload): # PEM-formatted EC key with open('tests/keys/testkey_ec', 'r') as ec_priv_file: priv_eckey = load_pem_private_key(ensure_bytes(ec_priv_file.read()), password=None, backend=default_backend()) jws_message = jws.encode(payload, priv_eckey, algorithm='ES512') with open('tests/keys/testkey_ec.pub', 'r') as ec_pub_file: pub_eckey = load_pem_public_key(ensure_bytes(ec_pub_file.read()), backend=default_backend()) jws.decode(jws_message, pub_eckey) # string-formatted key with open('tests/keys/testkey_ec', 'r') as ec_priv_file: priv_eckey = ec_priv_file.read() jws_message = jws.encode(payload, priv_eckey, algorithm='ES512') with open('tests/keys/testkey_ec.pub', 'r') as ec_pub_file: pub_eckey = ec_pub_file.read() jws.decode(jws_message, pub_eckey) def test_ecdsa_related_algorithms(self, jws): jws = PyJWS() jws_algorithms = jws.get_algorithms() if has_crypto: assert 'ES256' in jws_algorithms assert 'ES384' in jws_algorithms assert 'ES512' in jws_algorithms else: assert 'ES256' not in jws_algorithms assert 'ES384' not in jws_algorithms assert 'ES512' not in jws_algorithms def test_skip_check_signature(self, jws): token = ("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" ".eyJzb21lIjoicGF5bG9hZCJ9" ".4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZA") jws.decode(token, 'secret', options={'verify_signature': False}) def test_decode_options_must_be_dict(self, jws, payload): token = jws.encode(payload, 'secret') with pytest.raises(TypeError): jws.decode(token, 'secret', options=object()) with pytest.raises(TypeError): jws.decode(token, 'secret', options='something') def test_custom_json_encoder(self, jws, payload): class CustomJSONEncoder(json.JSONEncoder): def default(self, o): if isinstance(o, Decimal): return 'it worked' return super(CustomJSONEncoder, self).default(o) data = { 'some_decimal': Decimal('2.2') } with pytest.raises(TypeError): jws.encode(payload, 'secret', headers=data) token = jws.encode(payload, 'secret', headers=data, json_encoder=CustomJSONEncoder) header = ensure_bytes(ensure_unicode(token).split('.')[0]) header = json.loads(ensure_unicode(base64url_decode(header))) assert 'some_decimal' in header assert header['some_decimal'] == 'it worked' def test_encode_headers_parameter_adds_headers(self, jws, payload): headers = {'testheader': True} token = jws.encode(payload, 'secret', headers=headers) if not isinstance(token, string_types): token = token.decode() header = token[0:token.index('.')].encode() header = base64url_decode(header) if not isinstance(header, text_type): header = header.decode() header_obj = json.loads(header) assert 'testheader' in header_obj assert header_obj['testheader'] == headers['testheader'] PyJWT-1.3.0/tests/test_api_jwt.py0000644000076500000240000003620612527650137017622 0ustar jpadillastaff00000000000000 import json import time from calendar import timegm from datetime import datetime, timedelta from decimal import Decimal from jwt.api_jwt import PyJWT from jwt.exceptions import ( DecodeError, ExpiredSignatureError, ImmatureSignatureError, InvalidAudienceError, InvalidIssuedAtError, InvalidIssuerError ) import pytest from .test_api_jws import has_crypto from .utils import utc_timestamp @pytest.fixture def jwt(): return PyJWT() @pytest.fixture def payload(): """ Creates a sample JWT claimset for use as a payload during tests """ return { 'iss': 'jeff', 'exp': utc_timestamp() + 15, 'claim': 'insanity' } class TestJWT: def test_decodes_valid_jwt(self, jwt): example_payload = {'hello': 'world'} example_secret = 'secret' example_jwt = ( b'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9' b'.eyJoZWxsbyI6ICJ3b3JsZCJ9' b'.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8') decoded_payload = jwt.decode(example_jwt, example_secret) assert decoded_payload == example_payload def test_load_verify_valid_jwt(self, jwt): example_payload = {'hello': 'world'} example_secret = 'secret' example_jwt = ( b'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9' b'.eyJoZWxsbyI6ICJ3b3JsZCJ9' b'.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8') decoded_payload = jwt.decode(example_jwt, key=example_secret) assert decoded_payload == example_payload def test_decode_invalid_payload_string(self, jwt): example_jwt = ( 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.aGVsb' 'G8gd29ybGQ.SIr03zM64awWRdPrAM_61QWsZchAtgDV' '3pphfHPPWkI') example_secret = 'secret' with pytest.raises(DecodeError) as exc: jwt.decode(example_jwt, example_secret) assert 'Invalid payload string' in str(exc.value) def test_decode_with_non_mapping_payload_throws_exception(self, jwt): secret = 'secret' example_jwt = ('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.' 'MQ.' # == 1 'AbcSR3DWum91KOgfKxUHm78rLs_DrrZ1CrDgpUFFzls') with pytest.raises(DecodeError) as context: jwt.decode(example_jwt, secret) exception = context.value assert str(exception) == 'Invalid payload string: must be a json object' def test_decode_with_invalid_audience_param_throws_exception(self, jwt): secret = 'secret' example_jwt = ('eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9' '.eyJoZWxsbyI6ICJ3b3JsZCJ9' '.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8') with pytest.raises(TypeError) as context: jwt.decode(example_jwt, secret, audience=1) exception = context.value assert str(exception) == 'audience must be a string or None' def test_decode_with_nonlist_aud_claim_throws_exception(self, jwt): secret = 'secret' example_jwt = ('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9' '.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjoxfQ' # aud = 1 '.Rof08LBSwbm8Z_bhA2N3DFY-utZR1Gi9rbIS5Zthnnc') with pytest.raises(InvalidAudienceError) as context: jwt.decode(example_jwt, secret, audience='my_audience') exception = context.value assert str(exception) == 'Invalid claim format in token' def test_decode_with_invalid_aud_list_member_throws_exception(self, jwt): secret = 'secret' example_jwt = ('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9' '.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjpbMV19' '.iQgKpJ8shetwNMIosNXWBPFB057c2BHs-8t1d2CCM2A') with pytest.raises(InvalidAudienceError) as context: jwt.decode(example_jwt, secret, audience='my_audience') exception = context.value assert str(exception) == 'Invalid claim format in token' def test_encode_bad_type(self, jwt): types = ['string', tuple(), list(), 42, set()] for t in types: pytest.raises(TypeError, lambda: jwt.encode(t, 'secret')) def test_decode_raises_exception_if_exp_is_not_int(self, jwt): # >>> jwt.encode({'exp': 'not-an-int'}, 'secret') example_jwt = ('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.' 'eyJleHAiOiJub3QtYW4taW50In0.' 'P65iYgoHtBqB07PMtBSuKNUEIPPPfmjfJG217cEE66s') with pytest.raises(DecodeError) as exc: jwt.decode(example_jwt, 'secret') assert 'exp' in str(exc.value) def test_decode_raises_exception_if_iat_is_not_int(self, jwt): # >>> jwt.encode({'iat': 'not-an-int'}, 'secret') example_jwt = ('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.' 'eyJpYXQiOiJub3QtYW4taW50In0.' 'H1GmcQgSySa5LOKYbzGm--b1OmRbHFkyk8pq811FzZM') with pytest.raises(DecodeError): jwt.decode(example_jwt, 'secret') def test_decode_raises_exception_if_nbf_is_not_int(self, jwt): # >>> jwt.encode({'nbf': 'not-an-int'}, 'secret') example_jwt = ('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.' 'eyJuYmYiOiJub3QtYW4taW50In0.' 'c25hldC8G2ZamC8uKpax9sYMTgdZo3cxrmzFHaAAluw') with pytest.raises(DecodeError): jwt.decode(example_jwt, 'secret') def test_decode_raises_exception_if_iat_in_the_future(self, jwt): now = datetime.utcnow() token = jwt.encode({'iat': now + timedelta(days=1)}, key='secret') with pytest.raises(InvalidIssuedAtError): jwt.decode(token, 'secret') def test_encode_datetime(self, jwt): secret = 'secret' current_datetime = datetime.utcnow() payload = { 'exp': current_datetime, 'iat': current_datetime, 'nbf': current_datetime } jwt_message = jwt.encode(payload, secret) decoded_payload = jwt.decode(jwt_message, secret, leeway=1) assert (decoded_payload['exp'] == timegm(current_datetime.utctimetuple())) assert (decoded_payload['iat'] == timegm(current_datetime.utctimetuple())) assert (decoded_payload['nbf'] == timegm(current_datetime.utctimetuple())) # 'Control' Elliptic Curve JWT created by another library. # Used to test for regressions that could affect both # encoding / decoding operations equally (causing tests # to still pass). @pytest.mark.skipif(not has_crypto, reason="Can't run without cryptography library") def test_decodes_valid_es384_jwt(self, jwt): example_payload = {'hello': 'world'} with open('tests/keys/testkey_ec.pub', 'r') as fp: example_pubkey = fp.read() example_jwt = ( b'eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9' b'.eyJoZWxsbyI6IndvcmxkIn0' b'.AddMgkmRhzqptDYqlmy_f2dzM6O9YZmVo-txs_CeAJD' b'NoD8LN7YiPeLmtIhkO5_VZeHHKvtQcGc4lsq-Y72c4dK' b'pANr1f6HEYhjpBc03u_bv06PYMcr5N2-9k97-qf-JCSb' b'zqW6R250Q7gNCX5R7NrCl7MTM4DTBZkGbUlqsFUleiGlj') decoded_payload = jwt.decode(example_jwt, example_pubkey) assert decoded_payload == example_payload # 'Control' RSA JWT created by another library. # Used to test for regressions that could affect both # encoding / decoding operations equally (causing tests # to still pass). @pytest.mark.skipif(not has_crypto, reason="Can't run without cryptography library") def test_decodes_valid_rs384_jwt(self, jwt): example_payload = {'hello': 'world'} with open('tests/keys/testkey_rsa.pub', 'r') as fp: example_pubkey = fp.read() example_jwt = ( b'eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9' b'.eyJoZWxsbyI6IndvcmxkIn0' b'.yNQ3nI9vEDs7lEh-Cp81McPuiQ4ZRv6FL4evTYYAh1X' b'lRTTR3Cz8pPA9Stgso8Ra9xGB4X3rlra1c8Jz10nTUju' b'O06OMm7oXdrnxp1KIiAJDerWHkQ7l3dlizIk1bmMA457' b'W2fNzNfHViuED5ISM081dgf_a71qBwJ_yShMMrSOfxDx' b'mX9c4DjRogRJG8SM5PvpLqI_Cm9iQPGMvmYK7gzcq2cJ' b'urHRJDJHTqIdpLWXkY7zVikeen6FhuGyn060Dz9gYq9t' b'uwmrtSWCBUjiN8sqJ00CDgycxKqHfUndZbEAOjcCAhBr' b'qWW3mSVivUfubsYbwUdUG3fSRPjaUPcpe8A') decoded_payload = jwt.decode(example_jwt, example_pubkey) assert decoded_payload == example_payload def test_decode_with_expiration(self, jwt, payload): payload['exp'] = utc_timestamp() - 1 secret = 'secret' jwt_message = jwt.encode(payload, secret) with pytest.raises(ExpiredSignatureError): jwt.decode(jwt_message, secret) def test_decode_with_notbefore(self, jwt, payload): payload['nbf'] = utc_timestamp() + 10 secret = 'secret' jwt_message = jwt.encode(payload, secret) with pytest.raises(ImmatureSignatureError): jwt.decode(jwt_message, secret) def test_decode_skip_expiration_verification(self, jwt, payload): payload['exp'] = time.time() - 1 secret = 'secret' jwt_message = jwt.encode(payload, secret) jwt.decode(jwt_message, secret, options={'verify_exp': False}) def test_decode_skip_notbefore_verification(self, jwt, payload): payload['nbf'] = time.time() + 10 secret = 'secret' jwt_message = jwt.encode(payload, secret) jwt.decode(jwt_message, secret, options={'verify_nbf': False}) def test_decode_with_expiration_with_leeway(self, jwt, payload): payload['exp'] = utc_timestamp() - 2 secret = 'secret' jwt_message = jwt.encode(payload, secret) decoded_payload, signing, header, signature = jwt._load(jwt_message) # With 3 seconds leeway, should be ok for leeway in (3, timedelta(seconds=3)): jwt.decode(jwt_message, secret, leeway=leeway) # With 1 seconds, should fail for leeway in (1, timedelta(seconds=1)): with pytest.raises(ExpiredSignatureError): jwt.decode(jwt_message, secret, leeway=leeway) def test_decode_with_notbefore_with_leeway(self, jwt, payload): payload['nbf'] = utc_timestamp() + 10 secret = 'secret' jwt_message = jwt.encode(payload, secret) # With 13 seconds leeway, should be ok jwt.decode(jwt_message, secret, leeway=13) with pytest.raises(ImmatureSignatureError): jwt.decode(jwt_message, secret, leeway=1) def test_check_audience_when_valid(self, jwt): payload = { 'some': 'payload', 'aud': 'urn:me' } token = jwt.encode(payload, 'secret') jwt.decode(token, 'secret', audience='urn:me') def test_check_audience_in_array_when_valid(self, jwt): payload = { 'some': 'payload', 'aud': ['urn:me', 'urn:someone-else'] } token = jwt.encode(payload, 'secret') jwt.decode(token, 'secret', audience='urn:me') def test_raise_exception_invalid_audience(self, jwt): payload = { 'some': 'payload', 'aud': 'urn:someone-else' } token = jwt.encode(payload, 'secret') with pytest.raises(InvalidAudienceError): jwt.decode(token, 'secret', audience='urn-me') def test_raise_exception_invalid_audience_in_array(self, jwt): payload = { 'some': 'payload', 'aud': ['urn:someone', 'urn:someone-else'] } token = jwt.encode(payload, 'secret') with pytest.raises(InvalidAudienceError): jwt.decode(token, 'secret', audience='urn:me') def test_raise_exception_token_without_audience(self, jwt): payload = { 'some': 'payload', } token = jwt.encode(payload, 'secret') with pytest.raises(InvalidAudienceError): jwt.decode(token, 'secret', audience='urn:me') def test_check_issuer_when_valid(self, jwt): issuer = 'urn:foo' payload = { 'some': 'payload', 'iss': 'urn:foo' } token = jwt.encode(payload, 'secret') jwt.decode(token, 'secret', issuer=issuer) def test_raise_exception_invalid_issuer(self, jwt): issuer = 'urn:wrong' payload = { 'some': 'payload', 'iss': 'urn:foo' } token = jwt.encode(payload, 'secret') with pytest.raises(InvalidIssuerError): jwt.decode(token, 'secret', issuer=issuer) def test_raise_exception_token_without_issuer(self, jwt): issuer = 'urn:wrong' payload = { 'some': 'payload', } token = jwt.encode(payload, 'secret') with pytest.raises(InvalidIssuerError): jwt.decode(token, 'secret', issuer=issuer) 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_skip_check_signature(self, jwt): token = ("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" ".eyJzb21lIjoicGF5bG9hZCJ9" ".4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZA") jwt.decode(token, 'secret', options={'verify_signature': False}) def test_skip_check_iat(self, jwt): payload = { 'some': 'payload', 'iat': datetime.utcnow() + timedelta(days=1) } token = jwt.encode(payload, 'secret') jwt.decode(token, 'secret', options={'verify_iat': False}) def test_skip_check_nbf(self, jwt): payload = { 'some': 'payload', 'nbf': datetime.utcnow() + timedelta(days=1) } token = jwt.encode(payload, 'secret') jwt.decode(token, 'secret', options={'verify_nbf': False}) def test_custom_json_encoder(self, jwt): class CustomJSONEncoder(json.JSONEncoder): def default(self, o): if isinstance(o, Decimal): return 'it worked' return super(CustomJSONEncoder, self).default(o) data = { 'some_decimal': Decimal('2.2') } with pytest.raises(TypeError): jwt.encode(data, 'secret') token = jwt.encode(data, 'secret', json_encoder=CustomJSONEncoder) payload = jwt.decode(token, 'secret') assert payload == {'some_decimal': 'it worked'} def test_decode_with_verify_expiration_kwarg(self, jwt, payload): payload['exp'] = utc_timestamp() - 1 secret = 'secret' jwt_message = jwt.encode(payload, secret) pytest.deprecated_call( jwt.decode, jwt_message, secret, verify_expiration=False ) with pytest.raises(ExpiredSignatureError): pytest.deprecated_call( jwt.decode, jwt_message, secret, verify_expiration=True ) PyJWT-1.3.0/tests/test_compat.py0000644000076500000240000000116212517223733017436 0ustar jpadillastaff00000000000000from jwt.compat import constant_time_compare from .utils import ensure_bytes class TestCompat: def test_constant_time_compare_returns_true_if_same(self): assert constant_time_compare( ensure_bytes('abc'), ensure_bytes('abc') ) def test_constant_time_compare_returns_false_if_diff_lengths(self): assert not constant_time_compare( ensure_bytes('abc'), ensure_bytes('abcd') ) def test_constant_time_compare_returns_false_if_totally_different(self): assert not constant_time_compare( ensure_bytes('abcd'), ensure_bytes('efgh') ) PyJWT-1.3.0/tests/test_jwt.py0000644000076500000240000000114612517223733016761 0ustar jpadillastaff00000000000000import jwt from .utils import utc_timestamp def test_encode_decode(): """ This test exists primarily to ensure that calls to jwt.encode and jwt.decode don't explode. Most functionality is tested by the PyJWT class tests. This is primarily a sanity check to make sure we don't break the public global functions. """ payload = { 'iss': 'jeff', 'exp': utc_timestamp() + 15, 'claim': 'insanity' } secret = 'secret' jwt_message = jwt.encode(payload, secret) decoded_payload = jwt.decode(jwt_message, secret) assert decoded_payload == payload PyJWT-1.3.0/tests/test_jwt.pyc0000644000076500000240000007040512457345251017133 0ustar jpadillastaff00000000000000 ȽTc@skddlZddlZddlZddlmZddlmZmZddlmZddl Z ddl m Z m ZmZejddfkrddlZn ddlZejdd d fkreZny6dd lmZdd lmZmZmZeZWnek r"eZnXd Z d Z!dej"fdYZ#e$dkrgej%ndS(iN(ttimegm(tdatetimet timedelta(tDecimal(tloadtverify_signaturet _algorithmsiiii(tdefault_backend(tload_pem_private_keytload_pem_public_keytload_ssh_public_keycCsttjjS(N(RRtutcnowt utctimetuple(((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyt utc_timestamp$scCs%t|tr!|jd}n|S(Nsutf-8(t isinstancetunicodetencode(tkey((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyt ensure_bytes(stTestJWTcBsYeZdZdZdZdZdZdZdZe j e ddZ e j e dd Z d Zd Zd Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ dZ!dZ"dZ#d Z$e j e d!d"Z%e j e d!d#Z&e j e d!d$Z'd%Z(e j e dd&Z)e j e dd'Z*e j e dd(Z+d)Z,d*Z-d+Z.d,Z/d-Z0d.Z1d/Z2d0Z3d1Z4d2Z5RS(3cCs)idd6tdd6dd6|_dS(Ntjefftissitexptinsanitytclaim(R tpayload(tself((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pytsetUp1scCs*|jttjdiWdQXdS(NtAAA123(t assertRaisest TypeErrortjwttregister_algorithm(R((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyt1test_register_algorithm_rejects_non_algorithm_obj5scCsDd}tj|j|}tj||}|j||jdS(Ntsecret(RRRtdecodet assertEqual(RR"t jwt_messagetdecoded_payload((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_encode_decode9scsLdttdtg}x'|D]|jtfdq%WdS(Ntstringi*cstjdS(NR"(RR((tt(s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pytEs(ttupletlisttsetRR(Rttypes((R)s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_encode_bad_type@s cCsd}tj}i|d6|d6|d6}tj||}tj||dd}|j|dt|j|j|dt|j|j|dt|jdS(NR"Rtiattnbftleewayi(RR RRR#R$RR (RR"tcurrent_datetimeRR%R&((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_encode_datetimeGs"  csDd}dtj|j||jtjfddS(NtfootbarcstjS(N(RR#((t bad_secretR%(s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyR*cs(RRRRt DecodeError(Rt right_secret((R7R%s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_bad_secret\s cCs?idd6}d}d}tj||}|j||dS(NtworldthelloR"smeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8(RR#R$(Rtexample_payloadtexample_secrett example_jwtR&((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_decodes_valid_jwtes  s&Can't run without cryptography librarycCs]idd6}tdd}|j}WdQXd}tj||}|j||dS(NR;R<stests/testkey_ec.pubtrseyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6IndvcmxkIn0.MIGHAkEdh2kR7IRu5w0tGuY6Xz3Vqa7PHHY2DgXWeeeLXotEqpn9udp2NfVL-XFG0TDoCakzXbIGAWg42S69GFlKZzxhXAJCAPLPuJoKyAixFnXPBkvkti-UzSIj4s6DePeuTu7102G_QIXiijY5bx6mdmZa3xUuKeu-zobOIOqR8ZwFqGjBLZum(topentreadRR#R$(RR=tfptexample_pubkeyR?R&((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_decodes_valid_es384_jwtts  cCs]idd6}tdd}|j}WdQXd}tj||}|j||dS(NR;R<stests/testkey_rsa.pubRAseyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6IndvcmxkIn0.yNQ3nI9vEDs7lEh-Cp81McPuiQ4ZRv6FL4evTYYAh1XlRTTR3Cz8pPA9Stgso8Ra9xGB4X3rlra1c8Jz10nTUjuO06OMm7oXdrnxp1KIiAJDerWHkQ7l3dlizIk1bmMA457W2fNzNfHViuED5ISM081dgf_a71qBwJ_yShMMrSOfxDxmX9c4DjRogRJG8SM5PvpLqI_Cm9iQPGMvmYK7gzcq2cJurHRJDJHTqIdpLWXkY7zVikeen6FhuGyn060Dz9gYq9tuwmrtSWCBUjiN8sqJ00CDgycxKqHfUndZbEAOjcCAhBrqWW3mSVivUfubsYbwUdUG3fSRPjaUPcpe8A(RBRCRR#R$(RR=RDRER?R&((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_decodes_valid_rs384_jwts   cCs[idd6}d}d}t|\}}}}t||||||j||dS(NR;R<R"smeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8(tjwt_loadtjwt_verify_signatureR$(RR=R>R?R&tsigningtheadert signature((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_load_verify_valid_jwts   cCsGd}tj|j|}tj|dt}|j||jdS(NR5tverify(RRRR#tFalseR$(RR9R%R&((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_allow_skip_verificationscCsJd}tj|j|}t|\}}}}|j||jdS(NR5(RRRRHR$(RR9R%R&RJRKRL((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_load_no_verificationscs;d}tj|j||jtjfddS(NR5cs tjS(N(RR#((R%(s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyR*s(RRRRR8(RR9((R%s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_no_secrets cs\d}tj|j|}t|\|jtjfddS(NR5cstS(N(RI((R&RKRLRJ(s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyR*s (RRRRHRR8(RR9R%((R&RKRLRJs9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_verify_signature_no_secrets c Csd}idd6dd6}tj|j|d|}t|\}}}}x.|jD] \}} |j||| qZWdS(NR5R6ttesttkidtheaders(RRRRHtitemsR$( RR9RVR%R&RJRKRLRtvalue((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_custom_headerss cCs#|jttj|jdddS(NR"tHS1024(RtNotImplementedErrorRRR(R((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_invalid_crypto_algscCsd}tj|j|}tj||}|j||jt|\}}}}t||||||j||jdS(Ns(RRRR#R$RHRI(RR"R%R&RJRKRL((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_unicode_secrets  cCsd}tj|j|}tj||}|j||jt|\}}}}t||||||j||jdS(Ns(RRRR#R$RHRI(RR"R%R&RJRKRL((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_nonascii_secrets  cCsd}tj|j|}tj||}|j||jt|\}}}}t||||||j||jdS(Ns(RRRR#R$RHRI(RR"R%R&RJRKRL((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_bytes_secrets  cCsgidd6}d}d}tj||}|j||t|\}}}}|j||dS(NR;R<R"smeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8(RR#R$RH(RR=R>R?R&RJRKRL((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyttest_decode_unicode_values csKdd|jtjfd|jtjfddS(NsnaeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8R"cs tS(N(RH((R?(s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyR*scstjS(N(RR#((R?R>(s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyR* s(RRR8(R((R?R>s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyt"test_decode_invalid_header_paddingscCsd}d}yt|Wn/tjk rK}|jdt|knX|jdytj||Wn/tjk r}|jdt|knX|jddS(NsqeyJhbGciOiAiSFMyNTbpIiwgInR5cCI6ICJKV1QifQ==.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8R"sInvalid header stringsDecodeError not raised(RHRR8t assertTruetstrtfailR#(RR?R>te((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyt!test_decode_invalid_header_string"s csKdd|jtjfd|jtjfddS(NsneyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.aeyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8R"cs tS(N(RH((R?(s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyR*@scstjS(N(RR#((R?R>(s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyR*Ds(RRR8(R((R?R>s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyt#test_decode_invalid_payload_padding7scCsd}d}yt|Wn/tjk rK}|jdt|knX|jdytj||Wn/tjk r}|jdt|knX|jddS(NsqeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsb-kiOiAid29ybGQifQ==.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8R"sInvalid payload stringsDecodeError not raised(RHRR8RbRcRdR#(RR?R>Re((s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyt"test_decode_invalid_payload_stringFs csKdd|jtjfd|jtjfddS(NsoeyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.aatvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8R"cs tS(N(RH((R?(s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyR*dscstjS(N(RR#((R?R>(s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyR*hs(RRR8(R((R?R>s9/Users/jpadilla/Projects/Personal/pyjwt/tests/test_jwt.pyt"test_decode_invalid_crypto_padding[scstd|jds2            PyJWT-1.3.0/tests/utils.py0000644000076500000240000000203512527650137016257 0ustar jpadillastaff00000000000000import os import struct from calendar import timegm from datetime import datetime from .compat import text_type def ensure_bytes(key): if isinstance(key, text_type): key = key.encode('utf-8') return key def ensure_unicode(key): if not isinstance(key, text_type): key = key.decode() return key def utc_timestamp(): return timegm(datetime.utcnow().utctimetuple()) def key_path(key_name): return os.path.join(os.path.dirname(os.path.realpath(__file__)), 'keys', key_name) # Borrowed from `cryptography` if hasattr(int, "from_bytes"): int_from_bytes = int.from_bytes else: def int_from_bytes(data, byteorder, signed=False): assert byteorder == 'big' assert not signed if len(data) % 4 != 0: data = (b'\x00' * (4 - (len(data) % 4))) + data result = 0 while len(data) > 0: digit, = struct.unpack('>I', data[:4]) result = (result << 32) + digit data = data[4:] return result PyJWT-1.3.0/tests/utils.pyc0000644000076500000240000000236012517227064016421 0ustar jpadillastaff00000000000000 '=Uc@sdddlZddlmZddlmZddlmZdZdZdZd Z dS( iN(ttimegm(tdatetimei(t text_typecCs%t|tr!|jd}n|S(Nsutf-8(t isinstanceRtencode(tkey((s6/Users/jpadilla/Projects/Personal/pyjwt/tests/utils.pyt ensure_bytes scCs"t|ts|j}n|S(N(RRtdecode(R((s6/Users/jpadilla/Projects/Personal/pyjwt/tests/utils.pytensure_unicodescCsttjjS(N(RRtutcnowt utctimetuple(((s6/Users/jpadilla/Projects/Personal/pyjwt/tests/utils.pyt utc_timestampscCs.tjjtjjtjjtd|S(Ntkeys(tostpathtjointdirnametrealpatht__file__(tkey_name((s6/Users/jpadilla/Projects/Personal/pyjwt/tests/utils.pytkey_paths$( R tcalendarRRtcompatRRRR R(((s6/Users/jpadilla/Projects/Personal/pyjwt/tests/utils.pyts    PyJWT-1.3.0/tox.ini0000644000076500000240000000056312527650137014722 0ustar jpadillastaff00000000000000[tox] envlist = py{26,27,33,34}-crypto, py{27,34}-contrib_crypto, py{27,34}-nocrypto, flake8 [testenv] commands = python setup.py pytest deps = crypto: cryptography pytest pytest-cov pytest-runner contrib_crypto: pycrypto contrib_crypto: ecdsa [testenv:flake8] commands = flake8 deps = flake8 flake8-import-order pep8-naming