[Python-modules-commits] [python-fedora] 02/10: New upstream version 0.9.0

Sergio Durigan Junior sergiodj-guest at moszumanska.debian.org
Tue Aug 8 21:19:57 UTC 2017


This is an automated email from the git hooks/post-receive script.

sergiodj-guest pushed a commit to branch master
in repository python-fedora.

commit b2259efe141f4ec9690a8f76bce85bb2ba8dde34
Author: Sergio Durigan Junior <sergiodj at sergiodj.net>
Date:   Tue Aug 8 16:09:32 2017 -0400

    New upstream version 0.9.0
---
 NEWS                                | 12 +++++--
 PKG-INFO                            |  2 +-
 fedora/client/__init__.py           | 29 +++++++++++++++++
 fedora/client/bodhi.py              | 35 ++++++++++++++++++--
 fedora/client/openidbaseclient.py   | 25 ++++++++++++--
 fedora/client/openidcclient.py      | 65 +++++++++++++++++++++++++++++++++++++
 fedora/release.py                   |  4 +--
 fedora/tg/utils.py                  |  5 +++
 python_fedora.egg-info/PKG-INFO     |  2 +-
 python_fedora.egg-info/SOURCES.txt  |  1 +
 python_fedora.egg-info/requires.txt |  1 +
 setup.cfg                           |  1 -
 setup.py                            |  1 +
 13 files changed, 170 insertions(+), 13 deletions(-)

diff --git a/NEWS b/NEWS
index 0a5aff2..23ea4a2 100644
--- a/NEWS
+++ b/NEWS
@@ -3,8 +3,16 @@ NEWS
 ====
 
 :Authors: Toshio Kuratomi, Luke Macken, Ricky Elrod, Patrick Uiterwijk, Ralph Bean
-:Date: 21 Apr 2016
-:Version: 0.8.x
+:Date: 5 May 2017
+:Version: 0.9.x
+
+-----
+0.9.0
+-----
+
+* Deprecated fedora.client.bodhi in favor of bodhi.client.bindings.
+* Added OpenID Connect client
+* Added file permission checks on openidbaseclient cookies
 
 
 -----
diff --git a/PKG-INFO b/PKG-INFO
index 83258ca..c830284 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: python-fedora
-Version: 0.8.0
+Version: 0.9.0
 Summary: Python modules for interacting with Fedora Services
 Home-page: https://fedorahosted.org/python-fedora
 Author: Toshio Kuratomi, Luke Macken, Ricky Elrod, Ralph Bean, Patrick Uiterwijk
