Hello community, here is the log from the commit of package python-flask-jwt-extended for openSUSE:Factory checked in at 2019-08-13 13:27:12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-flask-jwt-extended (Old) and /work/SRC/openSUSE:Factory/.python-flask-jwt-extended.new.9556 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-flask-jwt-extended" Tue Aug 13 13:27:12 2019 rev:3 rq:722843 version:3.21.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-flask-jwt-extended/python-flask-jwt-extended.changes 2019-07-24 20:34:55.342578120 +0200 +++ /work/SRC/openSUSE:Factory/.python-flask-jwt-extended.new.9556/python-flask-jwt-extended.changes 2019-08-13 13:27:15.217323820 +0200 @@ -1,0 +2,9 @@ +Mon Aug 12 15:45:57 UTC 2019 - Tomáš Chvátal <tchva...@suse.com> + +- Update to 3.21.0: + * Require flask 1.0 or greater (#263) + * Move docs to pallets-sphinx-themes (#261) + * Add a new JWT_DECODE_ISSUER option for use with other JWT providers (#259) + * Gracefully handle errors for malformed tokens (#246) + +------------------------------------------------------------------- Old: ---- Flask-JWT-Extended-3.20.0.tar.gz New: ---- Flask-JWT-Extended-3.21.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-flask-jwt-extended.spec ++++++ --- /var/tmp/diff_new_pack.ng7oMd/_old 2019-08-13 13:27:15.873323647 +0200 +++ /var/tmp/diff_new_pack.ng7oMd/_new 2019-08-13 13:27:15.873323647 +0200 @@ -17,13 +17,13 @@ Name: python-flask-jwt-extended -Version: 3.20.0 +Version: 3.21.0 Release: 0 Summary: An open source Flask extension that provides JWT support License: MIT Group: Development/Languages/Python URL: https://github.com/vimalloc/flask-jwt-extended -Source: https://files.pythonhosted.org/packages/source/f/flask-jwt-extended/Flask-JWT-Extended-%{version}.tar.gz +Source: https://files.pythonhosted.org/packages/source/F/Flask-JWT-Extended/Flask-JWT-Extended-%{version}.tar.gz BuildRequires: %{python_module Flask >= 1.0} BuildRequires: %{python_module PyJWT >= 1.6.4} BuildRequires: %{python_module Werkzeug >= 0.14} ++++++ Flask-JWT-Extended-3.20.0.tar.gz -> Flask-JWT-Extended-3.21.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.20.0/Flask_JWT_Extended.egg-info/PKG-INFO new/Flask-JWT-Extended-3.21.0/Flask_JWT_Extended.egg-info/PKG-INFO --- old/Flask-JWT-Extended-3.20.0/Flask_JWT_Extended.egg-info/PKG-INFO 2019-07-03 17:26:49.000000000 +0200 +++ new/Flask-JWT-Extended-3.21.0/Flask_JWT_Extended.egg-info/PKG-INFO 2019-08-03 17:50:24.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: Flask-JWT-Extended -Version: 3.20.0 +Version: 3.21.0 Summary: Extended JWT integration with Flask Home-page: https://github.com/vimalloc/flask-jwt-extended Author: Landon Gilbert-Bland diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.20.0/Flask_JWT_Extended.egg-info/requires.txt new/Flask-JWT-Extended-3.21.0/Flask_JWT_Extended.egg-info/requires.txt --- old/Flask-JWT-Extended-3.20.0/Flask_JWT_Extended.egg-info/requires.txt 2019-07-03 17:26:49.000000000 +0200 +++ new/Flask-JWT-Extended-3.21.0/Flask_JWT_Extended.egg-info/requires.txt 2019-08-03 17:50:24.000000000 +0200 @@ -1,5 +1,5 @@ Werkzeug>=0.14 -Flask +Flask>=1.0 PyJWT>=1.6.4 six diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.20.0/PKG-INFO new/Flask-JWT-Extended-3.21.0/PKG-INFO --- old/Flask-JWT-Extended-3.20.0/PKG-INFO 2019-07-03 17:26:53.000000000 +0200 +++ new/Flask-JWT-Extended-3.21.0/PKG-INFO 2019-08-03 17:50:24.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: Flask-JWT-Extended -Version: 3.20.0 +Version: 3.21.0 Summary: Extended JWT integration with Flask Home-page: https://github.com/vimalloc/flask-jwt-extended Author: Landon Gilbert-Bland diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.20.0/flask_jwt_extended/__init__.py new/Flask-JWT-Extended-3.21.0/flask_jwt_extended/__init__.py --- old/Flask-JWT-Extended-3.20.0/flask_jwt_extended/__init__.py 2019-07-03 17:21:11.000000000 +0200 +++ new/Flask-JWT-Extended-3.21.0/flask_jwt_extended/__init__.py 2019-08-03 17:42:04.000000000 +0200 @@ -11,4 +11,4 @@ unset_jwt_cookies, unset_refresh_cookies ) -__version__ = '3.20.0' +__version__ = '3.21.0' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.20.0/flask_jwt_extended/config.py new/Flask-JWT-Extended-3.21.0/flask_jwt_extended/config.py --- old/Flask-JWT-Extended-3.20.0/flask_jwt_extended/config.py 2019-07-03 17:20:36.000000000 +0200 +++ new/Flask-JWT-Extended-3.21.0/flask_jwt_extended/config.py 2019-08-03 17:16:25.000000000 +0200 @@ -317,6 +317,10 @@ return current_app.config['JWT_DECODE_AUDIENCE'] @property + def issuer(self): + return current_app.config['JWT_DECODE_ISSUER'] + + @property def leeway(self): return current_app.config['JWT_DECODE_LEEWAY'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.20.0/flask_jwt_extended/jwt_manager.py new/Flask-JWT-Extended-3.21.0/flask_jwt_extended/jwt_manager.py --- old/Flask-JWT-Extended-3.20.0/flask_jwt_extended/jwt_manager.py 2019-07-03 17:20:36.000000000 +0200 +++ new/Flask-JWT-Extended-3.21.0/flask_jwt_extended/jwt_manager.py 2019-08-03 17:34:19.000000000 +0200 @@ -1,7 +1,10 @@ import datetime from warnings import warn -from jwt import ExpiredSignatureError, InvalidTokenError, InvalidAudienceError +from jwt import ( + ExpiredSignatureError, InvalidTokenError, InvalidAudienceError, + InvalidIssuerError, DecodeError +) try: from flask import _app_ctx_stack as ctx_stack except ImportError: # pragma: no cover @@ -110,6 +113,10 @@ def handle_invalid_header_error(e): return self._invalid_token_callback(str(e)) + @app.errorhandler(DecodeError) + def handle_invalid_header_error(e): + return self._invalid_token_callback(str(e)) + @app.errorhandler(InvalidTokenError) def handle_invalid_token_error(e): return self._invalid_token_callback(str(e)) @@ -126,6 +133,10 @@ def handle_invalid_audience_error(e): return self._invalid_token_callback(str(e)) + @app.errorhandler(InvalidIssuerError) + def handle_invalid_issuer_error(e): + return self._invalid_token_callback(str(e)) + @app.errorhandler(RevokedTokenError) def handle_revoked_token_error(e): return self._revoked_token_callback() @@ -214,6 +225,7 @@ app.config.setdefault('JWT_IDENTITY_CLAIM', 'identity') app.config.setdefault('JWT_USER_CLAIMS', 'user_claims') app.config.setdefault('JWT_DECODE_AUDIENCE', None) + app.config.setdefault('JWT_DECODE_ISSUER', None) app.config.setdefault('JWT_DECODE_LEEWAY', 0) app.config.setdefault('JWT_CLAIMS_IN_REFRESH_TOKEN', False) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.20.0/flask_jwt_extended/tokens.py new/Flask-JWT-Extended-3.21.0/flask_jwt_extended/tokens.py --- old/Flask-JWT-Extended-3.20.0/flask_jwt_extended/tokens.py 2019-07-03 17:20:36.000000000 +0200 +++ new/Flask-JWT-Extended-3.21.0/flask_jwt_extended/tokens.py 2019-08-03 17:34:38.000000000 +0200 @@ -114,7 +114,7 @@ def decode_jwt(encoded_token, secret, algorithms, identity_claim_key, user_claims_key, csrf_value=None, audience=None, - leeway=0, allow_expired=False): + leeway=0, allow_expired=False, issuer=None): """ Decodes an encoded JWT @@ -125,6 +125,7 @@ :param user_claims_key: expected key that contains the user claims :param csrf_value: Expected double submit csrf value :param audience: expected audience in the JWT + :param issuer: expected issuer in the JWT :param leeway: optional leeway to add some margin around expiration times :param allow_expired: Options to ignore exp claim validation in token :return: Dictionary containing contents of the JWT @@ -135,7 +136,7 @@ # This call verifies the ext, iat, nbf, and aud claims data = jwt.decode(encoded_token, secret, algorithms=algorithms, audience=audience, - leeway=leeway, options=options) + leeway=leeway, options=options, issuer=issuer) # Make sure that any custom claims we expect in the token are present if 'jti' not in data: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.20.0/flask_jwt_extended/utils.py new/Flask-JWT-Extended-3.21.0/flask_jwt_extended/utils.py --- old/Flask-JWT-Extended-3.20.0/flask_jwt_extended/utils.py 2019-07-03 17:20:36.000000000 +0200 +++ new/Flask-JWT-Extended-3.21.0/flask_jwt_extended/utils.py 2019-08-03 17:15:19.000000000 +0200 @@ -103,6 +103,7 @@ user_claims_key=config.user_claims_key, csrf_value=csrf_value, audience=config.audience, + issuer=config.issuer, leeway=config.leeway, allow_expired=allow_expired ) @@ -115,6 +116,7 @@ user_claims_key=config.user_claims_key, csrf_value=csrf_value, audience=config.audience, + issuer=config.issuer, leeway=config.leeway, allow_expired=True ) @@ -150,7 +152,7 @@ expiration. If this is None, it will use the 'JWT_ACCESS_TOKEN_EXPIRES` config value (see :ref:`Configuration Options`) - :param user_claims: Optionnal JSON serializable to override user claims. + :param user_claims: Optional JSON serializable to override user claims. :return: An encoded access token """ jwt_manager = _get_jwt_manager() @@ -172,7 +174,7 @@ expiration. If this is None, it will use the 'JWT_REFRESH_TOKEN_EXPIRES` config value (see :ref:`Configuration Options`) - :param user_claims: Optionnal JSON serializable to override user claims. + :param user_claims: Optional JSON serializable to override user claims. :return: An encoded refresh token """ jwt_manager = _get_jwt_manager() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.20.0/requirements.txt new/Flask-JWT-Extended-3.21.0/requirements.txt --- old/Flask-JWT-Extended-3.20.0/requirements.txt 2019-01-03 18:24:37.000000000 +0100 +++ new/Flask-JWT-Extended-3.21.0/requirements.txt 2019-08-03 16:59:26.000000000 +0200 @@ -1,35 +1,43 @@ alabaster==0.7.12 asn1crypto==0.24.0 -Babel==2.6.0 -certifi==2018.11.29 -cffi==1.11.5 +attrs==19.1.0 +Babel==2.7.0 +certifi==2019.6.16 +cffi==1.12.3 chardet==3.0.4 Click==7.0 -cryptography==2.4.2 -docutils==0.14 -filelock==3.0.10 -Flask==1.0.2 -Flask-Sphinx-Themes==1.0.2 +cryptography==2.7 +docutils==0.15.2 +filelock==3.0.12 +Flask==1.1.1 idna==2.8 imagesize==1.1.0 +importlib-metadata==0.19 itsdangerous==1.1.0 -Jinja2==2.10 -MarkupSafe==1.1.0 -packaging==18.0 -pluggy==0.8.0 -py==1.7.0 +Jinja2==2.10.1 +MarkupSafe==1.1.1 +packaging==19.1 +Pallets-Sphinx-Themes==1.2.1 +pluggy==0.12.0 +py==1.8.0 pycparser==2.19 -Pygments==2.3.1 +Pygments==2.4.2 PyJWT==1.7.1 -pyparsing==2.3.0 -pytz==2018.7 -requests==2.21.0 +pyparsing==2.4.2 +pytz==2019.2 +requests==2.22.0 six==1.12.0 -snowballstemmer==1.2.1 -Sphinx==1.8.3 -sphinxcontrib-websupport==1.1.0 +snowballstemmer==1.9.0 +Sphinx==2.1.2 +sphinxcontrib-applehelp==1.0.1 +sphinxcontrib-devhelp==1.0.1 +sphinxcontrib-htmlhelp==1.0.2 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-qthelp==1.0.2 +sphinxcontrib-serializinghtml==1.1.3 toml==0.10.0 -tox==3.6.1 -urllib3==1.24.1 -virtualenv==16.2.0 -Werkzeug==0.14.1 +tox==3.13.2 +urllib3==1.25.3 +virtualenv==16.7.2 +Werkzeug==0.15.5 +zipp==0.5.2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.20.0/setup.py new/Flask-JWT-Extended-3.21.0/setup.py --- old/Flask-JWT-Extended-3.20.0/setup.py 2019-05-10 23:50:27.000000000 +0200 +++ new/Flask-JWT-Extended-3.21.0/setup.py 2019-08-03 16:52:54.000000000 +0200 @@ -30,7 +30,7 @@ platforms='any', install_requires=[ 'Werkzeug>=0.14', # Needed for SameSite cookie functionality - 'Flask', + 'Flask>=1.0', 'PyJWT>=1.6.4', 'six', ], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.20.0/tests/test_decode_tokens.py new/Flask-JWT-Extended-3.21.0/tests/test_decode_tokens.py --- old/Flask-JWT-Extended-3.20.0/tests/test_decode_tokens.py 2019-03-02 05:58:44.000000000 +0100 +++ new/Flask-JWT-Extended-3.21.0/tests/test_decode_tokens.py 2019-08-03 17:35:12.000000000 +0200 @@ -8,7 +8,7 @@ from jwt import ( ExpiredSignatureError, InvalidSignatureError, InvalidAudienceError, - ImmatureSignatureError + ImmatureSignatureError, InvalidIssuerError, DecodeError ) from flask_jwt_extended import ( @@ -246,9 +246,9 @@ app.config['JWT_DECODE_AUDIENCE'] = ['foo', 'bar'] default_access_token['aud'] = token_aud - invalid_token = encode_token(app, default_access_token) + valid_token = encode_token(app, default_access_token) with app.test_request_context(): - decoded = decode_token(invalid_token) + decoded = decode_token(valid_token) assert decoded['aud'] == token_aud @@ -261,3 +261,28 @@ with pytest.raises(InvalidAudienceError): with app.test_request_context(): decode_token(invalid_token) + +def test_valid_iss(app, default_access_token): + app.config['JWT_DECODE_ISSUER'] = 'foobar' + + default_access_token['iss'] = 'foobar' + valid_token = encode_token(app, default_access_token) + with app.test_request_context(): + decoded = decode_token(valid_token) + assert decoded['iss'] == 'foobar' + +def test_invalid_iss(app, default_access_token): + app.config['JWT_DECODE_ISSUER'] = 'baz' + + default_access_token['iss'] = 'foobar' + invalid_token = encode_token(app, default_access_token) + with pytest.raises(InvalidIssuerError): + with app.test_request_context(): + decode_token(invalid_token) + + +def test_malformed_token(app): + invalid_token = 'foobarbaz' + with pytest.raises(DecodeError): + with app.test_request_context(): + decode_token(invalid_token) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.20.0/tests/test_view_decorators.py new/Flask-JWT-Extended-3.21.0/tests/test_view_decorators.py --- old/Flask-JWT-Extended-3.20.0/tests/test_view_decorators.py 2019-05-10 23:50:27.000000000 +0200 +++ new/Flask-JWT-Extended-3.21.0/tests/test_view_decorators.py 2019-08-03 17:37:29.000000000 +0200 @@ -216,7 +216,6 @@ def test_jwt_invalid_audience(app): url = '/protected' - jwtM = get_jwt_manager(app) test_client = app.test_client() # No audience claim expected or provided - OK @@ -238,6 +237,39 @@ assert response.get_json() == {'msg': 'Invalid audience'} +def test_jwt_invalid_issuer(app): + url = '/protected' + test_client = app.test_client() + + # No issuer claim expected or provided - OK + access_token = encode_token(app, {'identity': 'me'}) + response = test_client.get(url, headers=make_headers(access_token)) + assert response.status_code == 200 + + # Issuer claim expected and not provided - not OK + app.config['JWT_DECODE_ISSUER'] = 'my_issuer' + access_token = encode_token(app, {'identity': 'me'}) + response = test_client.get(url, headers=make_headers(access_token)) + assert response.status_code == 422 + assert response.get_json() == {'msg': 'Token is missing the "iss" claim'} + + # Issuer claim still expected and wrong one provided - not OK + access_token = encode_token(app, {'iss': 'different_issuer', 'identity': 'me'}) + response = test_client.get(url, headers=make_headers(access_token)) + assert response.status_code == 422 + assert response.get_json() == {'msg': 'Invalid issuer'} + + +def test_malformed_token(app): + url = '/protected' + test_client = app.test_client() + + access_token = 'foobarbaz' + response = test_client.get(url, headers=make_headers(access_token)) + assert response.status_code == 422 + assert response.get_json() == {'msg': 'Not enough segments'} + + @pytest.mark.parametrize("delta_func", [timedelta, relativedelta]) def test_expired_token(app, delta_func): url = '/protected'