Permalink
Browse files

osc can now store credentials in Gnome keyring if it is available (bn…

…c#460540)
  • Loading branch information...
1 parent 72532fb commit 7074362e90afb0ed6eac7fdd94537e504b9a441b @nijel nijel committed May 11, 2009
Showing with 94 additions and 13 deletions.
  1. +1 −0 NEWS
  2. +9 −0 README
  3. +5 −8 osc/commandline.py
  4. +79 −5 osc/conf.py
View
1 NEWS
@@ -12,6 +12,7 @@
- osc rlog now works with srcmd5 also
- plugins now should be placed in /usr/lib/osc-plugins to match FHS (the /var path is still supported though)
- osc now includes automatically generated man page
+- osc can now store credentials in Gnome keyring if it is available
0.117:
- support checkout of single package via "osc co PACKAGE" when local dir is project
View
9 README
@@ -115,6 +115,15 @@ described above. So basically just adjust all apiurl sections (it might be the
case that some sections already have the correct format).
+KEYRING USAGE
+
+Osc now can store passwords in Gnome keyring instead of ~/.oscrc. To use it,
+you need python-gnomekeyring and keyring daemon running.
+
+If you want to switch to using Gnome keyring you need to delete apiurl section
+from ~/.oscrc and you will be asked for credentials again, which will be then
+stored in Gnome keyring.
+
USAGE EXAMPLES:
(online at http://en.opensuse.org/Build_Service/CLI )
View
@@ -88,6 +88,8 @@ def get_optparser(self):
optparser.add_option('-c', '--config', dest='conffile',
metavar='FILE',
help='specify alternate configuration file')
+ optparser.add_option('--no-gnome-keyring', action='store_true',
+ help='disable usage of GNOME Keyring')
return optparser
@@ -99,7 +101,8 @@ def postoptparse(self, try_again = True):
override_debug = self.options.debug,
override_http_debug = self.options.http_debug,
override_traceback = self.options.traceback,
- override_post_mortem = self.options.post_mortem)
+ override_post_mortem = self.options.post_mortem,
+ override_no_gnome_keyring = self.options.no_gnome_keyring)
except oscerr.NoConfigfile, e:
print >>sys.stderr, e.msg
print >>sys.stderr, 'Creating osc configuration file %s ...' % e.file
@@ -118,13 +121,7 @@ def postoptparse(self, try_again = True):
import getpass
user = raw_input('Username: ')
passwd = getpass.getpass()
- cp = conf.get_configParser()
- cp.add_section(e.url)
- cp.set(e.url, 'user', user)
- cp.set(e.url, 'pass', passwd)
- file = open(e.file, 'w')
- cp.write(file, True)
- if file: file.close()
+ conf.add_section(e.file, e.url, user, passwd)
if try_again: self.postoptparse(try_again = False)
self.conf = conf
View
@@ -32,6 +32,14 @@
import OscConfigParser
from osc import oscerr
+try:
+ import gobject
+ gobject.set_application_name('osc')
+ import gnomekeyring
+ GNOME_KEYRING = gnomekeyring.is_available()
+except:
+ GNOME_KEYRING = False
+
# being global to this module, this dict can be accessed from outside
# it will hold the parsed configuration
config = { }
@@ -54,6 +62,7 @@
'http_debug': '0',
'traceback': '0',
'post_mortem': '0',
+ 'gnome_keyring': '1',
'cookiejar': '~/.osc_cookiejar',
# enable project tracking by default
'do_package_tracking': '1',
@@ -104,6 +113,9 @@
# print call traces in case of errors
#traceback = 1
+# use GNOME keyring for credentials if available
+#gnome_keyring = 0
+
[%(apiurl)s]
user = %(user)s
pass = %(pass)s
@@ -114,6 +126,8 @@
# additional headers to pass to a request, e.g. for special authentication
#http_headers = Host: foofoobar,
# User: mumblegack
+# Force using of keyring for this API
+#keyring = 1
"""
@@ -261,6 +275,16 @@ def write_initial_config(conffile, entries, custom_template = ''):
conf_template = custom_template or new_conf_template
config = DEFAULTS.copy()
config.update(entries)
+ if config['gnome_keyring'] and GNOME_KEYRING:
+ protocol, host = \
+ parse_apisrv_url(None, config['apisrv'])
+ gnomekeyring.set_network_password_sync(
+ user = config['user'],
+ password = config['pass'],
+ protocol = protocol,
+ server = host)
+ config['user'] = ''
+ config['pass'] = ''
sio = StringIO.StringIO(conf_template.strip() % config)
cp = OscConfigParser.OscConfigParser(DEFAULTS)
cp.readfp(sio)
@@ -279,13 +303,41 @@ def write_initial_config(conffile, entries, custom_template = ''):
finally:
if file: file.close()
+def add_section(filename, url, user, passwd):
+ """
+ Add a section to config file for new api url.
+ """
+ global config
+ cp = get_configParser(filename)
+ try:
+ cp.add_section(url)
+ except OscConfigParser.ConfigParser.DuplicateSectionError:
+ # Section might have existed, but was empty
+ pass
+ if config['gnome_keyring'] and GNOME_KEYRING:
+ protocol, host = \
+ parse_apisrv_url(None, url)
+ gnomekeyring.set_network_password_sync(
+ user = user,
+ password = passwd,
+ protocol = protocol,
+ server = host)
+ cp.set(url, 'keyring', '1')
+ else:
+ cp.set(url, 'user', user)
+ cp.set(url, 'pass', passwd)
+ file = open(filename, 'w')
+ cp.write(file, True)
+ if file: file.close()
+
def get_config(override_conffile = None,
override_apiurl = None,
override_debug = None,
override_http_debug = None,
override_traceback = None,
- override_post_mortem = None):
+ override_post_mortem = None,
+ override_no_gnome_keyring = None):
"""do the actual work (see module documentation)"""
import os
import sys
@@ -346,16 +398,38 @@ def get_config(override_conffile = None,
# 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_gnome_keyring:
+ config['gnome_keyring'] = False
+
aliases = {}
for url in [ x for x in cp.sections() if x != 'general' ]:
# backward compatiblity
scheme, host = \
parse_apisrv_url(config.get('scheme', 'https'), url)
apiurl = urljoin(scheme, host)
- #FIXME: this could actually be the ideal spot to take defaults
- #from the general section.
- user = cp.get(url, 'user')
- password = cp.get(url, 'pass')
+ user = None
+ # Read from gnome keyring if available
+ if config['gnome_keyring'] and GNOME_KEYRING:
+ try:
+ gk_data = gnomekeyring.find_network_password_sync(
+ protocol = scheme,
+ server = host)
+ password = gk_data[0]['password']
+ user = gk_data[0]['user']
+ except gnomekeyring.NoMatchError:
+ # Fallback to file based auth.
+ pass
+ # 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')
+ password = cp.get(url, 'pass')
+ if cp.has_option(url, 'keyring') and cp.get(url, 'keyring'):
+ # This APIURL was configured to use keyring by
+ continue
email = ''
if cp.has_option(url, 'email'):
email = cp.get(url, 'email')

0 comments on commit 7074362

Please sign in to comment.