diff --git a/fedora/client/__init__.py b/fedora/client/__init__.py
index 595e685..ab47476 100644
--- a/fedora/client/__init__.py
+++ b/fedora/client/__init__.py
@@ -28,6 +28,8 @@ fedora.client is used to interact with Fedora Services.
 .. moduleauthor:: Luke Macken <lmacken at redhat.com>
 .. moduleauthor:: Toshio Kuratomi <tkuratom at redhat.com>
 '''
+import errno
+import os
 import warnings
 
 from munch import Munch
@@ -113,6 +115,16 @@ class AppError(FedoraServiceError):
             self.name, self.message, self.extras)
 
 
+class UnsafeFileError(Exception):
+    def __init__(self, filename, message):
+        super(UnsafeFileError, self).__init__(message)
+        self.message = message
+        self.filename = filename
+
+    def __str__(self):
+        return 'Unsafe file permissions! {}: {}'.format(self.filename,
+                                                        self.message)
+
 
 # Backwards compatibility
 class DictContainer(Munch):
@@ -123,6 +135,23 @@ class DictContainer(Munch):
         Munch.__init__(self, *args, **kwargs)
 
 
+def check_file_permissions(filename, allow_notexists=False):
+    if os.path.islink(filename):
+        raise UnsafeFileError(filename, 'File is a symlink')
+    try:
+        stat = os.stat(filename)
+    except OSError as e:
+        if e.errno == errno.ENOENT and allow_notexists:
+            return
+        raise
+    if stat.st_uid != os.getuid():
+        raise UnsafeFileError(filename, 'File not owned by current user')
+    if stat.st_gid != os.getgid():
+        raise UnsafeFileError(filename, 'File not owner by primary group')
+    if stat.st_mode & 0o007:
+        raise UnsafeFileError(filename, 'File is world-readable')
+
+
 # We want people to be able to import fedora.client.*Client directly
 # pylint: disable-msg=W0611
 from fedora.client.proxyclient import ProxyClient
diff --git a/fedora/client/bodhi.py b/fedora/client/bodhi.py
index 3d7752c..831c28d 100644
--- a/fedora/client/bodhi.py
+++ b/fedora/client/bodhi.py
@@ -17,6 +17,10 @@
 # License along with python-fedora; if not, see <http://www.gnu.org/licenses/>
 #
 """
+DEPRECATED: This module is deprecated and has moved to bodhi.client.bindings.
+As the bodhi-0.9 client still uses it, it will remain here until Fedora 25 is
+EOL.
+
 This module provides a client interface for bodhi.
 
 
@@ -36,9 +40,14 @@ import re
 
 import six
 
-from fedora.client import OpenIdBaseClient, FedoraClientError, BaseClient
+from fedora.client import AuthError, OpenIdBaseClient, FedoraClientError, BaseClient
 import fedora.client.openidproxyclient
 
+
+warnings.warn('fedora.client.bodhi has been deprecated. Please use bodhi.client.bindings instead.',
+              DeprecationWarning)
+
+
 __version__ = '2.0.0'
 log = logging.getLogger(__name__)
 
@@ -79,7 +88,23 @@ def errorhandled(method):
     """ A decorator for Bodhi2Client that raises exceptions on failure. """
     @functools.wraps(method)
     def wrapper(*args, **kwargs):
-        result = method(*args, **kwargs)
+        try:
+            result = method(*args, **kwargs)
+        except AuthError:
+            # An AuthError can be raised for three different reasons:
+            #
+            # 0) The password is wrong.
+            # 1) The session cookies are expired. fedora.python does not handle this automatically.
+            # 2) The session cookies are not expired, but are no longer valid (for example, this can
+            #    happen if the server's auth secret has changed.)
+            #
+            # We don't know the difference between the cases, but case #1 is fairly common and we
+            # can work around it by removing the session cookies and csrf token and retrying the
+            # request. If the password is wrong, the second attempt will also fail but we won't
+            # guard it and the AuthError will still be raised.
+            args[0]._session.cookies.clear()
+            args[0].csrf_token = None
+            result = method(*args, **kwargs)
 
         if 'errors' not in result:
             return result
@@ -113,6 +138,10 @@ class Bodhi2Client(OpenIdBaseClient):
             self._password = getpass.getpass()
         return self._password
 
+    @password.setter
+    def password(self, value):
+        self._password = value
+
     @errorhandled
     def save(self, **kwargs):
         """ Save an update.
@@ -237,7 +266,7 @@ class Bodhi2Client(OpenIdBaseClient):
             # update ID, so try and figure it out
             if re.search(r'(\.el|\.fc)\d\d?', kwargs['package']):
                 kwargs['builds'] = kwargs['package']
-            elif re.search(r'FEDORA-(EPEL)?-\d{4,4}', kwargs['package']):
+            elif re.search(r'FEDORA-(EPEL-)?\d{4,4}', kwargs['package']):
                 kwargs['updateid'] = kwargs['package']
             else:
                 kwargs['packages'] = kwargs['package']
diff --git a/fedora/client/openidbaseclient.py b/fedora/client/openidbaseclient.py
index 48c8019..425d932 100644
--- a/fedora/client/openidbaseclient.py
+++ b/fedora/client/openidbaseclient.py
@@ -47,7 +47,11 @@ from munch import munchify
 from kitchen.text.converters import to_bytes
 
 from fedora import __version__
-from fedora.client import AuthError, LoginRequiredError, ServerError
+from fedora.client import (AuthError,
+                           LoginRequiredError,
+                           ServerError,
+                           UnsafeFileError,
+                           check_file_permissions)
 from fedora.client.openidproxyclient import (
     OpenIdProxyClient, absolute_url, openid_login)
 
@@ -80,7 +84,7 @@ def requires_login(func):
                 '<title>OpenID transaction in progress</title>' in output.text:
             raise LoginRequiredError(
                 '{0} requires a logged in user'.format(output.url))
-        elif output and output.status_code == 403:
+        elif output.status_code == 403:
             raise LoginRequiredError(
                 '{0} requires a logged in user'.format(output.url))
         return output
@@ -182,7 +186,7 @@ class OpenIdBaseClient(OpenIdProxyClient):
         # for their password over and over.
         if not os.path.isdir(b_SESSION_DIR):
             try:
-                os.makedirs(b_SESSION_DIR, mode=0o755)
+                os.makedirs(b_SESSION_DIR, mode=0o750)
             except OSError as err:
                 log.warning('Unable to create {file}: {error}'.format(
                     file=b_SESSION_DIR, error=err))
@@ -302,6 +306,12 @@ class OpenIdBaseClient(OpenIdProxyClient):
             return
 
         try:
+            check_file_permissions(b_SESSION_FILE, True)
+        except UnsafeFileError as e:
+            log.debug('Current sessions ignored: {}'.format(str(e)))
+            return
+
+        try:
             with self.cache_lock:
                 with open(b_SESSION_FILE, 'rb') as f:
                     data = json.loads(f.read().decode('utf-8'))
@@ -312,8 +322,10 @@ class OpenIdBaseClient(OpenIdProxyClient):
         except IOError:
             # The file doesn't exist, so create it.
             log.debug("Creating %s", b_SESSION_FILE)
+            oldmask = os.umask(0o027)
             with open(b_SESSION_FILE, 'wb') as f:
                 f.write(json.dumps({}).encode('utf-8'))
+            os.umask(oldmask)
 
     def _save_cookies(self):
         if not self.cache_session:
@@ -321,15 +333,22 @@ class OpenIdBaseClient(OpenIdProxyClient):
 
         with self.cache_lock:
             try:
+                check_file_permissions(b_SESSION_FILE, True)
                 with open(b_SESSION_FILE, 'rb') as f:
                     data = json.loads(f.read().decode('utf-8'))
+            except UnsafeFileError as e:
+                log.debug('Clearing sessions: {}'.format(str(e)))
+                os.unlink(b_SESSION_FILE)
+                data = {}
             except Exception:
                 log.warn("Failed to open cookie cache before saving.")
                 data = {}
 
+            oldmask = os.umask(0o027)
             data[self.session_key] = self._session.cookies.items()
             with open(b_SESSION_FILE, 'wb') as f:
                 f.write(json.dumps(data).encode('utf-8'))
+            os.umask(oldmask)
 
 
 __all__ = ('OpenIdBaseClient', 'requires_login')
diff --git a/fedora/client/openidcclient.py b/fedora/client/openidcclient.py
new file mode 100644
index 0000000..c227b56
--- /dev/null
+++ b/fedora/client/openidcclient.py
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2016, 2017  Red Hat, Inc.
+# This file is part of python-fedora
+#
+# python-fedora is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# python-fedora is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with python-fedora; if not, see <http://www.gnu.org/licenses/>
+#
+
+"""Base client for applications relying on OpenID Connect for authentication.
+
+Implementation note: this implementation hardcodes certain endpoints at the IdP
+to the ones as implemented by Ipsilon 2.0 and higher.
+
+.. moduleauthor:: Patrick Uiterwijk <puiterwijk at redhat.com>
+
+.. versionadded: 0.3.35
+
+"""
+
+from fedora import __version__
+
+from openidc_client import OpenIDCClient
+
+PROD_IDP = 'https://id.fedoraproject.org/openidc/'
+STG_IDP = 'https://id.stg.fedoraproject.org/openidc/'
+DEV_IDP = 'https://iddev.fedorainfracloud.org/openidc/'
+
+
+class OpenIDCBaseClient(OpenIDCClient):
+    def __init__(self, app_identifier, id_provider, client_id, use_post=False,
+                 cachedir=None):
+        """Client for interacting with web services relying on OpenID Connect.
+
+        :arg app_identifier: Identifier for storage of retrieved tokens
+        :kwarg id_provider: URL of the identity provider to get tokens from
+        :kwarg client_id: The Client Identifier used to request credentials
+        :kwarg use_post: Whether to use POST submission of client secrets
+            rather than Authorization header
+        :kwarg cachedir: The directory in which to store the token caches. Will
+            be put through expanduer. Default is ~/.fedora. If this does not
+            exist and we are unable to create it, the OSError will e thrown up.
+        """
+        if cachedir is None:
+            cachedir = '~/.fedora/'
+        super(OpenIDCBaseClient, self).__init__(
+            self,
+            app_identifier=app_identifier,
+            id_provider=id_provider,
+            id_provider_mapping={'Token': 'Token',
+                                 'Authorization': 'Authorization'},
+            client_id=client_id,
+            use_post=use_post,
+            useragent='Python-Fedora/%s' % __version__,
+            cachedir=cachedir)
diff --git a/fedora/release.py b/fedora/release.py
index ae23c36..b70d1bf 100644
--- a/fedora/release.py
+++ b/fedora/release.py
@@ -4,7 +4,7 @@ Information about this python-fedora release
 
 
 NAME = 'python-fedora'
-VERSION = '0.8.0'
+VERSION = '0.9.0'
 DESCRIPTION = 'Python modules for interacting with Fedora Services'
 LONG_DESCRIPTION = '''
 The Fedora Project runs many different services.  These services help us to
