Browse Source

YDB Import 603
733cd37277ee72b54fc223cbea2c1d141412ee3a

robot-ydb-importer 8 months ago
parent
commit
3cdeda6fa6

+ 115 - 0
contrib/python/PyJWT/py2/.dist-info/METADATA

@@ -0,0 +1,115 @@
+Metadata-Version: 2.1
+Name: PyJWT
+Version: 1.7.1
+Summary: JSON Web Token implementation in Python
+Home-page: http://github.com/jpadilla/pyjwt
+Author: Jose Padilla
+Author-email: hello@jpadilla.com
+License: MIT
+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.7
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Topic :: Utilities
+Provides-Extra: crypto
+Requires-Dist: cryptography (>=1.4) ; extra == 'crypto'
+Provides-Extra: flake8
+Requires-Dist: flake8 ; extra == 'flake8'
+Requires-Dist: flake8-import-order ; extra == 'flake8'
+Requires-Dist: pep8-naming ; extra == 'flake8'
+Provides-Extra: test
+Requires-Dist: pytest (<5.0.0,>=4.0.1) ; extra == 'test'
+Requires-Dist: pytest-cov (<3.0.0,>=2.6.0) ; extra == 'test'
+Requires-Dist: pytest-runner (<5.0.0,>=4.2) ; extra == 'test'
+
+PyJWT
+=====
+
+.. image:: https://travis-ci.com/jpadilla/pyjwt.svg?branch=master
+   :target: http://travis-ci.com/jpadilla/pyjwt?branch=master
+
+.. image:: https://ci.appveyor.com/api/projects/status/h8nt70aqtwhht39t?svg=true
+   :target: https://ci.appveyor.com/project/jpadilla/pyjwt
+
+.. image:: https://img.shields.io/pypi/v/pyjwt.svg
+   :target: https://pypi.python.org/pypi/pyjwt
+
+.. image:: https://coveralls.io/repos/jpadilla/pyjwt/badge.svg?branch=master
+   :target: https://coveralls.io/r/jpadilla/pyjwt?branch=master
+
+.. image:: https://readthedocs.org/projects/pyjwt/badge/?version=latest
+   :target: https://pyjwt.readthedocs.io
+
+A Python implementation of `RFC 7519 <https://tools.ietf.org/html/rfc7519>`_. Original implementation was written by `@progrium <https://github.com/progrium>`_.
+
+Sponsor
+-------
+
++--------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| |auth0-logo| | If you want to quickly add secure token-based authentication to Python projects, feel free to check Auth0's Python SDK and free plan at `auth0.com/overview <https://auth0.com/overview?utm_source=GHsponsor&utm_medium=GHsponsor&utm_campaign=pyjwt&utm_content=auth>`_. |
++--------------+-----------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+.. |auth0-logo| image:: https://user-images.githubusercontent.com/83319/31722733-de95bbde-b3ea-11e7-96bf-4f4e8f915588.png
+
+Installing
+----------
+
+Install with **pip**:
+
+.. code-block:: sh
+
+    $ pip install PyJWT
+
+
+Usage
+-----
+
+.. code:: python
+
+    >>> import jwt
+    >>> encoded = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256')
+    'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg'
+
+    >>> jwt.decode(encoded, 'secret', algorithms=['HS256'])
+    {'some': 'payload'}
+
+
+Command line
+------------
+
+Usage::
+
+    pyjwt [options] INPUT
+
+Decoding examples::
+
+    pyjwt --key=secret decode TOKEN
+    pyjwt decode --no-verify TOKEN
+
+See more options executing ``pyjwt --help``.
+
+
+Documentation
+-------------
+
+View the full docs online at https://pyjwt.readthedocs.io/en/latest/
+
+
+Tests
+-----
+
+You can run tests from the project root after cloning with:
+
+.. code-block:: sh
+
+    $ python setup.py test
+
+

+ 3 - 0
contrib/python/PyJWT/py2/.dist-info/entry_points.txt

@@ -0,0 +1,3 @@
+[console_scripts]
+pyjwt = jwt.__main__:main
+

+ 1 - 0
contrib/python/PyJWT/py2/.dist-info/top_level.txt

@@ -0,0 +1 @@
+jwt

