From 5fa1e73db6fbd80e7f08cf54c59c7cc8dd4998be Mon Sep 17 00:00:00 2001 From: lethliel Date: Wed, 16 Oct 2019 10:41:06 +0200 Subject: [PATCH] catch configured keyring without module installed If a python-keyring based backend is configured, but python-keyring is not installed osc fails without giving the user the opportunity to continue. This introduces a new class method `create` for the AbstractCredentialsManager. The CredentialsManagers for the backends that use a 3rd party software can now check if the software is present in its own create method. --- osc/conf.py | 7 ++++++- osc/credentials.py | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/osc/conf.py b/osc/conf.py index 9b518f0b..3544e691 100644 --- a/osc/conf.py +++ b/osc/conf.py @@ -789,7 +789,12 @@ def add_section(filename, url, user, passwd, creds_mgr_descriptor=None): def _get_credentials_manager(url, cp): if cp.has_option(url, credentials.AbstractCredentialsManager.config_entry): - return credentials.create_credentials_manager(url, cp) + creds_mgr = credentials.create_credentials_manager(url, cp) + if creds_mgr is None: + msg = 'Unable to instantiate creds mgr (section: %s)' % url + conffile = get_configParser.conffile + raise oscerr.ConfigMissingCredentialsError(msg, conffile, url) + return creds_mgr if config['use_keyring'] and GENERIC_KEYRING: return credentials.get_keyring_credentials_manager(cp) elif config['gnome_keyring'] and GNOME_KEYRING: diff --git a/osc/credentials.py b/osc/credentials.py index ba103d92..59c17ace 100644 --- a/osc/credentials.py +++ b/osc/credentials.py @@ -38,6 +38,10 @@ class AbstractCredentialsManager(object): self._cp = cp self._process_options(options) + @classmethod + def create(cls, cp, options): + return cls(cp, options) + def get_password(self, url, user, defer=True): # If defer is True a callable can be returned # and the password is retrieved if the callable @@ -166,6 +170,12 @@ class KeyringCredentialsManager(AbstractCredentialsManager): keyring_backend = keyring.core.load_keyring(self._backend_cls_name) keyring.set_keyring(keyring_backend) + @classmethod + def create(cls, cp, options): + if not has_keyring_support(): + return None + return super(cls, cls).create(cp, options) + def get_password(self, url, user, defer=True): self._load_backend() return keyring.get_password(self._appname, user) @@ -197,6 +207,12 @@ class KeyringCredentialsDescriptor(AbstractCredentialsManagerDescriptor): class GnomeKeyringCredentialsManager(AbstractCredentialsManager): + @classmethod + def create(cls, cp, options): + if gnomekeyring is None: + return None + return super(cls, cls).create(cp, options) + def get_password(self, url, user, defer=True): gk_data = self._keyring_data(url, user) if gk_data is None: @@ -288,7 +304,7 @@ def create_credentials_manager(url, cp): creds_mgr_cls = config_entry options = None mod, cls = creds_mgr_cls.rsplit('.', 1) - return getattr(importlib.import_module(mod), cls)(cp, options) + return getattr(importlib.import_module(mod), cls).create(cp, options) def qualified_name(obj):