diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2024-04-12 12:45:55 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2024-04-12 13:42:15 +0300 |
commit | a592841bc0deb67c364dea234d7c5adbe0dadad5 (patch) | |
tree | 90a280604bae87f20b5007a185611c45040bdd17 /contrib | |
parent | dd11d72c358cf78610025a4d12ef888be70054bf (diff) | |
download | ydb-a592841bc0deb67c364dea234d7c5adbe0dadad5.tar.gz |
Intermediate changes
Diffstat (limited to 'contrib')
25 files changed, 38 insertions, 1881 deletions
diff --git a/contrib/python/PyJWT/py2/.dist-info/METADATA b/contrib/python/PyJWT/py2/.dist-info/METADATA deleted file mode 100644 index 47ee558907..0000000000 --- a/contrib/python/PyJWT/py2/.dist-info/METADATA +++ /dev/null @@ -1,115 +0,0 @@ -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 - - diff --git a/contrib/python/PyJWT/py2/.dist-info/entry_points.txt b/contrib/python/PyJWT/py2/.dist-info/entry_points.txt deleted file mode 100644 index 78717b2661..0000000000 --- a/contrib/python/PyJWT/py2/.dist-info/entry_points.txt +++ /dev/null @@ -1,3 +0,0 @@ -[console_scripts] -pyjwt = jwt.__main__:main - diff --git a/contrib/python/PyJWT/py2/.dist-info/top_level.txt b/contrib/python/PyJWT/py2/.dist-info/top_level.txt deleted file mode 100644 index 27ccc9bc3a..0000000000 --- a/contrib/python/PyJWT/py2/.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -jwt diff --git a/contrib/python/PyJWT/py2/jwt/__init__.py b/contrib/python/PyJWT/py2/jwt/__init__.py deleted file mode 100644 index 946983f022..0000000000 --- a/contrib/python/PyJWT/py2/jwt/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- 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, -) diff --git a/contrib/python/PyJWT/py2/jwt/__main__.py b/contrib/python/PyJWT/py2/jwt/__main__.py deleted file mode 100644 index bf50aabf4a..0000000000 --- a/contrib/python/PyJWT/py2/jwt/__main__.py +++ /dev/null @@ -1,168 +0,0 @@ -#!/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() diff --git a/contrib/python/PyJWT/py2/jwt/algorithms.py b/contrib/python/PyJWT/py2/jwt/algorithms.py deleted file mode 100644 index 1343688341..0000000000 --- a/contrib/python/PyJWT/py2/jwt/algorithms.py +++ /dev/null @@ -1,403 +0,0 @@ -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 diff --git a/contrib/python/PyJWT/py2/jwt/api_jws.py b/contrib/python/PyJWT/py2/jwt/api_jws.py deleted file mode 100644 index a9354adb06..0000000000 --- a/contrib/python/PyJWT/py2/jwt/api_jws.py +++ /dev/null @@ -1,242 +0,0 @@ -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 diff --git a/contrib/python/PyJWT/py2/jwt/api_jwt.py b/contrib/python/PyJWT/py2/jwt/api_jwt.py deleted file mode 100644 index 85504acf93..0000000000 --- a/contrib/python/PyJWT/py2/jwt/api_jwt.py +++ /dev/null @@ -1,222 +0,0 @@ -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 diff --git a/contrib/python/PyJWT/py2/jwt/compat.py b/contrib/python/PyJWT/py2/jwt/compat.py deleted file mode 100644 index e79e258e56..0000000000 --- a/contrib/python/PyJWT/py2/jwt/compat.py +++ /dev/null @@ -1,68 +0,0 @@ -""" -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) diff --git a/contrib/python/PyJWT/py2/jwt/contrib/__init__.py b/contrib/python/PyJWT/py2/jwt/contrib/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/contrib/python/PyJWT/py2/jwt/contrib/__init__.py +++ /dev/null diff --git a/contrib/python/PyJWT/py2/jwt/contrib/algorithms/__init__.py b/contrib/python/PyJWT/py2/jwt/contrib/algorithms/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/contrib/python/PyJWT/py2/jwt/contrib/algorithms/__init__.py +++ /dev/null diff --git a/contrib/python/PyJWT/py2/jwt/contrib/algorithms/py_ecdsa.py b/contrib/python/PyJWT/py2/jwt/contrib/algorithms/py_ecdsa.py deleted file mode 100644 index bf0dea5ae2..0000000000 --- a/contrib/python/PyJWT/py2/jwt/contrib/algorithms/py_ecdsa.py +++ /dev/null @@ -1,60 +0,0 @@ -# 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 diff --git a/contrib/python/PyJWT/py2/jwt/contrib/algorithms/pycrypto.py b/contrib/python/PyJWT/py2/jwt/contrib/algorithms/pycrypto.py deleted file mode 100644 index e49cdbfe40..0000000000 --- a/contrib/python/PyJWT/py2/jwt/contrib/algorithms/pycrypto.py +++ /dev/null @@ -1,46 +0,0 @@ -import 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) diff --git a/contrib/python/PyJWT/py2/jwt/exceptions.py b/contrib/python/PyJWT/py2/jwt/exceptions.py deleted file mode 100644 index 2a6aa596ba..0000000000 --- a/contrib/python/PyJWT/py2/jwt/exceptions.py +++ /dev/null @@ -1,59 +0,0 @@ -class PyJWTError(Exception): - """ - Base class for all exceptions - """ - pass - - -class InvalidTokenError(PyJWTError): - pass - - -class DecodeError(InvalidTokenError): - pass - - -class InvalidSignatureError(DecodeError): - pass - - -class ExpiredSignatureError(InvalidTokenError): - pass - - -class InvalidAudienceError(InvalidTokenError): - pass - - -class InvalidIssuerError(InvalidTokenError): - pass - - -class InvalidIssuedAtError(InvalidTokenError): - pass - - -class ImmatureSignatureError(InvalidTokenError): - pass - - -class InvalidKeyError(PyJWTError): - pass - - -class InvalidAlgorithmError(InvalidTokenError): - pass - - -class MissingRequiredClaimError(InvalidTokenError): - def __init__(self, claim): - self.claim = claim - - def __str__(self): - return 'Token is missing the "%s" claim' % self.claim - - -# Compatibility aliases (deprecated) -ExpiredSignature = ExpiredSignatureError -InvalidAudience = InvalidAudienceError -InvalidIssuer = InvalidIssuerError diff --git a/contrib/python/PyJWT/py2/jwt/help.py b/contrib/python/PyJWT/py2/jwt/help.py deleted file mode 100644 index 55e39ebb27..0000000000 --- a/contrib/python/PyJWT/py2/jwt/help.py +++ /dev/null @@ -1,61 +0,0 @@ -from __future__ import print_function - -import json -import platform -import sys - -from . import __version__ as pyjwt_version - -try: - import cryptography -except ImportError: - cryptography = None - -try: - import ecdsa -except ImportError: - ecdsa = None - - -def info(): - """ - Generate information for a bug report. - Based on the requests package help utility module. - """ - try: - platform_info = {"system": platform.system(), "release": platform.release()} - except IOError: - platform_info = {"system": "Unknown", "release": "Unknown"} - - implementation = platform.python_implementation() - - if implementation == "CPython": - implementation_version = platform.python_version() - elif implementation == "PyPy": - implementation_version = "%s.%s.%s" % ( - sys.pypy_version_info.major, - sys.pypy_version_info.minor, - sys.pypy_version_info.micro, - ) - if sys.pypy_version_info.releaselevel != "final": - implementation_version = "".join( - [implementation_version, sys.pypy_version_info.releaselevel] - ) - else: - implementation_version = "Unknown" - - return { - "platform": platform_info, - "implementation": {"name": implementation, "version": implementation_version}, - "cryptography": {"version": getattr(cryptography, "__version__", "")}, - "pyjwt": {"version": pyjwt_version}, - } - - -def main(): - """Pretty-print the bug information as JSON.""" - print(json.dumps(info(), sort_keys=True, indent=2)) - - -if __name__ == "__main__": - main() diff --git a/contrib/python/PyJWT/py2/jwt/utils.py b/contrib/python/PyJWT/py2/jwt/utils.py deleted file mode 100644 index b33c7a2d45..0000000000 --- a/contrib/python/PyJWT/py2/jwt/utils.py +++ /dev/null @@ -1,113 +0,0 @@ -import base64 -import binascii -import struct - -from .compat import binary_type, bytes_from_int, text_type - -try: - from cryptography.hazmat.primitives.asymmetric.utils import ( - decode_dss_signature, encode_dss_signature - ) -except ImportError: - pass - - -def force_unicode(value): - if isinstance(value, binary_type): - return value.decode('utf-8') - elif isinstance(value, text_type): - return value - else: - raise TypeError('Expected a string value') - - -def force_bytes(value): - if isinstance(value, text_type): - return value.encode('utf-8') - elif isinstance(value, binary_type): - return value - else: - raise TypeError('Expected a string value') - - -def base64url_decode(input): - if isinstance(input, text_type): - input = input.encode('ascii') - - 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 to_base64url_uint(val): - if val < 0: - raise ValueError('Must be a positive integer') - - int_bytes = bytes_from_int(val) - - if len(int_bytes) == 0: - int_bytes = b'\x00' - - return base64url_encode(int_bytes) - - -def from_base64url_uint(val): - if isinstance(val, text_type): - val = val.encode('ascii') - - data = base64url_decode(val) - - buf = struct.unpack('%sB' % len(data), data) - return int(''.join(["%02x" % byte for byte in buf]), 16) - - -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_dss_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_dss_signature(r, s) diff --git a/contrib/python/PyJWT/py2/ya.make b/contrib/python/PyJWT/py2/ya.make deleted file mode 100644 index 57a9352fba..0000000000 --- a/contrib/python/PyJWT/py2/ya.make +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by devtools/yamaker (pypi). - -PY2_LIBRARY() - -VERSION(1.7.1) - -LICENSE(MIT) - -PEERDIR( - contrib/python/cryptography -) - -NO_LINT() - -NO_CHECK_IMPORTS( - jwt.contrib.* -) - -PY_SRCS( - TOP_LEVEL - jwt/__init__.py - jwt/__main__.py - jwt/algorithms.py - jwt/api_jws.py - jwt/api_jwt.py - jwt/compat.py - jwt/contrib/__init__.py - jwt/contrib/algorithms/__init__.py - jwt/contrib/algorithms/py_ecdsa.py - jwt/contrib/algorithms/pycrypto.py - jwt/exceptions.py - jwt/help.py - jwt/utils.py -) - -RESOURCE_FILES( - PREFIX contrib/python/PyJWT/py2/ - .dist-info/METADATA - .dist-info/entry_points.txt - .dist-info/top_level.txt -) - -END() diff --git a/contrib/python/ydb/py3/.dist-info/METADATA b/contrib/python/ydb/py3/.dist-info/METADATA index d921ac7f1f..e7397b376d 100644 --- a/contrib/python/ydb/py3/.dist-info/METADATA +++ b/contrib/python/ydb/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: ydb -Version: 3.9.0 +Version: 3.10.0 Summary: YDB Python SDK Home-page: http://github.com/ydb-platform/ydb-python-sdk Author: Yandex LLC @@ -18,7 +18,6 @@ Requires-Dist: grpcio >=1.42.0 Requires-Dist: packaging Requires-Dist: protobuf <5.0.0,>=3.13.0 Requires-Dist: aiohttp <4 -Requires-Dist: pyjwt ==2.8.0 Provides-Extra: yc Requires-Dist: yandexcloud ; extra == 'yc' diff --git a/contrib/python/ydb/py3/ya.make b/contrib/python/ydb/py3/ya.make index b8611eae13..df4b531e51 100644 --- a/contrib/python/ydb/py3/ya.make +++ b/contrib/python/ydb/py3/ya.make @@ -2,12 +2,11 @@ PY3_LIBRARY() -VERSION(3.9.0) +VERSION(3.10.0) LICENSE(Apache-2.0) PEERDIR( - contrib/python/PyJWT contrib/python/aiohttp contrib/python/grpcio contrib/python/packaging diff --git a/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_sync.py b/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_sync.py index e5b4e1a2b4..c266de828e 100644 --- a/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_sync.py +++ b/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_sync.py @@ -76,11 +76,11 @@ class TopicReaderSync: def async_wait_message(self) -> concurrent.futures.Future: """ - Return future, which will completed when the reader has least one message in queue. - If reader already has message - future will return completed. + Returns a future, which will complete when the reader has at least one message in queue. + If the reader already has a message - the future will complete immediately. - Possible situation when receive signal about message available, but no messages when try to receive a message. - If message expired between send event and try to retrieve message (for example connection broken). + A message may expire before it gets read so that the attempt to receive the massage will fail + despite the future has signaled about its availability. """ self._check_closed() diff --git a/contrib/python/ydb/py3/ydb/aio/iam.py b/contrib/python/ydb/py3/ydb/aio/iam.py index 40622f8a9d..eab8faffe0 100644 --- a/contrib/python/ydb/py3/ydb/aio/iam.py +++ b/contrib/python/ydb/py3/ydb/aio/iam.py @@ -5,19 +5,15 @@ import abc import logging from ydb.iam import auth from .credentials import AbstractExpiringTokenCredentials -from ydb import issues logger = logging.getLogger(__name__) try: - import jwt -except ImportError: - jwt = None - -try: from yandex.cloud.iam.v1 import iam_token_service_pb2_grpc from yandex.cloud.iam.v1 import iam_token_service_pb2 + import jwt except ImportError: + jwt = None iam_token_service_pb2_grpc = None iam_token_service_pb2 = None @@ -59,51 +55,6 @@ class TokenServiceCredentials(AbstractExpiringTokenCredentials): IamTokenCredentials = TokenServiceCredentials -class OAuth2JwtTokenExchangeCredentials(AbstractExpiringTokenCredentials, auth.BaseJWTCredentials): - def __init__( - self, - token_exchange_url, - account_id, - access_key_id, - private_key, - algorithm, - token_service_url, - subject=None, - ): - super(OAuth2JwtTokenExchangeCredentials, self).__init__() - auth.BaseJWTCredentials.__init__( - self, account_id, access_key_id, private_key, algorithm, token_service_url, subject - ) - assert aiohttp is not None, "Install aiohttp library to use OAuth 2.0 token exchange credentials provider" - self._token_exchange_url = token_exchange_url - - async def _make_token_request(self): - params = { - "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", - "requested_token_type": "urn:ietf:params:oauth:token-type:access_token", - "subject_token": self._get_jwt(), - "subject_token_type": "urn:ietf:params:oauth:token-type:jwt", - } - headers = {"Content-Type": "application/x-www-form-urlencoded"} - - timeout = aiohttp.ClientTimeout(total=2) - async with aiohttp.ClientSession(timeout=timeout) as session: - async with session.post(self._token_exchange_url, data=params, headers=headers) as response: - if response.status == 403: - raise issues.Unauthenticated(await response.text()) - if response.status >= 500: - raise issues.Unavailable(await response.text()) - if response.status >= 400: - raise issues.BadRequest(await response.text()) - if response.status != 200: - raise issues.Error(await response.text()) - - response_json = await response.json() - access_token = response_json["access_token"] - expires_in = response_json["expires_in"] - return {"access_token": access_token, "expires_in": expires_in} - - class JWTIamCredentials(TokenServiceCredentials, auth.BaseJWTCredentials): def __init__( self, @@ -114,39 +65,16 @@ class JWTIamCredentials(TokenServiceCredentials, auth.BaseJWTCredentials): iam_channel_credentials=None, ): TokenServiceCredentials.__init__(self, iam_endpoint, iam_channel_credentials) - auth.BaseJWTCredentials.__init__( - self, - account_id, - access_key_id, - private_key, - auth.YANDEX_CLOUD_JWT_ALGORITHM, - auth.YANDEX_CLOUD_IAM_TOKEN_SERVICE_URL, - ) + auth.BaseJWTCredentials.__init__(self, account_id, access_key_id, private_key) def _get_token_request(self): - return iam_token_service_pb2.CreateIamTokenRequest(jwt=self._get_jwt()) - - -class NebiusJWTIamCredentials(OAuth2JwtTokenExchangeCredentials): - def __init__( - self, - account_id, - access_key_id, - private_key, - token_exchange_url=None, - ): - url = token_exchange_url - if url is None: - url = auth.NEBIUS_CLOUD_IAM_TOKEN_EXCHANGE_URL - OAuth2JwtTokenExchangeCredentials.__init__( - self, - url, - account_id, - access_key_id, - private_key, - auth.NEBIUS_CLOUD_JWT_ALGORITHM, - auth.NEBIUS_CLOUD_IAM_TOKEN_SERVICE_AUDIENCE, - account_id, + return iam_token_service_pb2.CreateIamTokenRequest( + jwt=auth.get_jwt( + self._account_id, + self._access_key_id, + self._private_key, + self._jwt_expiration_timeout, + ) ) @@ -202,20 +130,3 @@ class ServiceAccountCredentials(JWTIamCredentials): iam_endpoint, iam_channel_credentials, ) - - -class NebiusServiceAccountCredentials(NebiusJWTIamCredentials): - def __init__( - self, - service_account_id, - access_key_id, - private_key, - iam_endpoint=None, - iam_channel_credentials=None, - ): - super(NebiusServiceAccountCredentials, self).__init__( - service_account_id, - access_key_id, - private_key, - iam_endpoint, - ) diff --git a/contrib/python/ydb/py3/ydb/driver.py b/contrib/python/ydb/py3/ydb/driver.py index 16bba15154..89109b9b57 100644 --- a/contrib/python/ydb/py3/ydb/driver.py +++ b/contrib/python/ydb/py3/ydb/driver.py @@ -38,13 +38,6 @@ def credentials_from_env_variables(tracer=None): return ydb.iam.ServiceAccountCredentials.from_file(service_account_key_file) - nebius_service_account_key_file = os.getenv("YDB_NEBIUS_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS") - if nebius_service_account_key_file is not None: - ctx.trace({"credentials.nebius_service_account_key_file": True}) - import ydb.iam - - return ydb.iam.NebiusServiceAccountCredentials.from_file(nebius_service_account_key_file) - anonymous_credetials = os.getenv("YDB_ANONYMOUS_CREDENTIALS", "0") == "1" if anonymous_credetials: ctx.trace({"credentials.anonymous": True}) diff --git a/contrib/python/ydb/py3/ydb/iam/__init__.py b/contrib/python/ydb/py3/ydb/iam/__init__.py index cf835769db..7167efe13e 100644 --- a/contrib/python/ydb/py3/ydb/iam/__init__.py +++ b/contrib/python/ydb/py3/ydb/iam/__init__.py @@ -1,4 +1,3 @@ # -*- coding: utf-8 -*- from .auth import ServiceAccountCredentials # noqa -from .auth import NebiusServiceAccountCredentials # noqa from .auth import MetadataUrlCredentials # noqa diff --git a/contrib/python/ydb/py3/ydb/iam/auth.py b/contrib/python/ydb/py3/ydb/iam/auth.py index 852c0c28bb..82e7c9f6c8 100644 --- a/contrib/python/ydb/py3/ydb/iam/auth.py +++ b/contrib/python/ydb/py3/ydb/iam/auth.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from ydb import credentials, tracing, issues +from ydb import credentials, tracing import grpc import time import abc @@ -8,14 +8,11 @@ import json import os try: - import jwt -except ImportError: - jwt = None - -try: from yandex.cloud.iam.v1 import iam_token_service_pb2_grpc from yandex.cloud.iam.v1 import iam_token_service_pb2 + import jwt except ImportError: + jwt = None iam_token_service_pb2_grpc = None iam_token_service_pb2 = None @@ -26,32 +23,22 @@ except ImportError: DEFAULT_METADATA_URL = "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token" -YANDEX_CLOUD_IAM_TOKEN_SERVICE_URL = "https://iam.api.cloud.yandex.net/iam/v1/tokens" -NEBIUS_CLOUD_IAM_TOKEN_SERVICE_AUDIENCE = "token-service.iam.new.nebiuscloud.net" -NEBIUS_CLOUD_IAM_TOKEN_EXCHANGE_URL = "https://auth.new.nebiuscloud.net/oauth2/token/exchange" -YANDEX_CLOUD_JWT_ALGORITHM = "PS256" -NEBIUS_CLOUD_JWT_ALGORITHM = "RS256" - -def get_jwt(account_id, access_key_id, private_key, jwt_expiration_timeout, algorithm, token_service_url, subject=None): - assert jwt is not None, "Install pyjwt library to use jwt tokens" +def get_jwt(account_id, access_key_id, private_key, jwt_expiration_timeout): now = time.time() now_utc = datetime.utcfromtimestamp(now) exp_utc = datetime.utcfromtimestamp(now + jwt_expiration_timeout) - payload = { - "iss": account_id, - "aud": token_service_url, - "iat": now_utc, - "exp": exp_utc, - } - if subject is not None: - payload["sub"] = subject return jwt.encode( key=private_key, - algorithm=algorithm, - headers={"typ": "JWT", "alg": algorithm, "kid": access_key_id}, - payload=payload, + algorithm="PS256", + headers={"typ": "JWT", "alg": "PS256", "kid": access_key_id}, + payload={ + "iss": account_id, + "aud": "https://iam.api.cloud.yandex.net/iam/v1/tokens", + "iat": now_utc, + "exp": exp_utc, + }, ) @@ -86,15 +73,12 @@ class TokenServiceCredentials(credentials.AbstractExpiringTokenCredentials): class BaseJWTCredentials(abc.ABC): - def __init__(self, account_id, access_key_id, private_key, algorithm, token_service_url, subject=None): + def __init__(self, account_id, access_key_id, private_key): self._account_id = account_id self._jwt_expiration_timeout = 60.0 * 60 self._token_expiration_timeout = 120 self._access_key_id = access_key_id self._private_key = private_key - self._algorithm = algorithm - self._token_service_url = token_service_url - self._subject = subject def set_token_expiration_timeout(self, value): self._token_expiration_timeout = value @@ -115,64 +99,6 @@ class BaseJWTCredentials(abc.ABC): iam_channel_credentials=iam_channel_credentials, ) - def _get_jwt(self): - return get_jwt( - self._account_id, - self._access_key_id, - self._private_key, - self._jwt_expiration_timeout, - self._algorithm, - self._token_service_url, - self._subject, - ) - - -class OAuth2JwtTokenExchangeCredentials(credentials.AbstractExpiringTokenCredentials, BaseJWTCredentials): - def __init__( - self, - token_exchange_url, - account_id, - access_key_id, - private_key, - algorithm, - token_service_url, - subject=None, - tracer=None, - ): - BaseJWTCredentials.__init__(self, account_id, access_key_id, private_key, algorithm, token_service_url, subject) - super(OAuth2JwtTokenExchangeCredentials, self).__init__(tracer) - assert requests is not None, "Install requests library to use OAuth 2.0 token exchange credentials provider" - self._token_exchange_url = token_exchange_url - - def _process_response_status_code(self, response): - if response.status_code == 403: - raise issues.Unauthenticated(response.content) - if response.status_code >= 500: - raise issues.Unavailable(response.content) - if response.status_code >= 400: - raise issues.BadRequest(response.content) - if response.status_code != 200: - raise issues.Error(response.content) - - def _process_response(self, response): - self._process_response_status_code(response) - response_json = json.loads(response.content) - access_token = response_json["access_token"] - expires_in = response_json["expires_in"] - return {"access_token": access_token, "expires_in": expires_in} - - @tracing.with_trace() - def _make_token_request(self): - params = { - "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", - "requested_token_type": "urn:ietf:params:oauth:token-type:access_token", - "subject_token": self._get_jwt(), - "subject_token_type": "urn:ietf:params:oauth:token-type:jwt", - } - headers = {"Content-Type": "application/x-www-form-urlencoded"} - response = requests.post(self._token_exchange_url, data=params, headers=headers) - return self._process_response(response) - class JWTIamCredentials(TokenServiceCredentials, BaseJWTCredentials): def __init__( @@ -184,34 +110,16 @@ class JWTIamCredentials(TokenServiceCredentials, BaseJWTCredentials): iam_channel_credentials=None, ): TokenServiceCredentials.__init__(self, iam_endpoint, iam_channel_credentials) - BaseJWTCredentials.__init__( - self, account_id, access_key_id, private_key, YANDEX_CLOUD_JWT_ALGORITHM, YANDEX_CLOUD_IAM_TOKEN_SERVICE_URL - ) + BaseJWTCredentials.__init__(self, account_id, access_key_id, private_key) def _get_token_request(self): - return self._iam_token_service_pb2.CreateIamTokenRequest(jwt=self._get_jwt()) - - -class NebiusJWTIamCredentials(OAuth2JwtTokenExchangeCredentials): - def __init__( - self, - account_id, - access_key_id, - private_key, - token_exchange_url=None, - ): - url = token_exchange_url - if url is None: - url = NEBIUS_CLOUD_IAM_TOKEN_EXCHANGE_URL - OAuth2JwtTokenExchangeCredentials.__init__( - self, - url, - account_id, - access_key_id, - private_key, - NEBIUS_CLOUD_JWT_ALGORITHM, - NEBIUS_CLOUD_IAM_TOKEN_SERVICE_AUDIENCE, - account_id, + return self._iam_token_service_pb2.CreateIamTokenRequest( + jwt=get_jwt( + self._account_id, + self._access_key_id, + self._private_key, + self._jwt_expiration_timeout, + ) ) @@ -268,20 +176,3 @@ class ServiceAccountCredentials(JWTIamCredentials): iam_endpoint, iam_channel_credentials, ) - - -class NebiusServiceAccountCredentials(NebiusJWTIamCredentials): - def __init__( - self, - service_account_id, - access_key_id, - private_key, - iam_endpoint=None, - iam_channel_credentials=None, - ): - super(NebiusServiceAccountCredentials, self).__init__( - service_account_id, - access_key_id, - private_key, - iam_endpoint, - ) diff --git a/contrib/python/ydb/py3/ydb/ydb_version.py b/contrib/python/ydb/py3/ydb/ydb_version.py index 10baa2a41a..71960e35b5 100644 --- a/contrib/python/ydb/py3/ydb/ydb_version.py +++ b/contrib/python/ydb/py3/ydb/ydb_version.py @@ -1 +1 @@ -VERSION = "3.9.0" +VERSION = "3.10.0" |