Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-Flask-HTTPAuth for 
openSUSE:Factory checked in at 2021-07-23 23:41:12
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-Flask-HTTPAuth (Old)
 and      /work/SRC/openSUSE:Factory/.python-Flask-HTTPAuth.new.1899 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-Flask-HTTPAuth"

Fri Jul 23 23:41:12 2021 rev:6 rq:907906 version:4.4.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-Flask-HTTPAuth/python-Flask-HTTPAuth.changes  
    2021-06-01 10:41:43.881249191 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-Flask-HTTPAuth.new.1899/python-Flask-HTTPAuth.changes
    2021-07-23 23:41:31.357807503 +0200
@@ -1,0 +2,22 @@
+Sun Jul  4 00:41:02 UTC 2021 - Arun Persaud <[email protected]>
+
+- specfile:
+  * update copyright year
+  * require importlib-metadata
+  * skip python 2
+
+- update to version 4.4.0:
+  * Replace safe_str_cmp with hmac.compare_digest to avoid a
+    deprecation warning from Werkzeug #126 (commit) (thanks Federico
+    Martinez!)
+  * Drop Python 2 support (commit)
+
+- changes from version 4.3.0 :
+  * Support token auth with custom header in MultiAuth class #125
+    (commit)
+  * Catch UnicodeDecodeError when passing malformed data in
+    authorization header #122 (commit) (thanks Bastian Raschke!)
+  * Fixes typo #116 (commit) (thanks Renato Oliveira!)
+  * Move builds to GitHub actions (commit)
+
+-------------------------------------------------------------------

Old:
----
  Flask-HTTPAuth-4.2.0.tar.gz

New:
----
  Flask-HTTPAuth-4.4.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-Flask-HTTPAuth.spec ++++++
--- /var/tmp/diff_new_pack.g4Z68V/_old  2021-07-23 23:41:31.829806900 +0200
+++ /var/tmp/diff_new_pack.g4Z68V/_new  2021-07-23 23:41:31.833806895 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-Flask-HTTPAuth
 #
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2021 SUSE LLC
 # Copyright (c) 2017 Dr. Axel Braun
 #
 # All modifications and additions to the file contributed by third parties
@@ -18,8 +18,9 @@
 
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
+%define         skip_python2 1
 Name:           python-Flask-HTTPAuth
-Version:        4.2.0
+Version:        4.4.0
 Release:        0
 Summary:        Basic and Digest HTTP authentication for Flask routes
 License:        MIT
@@ -27,6 +28,7 @@
 URL:            https://github.com/miguelgrinberg/flask-httpauth/
 Source:         
https://files.pythonhosted.org/packages/source/F/Flask-HTTPAuth/Flask-HTTPAuth-%{version}.tar.gz
 BuildRequires:  %{python_module Flask}
+BuildRequires:  %{python_module importlib-metadata}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros

++++++ Flask-HTTPAuth-4.2.0.tar.gz -> Flask-HTTPAuth-4.4.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/Flask-HTTPAuth-4.2.0/Flask_HTTPAuth.egg-info/PKG-INFO 
new/Flask-HTTPAuth-4.4.0/Flask_HTTPAuth.egg-info/PKG-INFO
--- old/Flask-HTTPAuth-4.2.0/Flask_HTTPAuth.egg-info/PKG-INFO   2020-11-16 
12:52:39.000000000 +0100
+++ new/Flask-HTTPAuth-4.4.0/Flask_HTTPAuth.egg-info/PKG-INFO   2021-05-13 
20:32:42.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Flask-HTTPAuth
-Version: 4.2.0
+Version: 4.4.0
 Summary: Basic and Digest HTTP authentication for Flask routes
 Home-page: http://github.com/miguelgrinberg/flask-httpauth/
 Author: Miguel Grinberg
@@ -18,7 +18,6 @@
 Classifier: License :: OSI Approved :: MIT License
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2
 Classifier: Programming Language :: Python :: 3
 Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/Flask-HTTPAuth-4.2.0/Flask_HTTPAuth.egg-info/SOURCES.txt 
new/Flask-HTTPAuth-4.4.0/Flask_HTTPAuth.egg-info/SOURCES.txt
--- old/Flask-HTTPAuth-4.2.0/Flask_HTTPAuth.egg-info/SOURCES.txt        
2020-11-16 12:52:40.000000000 +0100
+++ new/Flask-HTTPAuth-4.4.0/Flask_HTTPAuth.egg-info/SOURCES.txt        
2021-05-13 20:32:42.000000000 +0200
@@ -62,4 +62,5 @@
 tests/test_error_responses.py
 tests/test_multi.py
 tests/test_roles.py