+ 31 - 0
contrib/python/PyJWT/py2/jwt/__init__.py

@@ -0,0 +1,31 @@
+# -*- 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.7.1'
+__author__ = 'José Padilla'
+__license__ = 'MIT'
+__copyright__ = 'Copyright 2015-2018 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, InvalidAlgorithmError,
+    InvalidAudienceError, ExpiredSignatureError, ImmatureSignatureError,
+    InvalidIssuedAtError, InvalidIssuerError, ExpiredSignature,
+    InvalidAudience, InvalidIssuer, MissingRequiredClaimError,
+    InvalidSignatureError,
+    PyJWTError,
+)

+ 168 - 0
contrib/python/PyJWT/py2/jwt/__main__.py

@@ -0,0 +1,168 @@
+#!/usr/bin/env python
+
+from __future__ import absolute_import, print_function
+
+import argparse
+import json
+import sys
+import time
+
+from . import DecodeError, __version__, decode, encode
+
+
+def encode_payload(args):
+    # Try to encode
+    if args.key is None:
+        raise ValueError('Key is required when encoding. See --help for usage.')
+
+    # Build payload object to encode
+    payload = {}
+
+    for arg in args.payload:
+        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
+
+    token = encode(
+        payload,
+        key=args.key,
+        algorithm=args.algorithm
+    )
+
+    return token.decode('utf-8')
+
+
+def decode_payload(args):
+    try:
+        if args.token:
+            token = args.token
+        else:
+            if sys.stdin.isatty():
+                token = sys.stdin.readline().strip()
+            else:
+                raise IOError('Cannot read from stdin: terminal not a TTY')
+
+        token = token.encode('utf-8')
+        data = decode(token, key=args.key, verify=args.verify)
+
+        return json.dumps(data)
+
+    except DecodeError as e:
+        raise DecodeError('There was an error decoding the token: %s' % e)
+
+
+def build_argparser():
+
+    usage = '''
+    Encodes or decodes JSON Web Tokens based on input.
+
+    %(prog)s [options] <command> [options] input
+
+    Decoding examples:
+
+    %(prog)s --key=secret decode json.web.token
+    %(prog)s decode --no-verify json.web.token
+
+    Encoding requires the key option and takes space separated key/value pairs
+    separated by equals (=) as input. Examples:
+
+    %(prog)s --key=secret encode iss=me exp=1302049071
+    %(prog)s --key=secret encode foo=bar exp=+10
+
+    The exp key is special and can take an offset to current Unix time.
+    '''
+
+    arg_parser = argparse.ArgumentParser(
+        prog='pyjwt',
+        usage=usage
+    )
+
+    arg_parser.add_argument(
+        '-v', '--version',
+        action='version',
+        version='%(prog)s ' + __version__
+    )
+
+    arg_parser.add_argument(
+        '--key',
+        dest='key',
+        metavar='KEY',
+        default=None,
+        help='set the secret key to sign with'
+    )
+
+    arg_parser.add_argument(
+        '--alg',
+        dest='algorithm',
+        metavar='ALG',
+        default='HS256',
+        help='set crypto algorithm to sign with. default=HS256'
+    )
+
+    subparsers = arg_parser.add_subparsers(
+        title='PyJWT subcommands',
+        description='valid subcommands',
+        help='additional help'
+    )
+
+    # Encode subcommand
+    encode_parser = subparsers.add_parser('encode', help='use to encode a supplied payload')
+
+    payload_help = """Payload to encode. Must be a space separated list of key/value
+    pairs separated by equals (=) sign."""
+
+    encode_parser.add_argument('payload', nargs='+', help=payload_help)
+    encode_parser.set_defaults(func=encode_payload)
+
+    # Decode subcommand
+    decode_parser = subparsers.add_parser('decode', help='use to decode a supplied JSON web token')
+    decode_parser.add_argument(
+        'token',
+        help='JSON web token to decode.',
+        nargs='?')
+
+    decode_parser.add_argument(
+        '-n', '--no-verify',
+        action='store_false',
+        dest='verify',
+        default=True,
+        help='ignore signature and claims verification on decode'
+    )
+
+    decode_parser.set_defaults(func=decode_payload)
+
+    return arg_parser
+
+
+def main():
+    arg_parser = build_argparser()
+
+    try:
+        arguments = arg_parser.parse_args(sys.argv[1:])
+
+        output = arguments.func(arguments)
+
+        print(output)
+    except Exception as e:
+        print('There was an unforseen error: ', e)
+        arg_parser.print_help()

