Hello community, here is the log from the commit of package python-flask-jwt-extended for openSUSE:Factory checked in at 2019-09-10 00:06:05 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-flask-jwt-extended (Old) and /work/SRC/openSUSE:Factory/.python-flask-jwt-extended.new.7948 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-flask-jwt-extended" Tue Sep 10 00:06:05 2019 rev:5 rq:729500 version:3.22.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-flask-jwt-extended/python-flask-jwt-extended.changes 2019-08-28 18:35:01.141288537 +0200 +++ /work/SRC/openSUSE:Factory/.python-flask-jwt-extended.new.7948/python-flask-jwt-extended.changes 2019-09-10 00:06:09.805196678 +0200 @@ -1,0 +2,7 @@ +Mon Sep 9 15:00:48 UTC 2019 - Tomáš Chvátal <tchva...@suse.com> + +- Update to 3.22.0: + * Adds ability to check CSRF double submit token from form data instead of + headers + +------------------------------------------------------------------- Old: ---- Flask-JWT-Extended-3.21.0.tar.gz New: ---- Flask-JWT-Extended-3.22.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-flask-jwt-extended.spec ++++++ --- /var/tmp/diff_new_pack.PTmm5W/_old 2019-09-10 00:06:10.817196609 +0200 +++ /var/tmp/diff_new_pack.PTmm5W/_new 2019-09-10 00:06:10.825196609 +0200 @@ -17,7 +17,7 @@ Name: python-flask-jwt-extended -Version: 3.21.0 +Version: 3.22.0 Release: 0 Summary: A Flask extension that provides JWT support License: MIT ++++++ Flask-JWT-Extended-3.21.0.tar.gz -> Flask-JWT-Extended-3.22.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.21.0/Flask_JWT_Extended.egg-info/PKG-INFO new/Flask-JWT-Extended-3.22.0/Flask_JWT_Extended.egg-info/PKG-INFO --- old/Flask-JWT-Extended-3.21.0/Flask_JWT_Extended.egg-info/PKG-INFO 2019-08-03 17:50:24.000000000 +0200 +++ new/Flask-JWT-Extended-3.22.0/Flask_JWT_Extended.egg-info/PKG-INFO 2019-08-28 18:23:28.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: Flask-JWT-Extended -Version: 3.21.0 +Version: 3.22.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.21.0/PKG-INFO new/Flask-JWT-Extended-3.22.0/PKG-INFO --- old/Flask-JWT-Extended-3.21.0/PKG-INFO 2019-08-03 17:50:24.000000000 +0200 +++ new/Flask-JWT-Extended-3.22.0/PKG-INFO 2019-08-28 18:23:32.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: Flask-JWT-Extended -Version: 3.21.0 +Version: 3.22.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.21.0/flask_jwt_extended/__init__.py new/Flask-JWT-Extended-3.22.0/flask_jwt_extended/__init__.py --- old/Flask-JWT-Extended-3.21.0/flask_jwt_extended/__init__.py 2019-08-03 17:42:04.000000000 +0200 +++ new/Flask-JWT-Extended-3.22.0/flask_jwt_extended/__init__.py 2019-08-28 18:20:10.000000000 +0200 @@ -11,4 +11,4 @@ unset_jwt_cookies, unset_refresh_cookies ) -__version__ = '3.21.0' +__version__ = '3.22.0' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.21.0/flask_jwt_extended/config.py new/Flask-JWT-Extended-3.22.0/flask_jwt_extended/config.py --- old/Flask-JWT-Extended-3.21.0/flask_jwt_extended/config.py 2019-08-03 17:16:25.000000000 +0200 +++ new/Flask-JWT-Extended-3.22.0/flask_jwt_extended/config.py 2019-08-28 18:19:52.000000000 +0200 @@ -185,6 +185,18 @@ current_app.config['JWT_REFRESH_CSRF_HEADER_NAME'] @property + def csrf_check_form(self): + return current_app.config['JWT_CSRF_CHECK_FORM'] + + @property + def access_csrf_field_name(self): + return current_app.config['JWT_ACCESS_CSRF_FIELD_NAME'] + + @property + def refresh_csrf_field_name(self): + return current_app.config['JWT_REFRESH_CSRF_FIELD_NAME'] + + @property def access_expires(self): delta = current_app.config['JWT_ACCESS_TOKEN_EXPIRES'] if type(delta) is int: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.21.0/flask_jwt_extended/jwt_manager.py new/Flask-JWT-Extended-3.22.0/flask_jwt_extended/jwt_manager.py --- old/Flask-JWT-Extended-3.21.0/flask_jwt_extended/jwt_manager.py 2019-08-03 17:34:19.000000000 +0200 +++ new/Flask-JWT-Extended-3.22.0/flask_jwt_extended/jwt_manager.py 2019-08-28 18:19:52.000000000 +0200 @@ -196,6 +196,9 @@ app.config.setdefault('JWT_REFRESH_CSRF_COOKIE_NAME', 'csrf_refresh_token') app.config.setdefault('JWT_ACCESS_CSRF_COOKIE_PATH', '/') app.config.setdefault('JWT_REFRESH_CSRF_COOKIE_PATH', '/') + app.config.setdefault('JWT_CSRF_CHECK_FORM', False) + app.config.setdefault('JWT_ACCESS_CSRF_FIELD_NAME', 'csrf_token') + app.config.setdefault('JWT_REFRESH_CSRF_FIELD_NAME', 'csrf_token') # How long an a token will live before they expire. app.config.setdefault('JWT_ACCESS_TOKEN_EXPIRES', datetime.timedelta(minutes=15)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.21.0/flask_jwt_extended/view_decorators.py new/Flask-JWT-Extended-3.22.0/flask_jwt_extended/view_decorators.py --- old/Flask-JWT-Extended-3.21.0/flask_jwt_extended/view_decorators.py 2019-08-03 16:52:54.000000000 +0200 +++ new/Flask-JWT-Extended-3.22.0/flask_jwt_extended/view_decorators.py 2019-08-28 18:19:52.000000000 +0200 @@ -198,9 +198,11 @@ if request_type == 'access': cookie_key = config.access_cookie_name csrf_header_key = config.access_csrf_header_name + csrf_field_key = config.access_csrf_field_name else: cookie_key = config.refresh_cookie_name csrf_header_key = config.refresh_csrf_header_name + csrf_field_key = config.refresh_csrf_field_name encoded_token = request.cookies.get(cookie_key) if not encoded_token: @@ -208,8 +210,10 @@ if config.csrf_protect and request.method in config.csrf_request_methods: csrf_value = request.headers.get(csrf_header_key, None) + if not csrf_value and config.csrf_check_form: + csrf_value = request.form.get(csrf_field_key, None) if not csrf_value: - raise CSRFError("Missing CSRF token in headers") + raise CSRFError("Missing CSRF token") else: csrf_value = None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-JWT-Extended-3.21.0/tests/test_cookies.py new/Flask-JWT-Extended-3.22.0/tests/test_cookies.py --- old/Flask-JWT-Extended-3.21.0/tests/test_cookies.py 2018-09-16 07:27:45.000000000 +0200 +++ new/Flask-JWT-Extended-3.22.0/tests/test_cookies.py 2019-08-28 18:19:53.000000000 +0200 @@ -139,7 +139,7 @@ # Test you cannot post without the additional csrf protection response = test_client.post(post_url) assert response.status_code == 401 - assert response.get_json() == {'msg': 'Missing CSRF token in headers'} + assert response.get_json() == {'msg': 'Missing CSRF token'} # Test that you can post with the csrf double submit value csrf_headers = {'X-CSRF-TOKEN': csrf_token} @@ -202,6 +202,48 @@ @pytest.mark.parametrize("options", [ + ('/refresh_token', 'csrf_refresh_token', '/post_refresh_protected'), + ('/access_token', 'csrf_access_token', '/post_protected') +]) +def test_csrf_with_default_form_field(app, options): + app.config['JWT_CSRF_CHECK_FORM'] = True + test_client = app.test_client() + auth_url, csrf_cookie_name, post_url = options + + # Get the jwt cookies and csrf double submit tokens + response = test_client.get(auth_url) + csrf_token = _get_cookie_from_response(response, csrf_cookie_name)[csrf_cookie_name] + + # Test that you can post with the csrf double submit value + csrf_data = {'csrf_token': csrf_token} + response = test_client.post(post_url, data=csrf_data) + assert response.status_code == 200 + assert response.get_json() == {'foo': 'bar'} + + +@pytest.mark.parametrize("options", [ + ('/refresh_token', 'csrf_refresh_token', '/post_refresh_protected'), + ('/access_token', 'csrf_access_token', '/post_protected') +]) +def test_csrf_with_custom_form_field(app, options): + app.config['JWT_CSRF_CHECK_FORM'] = True + app.config['JWT_ACCESS_CSRF_FIELD_NAME'] = 'FOO' + app.config['JWT_REFRESH_CSRF_FIELD_NAME'] = 'FOO' + test_client = app.test_client() + auth_url, csrf_cookie_name, post_url = options + + # Get the jwt cookies and csrf double submit tokens + response = test_client.get(auth_url) + csrf_token = _get_cookie_from_response(response, csrf_cookie_name)[csrf_cookie_name] + + # Test that you can post with the csrf double submit value + csrf_data = {'FOO': csrf_token} + response = test_client.post(post_url, data=csrf_data) + assert response.status_code == 200 + assert response.get_json() == {'foo': 'bar'} + + +@pytest.mark.parametrize("options", [ ('/refresh_token', 'csrf_refresh_token', '/refresh_protected', '/post_refresh_protected'), # nopep8 ('/access_token', 'csrf_access_token', '/protected', '/post_protected') ]) @@ -222,7 +264,7 @@ # Insure GET requests now fail without csrf response = test_client.get(get_url) assert response.status_code == 401 - assert response.get_json() == {'msg': 'Missing CSRF token in headers'} + assert response.get_json() == {'msg': 'Missing CSRF token'} # Insure GET requests now succeed with csrf csrf_headers = {'X-CSRF-TOKEN': csrf_token} @@ -430,4 +472,4 @@ csrf_token = csrf_cookie['csrf_access_token'] response = test_client.post('/optional_post_protected') assert response.status_code == 401 - assert response.get_json() == {'msg': 'Missing CSRF token in headers'} + assert response.get_json() == {'msg': 'Missing CSRF token'}