-tests/test_token.py
\ No newline at end of file
+tests/test_token.py
+tests/test_x.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Flask-HTTPAuth-4.2.0/PKG-INFO 
new/Flask-HTTPAuth-4.4.0/PKG-INFO
--- old/Flask-HTTPAuth-4.2.0/PKG-INFO   2020-11-16 12:52:40.275509400 +0100
+++ new/Flask-HTTPAuth-4.4.0/PKG-INFO   2021-05-13 20:32:43.185671300 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: Flask-HTTPAuth
-Version: 4.2.0
+Version: 4.4.0
 Summary: Basic and Digest HTTP authentication for Flask routes
 Home-page: http://github.com/miguelgrinberg/flask-httpauth/
 Author: Miguel Grinberg
@@ -18,7 +18,6 @@
 Classifier: License :: OSI Approved :: MIT License
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2
 Classifier: Programming Language :: Python :: 3
 Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Flask-HTTPAuth-4.2.0/README.md 
new/Flask-HTTPAuth-4.4.0/README.md
--- old/Flask-HTTPAuth-4.2.0/README.md  2020-04-23 01:16:10.000000000 +0200
+++ new/Flask-HTTPAuth-4.4.0/README.md  2021-02-21 14:13:02.000000000 +0100
@@ -1,7 +1,7 @@
 Flask-HTTPAuth
 ==============
 