+ 403 - 0
contrib/python/PyJWT/py2/jwt/algorithms.py

@@ -0,0 +1,403 @@
+import hashlib
+import hmac
+import json
+
+
+from .compat import constant_time_compare, string_types
+from .exceptions import InvalidKeyError
+from .utils import (
+    base64url_decode, base64url_encode, der_to_raw_signature,
+    force_bytes, force_unicode, from_base64url_uint, raw_to_der_signature,
+    to_base64url_uint
+)
+
+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, RSAPrivateNumbers, RSAPublicNumbers,
+        rsa_recover_prime_factors, rsa_crt_dmp1, rsa_crt_dmq1, rsa_crt_iqmp
+    )
+    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
+
+requires_cryptography = set(['RS256', 'RS384', 'RS512', 'ES256', 'ES384',
+                             'ES521', 'ES512', 'PS256', 'PS384', 'PS512'])
+
+
+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),
+            'ES521': ECAlgorithm(ECAlgorithm.SHA512),
+            'ES512': ECAlgorithm(ECAlgorithm.SHA512),  # Backward compat for #219 fix
+            '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
+
+    @staticmethod
+    def to_jwk(key_obj):
+        """
+        Serializes a given RSA key into a JWK
+        """
+        raise NotImplementedError
+
+    @staticmethod
+    def from_jwk(jwk):
+        """
+        Deserializes a given RSA key from JWK back into a PublicKey or PrivateKey object
+        """
+        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):
+        key = force_bytes(key)
+
+        invalid_strings = [
+            b'-----BEGIN PUBLIC KEY-----',
+            b'-----BEGIN CERTIFICATE-----',
+            b'-----BEGIN RSA PUBLIC KEY-----',
+            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
+
+    @staticmethod
+    def to_jwk(key_obj):
+        return json.dumps({
+            'k': force_unicode(base64url_encode(force_bytes(key_obj))),
+            'kty': 'oct'
+        })
+
+    @staticmethod
+    def from_jwk(jwk):
+        obj = json.loads(jwk)
+
+        if obj.get('kty') != 'oct':
+            raise InvalidKeyError('Not an HMAC key')
+
+        return base64url_decode(obj['k'])
+
+    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):
+                key = force_bytes(key)
+
+                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
+
+        @staticmethod
+        def to_jwk(key_obj):
+            obj = None
+
+            if getattr(key_obj, 'private_numbers', None):
+                # Private key
+                numbers = key_obj.private_numbers()
+
+                obj = {
+                    'kty': 'RSA',
+                    'key_ops': ['sign'],
+                    'n': force_unicode(to_base64url_uint(numbers.public_numbers.n)),
+                    'e': force_unicode(to_base64url_uint(numbers.public_numbers.e)),
+                    'd': force_unicode(to_base64url_uint(numbers.d)),
+                    'p': force_unicode(to_base64url_uint(numbers.p)),
+                    'q': force_unicode(to_base64url_uint(numbers.q)),
+                    'dp': force_unicode(to_base64url_uint(numbers.dmp1)),
+                    'dq': force_unicode(to_base64url_uint(numbers.dmq1)),
+                    'qi': force_unicode(to_base64url_uint(numbers.iqmp))
+                }
+
+            elif getattr(key_obj, 'verify', None):
+                # Public key
+                numbers = key_obj.public_numbers()
+
+                obj = {
+                    'kty': 'RSA',
+                    'key_ops': ['verify'],
+                    'n': force_unicode(to_base64url_uint(numbers.n)),
+                    'e': force_unicode(to_base64url_uint(numbers.e))
+                }
+            else:
+                raise InvalidKeyError('Not a public or private key')
+
+            return json.dumps(obj)
+
+        @staticmethod
+        def from_jwk(jwk):
+            try:
+                obj = json.loads(jwk)
+            except ValueError:
+                raise InvalidKeyError('Key is not valid JSON')
+
+            if obj.get('kty') != 'RSA':
+                raise InvalidKeyError('Not an RSA key')
+
+            if 'd' in obj and 'e' in obj and 'n' in obj:
+                # Private key
+                if 'oth' in obj:
+                    raise InvalidKeyError('Unsupported RSA private key: > 2 primes not supported')
+
+                other_props = ['p', 'q', 'dp', 'dq', 'qi']
+                props_found = [prop in obj for prop in other_props]
+                any_props_found = any(props_found)
+
+                if any_props_found and not all(props_found):
+                    raise InvalidKeyError('RSA key must include all parameters if any are present besides d')
+
+                public_numbers = RSAPublicNumbers(
+                    from_base64url_uint(obj['e']), from_base64url_uint(obj['n'])
+                )
+
+                if any_props_found:
+                    numbers = RSAPrivateNumbers(
+                        d=from_base64url_uint(obj['d']),
+                        p=from_base64url_uint(obj['p']),
+                        q=from_base64url_uint(obj['q']),
+                        dmp1=from_base64url_uint(obj['dp']),
+                        dmq1=from_base64url_uint(obj['dq']),
+                        iqmp=from_base64url_uint(obj['qi']),
+                        public_numbers=public_numbers
+                    )
+                else:
+                    d = from_base64url_uint(obj['d'])
+                    p, q = rsa_recover_prime_factors(
+                        public_numbers.n, d, public_numbers.e
+                    )
+
+                    numbers = RSAPrivateNumbers(
+                        d=d,
+                        p=p,
+                        q=q,
+                        dmp1=rsa_crt_dmp1(d, p),
+                        dmq1=rsa_crt_dmq1(d, q),
+                        iqmp=rsa_crt_iqmp(p, q),
+                        public_numbers=public_numbers
+                    )
+
+                return numbers.private_key(default_backend())
+            elif 'n' in obj and 'e' in obj:
+                # Public key
+                numbers = RSAPublicNumbers(
+                    from_base64url_uint(obj['e']), from_base64url_uint(obj['n'])
+                )
+
+                return numbers.public_key(default_backend())
+            else:
+                raise InvalidKeyError('Not a public or private key')
+
+        def sign(self, msg, key):
+            return key.sign(msg, padding.PKCS1v15(), self.hash_alg())
+
+        def verify(self, msg, key, sig):
+            try:
+                key.verify(sig, msg, padding.PKCS1v15(), self.hash_alg())
+                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):
+                key = force_bytes(key)
+
+                # 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:
+                    if key.startswith(b'ecdsa-sha2-'):
+                        key = load_ssh_public_key(key, backend=default_backend())
+                    else:
+                        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):
+            der_sig = key.sign(msg, ec.ECDSA(self.hash_alg()))
+
+            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
+
+            try:
+                key.verify(der_sig, msg, ec.ECDSA(self.hash_alg()))
+                return True
+            except InvalidSignature:
+                return False
+
+    class RSAPSSAlgorithm(RSAAlgorithm):
+        """
+        Performs a signature using RSASSA-PSS with MGF1
+        """
+
+        def sign(self, msg, key):
+            return key.sign(
+                msg,
+                padding.PSS(
+                    mgf=padding.MGF1(self.hash_alg()),
+                    salt_length=self.hash_alg.digest_size
+                ),
+                self.hash_alg()
+            )
+
+        def verify(self, msg, key, sig):
+            try:
+                key.verify(
+                    sig,
+                    msg,
+                    padding.PSS(
+                        mgf=padding.MGF1(self.hash_alg()),
+                        salt_length=self.hash_alg.digest_size
+                    ),
+                    self.hash_alg()
+                )
+                return True
+            except InvalidSignature:
+                return False