@@ -13,7 +13,7 @@ This package contains software that helps us do that.
 '''
 AUTHOR = 'Toshio Kuratomi, Luke Macken, Ricky Elrod, Ralph Bean, Patrick Uiterwijk'
 EMAIL = 'admin at fedoraproject.org'
-COPYRIGHT = '2007-2016 Red Hat, Inc.'
+COPYRIGHT = '2007-2017 Red Hat, Inc.'
 URL = 'https://fedorahosted.org/python-fedora'
 DOWNLOAD_URL = 'https://pypi.python.org/pypi/python-fedora'
 LICENSE = 'LGPLv2+'
diff --git a/fedora/tg/utils.py b/fedora/tg/utils.py
index 4f18f31..9913df7 100644
--- a/fedora/tg/utils.py
+++ b/fedora/tg/utils.py
@@ -81,6 +81,11 @@ def url(tgpath, tgparams=None, **kwargs):
     '''
     if not isinstance(tgpath, six.string_types):
         tgpath = '/'.join(list(tgpath))
+    if not tgpath.startswith('/'):
+        # Do not allow the url() function to be used for external urls.
+        # This function is primarily used in redirect() calls, so this prevents
+        # covert redirects and thus CSRF leaking.
+        tgpath = '/'
     if tgpath.startswith('/'):
         webpath = (config.get('server.webpath') or '').rstrip('/')
         if tg_util.request_available():
