mirror of
https://github.com/openSUSE/osc.git
synced 2025-02-04 02:26:16 +01:00
Merge commit 'refs/pull/1022/head' of github.com:openSUSE/osc
Only ask for a password if it is really needed for authentication. The new lazy password approach is much smarter than the old callable hack. That's why we deprecate returning a callable from AbstractCredentialsManager.get_password. The current compatibility code for a callable will be removed in the near future. Minor nitpick: actually it would have been "cleaner" to introduce a new subclass like an AbstractLazyPasswordCredentialsManager that encapsulates the lazy password behavior. Currently, if, for instance, a credentials manager is always non-lazy it would just override get_password but still inherits the abstract (and unused) _get_password method.
This commit is contained in:
commit
90ccc84f95
@ -765,7 +765,7 @@ def config_set_option(section, opt, val=None, delete=False, update=True, creds_m
|
|||||||
# change password store
|
# change password store
|
||||||
creds_mgr = _get_credentials_manager(section, cp)
|
creds_mgr = _get_credentials_manager(section, cp)
|
||||||
user = _extract_user_compat(cp, section, creds_mgr)
|
user = _extract_user_compat(cp, section, creds_mgr)
|
||||||
val = creds_mgr.get_password(section, user)
|
val = creds_mgr.get_password(section, user, defer=False)
|
||||||
|
|
||||||
run = False
|
run = False
|
||||||
if val:
|
if val:
|
||||||
@ -885,6 +885,8 @@ class APIHostOptionsEntry(dict):
|
|||||||
def __getitem__(self, key, *args, **kwargs):
|
def __getitem__(self, key, *args, **kwargs):
|
||||||
value = super(self.__class__, self).__getitem__(key, *args, **kwargs)
|
value = super(self.__class__, self).__getitem__(key, *args, **kwargs)
|
||||||
if key == 'pass' and callable(value):
|
if key == 'pass' and callable(value):
|
||||||
|
print('Warning: use of a deprecated credentials manager API.',
|
||||||
|
file=sys.stderr)
|
||||||
value = value()
|
value = value()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@ -980,7 +982,7 @@ def get_config(override_conffile=None,
|
|||||||
user = _extract_user_compat(cp, url, creds_mgr)
|
user = _extract_user_compat(cp, url, creds_mgr)
|
||||||
if user is None:
|
if user is None:
|
||||||
raise oscerr.ConfigMissingCredentialsError('No user found in section %s' % url, conffile, url)
|
raise oscerr.ConfigMissingCredentialsError('No user found in section %s' % url, conffile, url)
|
||||||
password = creds_mgr.get_password(url, user)
|
password = creds_mgr.get_password(url, user, defer=True)
|
||||||
if password is None:
|
if password is None:
|
||||||
raise oscerr.ConfigMissingCredentialsError('No password found in section %s' % url, conffile, url)
|
raise oscerr.ConfigMissingCredentialsError('No password found in section %s' % url, conffile, url)
|
||||||
|
|
||||||
|
@ -33,6 +33,31 @@ from . import conf
|
|||||||
from . import oscerr
|
from . import oscerr
|
||||||
|
|
||||||
|
|
||||||
|
class _LazyPassword(object):
|
||||||
|
def __init__(self, pwfunc):
|
||||||
|
self._pwfunc = pwfunc
|
||||||
|
self._password = None
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self._password is None:
|
||||||
|
self._password = self._pwfunc()
|
||||||
|
if self._password is None:
|
||||||
|
raise oscerr.OscIOError(None, 'Unable to retrieve password')
|
||||||
|
return self._password
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(str(self))
|
||||||
|
|
||||||
|
def __add__(self, other):
|
||||||
|
return str(self) + other
|
||||||
|
|
||||||
|
def __radd__(self, other):
|
||||||
|
return other + str(self)
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return getattr(str(self), name)
|
||||||
|
|
||||||
|
|
||||||
class AbstractCredentialsManagerDescriptor(object):
|
class AbstractCredentialsManagerDescriptor(object):
|
||||||
def name(self):
|
def name(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
@ -64,14 +89,15 @@ class AbstractCredentialsManager(object):
|
|||||||
def create(cls, cp, options):
|
def create(cls, cp, options):
|
||||||
return cls(cp, options)
|
return cls(cp, options)
|
||||||
|
|
||||||
def get_password(self, url, user, defer=True):
|
def _get_password(self, url, user):
|
||||||
# If defer is True a callable can be returned
|
|
||||||
# and the password is retrieved if the callable
|
|
||||||
# is called. Implementations are free to ignore
|
|
||||||
# defer parameter and can directly return the password.
|
|
||||||
# If defer is False the password is directly returned.
|
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def get_password(self, url, user, defer=True):
|
||||||
|
if defer:
|
||||||
|
return _LazyPassword(lambda: self._get_password(url, user))
|
||||||
|
else:
|
||||||
|
return self._get_password(url, user)
|
||||||
|
|
||||||
def set_password(self, url, user, password):
|
def set_password(self, url, user, password):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@ -162,10 +188,10 @@ class TransientCredentialsManager(AbstractCredentialsManager):
|
|||||||
if options is not None:
|
if options is not None:
|
||||||
raise RuntimeError('options must be None')
|
raise RuntimeError('options must be None')
|
||||||
|
|
||||||
def get_password(self, url, user, defer=True):
|
def _get_password(self, url, user):
|
||||||
if defer:
|
if self._password is None:
|
||||||
return self
|
self._password = getpass.getpass('Password: ')
|
||||||
return self()
|
return self._password
|
||||||
|
|
||||||
def set_password(self, url, user, password):
|
def set_password(self, url, user, password):
|
||||||
self._password = password
|
self._password = password
|
||||||
@ -174,11 +200,6 @@ class TransientCredentialsManager(AbstractCredentialsManager):
|
|||||||
def delete_password(self, url, user):
|
def delete_password(self, url, user):
|
||||||
self._password = None
|
self._password = None
|
||||||
|
|
||||||
def __call__(self):
|
|
||||||
if self._password is None:
|
|
||||||
self._password = getpass.getpass('Password: ')
|
|
||||||
return self._password
|
|
||||||
|
|
||||||
|
|
||||||
class TransientDescriptor(AbstractCredentialsManagerDescriptor):
|
class TransientDescriptor(AbstractCredentialsManagerDescriptor):
|
||||||
def name(self):
|
def name(self):
|
||||||
@ -214,7 +235,7 @@ class KeyringCredentialsManager(AbstractCredentialsManager):
|
|||||||
return None
|
return None
|
||||||
return super(cls, cls).create(cp, options)
|
return super(cls, cls).create(cp, options)
|
||||||
|
|
||||||
def get_password(self, url, user, defer=True):
|
def _get_password(self, url, user):
|
||||||
self._load_backend()
|
self._load_backend()
|
||||||
return keyring.get_password(urlsplit(url)[1], user)
|
return keyring.get_password(urlsplit(url)[1], user)
|
||||||
|
|
||||||
@ -265,7 +286,7 @@ class GnomeKeyringCredentialsManager(AbstractCredentialsManager):
|
|||||||
return None
|
return None
|
||||||
return super(cls, cls).create(cp, options)
|
return super(cls, cls).create(cp, options)
|
||||||
|
|
||||||
def get_password(self, url, user, defer=True):
|
def _get_password(self, url, user):
|
||||||
gk_data = self._keyring_data(url, user)
|
gk_data = self._keyring_data(url, user)
|
||||||
if gk_data is None:
|
if gk_data is None:
|
||||||
return None
|
return None
|
||||||
|
Loading…
Reference in New Issue
Block a user