+ 242 - 0
contrib/python/PyJWT/py2/jwt/api_jws.py

@@ -0,0 +1,242 @@
+import binascii
+import json
+import warnings
+try:
+    # import required by mypy to perform type checking, not used for normal execution
+    from typing import Callable, Dict, List, Optional, Union # NOQA
+except ImportError:
+    pass
+
+from .algorithms import (
+    Algorithm, get_default_algorithms, has_crypto, requires_cryptography  # NOQA
+)
+from .compat import Mapping, binary_type, string_types, text_type
+from .exceptions import (
+    DecodeError, InvalidAlgorithmError, InvalidSignatureError,
+    InvalidTokenError
+)
+from .utils import base64url_decode, base64url_encode, force_bytes, 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,  # type: Union[Dict, bytes]
+               key,  # type: str
+               algorithm='HS256',  # type: str
+               headers=None,  # type: Optional[Dict]
+               json_encoder=None  # type: Optional[Callable]
+               ):
+        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:
+            self._validate_headers(headers)
+            header.update(headers)
+
+        json_header = force_bytes(
+            json.dumps(
+                header,
+                separators=(',', ':'),
+                cls=json_encoder
+            )
+        )
+
+        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:
+            if not has_crypto and algorithm in requires_cryptography:
+                raise NotImplementedError(
+                    "Algorithm '%s' could not be found. Do you have cryptography "
+                    "installed?" % algorithm
+                )
+            else:
+                raise NotImplementedError('Algorithm not supported')
+
+        segments.append(base64url_encode(signature))
+
+        return b'.'.join(segments)
+
+    def decode(self,
+               jwt,  # type: str
+               key='',   # type: str
+               verify=True,  # type: bool
+               algorithms=None,  # type: List[str]
+               options=None,  # type: Dict
+               **kwargs):
+
+        merged_options = merge_dict(self.options, options)
+        verify_signature = merged_options['verify_signature']
+
+        if verify_signature and not algorithms:
+            warnings.warn(
+                'It is strongly recommended that you pass in a ' +
+                'value for the "algorithms" argument when calling decode(). ' +
+                'This argument will be mandatory in a future version.',
+                DeprecationWarning
+            )
+
+        payload, signing_input, header, signature = self._load(jwt)
+
+        if not verify:
+            warnings.warn('The verify parameter is deprecated. '
+                          'Please use verify_signature in options instead.',
+                          DeprecationWarning, stacklevel=2)
+        elif verify_signature:
+            self._verify_signature(payload, signing_input, header, signature,
+                                   key, algorithms)
+
+        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
+        """
+        headers = self._load(jwt)[2]
+        self._validate_headers(headers)
+
+        return headers
+
+    def _load(self, jwt):
+        if isinstance(jwt, text_type):
+            jwt = jwt.encode('utf-8')
+
+        if not issubclass(type(jwt), binary_type):
+            raise DecodeError("Invalid token type. Token must be a {0}".format(
+                binary_type))
+
+        try:
+            signing_input, crypto_segment = jwt.rsplit(b'.', 1)
+            header_segment, payload_segment = signing_input.split(b'.', 1)
+        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.get('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 InvalidSignatureError('Signature verification failed')
+
+        except KeyError:
+            raise InvalidAlgorithmError('Algorithm not supported')
+
+    def _validate_headers(self, headers):
+        if 'kid' in headers:
+            self._validate_kid(headers['kid'])
+
+    def _validate_kid(self, kid):
+        if not isinstance(kid, string_types):
+            raise InvalidTokenError('Key ID header parameter must be a string')
+
+
+_jws_global_obj = PyJWS()
+encode = _jws_global_obj.encode
+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

+ 222 - 0
contrib/python/PyJWT/py2/jwt/api_jwt.py

@@ -0,0 +1,222 @@
+import json
+import warnings
+from calendar import timegm
+from datetime import datetime, timedelta
+try:
+    # import required by mypy to perform type checking, not used for normal execution
+    from typing import Callable, Dict, List, Optional, Union # NOQA
+except ImportError:
+    pass
+
+from .api_jws import PyJWS
+from .algorithms import Algorithm, get_default_algorithms  # NOQA
+from .compat import Iterable, Mapping, string_types
+from .exceptions import (
+    DecodeError, ExpiredSignatureError, ImmatureSignatureError,
+    InvalidAudienceError, InvalidIssuedAtError,
+    InvalidIssuerError, MissingRequiredClaimError
+)
+from .utils import merge_dict
+
+
+class PyJWT(PyJWS):
+    header_type = 'JWT'
+
+    @staticmethod
+    def _get_default_options():
+        # type: () -> Dict[str, bool]
+        return {
+            'verify_signature': True,
+            'verify_exp': True,
+            'verify_nbf': True,
+            'verify_iat': True,
+            'verify_aud': True,
+            'verify_iss': True,
+            'require_exp': False,
+            'require_iat': False,
+            'require_nbf': False
+        }
+
+    def encode(self,
+               payload,  # type: Union[Dict, bytes]
+               key,  # type: str
+               algorithm='HS256',  # type: str
+               headers=None,  # type: Optional[Dict]
+               json_encoder=None  # type: Optional[Callable]
+               ):
+        # 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())  # type: ignore
+
+        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,  # type: str
+               key='',   # type: str
+               verify=True,  # type: bool
+               algorithms=None,  # type: List[str]
+               options=None,  # type: Dict
+               **kwargs):
+
+        if verify and not algorithms:
+            warnings.warn(
+                'It is strongly recommended that you pass in a ' +
+                'value for the "algorithms" argument when calling decode(). ' +
+                'This argument will be mandatory in a future version.',
+                DeprecationWarning
+            )
+
+        payload, _, _, _ = self._load(jwt)
+
+        if options is None:
+            options = {'verify_signature': verify}
+        else:
+            options.setdefault('verify_signature', verify)
+
+        decoded = super(PyJWT, self).decode(
+            jwt, key=key, algorithms=algorithms, options=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 verify_exp in options instead.',
+                          DeprecationWarning)
+
+        if isinstance(leeway, timedelta):
+            leeway = leeway.total_seconds()
+
+        if not isinstance(audience, (string_types, type(None), Iterable)):
+            raise TypeError('audience must be a string, iterable, or None')
+
+        self._validate_required_claims(payload, options)
+
+        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_required_claims(self, payload, options):
+        if options.get('require_exp') and payload.get('exp') is None:
+            raise MissingRequiredClaimError('exp')
+
+        if options.get('require_iat') and payload.get('iat') is None:
+            raise MissingRequiredClaimError('iat')
+
+        if options.get('require_nbf') and payload.get('nbf') is None:
+            raise MissingRequiredClaimError('nbf')
+
+    def _validate_iat(self, payload, now, leeway):
+        try:
+            int(payload['iat'])
+        except ValueError:
+            raise InvalidIssuedAtError('Issued At claim (iat) must be an integer.')
+
+    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 MissingRequiredClaimError('aud')
+
+        if audience is None and 'aud' in payload:
+            # Application did not specify an audience, but
+            # the token has the 'aud' claim
+            raise InvalidAudienceError('Invalid audience')
+
+        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 isinstance(audience, string_types):
+            audience = [audience]
+
+        if not any(aud in audience_claims for aud in audience):
+            raise InvalidAudienceError('Invalid audience')
+
+    def _validate_iss(self, payload, issuer):
+        if issuer is None:
+            return
+
+        if 'iss' not in payload:
+            raise MissingRequiredClaimError('iss')
+
+        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

+ 68 - 0
contrib/python/PyJWT/py2/jwt/compat.py

@@ -0,0 +1,68 @@
+"""
+The `compat` module provides support for backwards compatibility with older
+versions of python, and compatibility wrappers around optional packages.
+"""
+# flake8: noqa
+import hmac
+import struct
+import sys
+
+
+PY3 = sys.version_info[0] == 3
+
+
+if PY3:
+    text_type = str
+    binary_type = bytes
+else:
+    text_type = unicode
+    binary_type = str
+
+string_types = (text_type, binary_type)
+
+try:
+    # Importing ABCs from collections will be removed in PY3.8
+    from collections.abc import Iterable, Mapping
+except ImportError:
+    from collections import Iterable, Mapping
+
+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
+
+# Use int.to_bytes if it exists (Python 3)
+if getattr(int, 'to_bytes', None):
+    def bytes_from_int(val):
+        remaining = val
+        byte_length = 0
+
+        while remaining != 0:
+            remaining = remaining >> 8
+            byte_length += 1
+
+        return val.to_bytes(byte_length, 'big', signed=False)
+else:
+    def bytes_from_int(val):
+        buf = []
+        while val:
+            val, remainder = divmod(val, 256)
+            buf.append(remainder)
+
+        buf.reverse()
+        return struct.pack('%sB' % len(buf), *buf)

+ 0 - 0
contrib/python/PyJWT/py2/jwt/contrib/__init__.py


Some files were not shown because too many files changed in this diff