-[![Build 
Status](https://travis-ci.org/miguelgrinberg/Flask-HTTPAuth.png?branch=master)](https://travis-ci.org/miguelgrinberg/Flask-HTTPAuth)
+[![Build 
status](https://github.com/miguelgrinberg/Flask-HTTPAuth/workflows/build/badge.svg)](https://github.com/miguelgrinberg/Flask-HTTPAuth/actions)
 
[![codecov](https://codecov.io/gh/miguelgrinberg/Flask-HTTPAuth/branch/master/graph/badge.svg?token=KeU2002DHo)](https://codecov.io/gh/miguelgrinberg/Flask-HTTPAuth)
 
 Simple extension that provides Basic and Digest HTTP authentication for Flask 
routes.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Flask-HTTPAuth-4.2.0/docs/index.rst 
new/Flask-HTTPAuth-4.4.0/docs/index.rst
--- old/Flask-HTTPAuth-4.2.0/docs/index.rst     2020-04-26 19:51:16.000000000 
+0200
+++ new/Flask-HTTPAuth-4.4.0/docs/index.rst     2021-02-01 01:04:55.000000000 
+0100
@@ -39,7 +39,7 @@
    if __name__ == '__main__':
        app.run()
 
-The function decorated with the ``verify_password`` decorator receives the 
username and password sent by the client. If the credentials belong to a user, 
then the function should return the user object. If the credentials are invalid 
the functon can return ``None`` or ``False``. The user object can then be 
queries from the ``current_user()`` method of the authentication instance.
+The function decorated with the ``verify_password`` decorator receives the 
username and password sent by the client. If the credentials belong to a user, 
then the function should return the user object. If the credentials are invalid 
the functon can return ``None`` or ``False``. The user object can then be 
queried from the ``current_user()`` method of the authentication instance.
 
 Digest authentication example
 -----------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Flask-HTTPAuth-4.2.0/flask_httpauth.py 
new/Flask-HTTPAuth-4.4.0/flask_httpauth.py
--- old/Flask-HTTPAuth-4.2.0/flask_httpauth.py  2020-11-16 12:52:31.000000000 
+0100
+++ new/Flask-HTTPAuth-4.4.0/flask_httpauth.py  2021-05-13 20:32:40.000000000 
+0200
@@ -7,16 +7,16 @@
 :copyright: (C) 2014 by Miguel Grinberg.
 :license:   MIT, see LICENSE for more details.
 """
-
+import hmac
 from base64 import b64decode
 from functools import wraps
 from hashlib import md5
 from random import Random, SystemRandom
 from flask import request, make_response, session, g, Response
 from werkzeug.datastructures import Authorization
-from werkzeug.security import safe_str_cmp
 
-__version__ = '4.2.0'
+
+__version__ = '4.4.0'
 
 
 class HTTPAuth(object):
@@ -37,6 +37,18 @@
         self.get_password(default_get_password)
         self.error_handler(default_auth_error)
 
+    def is_compatible_auth(self, headers):
+        if self.header is None or self.header == 'Authorization':
+            try:
+                scheme, _ = request.headers.get('Authorization', '').split(
+                    None, 1)
+            except ValueError:
+                # malformed Authorization header
+                return False
+            return scheme == self.scheme
+        else:
+            return self.header in headers
+
     def get_password(self, f):
         self.get_password_callback = f
         return f
@@ -169,9 +181,10 @@
         return login_required_internal
 
     def username(self):
-        if not request.authorization:
+        auth = self.get_auth()
+        if not auth:
             return ""
-        return request.authorization.username
+        return auth.username
 
     def current_user(self):
         if hasattr(g, 'flask_httpauth_user'):
@@ -205,9 +218,14 @@
             username, password = b64decode(credentials).split(b':', 1)
         except (ValueError, TypeError):
             return None
+        try:
+            username = username.decode('utf-8')
+            password = password.decode('utf-8')
+        except UnicodeDecodeError:
+            username = None
+            password = None
         return Authorization(
-            scheme, {'username': username.decode('utf-8'),
-                     'password': password.decode('utf-8')})
+            scheme, {'username': username, 'password': password})
 
     def authenticate(self, auth, stored_password):
         if auth:
@@ -228,7 +246,7 @@
                                                               client_password)
         return auth.username if client_password is not None and \
             stored_password is not None and \
-            safe_str_cmp(client_password, stored_password) else None
+            hmac.compare_digest(client_password, stored_password) else None
 
 
 class HTTPDigestAuth(HTTPAuth):
@@ -257,7 +275,7 @@
             session_nonce = session.get("auth_nonce")
             if nonce is None or session_nonce is None:
                 return False
-            return safe_str_cmp(nonce, session_nonce)
+            return hmac.compare_digest(nonce, session_nonce)
 
         def default_generate_opaque():
             session["auth_opaque"] = _generate_random()
@@ -267,7 +285,7 @@
             session_opaque = session.get("auth_opaque")
             if opaque is None or session_opaque is None:  # pragma: no cover
                 return False
-            return safe_str_cmp(opaque, session_opaque)
+            return hmac.compare_digest(opaque, session_opaque)
 
         self.generate_nonce(default_generate_nonce)
         self.generate_opaque(default_generate_opaque)
@@ -326,7 +344,7 @@
         ha2 = md5(a2.encode('utf-8')).hexdigest()
         a3 = ha1 + ":" + auth.nonce + ":" + ha2
         response = md5(a3.encode('utf-8')).hexdigest()
-        return safe_str_cmp(response, auth.response)
+        return hmac.compare_digest(response, auth.response)
 
 
 class HTTPTokenAuth(HTTPAuth):
@@ -362,21 +380,12 @@
         def login_required_internal(f):
             @wraps(f)
             def decorated(*args, **kwargs):
-                selected_auth = None
-                if 'Authorization' in request.headers:
-                    try:
-                        scheme, creds = request.headers[
-                            'Authorization'].split(None, 1)
-                    except ValueError:
-                        # malformed Authorization header
-                        pass
-                    else:
-                        for auth in self.additional_auth:
-                            if auth.scheme == scheme:
-                                selected_auth = auth
-                                break
-                if selected_auth is None:
-                    selected_auth = self.main_auth
+                selected_auth = self.main_auth
+                if not self.main_auth.is_compatible_auth(request.headers):
+                    for auth in self.additional_auth:
+                        if auth.is_compatible_auth(request.headers):
+                            selected_auth = auth
+                            break
                 return selected_auth.login_required(role=role,
                                                     optional=optional
                                                     )(f)(*args, **kwargs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Flask-HTTPAuth-4.2.0/setup.py 
new/Flask-HTTPAuth-4.4.0/setup.py
--- old/Flask-HTTPAuth-4.2.0/setup.py   2020-04-19 18:49:09.000000000 +0200
+++ new/Flask-HTTPAuth-4.4.0/setup.py   2021-05-13 20:26:17.000000000 +0200
@@ -34,7 +34,6 @@
         'License :: OSI Approved :: MIT License',
         'Operating System :: OS Independent',
         'Programming Language :: Python',
-        'Programming Language :: Python :: 2',
         'Programming Language :: Python :: 3',
         'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
         'Topic :: Software Development :: Libraries :: Python Modules'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/Flask-HTTPAuth-4.2.0/tests/test_basic_verify_password.py 
new/Flask-HTTPAuth-4.4.0/tests/test_basic_verify_password.py
--- old/Flask-HTTPAuth-4.2.0/tests/test_basic_verify_password.py        
2020-06-04 11:42:04.000000000 +0200
+++ new/Flask-HTTPAuth-4.4.0/tests/test_basic_verify_password.py        
2021-02-21 14:12:46.000000000 +0100
@@ -75,6 +75,13 @@
         self.assertEqual(response.status_code, 403)
         self.assertTrue('WWW-Authenticate' in response.headers)
 
+    def test_verify_auth_login_malformed_password(self):
+        creds = 'eyJhbGciOieyJp=='
+        response = self.client.get('/basic-verify',
+                                   headers={'Authorization': 'Basic ' + creds})
+        self.assertEqual(response.status_code, 403)
+        self.assertTrue('WWW-Authenticate' in response.headers)
+
 
 class HTTPAuthTestCaseOldStyle(HTTPAuthTestCase):
     use_old_style_callback = True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Flask-HTTPAuth-4.2.0/tests/test_multi.py 
new/Flask-HTTPAuth-4.4.0/tests/test_multi.py
--- old/Flask-HTTPAuth-4.2.0/tests/test_multi.py        2020-04-23 
01:11:02.000000000 +0200
+++ new/Flask-HTTPAuth-4.4.0/tests/test_multi.py        2021-05-01 
16:19:05.000000000 +0200
@@ -11,7 +11,8 @@
 
         basic_auth = HTTPBasicAuth()
         token_auth = HTTPTokenAuth('MyToken')
-        multi_auth = MultiAuth(basic_auth, token_auth)
+        custom_token_auth = HTTPTokenAuth(header='X-Token')
+        multi_auth = MultiAuth(basic_auth, token_auth, custom_token_auth)
 
         @basic_auth.verify_password
         def verify_password(username, password):
@@ -37,6 +38,16 @@
         def error_handler():
             return 'error', 401, {'WWW-Authenticate': 'MyToken realm="Foo"'}
 
+        @custom_token_auth.verify_token
+        def verify_custom_token(token):
+            return token == 'this-is-the-custom-token!'
+
+        @custom_token_auth.get_user_roles
+        def get_custom_token_role(auth):
+            if auth['token'] == 'this-is-the-custom-token!':
+                return 'foo'
+            return
+
         @app.route('/')
         def index():
             return 'index'
@@ -91,6 +102,19 @@
         self.assertEqual(response.headers['WWW-Authenticate'],
                          'MyToken realm="Foo"')
 
+    def test_multi_auth_login_valid_custom_token(self):
+        response = self.client.get(
+            '/protected', headers={'X-Token': 'this-is-the-custom-token!'})
+        self.assertEqual(response.data.decode('utf-8'), 'access granted:None')
+
+    def test_multi_auth_login_invalid_custom_token(self):
+        response = self.client.get(
+            '/protected', headers={'X-Token': 'this-is-not-the-token!'})
+        self.assertEqual(response.status_code, 401)
+        self.assertTrue('WWW-Authenticate' in response.headers)
+        self.assertEqual(response.headers['WWW-Authenticate'],
+                         'Bearer realm="Authentication Required"')
+
     def test_multi_auth_login_invalid_scheme(self):
         response = self.client.get(
             '/protected', headers={'Authorization': 'Foo this-is-the-token!'})
@@ -116,3 +140,9 @@
             '/protected-with-role', headers={'Authorization':
                                              'MyToken this-is-the-token!'})
         self.assertEqual(response.data.decode('utf-8'), 'role access granted')
+
+    def test_multi_auth_login_valid_custom_token_role(self):
+        response = self.client.get(
+            '/protected-with-role', headers={'X-Token':
+                                             'this-is-the-custom-token!'})
+        self.assertEqual(response.data.decode('utf-8'), 'role access granted')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Flask-HTTPAuth-4.2.0/tests/test_x.py 
new/Flask-HTTPAuth-4.4.0/tests/test_x.py
--- old/Flask-HTTPAuth-4.2.0/tests/test_x.py    1970-01-01 01:00:00.000000000 
+0100
+++ new/Flask-HTTPAuth-4.4.0/tests/test_x.py    2021-01-30 00:00:53.000000000 
+0100
@@ -0,0 +1,26 @@
+import unittest
+from flask import Flask
+from flask_httpauth import HTTPBasicAuth
+
+
+class HTTPAuthTestCase(unittest.TestCase):
+
+    def setUp(self):
+        app = Flask(__name__)
+        app.config['SECRET_KEY'] = 'my secret'
+
+        basic_verify_auth = HTTPBasicAuth()
+
+        @app.route('/')
+        @basic_verify_auth.login_required
+        def index():
+            return 'index'
+
+        self.app = app
+        self.basic_verify_auth = basic_verify_auth
+        self.client = app.test_client()
+
+    def test_verify_auth_login_malformed_password(self):
+        creds = 'eyJhbGciOieyJp=='
+        response = self.client.get('/', headers={'Authorization': 'Basic ' + 
creds})
+        self.assertEqual(response.status_code, 401)

Reply via email to