Exemple #1
0
def config_set_option(section, opt, val=None, delete=False, update=True, **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.
    If an option was modified get_config is called with **kwargs unless update is set
    to False (override_conffile defaults to config['conffile']).
    If val is not specified and delete is True then the option is removed from the
    config/reset to the default value.
    """
    cp = get_configParser(config['conffile'])
    # don't allow "internal" options
    general_opts = [i for i in DEFAULTS.keys() if not i in ['user', 'pass', 'passx']]
    if section != 'general':
        section = config['apiurl_aliases'].get(section, section)
        scheme, host, path = \
            parse_apisrv_url(config.get('scheme', 'https'), section)
        section = urljoin(scheme, host, path)

    sections = {}
    for url in cp.sections():
        if url == 'general':
            sections[url] = url
        else:
            scheme, host, path = \
                parse_apisrv_url(config.get('scheme', 'https'), url)
            apiurl = urljoin(scheme, host, path)
            sections[apiurl] = url

    section = sections.get(section.rstrip('/'), section)
    if not section in cp.sections():
        raise oscerr.ConfigError('unknown section \'%s\'' % section, config['conffile'])
    if section == 'general' and not opt in general_opts or \
       section != 'general' and not opt in api_host_options:
        raise oscerr.ConfigError('unknown config option \'%s\'' % opt, config['conffile'])
    run = False
    if val:
        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)
        write_config(config['conffile'], cp)
        run = True
    if run and update:
        kw = {'override_conffile': config['conffile'],
              'override_no_keyring': config['use_keyring'],
              'override_no_gnome_keyring': config['gnome_keyring']}
        kw.update(kwargs)
        get_config(**kw)
    if cp.has_option(section, opt):
        return (opt, cp.get(section, opt, raw=True))
    return (opt, None)
Exemple #2
0
def get_config(override_conffile=None,
               override_apiurl=None,
               override_debug=None,
               override_http_debug=None,
               override_http_full_debug=None,
               override_traceback=None,
               override_post_mortem=None,
               override_no_keyring=None,
               override_no_gnome_keyring=None,
               override_verbose=None):
    """do the actual work (see module documentation)"""
    global config

    conffile = override_conffile or os.environ.get('OSC_CONFIG', '~/.oscrc')
    conffile = os.path.expanduser(conffile)

    if not os.path.exists(conffile):
        raise oscerr.NoConfigfile(conffile, \
                                  account_not_configured_text % conffile)

    # okay, we made sure that .oscrc exists

    # make sure it is not world readable, it may contain a password.
    os.chmod(conffile, 0600)

    cp = get_configParser(conffile)

    if not cp.has_section('general'):
        # FIXME: it might be sufficient to just assume defaults?
        msg = config_incomplete_text % conffile
        msg += new_conf_template % DEFAULTS
        raise oscerr.ConfigError(msg, conffile)

    config = dict(cp.items('general', raw=1))
    config['conffile'] = conffile

    for i in boolean_opts:
        try:
            config[i] = cp.getboolean('general', i)
        except ValueError, e:
            raise oscerr.ConfigError(
                'cannot parse \'%s\' setting: ' % i + str(e), conffile)
Exemple #3
0
def get_config(override_conffile=None,
               override_apiurl=None,
               override_debug=None,
               override_http_debug=None,
               override_http_full_debug=None,
               override_traceback=None,
               override_post_mortem=None,
               override_no_keyring=None,
               override_no_gnome_keyring=None,
               override_verbose=None):
    """do the actual work (see module documentation)"""
    global config

    conffile = override_conffile or os.environ.get('OSC_CONFIG', '~/.oscrc')
    conffile = os.path.expanduser(conffile)

    if not os.path.exists(conffile):
        raise oscerr.NoConfigfile(conffile, \
                                  account_not_configured_text % conffile)

    # okay, we made sure that .oscrc exists

    # make sure it is not world readable, it may contain a password.
    os.chmod(conffile, 0o600)

    cp = get_configParser(conffile)

    if not cp.has_section('general'):
        # FIXME: it might be sufficient to just assume defaults?
        msg = config_incomplete_text % conffile
        msg += new_conf_template % DEFAULTS
        raise oscerr.ConfigError(msg, conffile)

    config = dict(cp.items('general', raw=1))
    config['conffile'] = conffile

    for i in boolean_opts:
        try:
            config[i] = cp.getboolean('general', i)
        except ValueError as e:
            raise oscerr.ConfigError(
                'cannot parse \'%s\' setting: ' % i + str(e), conffile)

    config['packagecachedir'] = os.path.expanduser(config['packagecachedir'])
    config['exclude_glob'] = config['exclude_glob'].split()

    re_clist = re.compile('[, ]+')
    config['extra-pkgs'] = [
        i.strip() for i in re_clist.split(config['extra-pkgs'].strip()) if i
    ]

    # collect the usernames, passwords and additional options for each api host
    api_host_options = {}

    # Regexp to split extra http headers into a dictionary
    # the text to be matched looks essentially looks this:
    # "Attribute1: value1, Attribute2: value2, ..."
    # there may be arbitray leading and intermitting whitespace.
    # the following regexp does _not_ support quoted commas within the value.
    http_header_regexp = re.compile(r"\s*(.*?)\s*:\s*(.*?)\s*(?:,\s*|\Z)")

    # override values which we were called with
    # This needs to be done before processing API sections as it might be already used there
    if override_no_keyring:
        config['use_keyring'] = False
    if override_no_gnome_keyring:
        config['gnome_keyring'] = False

    aliases = {}
    for url in [x for x in cp.sections() if x != 'general']:
        # backward compatiblity
        scheme, host, path = parse_apisrv_url(config.get('scheme', 'https'),
                                              url)
        apiurl = urljoin(scheme, host, path)
        user = None
        password = None
        if config['use_keyring'] and GENERIC_KEYRING:
            try:
                # Read from keyring lib if available
                user = cp.get(url, 'user', raw=True)
                password = str(keyring.get_password(host, user))
            except:
                # Fallback to file based auth.
                pass
        elif config['gnome_keyring'] and GNOME_KEYRING:
            # Read from gnome keyring if available
            try:
                gk_data = gnomekeyring.find_network_password_sync(
                    protocol=scheme, server=host, object=path)
                if not 'user' in gk_data[0]:
                    raise oscerr.ConfigError('no user found in keyring',
                                             conffile)
                user = gk_data[0]['user']
                if 'password' in gk_data[0]:
                    password = str(gk_data[0]['password'])
                else:
                    # this is most likely an error
                    print('warning: no password found in keyring',
                          file=sys.stderr)
            except gnomekeyring.NoMatchError:
                # Fallback to file based auth.
                pass

        if not user is None and len(user) == 0:
            user = None
            print('Warning: blank user in the keyring for the ' \
                'apiurl %s.\nPlease fix your keyring entry.', file=sys.stderr)

        if user is not None and password is None:
            err = (
                'no password defined for "%s".\nPlease fix your keyring '
                'entry or gnome-keyring setup.\nAssuming an empty password.' %
                url)
            print(err, file=sys.stderr)
            password = ''

        # Read credentials from config
        if user is None:
            #FIXME: this could actually be the ideal spot to take defaults
            #from the general section.
            user = cp.get(url, 'user',
                          raw=True)  # need to set raw to prevent '%' expansion
            password = cp.get(url, 'pass', raw=True)  # especially on password!
            try:
                passwordx = passx_decode(cp.get(
                    url, 'passx', raw=True))  # especially on password!
            except:
                passwordx = ''

            if password == None or password == 'your_password':
                password = ''

            if user is None or user == '':
                raise oscerr.ConfigError(
                    'user is blank for %s, please delete or complete the "user=" entry in %s.'
                    % (apiurl, config['conffile']), config['conffile'])

            if config['plaintext_passwd'] and passwordx or not config[
                    'plaintext_passwd'] and password:
                if config['plaintext_passwd']:
                    if password != passwordx:
                        print('%s: rewriting from encoded pass to plain pass' %
                              url,
                              file=sys.stderr)
                    add_section(conffile, url, user, passwordx)
                    password = passwordx
                else:
                    if password != passwordx:
                        print('%s: rewriting from plain pass to encoded pass' %
                              url,
                              file=sys.stderr)
                    add_section(conffile, url, user, password)

            if not config['plaintext_passwd']:
                password = passwordx

        if cp.has_option(url, 'http_headers'):
            http_headers = cp.get(url, 'http_headers')
            http_headers = http_header_regexp.findall(http_headers)
        else:
            http_headers = []
        if cp.has_option(url, 'aliases'):
            for i in cp.get(url, 'aliases').split(','):
                key = i.strip()
                if key == '':
                    continue
                if key in aliases:
                    msg = 'duplicate alias entry: \'%s\' is already used for another apiurl' % key
                    raise oscerr.ConfigError(msg, conffile)
                aliases[key] = url

        api_host_options[apiurl] = {
            'user': user,
            'pass': password,
            'http_headers': http_headers
        }

        optional = ('email', 'sslcertck', 'cafile', 'capath')
        for key in optional:
            if cp.has_option(url, key):
                if key == 'sslcertck':
                    api_host_options[apiurl][key] = cp.getboolean(url, key)
                else:
                    api_host_options[apiurl][key] = cp.get(url, key)
        if cp.has_option(url, 'build-root', proper=True):
            api_host_options[apiurl]['build-root'] = cp.get(url,
                                                            'build-root',
                                                            raw=True)

        if not 'sslcertck' in api_host_options[apiurl]:
            api_host_options[apiurl]['sslcertck'] = True

        if scheme == 'http':
            api_host_options[apiurl]['sslcertck'] = False

        if cp.has_option(url, 'trusted_prj'):
            api_host_options[apiurl]['trusted_prj'] = cp.get(
                url, 'trusted_prj').split(' ')
        else:
            api_host_options[apiurl]['trusted_prj'] = []

    # add the auth data we collected to the config dict
    config['api_host_options'] = api_host_options
    config['apiurl_aliases'] = aliases

    apiurl = aliases.get(config['apiurl'], config['apiurl'])
    config['apiurl'] = urljoin(*parse_apisrv_url(None, apiurl))
    # backward compatibility
    if 'apisrv' in config:
        apisrv = config['apisrv'].lstrip('http://')
        apisrv = apisrv.lstrip('https://')
        scheme = config.get('scheme', 'https')
        config['apiurl'] = urljoin(scheme, apisrv)
    if 'apisrc' in config or 'scheme' in config:
        print('Warning: Use of the \'scheme\' or \'apisrv\' in ~/.oscrc is deprecated!\n' \
                            'Warning: See README for migration details.', file=sys.stderr)
    if 'build_platform' in config:
        print(
            'Warning: Use of \'build_platform\' config option is deprecated! (use \'build_repository\' instead)',
            file=sys.stderr)
        config['build_repository'] = config['build_platform']

    config['verbose'] = int(config['verbose'])
    # override values which we were called with
    if override_verbose:
        config['verbose'] = override_verbose + 1

    if override_debug:
        config['debug'] = override_debug
    if override_http_debug:
        config['http_debug'] = override_http_debug
    if override_http_full_debug:
        config['http_debug'] = override_http_full_debug or config['http_debug']
        config['http_full_debug'] = override_http_full_debug
    if override_traceback:
        config['traceback'] = override_traceback
    if override_post_mortem:
        config['post_mortem'] = override_post_mortem
    if override_apiurl:
        apiurl = aliases.get(override_apiurl, override_apiurl)
        # check if apiurl is a valid url
        config['apiurl'] = urljoin(*parse_apisrv_url(None, apiurl))

    # XXX unless config['user'] goes away (and is replaced with a handy function, or
    # config becomes an object, even better), set the global 'user' here as well,
    # provided that there _are_ credentials for the chosen apiurl:
    try:
        config['user'] = get_apiurl_usr(config['apiurl'])
    except oscerr.ConfigMissingApiurl as e:
        e.msg = config_missing_apiurl_text % config['apiurl']
        e.file = conffile
        raise e

    # finally, initialize urllib2 for to use the credentials for Basic Authentication
    init_basicauth(config)
Exemple #4
0
def get_config(override_conffile=None,
               override_apiurl=None,
               override_debug=None,
               override_http_debug=None,
               override_http_full_debug=None,
               override_traceback=None,
               override_post_mortem=None,
               override_no_keyring=None,
               override_no_gnome_keyring=None,
               override_verbose=None):
    """do the actual work (see module documentation)"""
    global config

    if not override_conffile:
        conffile = identify_conf()
    else:
        conffile = override_conffile

    conffile = os.path.expanduser(conffile)
    if not os.path.exists(conffile):
        raise oscerr.NoConfigfile(conffile, \
                                  account_not_configured_text % conffile)

    # okay, we made sure that oscrc exists

    # make sure it is not world readable, it may contain a password.
    os.chmod(conffile, 0o600)

    cp = get_configParser(conffile)

    if not cp.has_section('general'):
        # FIXME: it might be sufficient to just assume defaults?
        msg = config_incomplete_text % conffile
        msg += new_conf_template % DEFAULTS
        raise oscerr.ConfigError(msg, conffile)

    config = dict(cp.items('general', raw=1))
    config['conffile'] = conffile

    typed_opts = ((boolean_opts, cp.getboolean), (integer_opts, cp.getint))
    for opts, meth in typed_opts:
        for opt in opts:
            try:
                config[opt] = meth('general', opt)
            except ValueError as e:
                msg = 'cannot parse \'%s\' setting: %s' % (opt, str(e))
                raise oscerr.ConfigError(msg, conffile)

    config['packagecachedir'] = os.path.expanduser(config['packagecachedir'])
    config['exclude_glob'] = config['exclude_glob'].split()

    re_clist = re.compile('[, ]+')
    config['extra-pkgs'] = [
        i.strip() for i in re_clist.split(config['extra-pkgs'].strip()) if i
    ]

    # collect the usernames, passwords and additional options for each api host
    api_host_options = {}

    # Regexp to split extra http headers into a dictionary
    # the text to be matched looks essentially looks this:
    # "Attribute1: value1, Attribute2: value2, ..."
    # there may be arbitray leading and intermitting whitespace.
    # the following regexp does _not_ support quoted commas within the value.
    http_header_regexp = re.compile(r"\s*(.*?)\s*:\s*(.*?)\s*(?:,\s*|\Z)")

    # override values which we were called with
    # This needs to be done before processing API sections as it might be already used there
    if override_no_keyring:
        config['use_keyring'] = False
    if override_no_gnome_keyring:
        config['gnome_keyring'] = False

    aliases = {}
    for url in [x for x in cp.sections() if x != 'general']:
        # backward compatiblity
        scheme, host, path = parse_apisrv_url(config.get('scheme', 'https'),
                                              url)
        apiurl = urljoin(scheme, host, path)
        creds_mgr = _get_credentials_manager(url, cp)
        # if the deprecated gnomekeyring is used we should use the apiurl instead of url
        # (that's what the old code did), but this makes things more complex
        # (also, it is very unlikely that url and apiurl differ)
        user = _extract_user_compat(cp, url, creds_mgr)
        if user is None:
            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.ConfigMissingCredentialsError(
                'No password found in section %s' % url, conffile, url)

        if cp.has_option(url, 'http_headers'):
            http_headers = cp.get(url, 'http_headers')
            http_headers = http_header_regexp.findall(http_headers)
        else:
            http_headers = []
        if cp.has_option(url, 'aliases'):
            for i in cp.get(url, 'aliases').split(','):
                key = i.strip()
                if key == '':
                    continue
                if key in aliases:
                    msg = 'duplicate alias entry: \'%s\' is already used for another apiurl' % key
                    raise oscerr.ConfigError(msg, conffile)
                aliases[key] = url

        entry = {'user': user, 'pass': password, 'http_headers': http_headers}
        api_host_options[apiurl] = APIHostOptionsEntry(entry)

        optional = ('realname', 'email', 'sslcertck', 'cafile', 'capath')
        for key in optional:
            if cp.has_option(url, key):
                if key == 'sslcertck':
                    api_host_options[apiurl][key] = cp.getboolean(url, key)
                else:
                    api_host_options[apiurl][key] = cp.get(url, key)
        if cp.has_option(url, 'build-root', proper=True):
            api_host_options[apiurl]['build-root'] = cp.get(url,
                                                            'build-root',
                                                            raw=True)

        if not 'sslcertck' in api_host_options[apiurl]:
            api_host_options[apiurl]['sslcertck'] = True

        if scheme == 'http':
            api_host_options[apiurl]['sslcertck'] = False

        if cp.has_option(url, 'trusted_prj'):
            api_host_options[apiurl]['trusted_prj'] = cp.get(
                url, 'trusted_prj').split(' ')
        else:
            api_host_options[apiurl]['trusted_prj'] = []

    # add the auth data we collected to the config dict
    config['api_host_options'] = api_host_options
    config['apiurl_aliases'] = aliases

    apiurl = aliases.get(config['apiurl'], config['apiurl'])
    config['apiurl'] = urljoin(*parse_apisrv_url(None, apiurl))
    # backward compatibility
    if 'apisrv' in config:
        apisrv = config['apisrv'].lstrip('http://')
        apisrv = apisrv.lstrip('https://')
        scheme = config.get('scheme', 'https')
        config['apiurl'] = urljoin(scheme, apisrv)
    if 'apisrc' in config or 'scheme' in config:
        print('Warning: Use of the \'scheme\' or \'apisrv\' in oscrc is deprecated!\n' \
                            'Warning: See README for migration details.', file=sys.stderr)
    if 'build_platform' in config:
        print(
            'Warning: Use of \'build_platform\' config option is deprecated! (use \'build_repository\' instead)',
            file=sys.stderr)
        config['build_repository'] = config['build_platform']
    if config['plaintext_passwd']:
        print(
            'The \'plaintext_passwd\' option is deprecated and will be ignored',
            file=sys.stderr)

    config['verbose'] = int(config['verbose'])
    # override values which we were called with
    if override_verbose:
        config['verbose'] = override_verbose + 1

    if override_debug:
        config['debug'] = override_debug
    if override_http_debug:
        config['http_debug'] = override_http_debug
    if override_http_full_debug:
        config['http_debug'] = override_http_full_debug or config['http_debug']
        config['http_full_debug'] = override_http_full_debug
    if override_traceback:
        config['traceback'] = override_traceback
    if override_post_mortem:
        config['post_mortem'] = override_post_mortem
    if override_apiurl:
        apiurl = aliases.get(override_apiurl, override_apiurl)
        # check if apiurl is a valid url
        config['apiurl'] = urljoin(*parse_apisrv_url(None, apiurl))

    # XXX unless config['user'] goes away (and is replaced with a handy function, or
    # config becomes an object, even better), set the global 'user' here as well,
    # provided that there _are_ credentials for the chosen apiurl:
    try:
        config['user'] = get_apiurl_usr(config['apiurl'])
    except oscerr.ConfigMissingApiurl as e:
        e.msg = config_missing_apiurl_text % config['apiurl']
        e.file = conffile
        raise e

    # finally, initialize urllib2 for to use the credentials for Basic Authentication
    init_basicauth(config, os.stat(conffile).st_mtime)
Exemple #5
0
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.
    If an option was modified get_config is called with **kwargs unless update is set
    to False (override_conffile defaults to config['conffile']).
    If val is not specified and delete is True then the option is removed from the
    config/reset to the default value.
    """
    cp = get_configParser(config['conffile'])
    # don't allow "internal" options
    general_opts = [
        i for i in DEFAULTS.keys() if not i in ['user', 'pass', 'passx']
    ]
    if section != 'general':
        section = config['apiurl_aliases'].get(section, section)
        scheme, host, path = \
            parse_apisrv_url(config.get('scheme', 'https'), section)
        section = urljoin(scheme, host, path)

    sections = {}
    for url in cp.sections():
        if url == 'general':
            sections[url] = url
        else:
            scheme, host, path = \
                parse_apisrv_url(config.get('scheme', 'https'), url)
            apiurl = urljoin(scheme, host, path)
            sections[apiurl] = url

    section = sections.get(section.rstrip('/'), section)
    if not section in cp.sections():
        raise oscerr.ConfigError('unknown section \'%s\'' % section,
                                 config['conffile'])
    if section == 'general' and not opt in general_opts or \
       section != 'general' and not opt in api_host_options:
        raise oscerr.ConfigError('unknown config option \'%s\'' % opt,
                                 config['conffile'])
    run = False
    if val:
        if opt == 'pass':
            creds_mgr = _get_credentials_manager(section, cp)
            user = _extract_user_compat(cp, section, creds_mgr)
            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) or opt == 'pass'):
        if opt == 'pass':
            creds_mgr = _get_credentials_manager(section, cp)
            user = _extract_user_compar(cp, section, creds_mgr)
            creds_mgr.delete_password(section, user)
        else:
            cp.remove_option(section, opt)
        write_config(config['conffile'], cp)
        run = True
    if run and update:
        kw = {
            'override_conffile': config['conffile'],
            'override_no_keyring': config['use_keyring'],
            'override_no_gnome_keyring': config['gnome_keyring']
        }
        kw.update(kwargs)
        get_config(**kw)
    if cp.has_option(section, opt):
        return (opt, cp.get(section, opt, raw=True))
    return (opt, None)
Exemple #6
0
        # Read credentials from config
        if user is None:
            #FIXME: this could actually be the ideal spot to take defaults
            #from the general section.
            user = cp.get(url, 'user', raw=True)        # need to set raw to prevent '%' expansion
            password = cp.get(url, 'pass', raw=True)    # especially on password!
            try:
                passwordx = cp.get(url, 'passx', raw=True).decode('base64').decode('bz2')  # especially on password!
            except:
                passwordx = ''

            if password == None or password == 'your_password':
                password = ''

            if user is None or user == '':
                raise oscerr.ConfigError('user is blank for %s, please delete of complete the "user=" entry in %s.' % (apiurl, config['conffile']), config['conffile'])

            if config['plaintext_passwd'] and passwordx or not config['plaintext_passwd'] and password:
                if config['plaintext_passwd']:
                    if password != passwordx:
                        print >>sys.stderr, '%s: rewriting from encoded pass to plain pass' % url
                    add_section(conffile, url, user, passwordx)
                    password = passwordx
                else:
                    if password != passwordx:
                        print >>sys.stderr, '%s: rewriting from plain pass to encoded pass' % url
                    add_section(conffile, url, user, password)

            if not config['plaintext_passwd']:
                password = passwordx