mirror of
https://github.com/openSUSE/osc.git
synced 2025-01-13 17:16:23 +01:00
Improve password handling
* Adapt do_config to use the new credentials manager implementation and add a --change-password option which can be used to change the password. * Adapt config_set_option to follow the change in do_config. * Split selection of the credentials manager descriptor to reuse it in do_config and interactive_config_setup. * Introduce new ConfigMissingCredentialsError which is raised in case of missing credentials (user or password). In this case the user will be asked to enter the new credentials.
This commit is contained in:
parent
36ec0c48d4
commit
cba4b58bbe
@ -158,6 +158,12 @@ class Osc(cmdln.Cmdln):
|
||||
conf.interactive_config_setup(e.file, e.url, initial=False)
|
||||
if try_again:
|
||||
self.postoptparse(try_again = False)
|
||||
except oscerr.ConfigMissingCredentialsError as e:
|
||||
print(e.msg)
|
||||
print('Please enter new credentials.')
|
||||
conf.interactive_config_setup(e.file, e.url, initial=False)
|
||||
if try_again:
|
||||
self.postoptparse(try_again = False)
|
||||
|
||||
self.options.verbose = conf.config['verbose']
|
||||
self.download_progress = None
|
||||
@ -8964,6 +8970,10 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
||||
help='indicates that the config value should be read from stdin')
|
||||
@cmdln.option('-p', '--prompt', action='store_true',
|
||||
help='prompt for a value')
|
||||
@cmdln.option('--change-password', action='store_true',
|
||||
help='Change password')
|
||||
@cmdln.option('--select-password-store', action='store_true',
|
||||
help='Change the password store')
|
||||
@cmdln.option('--no-echo', action='store_true',
|
||||
help='prompt for a value but do not echo entered characters')
|
||||
@cmdln.option('--dump', action='store_true',
|
||||
@ -8983,6 +8993,15 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
||||
${cmd_usage}
|
||||
${cmd_option_list}
|
||||
"""
|
||||
prompt_value = 'Value: '
|
||||
if opts.change_password:
|
||||
opts.no_echo = True
|
||||
opts.prompt = True
|
||||
opts.select_password_store = True
|
||||
prompt_value = 'Password: '
|
||||
if len(args) != 1:
|
||||
raise oscerr.WrongArgs('--change-password only needs the apiurl')
|
||||
args = [args[0], 'pass']
|
||||
if len(args) < 2 and not (opts.dump or opts.dump_full):
|
||||
raise oscerr.WrongArgs('Too few arguments')
|
||||
elif opts.dump or opts.dump_full:
|
||||
@ -9016,24 +9035,27 @@ Please submit there instead, or use --nodevelproject to force direct submission.
|
||||
elif opts.no_echo or opts.prompt:
|
||||
if opts.no_echo:
|
||||
import getpass
|
||||
inp = getpass.getpass('Value: ').strip()
|
||||
inp = getpass.getpass(prompt_value).strip()
|
||||
else:
|
||||
inp = raw_input('Value: ').strip()
|
||||
inp = raw_input(prompt_value).strip()
|
||||
if not inp:
|
||||
raise oscerr.WrongArgs('error: no value was entered')
|
||||
val = [inp]
|
||||
opt, newval = conf.config_set_option(section, opt, ' '.join(val), delete=opts.delete, update=True)
|
||||
creds_mgr_descr = None
|
||||
if opt == 'pass' and opts.select_password_store:
|
||||
creds_mgr_descr = conf.select_credentials_manager_descr()
|
||||
orig_opt = opt
|
||||
opt, newval = conf.config_set_option(section, opt, ' '.join(val), delete=opts.delete, update=True, creds_mgr_descr=creds_mgr_descr)
|
||||
if newval is None and opts.delete:
|
||||
print('\'%s\': \'%s\' got removed' % (section, opt))
|
||||
elif newval is None:
|
||||
print('\'%s\': \'%s\' is not set' % (section, opt))
|
||||
else:
|
||||
if opts.no_echo:
|
||||
if orig_opt == 'pass':
|
||||
print('Password has been changed.')
|
||||
elif opts.no_echo:
|
||||
# supress value
|
||||
print('\'%s\': set \'%s\'' % (section, opt))
|
||||
elif opt == 'pass' and not conf.config['plaintext_passwd'] and newval == 'your_password':
|
||||
opt, newval = conf.config_set_option(section, 'passx')
|
||||
print('\'%s\': \'pass\' was rewritten to \'passx\': \'%s\'' % (section, newval))
|
||||
else:
|
||||
print('\'%s\': \'%s\' is set to \'%s\'' % (section, opt, newval))
|
||||
|
||||
|
64
osc/conf.py
64
osc/conf.py
@ -657,7 +657,7 @@ def write_config(fname, cp):
|
||||
raise
|
||||
|
||||
|
||||
def config_set_option(section, opt, val=None, delete=False, update=True, **kwargs):
|
||||
def config_set_option(section, opt, val=None, delete=False, update=True, creds_mgr_descr=None, **kwargs):
|
||||
"""
|
||||
Sets a config option. If val is not specified the current/default value is
|
||||
returned. If val is specified, opt is set to val and the new value is returned.
|
||||
@ -693,11 +693,41 @@ def config_set_option(section, opt, val=None, delete=False, update=True, **kwarg
|
||||
raise oscerr.ConfigError('unknown config option \'%s\'' % opt, config['conffile'])
|
||||
run = False
|
||||
if val:
|
||||
cp.set(section, opt, val)
|
||||
write_config(config['conffile'], cp)
|
||||
if opt == 'pass':
|
||||
user = cp.get(section, 'user')
|
||||
creds_mgr = _get_credentials_manager(section, cp)
|
||||
if user is None and hasattr(creds_mgr, 'get_user'):
|
||||
user = creds_mgr.get_user(section)
|
||||
old_pw = creds_mgr.get_password(section, user, defer=False)
|
||||
try:
|
||||
creds_mgr.delete_password(section, user)
|
||||
if creds_mgr_descr:
|
||||
creds_mgr_new = creds_mgr_descr.create(cp)
|
||||
else:
|
||||
creds_mgr_new = creds_mgr
|
||||
creds_mgr_new.set_password(section, user, val)
|
||||
write_config(config['conffile'], cp)
|
||||
opt = credentials.AbstractCredentialsManager.config_entry
|
||||
old_pw = None
|
||||
finally:
|
||||
if old_pw is not None:
|
||||
creds_mgr.set_password(section, user, old_pw)
|
||||
# not nice, but needed if the Credentials Manager will change
|
||||
# something in cp
|
||||
write_config(config['conffile'], cp)
|
||||
else:
|
||||
cp.set(section, opt, val)
|
||||
write_config(config['conffile'], cp)
|
||||
run = True
|
||||
elif delete and cp.has_option(section, opt):
|
||||
cp.remove_option(section, opt)
|
||||
elif delete and (cp.has_option(section, opt) or opt == 'pass'):
|
||||
if opt == 'pass':
|
||||
user = cp.get(section, 'user')
|
||||
creds_mgr = _get_credentials_manager(section, cp)
|
||||
if user is None and hasattr(creds_mgr, 'get_user'):
|
||||
user = creds_mgr.get_user(section)
|
||||
creds_mgr.delete_password(section, user)
|
||||
else:
|
||||
cp.remove_option(section, opt)
|
||||
write_config(config['conffile'], cp)
|
||||
run = True
|
||||
if run and update:
|
||||
@ -857,10 +887,10 @@ def get_config(override_conffile=None,
|
||||
if user is None and hasattr(creds_mgr, 'get_user'):
|
||||
user = creds_mgr.get_user(url)
|
||||
if user is None:
|
||||
raise oscerr.ConfigError('No user found in section %s' % url, conffile)
|
||||
raise oscerr.ConfigMissingCredentialsError('No user found in section %s' % url, conffile, url)
|
||||
password = creds_mgr.get_password(url, user)
|
||||
if password is None:
|
||||
raise oscerr.ConfigError('No password found in section %s' % url, conffile)
|
||||
raise oscerr.ConfigMissingCredentialsError('No password found in section %s' % url, conffile, url)
|
||||
|
||||
if cp.has_option(url, 'http_headers'):
|
||||
http_headers = cp.get(url, 'http_headers')
|
||||
@ -972,6 +1002,16 @@ def identify_conf():
|
||||
def interactive_config_setup(conffile, apiurl, initial=True):
|
||||
user = raw_input('Username: ')
|
||||
passwd = getpass.getpass()
|
||||
creds_mgr_descr = select_credentials_manager_descr()
|
||||
if initial:
|
||||
config = {'user': user, 'pass': passwd}
|
||||
if apiurl:
|
||||
config['apiurl'] = apiurl
|
||||
write_initial_config(conffile, config, creds_mgr_descriptor=creds_mgr_descr)
|
||||
else:
|
||||
add_section(conffile, apiurl, user, passwd, creds_mgr_descriptor=creds_mgr_descr)
|
||||
|
||||
def select_credentials_manager_descr():
|
||||
if not credentials.has_keyring_support():
|
||||
print('To use keyrings please install python-keyring.')
|
||||
creds_mgr_descriptors = credentials.get_credentials_manager_descriptors()
|
||||
@ -983,14 +1023,6 @@ def interactive_config_setup(conffile, apiurl, initial=True):
|
||||
i = int(i) - 1
|
||||
if i < 0 or i >= len(creds_mgr_descriptors):
|
||||
sys.exit('Invalid selection')
|
||||
creds_mgr_descr = creds_mgr_descriptors[i]
|
||||
if initial:
|
||||
config = {'user': user, 'pass': passwd}
|
||||
if apiurl:
|
||||
config['apiurl'] = apiurl
|
||||
write_initial_config(conffile, config, creds_mgr_descriptor=creds_mgr_descr)
|
||||
else:
|
||||
add_section(conffile, apiurl, user, passwd, creds_mgr_descriptor=creds_mgr_descr)
|
||||
|
||||
return creds_mgr_descriptors[i]
|
||||
|
||||
# vim: sw=4 et
|
||||
|
@ -28,6 +28,11 @@ class ConfigMissingApiurl(ConfigError):
|
||||
ConfigError.__init__(self, msg, fname)
|
||||
self.url = url
|
||||
|
||||
class ConfigMissingCredentialsError(ConfigError):
|
||||
def __init__(self, msg, fname, url):
|
||||
ConfigError.__init__(self, msg, fname)
|
||||
self.url = url
|
||||
|
||||
class APIError(OscBaseError):
|
||||
"""Exception raised when there is an error in the output from the API"""
|
||||
def __init__(self, msg):
|
||||
|
Loading…
Reference in New Issue
Block a user