diff --git a/python_fedora.egg-info/PKG-INFO b/python_fedora.egg-info/PKG-INFO
index 83258ca..c830284 100644
--- a/python_fedora.egg-info/PKG-INFO
+++ b/python_fedora.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: python-fedora
-Version: 0.8.0
+Version: 0.9.0
 Summary: Python modules for interacting with Fedora Services
 Home-page: https://fedorahosted.org/python-fedora
 Author: Toshio Kuratomi, Luke Macken, Ricky Elrod, Ralph Bean, Patrick Uiterwijk
diff --git a/python_fedora.egg-info/SOURCES.txt b/python_fedora.egg-info/SOURCES.txt
index 5d11162..3367d5f 100644
--- a/python_fedora.egg-info/SOURCES.txt
+++ b/python_fedora.egg-info/SOURCES.txt
@@ -34,6 +34,7 @@ fedora/client/bodhi.py
 fedora/client/fas2.py
 fedora/client/fasproxy.py
 fedora/client/openidbaseclient.py
+fedora/client/openidcclient.py
 fedora/client/openidproxyclient.py
 fedora/client/proxyclient.py
 fedora/client/wiki.py
diff --git a/python_fedora.egg-info/requires.txt b/python_fedora.egg-info/requires.txt
index fcbb584..dbb271d 100644
--- a/python_fedora.egg-info/requires.txt
+++ b/python_fedora.egg-info/requires.txt
@@ -5,6 +5,7 @@ beautifulsoup4
 urllib3
 six >= 1.4.0
 lockfile
+openidc-client
 
 [flask]
 Flask
diff --git a/setup.cfg b/setup.cfg
index 2533e23..9140104 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -11,5 +11,4 @@ exclude = setup.py,./fedora/tg/identity/soprovidercsrf.py,./fedora/tg2/templates
 [egg_info]
 tag_build = 
 tag_date = 0
-tag_svn_revision = 0
 
diff --git a/setup.py b/setup.py
index be0f27e..ee388be 100755
--- a/setup.py
+++ b/setup.py
@@ -28,6 +28,7 @@ setup(
         'urllib3',
         'six >= 1.4.0',
         'lockfile',
+        'openidc-client',
     ],
     extras_require={
         'tg': ['TurboGears >= 1.0.4', 'SQLAlchemy', 'decorator'],

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-fedora.git



More information about the Python-modules-commits mailing list